1/* Run the Expat test suite
2                            __  __            _
3                         ___\ \/ /_ __   __ _| |_
4                        / _ \\  /| '_ \ / _` | __|
5                       |  __//  \| |_) | (_| | |_
6                        \___/_/\_\ .__/ \__,_|\__|
7                                 |_| XML parser
8
9   Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
10   Copyright (c) 2000-2017 Expat development team
11   Licensed under the MIT license:
12
13   Permission is  hereby granted,  free of charge,  to any  person obtaining
14   a  copy  of  this  software   and  associated  documentation  files  (the
15   "Software"),  to  deal in  the  Software  without restriction,  including
16   without  limitation the  rights  to use,  copy,  modify, merge,  publish,
17   distribute, sublicense, and/or sell copies of the Software, and to permit
18   persons  to whom  the Software  is  furnished to  do so,  subject to  the
19   following conditions:
20
21   The above copyright  notice and this permission notice  shall be included
22   in all copies or substantial portions of the Software.
23
24   THE  SOFTWARE  IS  PROVIDED  "AS  IS",  WITHOUT  WARRANTY  OF  ANY  KIND,
25   EXPRESS  OR IMPLIED,  INCLUDING  BUT  NOT LIMITED  TO  THE WARRANTIES  OF
26   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
27   NO EVENT SHALL THE AUTHORS OR  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
28   DAMAGES OR  OTHER LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT,  TORT OR
29   OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
30   USE OR OTHER DEALINGS IN THE SOFTWARE.
31*/
32
33#if defined(NDEBUG)
34#  undef NDEBUG /* because test suite relies on assert(...) at the moment */
35#endif
36
37#ifdef HAVE_EXPAT_CONFIG_H
38#  include <expat_config.h>
39#endif
40
41#include <assert.h>
42#include <stdlib.h>
43#include <stdio.h>
44#include <string.h>
45#include <stddef.h> /* ptrdiff_t */
46#include <ctype.h>
47#include <limits.h>
48
49#if defined(_WIN32) && defined(_MSC_VER) && (_MSC_VER < 1600)
50/* For vs2003/7.1 up to vs2008/9.0; _MSC_VER 1600 is vs2010/10.0 */
51#  if defined(_WIN64)
52typedef __int64 intptr_t;
53#  else
54typedef __int32 intptr_t;
55#  endif
56typedef unsigned __int64 uint64_t;
57#else
58#  include <stdint.h> /* intptr_t uint64_t */
59#endif
60
61#if ! defined(__cplusplus)
62#  if defined(_MSC_VER) && (_MSC_VER <= 1700)
63/* for vs2012/11.0/1700 and earlier Visual Studio compilers */
64#    define bool int
65#    define false 0
66#    define true 1
67#  else
68#    include <stdbool.h>
69#  endif
70#endif
71
72#include "expat.h"
73#include "chardata.h"
74#include "structdata.h"
75#include "internal.h" /* for UNUSED_P only */
76#include "minicheck.h"
77#include "memcheck.h"
78#include "siphash.h"
79#include "ascii.h" /* for ASCII_xxx */
80
81#ifdef XML_LARGE_SIZE
82#  define XML_FMT_INT_MOD "ll"
83#else
84#  define XML_FMT_INT_MOD "l"
85#endif
86
87#ifdef XML_UNICODE_WCHAR_T
88#  define XML_FMT_CHAR "lc"
89#  define XML_FMT_STR "ls"
90#  include <wchar.h>
91#  define xcstrlen(s) wcslen(s)
92#  define xcstrcmp(s, t) wcscmp((s), (t))
93#  define xcstrncmp(s, t, n) wcsncmp((s), (t), (n))
94#  define XCS(s) _XCS(s)
95#  define _XCS(s) L##s
96#else
97#  ifdef XML_UNICODE
98#    error "No support for UTF-16 character without wchar_t in tests"
99#  else
100#    define XML_FMT_CHAR "c"
101#    define XML_FMT_STR "s"
102#    define xcstrlen(s) strlen(s)
103#    define xcstrcmp(s, t) strcmp((s), (t))
104#    define xcstrncmp(s, t, n) strncmp((s), (t), (n))
105#    define XCS(s) s
106#  endif /* XML_UNICODE */
107#endif   /* XML_UNICODE_WCHAR_T */
108
109static XML_Parser g_parser = NULL;
110
111static void
112basic_setup(void) {
113  g_parser = XML_ParserCreate(NULL);
114  if (g_parser == NULL)
115    fail("Parser not created.");
116}
117
118static void
119basic_teardown(void) {
120  if (g_parser != NULL) {
121    XML_ParserFree(g_parser);
122    g_parser = NULL;
123  }
124}
125
126/* Generate a failure using the parser state to create an error message;
127   this should be used when the parser reports an error we weren't
128   expecting.
129*/
130static void
131_xml_failure(XML_Parser parser, const char *file, int line) {
132  char buffer[1024];
133  enum XML_Error err = XML_GetErrorCode(parser);
134  sprintf(buffer,
135          "    %d: %" XML_FMT_STR " (line %" XML_FMT_INT_MOD
136          "u, offset %" XML_FMT_INT_MOD "u)\n    reported from %s, line %d\n",
137          err, XML_ErrorString(err), XML_GetCurrentLineNumber(parser),
138          XML_GetCurrentColumnNumber(parser), file, line);
139  _fail_unless(0, file, line, buffer);
140}
141
142static enum XML_Status
143_XML_Parse_SINGLE_BYTES(XML_Parser parser, const char *s, int len,
144                        int isFinal) {
145  enum XML_Status res = XML_STATUS_ERROR;
146  int offset = 0;
147
148  if (len == 0) {
149    return XML_Parse(parser, s, len, isFinal);
150  }
151
152  for (; offset < len; offset++) {
153    const int innerIsFinal = (offset == len - 1) && isFinal;
154    const char c = s[offset]; /* to help out-of-bounds detection */
155    res = XML_Parse(parser, &c, sizeof(char), innerIsFinal);
156    if (res != XML_STATUS_OK) {
157      return res;
158    }
159  }
160  return res;
161}
162
163#define xml_failure(parser) _xml_failure((parser), __FILE__, __LINE__)
164
165static void
166_expect_failure(const char *text, enum XML_Error errorCode,
167                const char *errorMessage, const char *file, int lineno) {
168  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
169      == XML_STATUS_OK)
170    /* Hackish use of _fail_unless() macro, but let's us report
171       the right filename and line number. */
172    _fail_unless(0, file, lineno, errorMessage);
173  if (XML_GetErrorCode(g_parser) != errorCode)
174    _xml_failure(g_parser, file, lineno);
175}
176
177#define expect_failure(text, errorCode, errorMessage)                          \
178  _expect_failure((text), (errorCode), (errorMessage), __FILE__, __LINE__)
179
180/* Dummy handlers for when we need to set a handler to tickle a bug,
181   but it doesn't need to do anything.
182*/
183static unsigned long dummy_handler_flags = 0;
184
185#define DUMMY_START_DOCTYPE_HANDLER_FLAG (1UL << 0)
186#define DUMMY_END_DOCTYPE_HANDLER_FLAG (1UL << 1)
187#define DUMMY_ENTITY_DECL_HANDLER_FLAG (1UL << 2)
188#define DUMMY_NOTATION_DECL_HANDLER_FLAG (1UL << 3)
189#define DUMMY_ELEMENT_DECL_HANDLER_FLAG (1UL << 4)
190#define DUMMY_ATTLIST_DECL_HANDLER_FLAG (1UL << 5)
191#define DUMMY_COMMENT_HANDLER_FLAG (1UL << 6)
192#define DUMMY_PI_HANDLER_FLAG (1UL << 7)
193#define DUMMY_START_ELEMENT_HANDLER_FLAG (1UL << 8)
194#define DUMMY_START_CDATA_HANDLER_FLAG (1UL << 9)
195#define DUMMY_END_CDATA_HANDLER_FLAG (1UL << 10)
196#define DUMMY_UNPARSED_ENTITY_DECL_HANDLER_FLAG (1UL << 11)
197#define DUMMY_START_NS_DECL_HANDLER_FLAG (1UL << 12)
198#define DUMMY_END_NS_DECL_HANDLER_FLAG (1UL << 13)
199#define DUMMY_START_DOCTYPE_DECL_HANDLER_FLAG (1UL << 14)
200#define DUMMY_END_DOCTYPE_DECL_HANDLER_FLAG (1UL << 15)
201#define DUMMY_SKIP_HANDLER_FLAG (1UL << 16)
202#define DUMMY_DEFAULT_HANDLER_FLAG (1UL << 17)
203
204static void XMLCALL
205dummy_xdecl_handler(void *userData, const XML_Char *version,
206                    const XML_Char *encoding, int standalone) {
207  UNUSED_P(userData);
208  UNUSED_P(version);
209  UNUSED_P(encoding);
210  UNUSED_P(standalone);
211}
212
213static void XMLCALL
214dummy_start_doctype_handler(void *userData, const XML_Char *doctypeName,
215                            const XML_Char *sysid, const XML_Char *pubid,
216                            int has_internal_subset) {
217  UNUSED_P(userData);
218  UNUSED_P(doctypeName);
219  UNUSED_P(sysid);
220  UNUSED_P(pubid);
221  UNUSED_P(has_internal_subset);
222  dummy_handler_flags |= DUMMY_START_DOCTYPE_HANDLER_FLAG;
223}
224
225static void XMLCALL
226dummy_end_doctype_handler(void *userData) {
227  UNUSED_P(userData);
228  dummy_handler_flags |= DUMMY_END_DOCTYPE_HANDLER_FLAG;
229}
230
231static void XMLCALL
232dummy_entity_decl_handler(void *userData, const XML_Char *entityName,
233                          int is_parameter_entity, const XML_Char *value,
234                          int value_length, const XML_Char *base,
235                          const XML_Char *systemId, const XML_Char *publicId,
236                          const XML_Char *notationName) {
237  UNUSED_P(userData);
238  UNUSED_P(entityName);
239  UNUSED_P(is_parameter_entity);
240  UNUSED_P(value);
241  UNUSED_P(value_length);
242  UNUSED_P(base);
243  UNUSED_P(systemId);
244  UNUSED_P(publicId);
245  UNUSED_P(notationName);
246  dummy_handler_flags |= DUMMY_ENTITY_DECL_HANDLER_FLAG;
247}
248
249static void XMLCALL
250dummy_notation_decl_handler(void *userData, const XML_Char *notationName,
251                            const XML_Char *base, const XML_Char *systemId,
252                            const XML_Char *publicId) {
253  UNUSED_P(userData);
254  UNUSED_P(notationName);
255  UNUSED_P(base);
256  UNUSED_P(systemId);
257  UNUSED_P(publicId);
258  dummy_handler_flags |= DUMMY_NOTATION_DECL_HANDLER_FLAG;
259}
260
261static void XMLCALL
262dummy_element_decl_handler(void *userData, const XML_Char *name,
263                           XML_Content *model) {
264  UNUSED_P(userData);
265  UNUSED_P(name);
266  /* The content model must be freed by the handler.  Unfortunately
267   * we cannot pass the parser as the userData because this is used
268   * with other handlers that require other userData.
269   */
270  XML_FreeContentModel(g_parser, model);
271  dummy_handler_flags |= DUMMY_ELEMENT_DECL_HANDLER_FLAG;
272}
273
274static void XMLCALL
275dummy_attlist_decl_handler(void *userData, const XML_Char *elname,
276                           const XML_Char *attname, const XML_Char *att_type,
277                           const XML_Char *dflt, int isrequired) {
278  UNUSED_P(userData);
279  UNUSED_P(elname);
280  UNUSED_P(attname);
281  UNUSED_P(att_type);
282  UNUSED_P(dflt);
283  UNUSED_P(isrequired);
284  dummy_handler_flags |= DUMMY_ATTLIST_DECL_HANDLER_FLAG;
285}
286
287static void XMLCALL
288dummy_comment_handler(void *userData, const XML_Char *data) {
289  UNUSED_P(userData);
290  UNUSED_P(data);
291  dummy_handler_flags |= DUMMY_COMMENT_HANDLER_FLAG;
292}
293
294static void XMLCALL
295dummy_pi_handler(void *userData, const XML_Char *target, const XML_Char *data) {
296  UNUSED_P(userData);
297  UNUSED_P(target);
298  UNUSED_P(data);
299  dummy_handler_flags |= DUMMY_PI_HANDLER_FLAG;
300}
301
302static void XMLCALL
303dummy_start_element(void *userData, const XML_Char *name,
304                    const XML_Char **atts) {
305  UNUSED_P(userData);
306  UNUSED_P(name);
307  UNUSED_P(atts);
308  dummy_handler_flags |= DUMMY_START_ELEMENT_HANDLER_FLAG;
309}
310
311static void XMLCALL
312dummy_end_element(void *userData, const XML_Char *name) {
313  UNUSED_P(userData);
314  UNUSED_P(name);
315}
316
317static void XMLCALL
318dummy_start_cdata_handler(void *userData) {
319  UNUSED_P(userData);
320  dummy_handler_flags |= DUMMY_START_CDATA_HANDLER_FLAG;
321}
322
323static void XMLCALL
324dummy_end_cdata_handler(void *userData) {
325  UNUSED_P(userData);
326  dummy_handler_flags |= DUMMY_END_CDATA_HANDLER_FLAG;
327}
328
329static void XMLCALL
330dummy_cdata_handler(void *userData, const XML_Char *s, int len) {
331  UNUSED_P(userData);
332  UNUSED_P(s);
333  UNUSED_P(len);
334}
335
336static void XMLCALL
337dummy_start_namespace_decl_handler(void *userData, const XML_Char *prefix,
338                                   const XML_Char *uri) {
339  UNUSED_P(userData);
340  UNUSED_P(prefix);
341  UNUSED_P(uri);
342  dummy_handler_flags |= DUMMY_START_NS_DECL_HANDLER_FLAG;
343}
344
345static void XMLCALL
346dummy_end_namespace_decl_handler(void *userData, const XML_Char *prefix) {
347  UNUSED_P(userData);
348  UNUSED_P(prefix);
349  dummy_handler_flags |= DUMMY_END_NS_DECL_HANDLER_FLAG;
350}
351
352/* This handler is obsolete, but while the code exists we should
353 * ensure that dealing with the handler is covered by tests.
354 */
355static void XMLCALL
356dummy_unparsed_entity_decl_handler(void *userData, const XML_Char *entityName,
357                                   const XML_Char *base,
358                                   const XML_Char *systemId,
359                                   const XML_Char *publicId,
360                                   const XML_Char *notationName) {
361  UNUSED_P(userData);
362  UNUSED_P(entityName);
363  UNUSED_P(base);
364  UNUSED_P(systemId);
365  UNUSED_P(publicId);
366  UNUSED_P(notationName);
367  dummy_handler_flags |= DUMMY_UNPARSED_ENTITY_DECL_HANDLER_FLAG;
368}
369
370static void XMLCALL
371dummy_default_handler(void *userData, const XML_Char *s, int len) {
372  UNUSED_P(userData);
373  UNUSED_P(s);
374  UNUSED_P(len);
375}
376
377static void XMLCALL
378dummy_start_doctype_decl_handler(void *userData, const XML_Char *doctypeName,
379                                 const XML_Char *sysid, const XML_Char *pubid,
380                                 int has_internal_subset) {
381  UNUSED_P(userData);
382  UNUSED_P(doctypeName);
383  UNUSED_P(sysid);
384  UNUSED_P(pubid);
385  UNUSED_P(has_internal_subset);
386  dummy_handler_flags |= DUMMY_START_DOCTYPE_DECL_HANDLER_FLAG;
387}
388
389static void XMLCALL
390dummy_end_doctype_decl_handler(void *userData) {
391  UNUSED_P(userData);
392  dummy_handler_flags |= DUMMY_END_DOCTYPE_DECL_HANDLER_FLAG;
393}
394
395static void XMLCALL
396dummy_skip_handler(void *userData, const XML_Char *entityName,
397                   int is_parameter_entity) {
398  UNUSED_P(userData);
399  UNUSED_P(entityName);
400  UNUSED_P(is_parameter_entity);
401  dummy_handler_flags |= DUMMY_SKIP_HANDLER_FLAG;
402}
403
404/* Useful external entity handler */
405typedef struct ExtOption {
406  const XML_Char *system_id;
407  const char *parse_text;
408} ExtOption;
409
410static int XMLCALL
411external_entity_optioner(XML_Parser parser, const XML_Char *context,
412                         const XML_Char *base, const XML_Char *systemId,
413                         const XML_Char *publicId) {
414  ExtOption *options = (ExtOption *)XML_GetUserData(parser);
415  XML_Parser ext_parser;
416
417  UNUSED_P(base);
418  UNUSED_P(publicId);
419  while (options->parse_text != NULL) {
420    if (! xcstrcmp(systemId, options->system_id)) {
421      enum XML_Status rc;
422      ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
423      if (ext_parser == NULL)
424        return XML_STATUS_ERROR;
425      rc = _XML_Parse_SINGLE_BYTES(ext_parser, options->parse_text,
426                                   (int)strlen(options->parse_text), XML_TRUE);
427      XML_ParserFree(ext_parser);
428      return rc;
429    }
430    options++;
431  }
432  fail("No suitable option found");
433  return XML_STATUS_ERROR;
434}
435
436/*
437 * Parameter entity evaluation support.
438 */
439#define ENTITY_MATCH_FAIL (-1)
440#define ENTITY_MATCH_NOT_FOUND (0)
441#define ENTITY_MATCH_SUCCESS (1)
442static const XML_Char *entity_name_to_match = NULL;
443static const XML_Char *entity_value_to_match = NULL;
444static int entity_match_flag = ENTITY_MATCH_NOT_FOUND;
445
446static void XMLCALL
447param_entity_match_handler(void *userData, const XML_Char *entityName,
448                           int is_parameter_entity, const XML_Char *value,
449                           int value_length, const XML_Char *base,
450                           const XML_Char *systemId, const XML_Char *publicId,
451                           const XML_Char *notationName) {
452  UNUSED_P(userData);
453  UNUSED_P(base);
454  UNUSED_P(systemId);
455  UNUSED_P(publicId);
456  UNUSED_P(notationName);
457  if (! is_parameter_entity || entity_name_to_match == NULL
458      || entity_value_to_match == NULL) {
459    return;
460  }
461  if (! xcstrcmp(entityName, entity_name_to_match)) {
462    /* The cast here is safe because we control the horizontal and
463     * the vertical, and we therefore know our strings are never
464     * going to overflow an int.
465     */
466    if (value_length != (int)xcstrlen(entity_value_to_match)
467        || xcstrncmp(value, entity_value_to_match, value_length)) {
468      entity_match_flag = ENTITY_MATCH_FAIL;
469    } else {
470      entity_match_flag = ENTITY_MATCH_SUCCESS;
471    }
472  }
473  /* Else leave the match flag alone */
474}
475
476/*
477 * Character & encoding tests.
478 */
479
480START_TEST(test_nul_byte) {
481  char text[] = "<doc>\0</doc>";
482
483  /* test that a NUL byte (in US-ASCII data) is an error */
484  if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
485      == XML_STATUS_OK)
486    fail("Parser did not report error on NUL-byte.");
487  if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
488    xml_failure(g_parser);
489}
490END_TEST
491
492START_TEST(test_u0000_char) {
493  /* test that a NUL byte (in US-ASCII data) is an error */
494  expect_failure("<doc>&#0;</doc>", XML_ERROR_BAD_CHAR_REF,
495                 "Parser did not report error on NUL-byte.");
496}
497END_TEST
498
499START_TEST(test_siphash_self) {
500  if (! sip24_valid())
501    fail("SipHash self-test failed");
502}
503END_TEST
504
505START_TEST(test_siphash_spec) {
506  /* https://131002.net/siphash/siphash.pdf (page 19, "Test values") */
507  const char message[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09"
508                         "\x0a\x0b\x0c\x0d\x0e";
509  const size_t len = sizeof(message) - 1;
510  const uint64_t expected = _SIP_ULL(0xa129ca61U, 0x49be45e5U);
511  struct siphash state;
512  struct sipkey key;
513
514  sip_tokey(&key, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09"
515                  "\x0a\x0b\x0c\x0d\x0e\x0f");
516  sip24_init(&state, &key);
517
518  /* Cover spread across calls */
519  sip24_update(&state, message, 4);
520  sip24_update(&state, message + 4, len - 4);
521
522  /* Cover null length */
523  sip24_update(&state, message, 0);
524
525  if (sip24_final(&state) != expected)
526    fail("sip24_final failed spec test\n");
527
528  /* Cover wrapper */
529  if (siphash24(message, len, &key) != expected)
530    fail("siphash24 failed spec test\n");
531}
532END_TEST
533
534START_TEST(test_bom_utf8) {
535  /* This test is really just making sure we don't core on a UTF-8 BOM. */
536  const char *text = "\357\273\277<e/>";
537
538  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
539      == XML_STATUS_ERROR)
540    xml_failure(g_parser);
541}
542END_TEST
543
544START_TEST(test_bom_utf16_be) {
545  char text[] = "\376\377\0<\0e\0/\0>";
546
547  if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
548      == XML_STATUS_ERROR)
549    xml_failure(g_parser);
550}
551END_TEST
552
553START_TEST(test_bom_utf16_le) {
554  char text[] = "\377\376<\0e\0/\0>\0";
555
556  if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
557      == XML_STATUS_ERROR)
558    xml_failure(g_parser);
559}
560END_TEST
561
562/* Parse whole buffer at once to exercise a different code path */
563START_TEST(test_nobom_utf16_le) {
564  char text[] = " \0<\0e\0/\0>\0";
565
566  if (XML_Parse(g_parser, text, sizeof(text) - 1, XML_TRUE) == XML_STATUS_ERROR)
567    xml_failure(g_parser);
568}
569END_TEST
570
571static void XMLCALL
572accumulate_characters(void *userData, const XML_Char *s, int len) {
573  CharData_AppendXMLChars((CharData *)userData, s, len);
574}
575
576static void XMLCALL
577accumulate_attribute(void *userData, const XML_Char *name,
578                     const XML_Char **atts) {
579  CharData *storage = (CharData *)userData;
580  UNUSED_P(name);
581  /* Check there are attributes to deal with */
582  if (atts == NULL)
583    return;
584
585  while (storage->count < 0 && atts[0] != NULL) {
586    /* "accumulate" the value of the first attribute we see */
587    CharData_AppendXMLChars(storage, atts[1], -1);
588    atts += 2;
589  }
590}
591
592static void
593_run_character_check(const char *text, const XML_Char *expected,
594                     const char *file, int line) {
595  CharData storage;
596
597  CharData_Init(&storage);
598  XML_SetUserData(g_parser, &storage);
599  XML_SetCharacterDataHandler(g_parser, accumulate_characters);
600  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
601      == XML_STATUS_ERROR)
602    _xml_failure(g_parser, file, line);
603  CharData_CheckXMLChars(&storage, expected);
604}
605
606#define run_character_check(text, expected)                                    \
607  _run_character_check(text, expected, __FILE__, __LINE__)
608
609static void
610_run_attribute_check(const char *text, const XML_Char *expected,
611                     const char *file, int line) {
612  CharData storage;
613
614  CharData_Init(&storage);
615  XML_SetUserData(g_parser, &storage);
616  XML_SetStartElementHandler(g_parser, accumulate_attribute);
617  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
618      == XML_STATUS_ERROR)
619    _xml_failure(g_parser, file, line);
620  CharData_CheckXMLChars(&storage, expected);
621}
622
623#define run_attribute_check(text, expected)                                    \
624  _run_attribute_check(text, expected, __FILE__, __LINE__)
625
626typedef struct ExtTest {
627  const char *parse_text;
628  const XML_Char *encoding;
629  CharData *storage;
630} ExtTest;
631
632static void XMLCALL
633ext_accumulate_characters(void *userData, const XML_Char *s, int len) {
634  ExtTest *test_data = (ExtTest *)userData;
635  accumulate_characters(test_data->storage, s, len);
636}
637
638static void
639_run_ext_character_check(const char *text, ExtTest *test_data,
640                         const XML_Char *expected, const char *file, int line) {
641  CharData *const storage = (CharData *)malloc(sizeof(CharData));
642
643  CharData_Init(storage);
644  test_data->storage = storage;
645  XML_SetUserData(g_parser, test_data);
646  XML_SetCharacterDataHandler(g_parser, ext_accumulate_characters);
647  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
648      == XML_STATUS_ERROR)
649    _xml_failure(g_parser, file, line);
650  CharData_CheckXMLChars(storage, expected);
651
652  free(storage);
653}
654
655#define run_ext_character_check(text, test_data, expected)                     \
656  _run_ext_character_check(text, test_data, expected, __FILE__, __LINE__)
657
658/* Regression test for SF bug #491986. */
659START_TEST(test_danish_latin1) {
660  const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
661                     "<e>J\xF8rgen \xE6\xF8\xE5\xC6\xD8\xC5</e>";
662#ifdef XML_UNICODE
663  const XML_Char *expected
664      = XCS("J\x00f8rgen \x00e6\x00f8\x00e5\x00c6\x00d8\x00c5");
665#else
666  const XML_Char *expected
667      = XCS("J\xC3\xB8rgen \xC3\xA6\xC3\xB8\xC3\xA5\xC3\x86\xC3\x98\xC3\x85");
668#endif
669  run_character_check(text, expected);
670}
671END_TEST
672
673/* Regression test for SF bug #514281. */
674START_TEST(test_french_charref_hexidecimal) {
675  const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
676                     "<doc>&#xE9;&#xE8;&#xE0;&#xE7;&#xEA;&#xC8;</doc>";
677#ifdef XML_UNICODE
678  const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8");
679#else
680  const XML_Char *expected
681      = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
682#endif
683  run_character_check(text, expected);
684}
685END_TEST
686
687START_TEST(test_french_charref_decimal) {
688  const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
689                     "<doc>&#233;&#232;&#224;&#231;&#234;&#200;</doc>";
690#ifdef XML_UNICODE
691  const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8");
692#else
693  const XML_Char *expected
694      = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
695#endif
696  run_character_check(text, expected);
697}
698END_TEST
699
700START_TEST(test_french_latin1) {
701  const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
702                     "<doc>\xE9\xE8\xE0\xE7\xEa\xC8</doc>";
703#ifdef XML_UNICODE
704  const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8");
705#else
706  const XML_Char *expected
707      = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
708#endif
709  run_character_check(text, expected);
710}
711END_TEST
712
713START_TEST(test_french_utf8) {
714  const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
715                     "<doc>\xC3\xA9</doc>";
716#ifdef XML_UNICODE
717  const XML_Char *expected = XCS("\x00e9");
718#else
719  const XML_Char *expected = XCS("\xC3\xA9");
720#endif
721  run_character_check(text, expected);
722}
723END_TEST
724
725/* Regression test for SF bug #600479.
726   XXX There should be a test that exercises all legal XML Unicode
727   characters as PCDATA and attribute value content, and XML Name
728   characters as part of element and attribute names.
729*/
730START_TEST(test_utf8_false_rejection) {
731  const char *text = "<doc>\xEF\xBA\xBF</doc>";
732#ifdef XML_UNICODE
733  const XML_Char *expected = XCS("\xfebf");
734#else
735  const XML_Char *expected = XCS("\xEF\xBA\xBF");
736#endif
737  run_character_check(text, expected);
738}
739END_TEST
740
741/* Regression test for SF bug #477667.
742   This test assures that any 8-bit character followed by a 7-bit
743   character will not be mistakenly interpreted as a valid UTF-8
744   sequence.
745*/
746START_TEST(test_illegal_utf8) {
747  char text[100];
748  int i;
749
750  for (i = 128; i <= 255; ++i) {
751    sprintf(text, "<e>%ccd</e>", i);
752    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
753        == XML_STATUS_OK) {
754      sprintf(text, "expected token error for '%c' (ordinal %d) in UTF-8 text",
755              i, i);
756      fail(text);
757    } else if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
758      xml_failure(g_parser);
759    /* Reset the parser since we use the same parser repeatedly. */
760    XML_ParserReset(g_parser, NULL);
761  }
762}
763END_TEST
764
765/* Examples, not masks: */
766#define UTF8_LEAD_1 "\x7f" /* 0b01111111 */
767#define UTF8_LEAD_2 "\xdf" /* 0b11011111 */
768#define UTF8_LEAD_3 "\xef" /* 0b11101111 */
769#define UTF8_LEAD_4 "\xf7" /* 0b11110111 */
770#define UTF8_FOLLOW "\xbf" /* 0b10111111 */
771
772START_TEST(test_utf8_auto_align) {
773  struct TestCase {
774    ptrdiff_t expectedMovementInChars;
775    const char *input;
776  };
777
778  struct TestCase cases[] = {
779      {00, ""},
780
781      {00, UTF8_LEAD_1},
782
783      {-1, UTF8_LEAD_2},
784      {00, UTF8_LEAD_2 UTF8_FOLLOW},
785
786      {-1, UTF8_LEAD_3},
787      {-2, UTF8_LEAD_3 UTF8_FOLLOW},
788      {00, UTF8_LEAD_3 UTF8_FOLLOW UTF8_FOLLOW},
789
790      {-1, UTF8_LEAD_4},
791      {-2, UTF8_LEAD_4 UTF8_FOLLOW},
792      {-3, UTF8_LEAD_4 UTF8_FOLLOW UTF8_FOLLOW},
793      {00, UTF8_LEAD_4 UTF8_FOLLOW UTF8_FOLLOW UTF8_FOLLOW},
794  };
795
796  size_t i = 0;
797  bool success = true;
798  for (; i < sizeof(cases) / sizeof(*cases); i++) {
799    const char *fromLim = cases[i].input + strlen(cases[i].input);
800    const char *const fromLimInitially = fromLim;
801    ptrdiff_t actualMovementInChars;
802
803    _INTERNAL_trim_to_complete_utf8_characters(cases[i].input, &fromLim);
804
805    actualMovementInChars = (fromLim - fromLimInitially);
806    if (actualMovementInChars != cases[i].expectedMovementInChars) {
807      size_t j = 0;
808      success = false;
809      printf("[-] UTF-8 case %2u: Expected movement by %2d chars"
810             ", actually moved by %2d chars: \"",
811             (unsigned)(i + 1), (int)cases[i].expectedMovementInChars,
812             (int)actualMovementInChars);
813      for (; j < strlen(cases[i].input); j++) {
814        printf("\\x%02x", (unsigned char)cases[i].input[j]);
815      }
816      printf("\"\n");
817    }
818  }
819
820  if (! success) {
821    fail("UTF-8 auto-alignment is not bullet-proof\n");
822  }
823}
824END_TEST
825
826START_TEST(test_utf16) {
827  /* <?xml version="1.0" encoding="UTF-16"?>
828   *  <doc a='123'>some {A} text</doc>
829   *
830   * where {A} is U+FF21, FULLWIDTH LATIN CAPITAL LETTER A
831   */
832  char text[]
833      = "\000<\000?\000x\000m\000\154\000 \000v\000e\000r\000s\000i\000o"
834        "\000n\000=\000'\0001\000.\000\060\000'\000 \000e\000n\000c\000o"
835        "\000d\000i\000n\000g\000=\000'\000U\000T\000F\000-\0001\000\066"
836        "\000'\000?\000>\000\n"
837        "\000<\000d\000o\000c\000 \000a\000=\000'\0001\0002\0003\000'\000>"
838        "\000s\000o\000m\000e\000 \xff\x21\000 \000t\000e\000x\000t\000"
839        "<\000/\000d\000o\000c\000>";
840#ifdef XML_UNICODE
841  const XML_Char *expected = XCS("some \xff21 text");
842#else
843  const XML_Char *expected = XCS("some \357\274\241 text");
844#endif
845  CharData storage;
846
847  CharData_Init(&storage);
848  XML_SetUserData(g_parser, &storage);
849  XML_SetCharacterDataHandler(g_parser, accumulate_characters);
850  if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
851      == XML_STATUS_ERROR)
852    xml_failure(g_parser);
853  CharData_CheckXMLChars(&storage, expected);
854}
855END_TEST
856
857START_TEST(test_utf16_le_epilog_newline) {
858  unsigned int first_chunk_bytes = 17;
859  char text[] = "\xFF\xFE"                  /* BOM */
860                "<\000e\000/\000>\000"      /* document element */
861                "\r\000\n\000\r\000\n\000"; /* epilog */
862
863  if (first_chunk_bytes >= sizeof(text) - 1)
864    fail("bad value of first_chunk_bytes");
865  if (_XML_Parse_SINGLE_BYTES(g_parser, text, first_chunk_bytes, XML_FALSE)
866      == XML_STATUS_ERROR)
867    xml_failure(g_parser);
868  else {
869    enum XML_Status rc;
870    rc = _XML_Parse_SINGLE_BYTES(g_parser, text + first_chunk_bytes,
871                                 sizeof(text) - first_chunk_bytes - 1,
872                                 XML_TRUE);
873    if (rc == XML_STATUS_ERROR)
874      xml_failure(g_parser);
875  }
876}
877END_TEST
878
879/* Test that an outright lie in the encoding is faulted */
880START_TEST(test_not_utf16) {
881  const char *text = "<?xml version='1.0' encoding='utf-16'?>"
882                     "<doc>Hi</doc>";
883
884  /* Use a handler to provoke the appropriate code paths */
885  XML_SetXmlDeclHandler(g_parser, dummy_xdecl_handler);
886  expect_failure(text, XML_ERROR_INCORRECT_ENCODING,
887                 "UTF-16 declared in UTF-8 not faulted");
888}
889END_TEST
890
891/* Test that an unknown encoding is rejected */
892START_TEST(test_bad_encoding) {
893  const char *text = "<doc>Hi</doc>";
894
895  if (! XML_SetEncoding(g_parser, XCS("unknown-encoding")))
896    fail("XML_SetEncoding failed");
897  expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
898                 "Unknown encoding not faulted");
899}
900END_TEST
901
902/* Regression test for SF bug #481609, #774028. */
903START_TEST(test_latin1_umlauts) {
904  const char *text
905      = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
906        "<e a='\xE4 \xF6 \xFC &#228; &#246; &#252; &#x00E4; &#x0F6; &#xFC; >'\n"
907        "  >\xE4 \xF6 \xFC &#228; &#246; &#252; &#x00E4; &#x0F6; &#xFC; ></e>";
908#ifdef XML_UNICODE
909  /* Expected results in UTF-16 */
910  const XML_Char *expected = XCS("\x00e4 \x00f6 \x00fc ")
911      XCS("\x00e4 \x00f6 \x00fc ") XCS("\x00e4 \x00f6 \x00fc >");
912#else
913  /* Expected results in UTF-8 */
914  const XML_Char *expected = XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC ")
915      XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC ") XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC >");
916#endif
917
918  run_character_check(text, expected);
919  XML_ParserReset(g_parser, NULL);
920  run_attribute_check(text, expected);
921  /* Repeat with a default handler */
922  XML_ParserReset(g_parser, NULL);
923  XML_SetDefaultHandler(g_parser, dummy_default_handler);
924  run_character_check(text, expected);
925  XML_ParserReset(g_parser, NULL);
926  XML_SetDefaultHandler(g_parser, dummy_default_handler);
927  run_attribute_check(text, expected);
928}
929END_TEST
930
931/* Test that an element name with a 4-byte UTF-8 character is rejected */
932START_TEST(test_long_utf8_character) {
933  const char *text
934      = "<?xml version='1.0' encoding='utf-8'?>\n"
935        /* 0xf0 0x90 0x80 0x80 = U+10000, the first Linear B character */
936        "<do\xf0\x90\x80\x80/>";
937  expect_failure(text, XML_ERROR_INVALID_TOKEN,
938                 "4-byte UTF-8 character in element name not faulted");
939}
940END_TEST
941
942/* Test that a long latin-1 attribute (too long to convert in one go)
943 * is correctly converted
944 */
945START_TEST(test_long_latin1_attribute) {
946  const char *text
947      = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
948        "<doc att='"
949        /* 64 characters per line */
950        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
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        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
966        /* Last character splits across a buffer boundary */
967        "\xe4'>\n</doc>";
968
969  const XML_Char *expected =
970      /* 64 characters per line */
971      /* clang-format off */
972        XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
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("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO")
988  /* clang-format on */
989#ifdef XML_UNICODE
990                                                  XCS("\x00e4");
991#else
992                                                  XCS("\xc3\xa4");
993#endif
994
995  run_attribute_check(text, expected);
996}
997END_TEST
998
999/* Test that a long ASCII attribute (too long to convert in one go)
1000 * is correctly converted
1001 */
1002START_TEST(test_long_ascii_attribute) {
1003  const char *text
1004      = "<?xml version='1.0' encoding='us-ascii'?>\n"
1005        "<doc att='"
1006        /* 64 characters per line */
1007        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
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        "01234'>\n</doc>";
1024  const XML_Char *expected =
1025      /* 64 characters per line */
1026      /* clang-format off */
1027        XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
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("01234");
1044  /* clang-format on */
1045
1046  run_attribute_check(text, expected);
1047}
1048END_TEST
1049
1050/* Regression test #1 for SF bug #653180. */
1051START_TEST(test_line_number_after_parse) {
1052  const char *text = "<tag>\n"
1053                     "\n"
1054                     "\n</tag>";
1055  XML_Size lineno;
1056
1057  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
1058      == XML_STATUS_ERROR)
1059    xml_failure(g_parser);
1060  lineno = XML_GetCurrentLineNumber(g_parser);
1061  if (lineno != 4) {
1062    char buffer[100];
1063    sprintf(buffer, "expected 4 lines, saw %" XML_FMT_INT_MOD "u", lineno);
1064    fail(buffer);
1065  }
1066}
1067END_TEST
1068
1069/* Regression test #2 for SF bug #653180. */
1070START_TEST(test_column_number_after_parse) {
1071  const char *text = "<tag></tag>";
1072  XML_Size colno;
1073
1074  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
1075      == XML_STATUS_ERROR)
1076    xml_failure(g_parser);
1077  colno = XML_GetCurrentColumnNumber(g_parser);
1078  if (colno != 11) {
1079    char buffer[100];
1080    sprintf(buffer, "expected 11 columns, saw %" XML_FMT_INT_MOD "u", colno);
1081    fail(buffer);
1082  }
1083}
1084END_TEST
1085
1086#define STRUCT_START_TAG 0
1087#define STRUCT_END_TAG 1
1088static void XMLCALL
1089start_element_event_handler2(void *userData, const XML_Char *name,
1090                             const XML_Char **attr) {
1091  StructData *storage = (StructData *)userData;
1092  UNUSED_P(attr);
1093  StructData_AddItem(storage, name, XML_GetCurrentColumnNumber(g_parser),
1094                     XML_GetCurrentLineNumber(g_parser), STRUCT_START_TAG);
1095}
1096
1097static void XMLCALL
1098end_element_event_handler2(void *userData, const XML_Char *name) {
1099  StructData *storage = (StructData *)userData;
1100  StructData_AddItem(storage, name, XML_GetCurrentColumnNumber(g_parser),
1101                     XML_GetCurrentLineNumber(g_parser), STRUCT_END_TAG);
1102}
1103
1104/* Regression test #3 for SF bug #653180. */
1105START_TEST(test_line_and_column_numbers_inside_handlers) {
1106  const char *text = "<a>\n"      /* Unix end-of-line */
1107                     "  <b>\r\n"  /* Windows end-of-line */
1108                     "    <c/>\r" /* Mac OS end-of-line */
1109                     "  </b>\n"
1110                     "  <d>\n"
1111                     "    <f/>\n"
1112                     "  </d>\n"
1113                     "</a>";
1114  const StructDataEntry expected[]
1115      = {{XCS("a"), 0, 1, STRUCT_START_TAG}, {XCS("b"), 2, 2, STRUCT_START_TAG},
1116         {XCS("c"), 4, 3, STRUCT_START_TAG}, {XCS("c"), 8, 3, STRUCT_END_TAG},
1117         {XCS("b"), 2, 4, STRUCT_END_TAG},   {XCS("d"), 2, 5, STRUCT_START_TAG},
1118         {XCS("f"), 4, 6, STRUCT_START_TAG}, {XCS("f"), 8, 6, STRUCT_END_TAG},
1119         {XCS("d"), 2, 7, STRUCT_END_TAG},   {XCS("a"), 0, 8, STRUCT_END_TAG}};
1120  const int expected_count = sizeof(expected) / sizeof(StructDataEntry);
1121  StructData storage;
1122
1123  StructData_Init(&storage);
1124  XML_SetUserData(g_parser, &storage);
1125  XML_SetStartElementHandler(g_parser, start_element_event_handler2);
1126  XML_SetEndElementHandler(g_parser, end_element_event_handler2);
1127  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1128      == XML_STATUS_ERROR)
1129    xml_failure(g_parser);
1130
1131  StructData_CheckItems(&storage, expected, expected_count);
1132  StructData_Dispose(&storage);
1133}
1134END_TEST
1135
1136/* Regression test #4 for SF bug #653180. */
1137START_TEST(test_line_number_after_error) {
1138  const char *text = "<a>\n"
1139                     "  <b>\n"
1140                     "  </a>"; /* missing </b> */
1141  XML_Size lineno;
1142  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
1143      != XML_STATUS_ERROR)
1144    fail("Expected a parse error");
1145
1146  lineno = XML_GetCurrentLineNumber(g_parser);
1147  if (lineno != 3) {
1148    char buffer[100];
1149    sprintf(buffer, "expected 3 lines, saw %" XML_FMT_INT_MOD "u", lineno);
1150    fail(buffer);
1151  }
1152}
1153END_TEST
1154
1155/* Regression test #5 for SF bug #653180. */
1156START_TEST(test_column_number_after_error) {
1157  const char *text = "<a>\n"
1158                     "  <b>\n"
1159                     "  </a>"; /* missing </b> */
1160  XML_Size colno;
1161  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
1162      != XML_STATUS_ERROR)
1163    fail("Expected a parse error");
1164
1165  colno = XML_GetCurrentColumnNumber(g_parser);
1166  if (colno != 4) {
1167    char buffer[100];
1168    sprintf(buffer, "expected 4 columns, saw %" XML_FMT_INT_MOD "u", colno);
1169    fail(buffer);
1170  }
1171}
1172END_TEST
1173
1174/* Regression test for SF bug #478332. */
1175START_TEST(test_really_long_lines) {
1176  /* This parses an input line longer than INIT_DATA_BUF_SIZE
1177     characters long (defined to be 1024 in xmlparse.c).  We take a
1178     really cheesy approach to building the input buffer, because
1179     this avoids writing bugs in buffer-filling code.
1180  */
1181  const char *text
1182      = "<e>"
1183        /* 64 chars */
1184        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1185        /* until we have at least 1024 characters on the line: */
1186        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
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        "</e>";
1203  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1204      == XML_STATUS_ERROR)
1205    xml_failure(g_parser);
1206}
1207END_TEST
1208
1209/* Test cdata processing across a buffer boundary */
1210START_TEST(test_really_long_encoded_lines) {
1211  /* As above, except that we want to provoke an output buffer
1212   * overflow with a non-trivial encoding.  For this we need to pass
1213   * the whole cdata in one go, not byte-by-byte.
1214   */
1215  void *buffer;
1216  const char *text
1217      = "<?xml version='1.0' encoding='iso-8859-1'?>"
1218        "<e>"
1219        /* 64 chars */
1220        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
1221        /* until we have at least 1024 characters on the line: */
1222        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
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        "</e>";
1239  int parse_len = (int)strlen(text);
1240
1241  /* Need a cdata handler to provoke the code path we want to test */
1242  XML_SetCharacterDataHandler(g_parser, dummy_cdata_handler);
1243  buffer = XML_GetBuffer(g_parser, parse_len);
1244  if (buffer == NULL)
1245    fail("Could not allocate parse buffer");
1246  assert(buffer != NULL);
1247  memcpy(buffer, text, parse_len);
1248  if (XML_ParseBuffer(g_parser, parse_len, XML_TRUE) == XML_STATUS_ERROR)
1249    xml_failure(g_parser);
1250}
1251END_TEST
1252
1253/*
1254 * Element event tests.
1255 */
1256
1257static void XMLCALL
1258start_element_event_handler(void *userData, const XML_Char *name,
1259                            const XML_Char **atts) {
1260  UNUSED_P(atts);
1261  CharData_AppendXMLChars((CharData *)userData, name, -1);
1262}
1263
1264static void XMLCALL
1265end_element_event_handler(void *userData, const XML_Char *name) {
1266  CharData *storage = (CharData *)userData;
1267  CharData_AppendXMLChars(storage, XCS("/"), 1);
1268  CharData_AppendXMLChars(storage, name, -1);
1269}
1270
1271START_TEST(test_end_element_events) {
1272  const char *text = "<a><b><c/></b><d><f/></d></a>";
1273  const XML_Char *expected = XCS("/c/b/f/d/a");
1274  CharData storage;
1275
1276  CharData_Init(&storage);
1277  XML_SetUserData(g_parser, &storage);
1278  XML_SetEndElementHandler(g_parser, end_element_event_handler);
1279  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1280      == XML_STATUS_ERROR)
1281    xml_failure(g_parser);
1282  CharData_CheckXMLChars(&storage, expected);
1283}
1284END_TEST
1285
1286/*
1287 * Attribute tests.
1288 */
1289
1290/* Helpers used by the following test; this checks any "attr" and "refs"
1291   attributes to make sure whitespace has been normalized.
1292
1293   Return true if whitespace has been normalized in a string, using
1294   the rules for attribute value normalization.  The 'is_cdata' flag
1295   is needed since CDATA attributes don't need to have multiple
1296   whitespace characters collapsed to a single space, while other
1297   attribute data types do.  (Section 3.3.3 of the recommendation.)
1298*/
1299static int
1300is_whitespace_normalized(const XML_Char *s, int is_cdata) {
1301  int blanks = 0;
1302  int at_start = 1;
1303  while (*s) {
1304    if (*s == XCS(' '))
1305      ++blanks;
1306    else if (*s == XCS('\t') || *s == XCS('\n') || *s == XCS('\r'))
1307      return 0;
1308    else {
1309      if (at_start) {
1310        at_start = 0;
1311        if (blanks && ! is_cdata)
1312          /* illegal leading blanks */
1313          return 0;
1314      } else if (blanks > 1 && ! is_cdata)
1315        return 0;
1316      blanks = 0;
1317    }
1318    ++s;
1319  }
1320  if (blanks && ! is_cdata)
1321    return 0;
1322  return 1;
1323}
1324
1325/* Check the attribute whitespace checker: */
1326static void
1327testhelper_is_whitespace_normalized(void) {
1328  assert(is_whitespace_normalized(XCS("abc"), 0));
1329  assert(is_whitespace_normalized(XCS("abc"), 1));
1330  assert(is_whitespace_normalized(XCS("abc def ghi"), 0));
1331  assert(is_whitespace_normalized(XCS("abc def ghi"), 1));
1332  assert(! is_whitespace_normalized(XCS(" abc def ghi"), 0));
1333  assert(is_whitespace_normalized(XCS(" abc def ghi"), 1));
1334  assert(! is_whitespace_normalized(XCS("abc  def ghi"), 0));
1335  assert(is_whitespace_normalized(XCS("abc  def ghi"), 1));
1336  assert(! is_whitespace_normalized(XCS("abc def ghi "), 0));
1337  assert(is_whitespace_normalized(XCS("abc def ghi "), 1));
1338  assert(! is_whitespace_normalized(XCS(" "), 0));
1339  assert(is_whitespace_normalized(XCS(" "), 1));
1340  assert(! is_whitespace_normalized(XCS("\t"), 0));
1341  assert(! is_whitespace_normalized(XCS("\t"), 1));
1342  assert(! is_whitespace_normalized(XCS("\n"), 0));
1343  assert(! is_whitespace_normalized(XCS("\n"), 1));
1344  assert(! is_whitespace_normalized(XCS("\r"), 0));
1345  assert(! is_whitespace_normalized(XCS("\r"), 1));
1346  assert(! is_whitespace_normalized(XCS("abc\t def"), 1));
1347}
1348
1349static void XMLCALL
1350check_attr_contains_normalized_whitespace(void *userData, const XML_Char *name,
1351                                          const XML_Char **atts) {
1352  int i;
1353  UNUSED_P(userData);
1354  UNUSED_P(name);
1355  for (i = 0; atts[i] != NULL; i += 2) {
1356    const XML_Char *attrname = atts[i];
1357    const XML_Char *value = atts[i + 1];
1358    if (xcstrcmp(XCS("attr"), attrname) == 0
1359        || xcstrcmp(XCS("ents"), attrname) == 0
1360        || xcstrcmp(XCS("refs"), attrname) == 0) {
1361      if (! is_whitespace_normalized(value, 0)) {
1362        char buffer[256];
1363        sprintf(buffer,
1364                "attribute value not normalized: %" XML_FMT_STR
1365                "='%" XML_FMT_STR "'",
1366                attrname, value);
1367        fail(buffer);
1368      }
1369    }
1370  }
1371}
1372
1373START_TEST(test_attr_whitespace_normalization) {
1374  const char *text
1375      = "<!DOCTYPE doc [\n"
1376        "  <!ATTLIST doc\n"
1377        "            attr NMTOKENS #REQUIRED\n"
1378        "            ents ENTITIES #REQUIRED\n"
1379        "            refs IDREFS   #REQUIRED>\n"
1380        "]>\n"
1381        "<doc attr='    a  b c\t\td\te\t' refs=' id-1   \t  id-2\t\t'  \n"
1382        "     ents=' ent-1   \t\r\n"
1383        "            ent-2  ' >\n"
1384        "  <e id='id-1'/>\n"
1385        "  <e id='id-2'/>\n"
1386        "</doc>";
1387
1388  XML_SetStartElementHandler(g_parser,
1389                             check_attr_contains_normalized_whitespace);
1390  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1391      == XML_STATUS_ERROR)
1392    xml_failure(g_parser);
1393}
1394END_TEST
1395
1396/*
1397 * XML declaration tests.
1398 */
1399
1400START_TEST(test_xmldecl_misplaced) {
1401  expect_failure("\n"
1402                 "<?xml version='1.0'?>\n"
1403                 "<a/>",
1404                 XML_ERROR_MISPLACED_XML_PI,
1405                 "failed to report misplaced XML declaration");
1406}
1407END_TEST
1408
1409START_TEST(test_xmldecl_invalid) {
1410  expect_failure("<?xml version='1.0' \xc3\xa7?>\n<doc/>", XML_ERROR_XML_DECL,
1411                 "Failed to report invalid XML declaration");
1412}
1413END_TEST
1414
1415START_TEST(test_xmldecl_missing_attr) {
1416  expect_failure("<?xml ='1.0'?>\n<doc/>\n", XML_ERROR_XML_DECL,
1417                 "Failed to report missing XML declaration attribute");
1418}
1419END_TEST
1420
1421START_TEST(test_xmldecl_missing_value) {
1422  expect_failure("<?xml version='1.0' encoding='us-ascii' standalone?>\n"
1423                 "<doc/>",
1424                 XML_ERROR_XML_DECL,
1425                 "Failed to report missing attribute value");
1426}
1427END_TEST
1428
1429/* Regression test for SF bug #584832. */
1430static int XMLCALL
1431UnknownEncodingHandler(void *data, const XML_Char *encoding,
1432                       XML_Encoding *info) {
1433  UNUSED_P(data);
1434  if (xcstrcmp(encoding, XCS("unsupported-encoding")) == 0) {
1435    int i;
1436    for (i = 0; i < 256; ++i)
1437      info->map[i] = i;
1438    info->data = NULL;
1439    info->convert = NULL;
1440    info->release = NULL;
1441    return XML_STATUS_OK;
1442  }
1443  return XML_STATUS_ERROR;
1444}
1445
1446START_TEST(test_unknown_encoding_internal_entity) {
1447  const char *text = "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
1448                     "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
1449                     "<test a='&foo;'/>";
1450
1451  XML_SetUnknownEncodingHandler(g_parser, UnknownEncodingHandler, NULL);
1452  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1453      == XML_STATUS_ERROR)
1454    xml_failure(g_parser);
1455}
1456END_TEST
1457
1458/* Test unrecognised encoding handler */
1459static void
1460dummy_release(void *data) {
1461  UNUSED_P(data);
1462}
1463
1464static int XMLCALL
1465UnrecognisedEncodingHandler(void *data, const XML_Char *encoding,
1466                            XML_Encoding *info) {
1467  UNUSED_P(data);
1468  UNUSED_P(encoding);
1469  info->data = NULL;
1470  info->convert = NULL;
1471  info->release = dummy_release;
1472  return XML_STATUS_ERROR;
1473}
1474
1475START_TEST(test_unrecognised_encoding_internal_entity) {
1476  const char *text = "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
1477                     "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
1478                     "<test a='&foo;'/>";
1479
1480  XML_SetUnknownEncodingHandler(g_parser, UnrecognisedEncodingHandler, NULL);
1481  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1482      != XML_STATUS_ERROR)
1483    fail("Unrecognised encoding not rejected");
1484}
1485END_TEST
1486
1487/* Regression test for SF bug #620106. */
1488static int XMLCALL
1489external_entity_loader(XML_Parser parser, const XML_Char *context,
1490                       const XML_Char *base, const XML_Char *systemId,
1491                       const XML_Char *publicId) {
1492  ExtTest *test_data = (ExtTest *)XML_GetUserData(parser);
1493  XML_Parser extparser;
1494
1495  UNUSED_P(base);
1496  UNUSED_P(systemId);
1497  UNUSED_P(publicId);
1498  extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
1499  if (extparser == NULL)
1500    fail("Could not create external entity parser.");
1501  if (test_data->encoding != NULL) {
1502    if (! XML_SetEncoding(extparser, test_data->encoding))
1503      fail("XML_SetEncoding() ignored for external entity");
1504  }
1505  if (_XML_Parse_SINGLE_BYTES(extparser, test_data->parse_text,
1506                              (int)strlen(test_data->parse_text), XML_TRUE)
1507      == XML_STATUS_ERROR) {
1508    xml_failure(extparser);
1509    return XML_STATUS_ERROR;
1510  }
1511  XML_ParserFree(extparser);
1512  return XML_STATUS_OK;
1513}
1514
1515START_TEST(test_ext_entity_set_encoding) {
1516  const char *text = "<!DOCTYPE doc [\n"
1517                     "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
1518                     "]>\n"
1519                     "<doc>&en;</doc>";
1520  ExtTest test_data
1521      = {/* This text says it's an unsupported encoding, but it's really
1522            UTF-8, which we tell Expat using XML_SetEncoding().
1523         */
1524         "<?xml encoding='iso-8859-3'?>\xC3\xA9", XCS("utf-8"), NULL};
1525#ifdef XML_UNICODE
1526  const XML_Char *expected = XCS("\x00e9");
1527#else
1528  const XML_Char *expected = XCS("\xc3\xa9");
1529#endif
1530
1531  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1532  run_ext_character_check(text, &test_data, expected);
1533}
1534END_TEST
1535
1536/* Test external entities with no handler */
1537START_TEST(test_ext_entity_no_handler) {
1538  const char *text = "<!DOCTYPE doc [\n"
1539                     "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
1540                     "]>\n"
1541                     "<doc>&en;</doc>";
1542
1543  XML_SetDefaultHandler(g_parser, dummy_default_handler);
1544  run_character_check(text, XCS(""));
1545}
1546END_TEST
1547
1548/* Test UTF-8 BOM is accepted */
1549START_TEST(test_ext_entity_set_bom) {
1550  const char *text = "<!DOCTYPE doc [\n"
1551                     "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
1552                     "]>\n"
1553                     "<doc>&en;</doc>";
1554  ExtTest test_data = {"\xEF\xBB\xBF" /* BOM */
1555                       "<?xml encoding='iso-8859-3'?>"
1556                       "\xC3\xA9",
1557                       XCS("utf-8"), NULL};
1558#ifdef XML_UNICODE
1559  const XML_Char *expected = XCS("\x00e9");
1560#else
1561  const XML_Char *expected = XCS("\xc3\xa9");
1562#endif
1563
1564  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1565  run_ext_character_check(text, &test_data, expected);
1566}
1567END_TEST
1568
1569/* Test that bad encodings are faulted */
1570typedef struct ext_faults {
1571  const char *parse_text;
1572  const char *fail_text;
1573  const XML_Char *encoding;
1574  enum XML_Error error;
1575} ExtFaults;
1576
1577static int XMLCALL
1578external_entity_faulter(XML_Parser parser, const XML_Char *context,
1579                        const XML_Char *base, const XML_Char *systemId,
1580                        const XML_Char *publicId) {
1581  XML_Parser ext_parser;
1582  ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser);
1583
1584  UNUSED_P(base);
1585  UNUSED_P(systemId);
1586  UNUSED_P(publicId);
1587  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
1588  if (ext_parser == NULL)
1589    fail("Could not create external entity parser");
1590  if (fault->encoding != NULL) {
1591    if (! XML_SetEncoding(ext_parser, fault->encoding))
1592      fail("XML_SetEncoding failed");
1593  }
1594  if (_XML_Parse_SINGLE_BYTES(ext_parser, fault->parse_text,
1595                              (int)strlen(fault->parse_text), XML_TRUE)
1596      != XML_STATUS_ERROR)
1597    fail(fault->fail_text);
1598  if (XML_GetErrorCode(ext_parser) != fault->error)
1599    xml_failure(ext_parser);
1600
1601  XML_ParserFree(ext_parser);
1602  return XML_STATUS_ERROR;
1603}
1604
1605START_TEST(test_ext_entity_bad_encoding) {
1606  const char *text = "<!DOCTYPE doc [\n"
1607                     "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
1608                     "]>\n"
1609                     "<doc>&en;</doc>";
1610  ExtFaults fault
1611      = {"<?xml encoding='iso-8859-3'?>u", "Unsupported encoding not faulted",
1612         XCS("unknown"), XML_ERROR_UNKNOWN_ENCODING};
1613
1614  XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
1615  XML_SetUserData(g_parser, &fault);
1616  expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
1617                 "Bad encoding should not have been accepted");
1618}
1619END_TEST
1620
1621/* Try handing an invalid encoding to an external entity parser */
1622START_TEST(test_ext_entity_bad_encoding_2) {
1623  const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
1624                     "<!DOCTYPE doc SYSTEM 'foo'>\n"
1625                     "<doc>&entity;</doc>";
1626  ExtFaults fault
1627      = {"<!ELEMENT doc (#PCDATA)*>", "Unknown encoding not faulted",
1628         XCS("unknown-encoding"), XML_ERROR_UNKNOWN_ENCODING};
1629
1630  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1631  XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
1632  XML_SetUserData(g_parser, &fault);
1633  expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
1634                 "Bad encoding not faulted in external entity handler");
1635}
1636END_TEST
1637
1638/* Test that no error is reported for unknown entities if we don't
1639   read an external subset.  This was fixed in Expat 1.95.5.
1640*/
1641START_TEST(test_wfc_undeclared_entity_unread_external_subset) {
1642  const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
1643                     "<doc>&entity;</doc>";
1644
1645  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1646      == XML_STATUS_ERROR)
1647    xml_failure(g_parser);
1648}
1649END_TEST
1650
1651/* Test that an error is reported for unknown entities if we don't
1652   have an external subset.
1653*/
1654START_TEST(test_wfc_undeclared_entity_no_external_subset) {
1655  expect_failure("<doc>&entity;</doc>", XML_ERROR_UNDEFINED_ENTITY,
1656                 "Parser did not report undefined entity w/out a DTD.");
1657}
1658END_TEST
1659
1660/* Test that an error is reported for unknown entities if we don't
1661   read an external subset, but have been declared standalone.
1662*/
1663START_TEST(test_wfc_undeclared_entity_standalone) {
1664  const char *text
1665      = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
1666        "<!DOCTYPE doc SYSTEM 'foo'>\n"
1667        "<doc>&entity;</doc>";
1668
1669  expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
1670                 "Parser did not report undefined entity (standalone).");
1671}
1672END_TEST
1673
1674/* Test that an error is reported for unknown entities if we have read
1675   an external subset, and standalone is true.
1676*/
1677START_TEST(test_wfc_undeclared_entity_with_external_subset_standalone) {
1678  const char *text
1679      = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
1680        "<!DOCTYPE doc SYSTEM 'foo'>\n"
1681        "<doc>&entity;</doc>";
1682  ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
1683
1684  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1685  XML_SetUserData(g_parser, &test_data);
1686  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1687  expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
1688                 "Parser did not report undefined entity (external DTD).");
1689}
1690END_TEST
1691
1692/* Test that external entity handling is not done if the parsing flag
1693 * is set to UNLESS_STANDALONE
1694 */
1695START_TEST(test_entity_with_external_subset_unless_standalone) {
1696  const char *text
1697      = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
1698        "<!DOCTYPE doc SYSTEM 'foo'>\n"
1699        "<doc>&entity;</doc>";
1700  ExtTest test_data = {"<!ENTITY entity 'bar'>", NULL, NULL};
1701
1702  XML_SetParamEntityParsing(g_parser,
1703                            XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE);
1704  XML_SetUserData(g_parser, &test_data);
1705  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1706  expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
1707                 "Parser did not report undefined entity");
1708}
1709END_TEST
1710
1711/* Test that no error is reported for unknown entities if we have read
1712   an external subset, and standalone is false.
1713*/
1714START_TEST(test_wfc_undeclared_entity_with_external_subset) {
1715  const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
1716                     "<!DOCTYPE doc SYSTEM 'foo'>\n"
1717                     "<doc>&entity;</doc>";
1718  ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
1719
1720  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1721  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1722  run_ext_character_check(text, &test_data, XCS(""));
1723}
1724END_TEST
1725
1726/* Test that an error is reported if our NotStandalone handler fails */
1727static int XMLCALL
1728reject_not_standalone_handler(void *userData) {
1729  UNUSED_P(userData);
1730  return XML_STATUS_ERROR;
1731}
1732
1733START_TEST(test_not_standalone_handler_reject) {
1734  const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
1735                     "<!DOCTYPE doc SYSTEM 'foo'>\n"
1736                     "<doc>&entity;</doc>";
1737  ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
1738
1739  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1740  XML_SetUserData(g_parser, &test_data);
1741  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1742  XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler);
1743  expect_failure(text, XML_ERROR_NOT_STANDALONE,
1744                 "NotStandalone handler failed to reject");
1745
1746  /* Try again but without external entity handling */
1747  XML_ParserReset(g_parser, NULL);
1748  XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler);
1749  expect_failure(text, XML_ERROR_NOT_STANDALONE,
1750                 "NotStandalone handler failed to reject");
1751}
1752END_TEST
1753
1754/* Test that no error is reported if our NotStandalone handler succeeds */
1755static int XMLCALL
1756accept_not_standalone_handler(void *userData) {
1757  UNUSED_P(userData);
1758  return XML_STATUS_OK;
1759}
1760
1761START_TEST(test_not_standalone_handler_accept) {
1762  const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
1763                     "<!DOCTYPE doc SYSTEM 'foo'>\n"
1764                     "<doc>&entity;</doc>";
1765  ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
1766
1767  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1768  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
1769  XML_SetNotStandaloneHandler(g_parser, accept_not_standalone_handler);
1770  run_ext_character_check(text, &test_data, XCS(""));
1771
1772  /* Repeat wtihout the external entity handler */
1773  XML_ParserReset(g_parser, NULL);
1774  XML_SetNotStandaloneHandler(g_parser, accept_not_standalone_handler);
1775  run_character_check(text, XCS(""));
1776}
1777END_TEST
1778
1779START_TEST(test_wfc_no_recursive_entity_refs) {
1780  const char *text = "<!DOCTYPE doc [\n"
1781                     "  <!ENTITY entity '&#38;entity;'>\n"
1782                     "]>\n"
1783                     "<doc>&entity;</doc>";
1784
1785  expect_failure(text, XML_ERROR_RECURSIVE_ENTITY_REF,
1786                 "Parser did not report recursive entity reference.");
1787}
1788END_TEST
1789
1790/* Test incomplete external entities are faulted */
1791START_TEST(test_ext_entity_invalid_parse) {
1792  const char *text = "<!DOCTYPE doc [\n"
1793                     "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
1794                     "]>\n"
1795                     "<doc>&en;</doc>";
1796  const ExtFaults faults[]
1797      = {{"<", "Incomplete element declaration not faulted", NULL,
1798          XML_ERROR_UNCLOSED_TOKEN},
1799         {"<\xe2\x82", /* First two bytes of a three-byte char */
1800          "Incomplete character not faulted", NULL, XML_ERROR_PARTIAL_CHAR},
1801         {"<tag>\xe2\x82", "Incomplete character in CDATA not faulted", NULL,
1802          XML_ERROR_PARTIAL_CHAR},
1803         {NULL, NULL, NULL, XML_ERROR_NONE}};
1804  const ExtFaults *fault = faults;
1805
1806  for (; fault->parse_text != NULL; fault++) {
1807    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1808    XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
1809    XML_SetUserData(g_parser, (void *)fault);
1810    expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
1811                   "Parser did not report external entity error");
1812    XML_ParserReset(g_parser, NULL);
1813  }
1814}
1815END_TEST
1816
1817/* Regression test for SF bug #483514. */
1818START_TEST(test_dtd_default_handling) {
1819  const char *text = "<!DOCTYPE doc [\n"
1820                     "<!ENTITY e SYSTEM 'http://example.org/e'>\n"
1821                     "<!NOTATION n SYSTEM 'http://example.org/n'>\n"
1822                     "<!ELEMENT doc EMPTY>\n"
1823                     "<!ATTLIST doc a CDATA #IMPLIED>\n"
1824                     "<?pi in dtd?>\n"
1825                     "<!--comment in dtd-->\n"
1826                     "]><doc/>";
1827
1828  XML_SetDefaultHandler(g_parser, accumulate_characters);
1829  XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
1830  XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
1831  XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
1832  XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
1833  XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
1834  XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
1835  XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
1836  XML_SetCommentHandler(g_parser, dummy_comment_handler);
1837  XML_SetStartCdataSectionHandler(g_parser, dummy_start_cdata_handler);
1838  XML_SetEndCdataSectionHandler(g_parser, dummy_end_cdata_handler);
1839  run_character_check(text, XCS("\n\n\n\n\n\n\n<doc/>"));
1840}
1841END_TEST
1842
1843/* Test handling of attribute declarations */
1844typedef struct AttTest {
1845  const char *definition;
1846  const XML_Char *element_name;
1847  const XML_Char *attr_name;
1848  const XML_Char *attr_type;
1849  const XML_Char *default_value;
1850  int is_required;
1851} AttTest;
1852
1853static void XMLCALL
1854verify_attlist_decl_handler(void *userData, const XML_Char *element_name,
1855                            const XML_Char *attr_name,
1856                            const XML_Char *attr_type,
1857                            const XML_Char *default_value, int is_required) {
1858  AttTest *at = (AttTest *)userData;
1859
1860  if (xcstrcmp(element_name, at->element_name))
1861    fail("Unexpected element name in attribute declaration");
1862  if (xcstrcmp(attr_name, at->attr_name))
1863    fail("Unexpected attribute name in attribute declaration");
1864  if (xcstrcmp(attr_type, at->attr_type))
1865    fail("Unexpected attribute type in attribute declaration");
1866  if ((default_value == NULL && at->default_value != NULL)
1867      || (default_value != NULL && at->default_value == NULL)
1868      || (default_value != NULL && xcstrcmp(default_value, at->default_value)))
1869    fail("Unexpected default value in attribute declaration");
1870  if (is_required != at->is_required)
1871    fail("Requirement mismatch in attribute declaration");
1872}
1873
1874START_TEST(test_dtd_attr_handling) {
1875  const char *prolog = "<!DOCTYPE doc [\n"
1876                       "<!ELEMENT doc EMPTY>\n";
1877  AttTest attr_data[]
1878      = {{"<!ATTLIST doc a ( one | two | three ) #REQUIRED>\n"
1879          "]>"
1880          "<doc a='two'/>",
1881          XCS("doc"), XCS("a"),
1882          XCS("(one|two|three)"), /* Extraneous spaces will be removed */
1883          NULL, XML_TRUE},
1884         {"<!NOTATION foo SYSTEM 'http://example.org/foo'>\n"
1885          "<!ATTLIST doc a NOTATION (foo) #IMPLIED>\n"
1886          "]>"
1887          "<doc/>",
1888          XCS("doc"), XCS("a"), XCS("NOTATION(foo)"), NULL, XML_FALSE},
1889         {"<!ATTLIST doc a NOTATION (foo) 'bar'>\n"
1890          "]>"
1891          "<doc/>",
1892          XCS("doc"), XCS("a"), XCS("NOTATION(foo)"), XCS("bar"), XML_FALSE},
1893         {"<!ATTLIST doc a CDATA '\xdb\xb2'>\n"
1894          "]>"
1895          "<doc/>",
1896          XCS("doc"), XCS("a"), XCS("CDATA"),
1897#ifdef XML_UNICODE
1898          XCS("\x06f2"),
1899#else
1900          XCS("\xdb\xb2"),
1901#endif
1902          XML_FALSE},
1903         {NULL, NULL, NULL, NULL, NULL, XML_FALSE}};
1904  AttTest *test;
1905
1906  for (test = attr_data; test->definition != NULL; test++) {
1907    XML_SetAttlistDeclHandler(g_parser, verify_attlist_decl_handler);
1908    XML_SetUserData(g_parser, test);
1909    if (_XML_Parse_SINGLE_BYTES(g_parser, prolog, (int)strlen(prolog),
1910                                XML_FALSE)
1911        == XML_STATUS_ERROR)
1912      xml_failure(g_parser);
1913    if (_XML_Parse_SINGLE_BYTES(g_parser, test->definition,
1914                                (int)strlen(test->definition), XML_TRUE)
1915        == XML_STATUS_ERROR)
1916      xml_failure(g_parser);
1917    XML_ParserReset(g_parser, NULL);
1918  }
1919}
1920END_TEST
1921
1922/* See related SF bug #673791.
1923   When namespace processing is enabled, setting the namespace URI for
1924   a prefix is not allowed; this test ensures that it *is* allowed
1925   when namespace processing is not enabled.
1926   (See Namespaces in XML, section 2.)
1927*/
1928START_TEST(test_empty_ns_without_namespaces) {
1929  const char *text = "<doc xmlns:prefix='http://example.org/'>\n"
1930                     "  <e xmlns:prefix=''/>\n"
1931                     "</doc>";
1932
1933  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1934      == XML_STATUS_ERROR)
1935    xml_failure(g_parser);
1936}
1937END_TEST
1938
1939/* Regression test for SF bug #824420.
1940   Checks that an xmlns:prefix attribute set in an attribute's default
1941   value isn't misinterpreted.
1942*/
1943START_TEST(test_ns_in_attribute_default_without_namespaces) {
1944  const char *text = "<!DOCTYPE e:element [\n"
1945                     "  <!ATTLIST e:element\n"
1946                     "    xmlns:e CDATA 'http://example.org/'>\n"
1947                     "      ]>\n"
1948                     "<e:element/>";
1949
1950  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
1951      == XML_STATUS_ERROR)
1952    xml_failure(g_parser);
1953}
1954END_TEST
1955
1956static const char *long_character_data_text
1957    = "<?xml version='1.0' encoding='iso-8859-1'?><s>"
1958      "012345678901234567890123456789012345678901234567890123456789"
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      "</s>";
1979
1980static XML_Bool resumable = XML_FALSE;
1981
1982static void
1983clearing_aborting_character_handler(void *userData, const XML_Char *s,
1984                                    int len) {
1985  UNUSED_P(userData);
1986  UNUSED_P(s);
1987  UNUSED_P(len);
1988  XML_StopParser(g_parser, resumable);
1989  XML_SetCharacterDataHandler(g_parser, NULL);
1990}
1991
1992/* Regression test for SF bug #1515266: missing check of stopped
1993   parser in doContext() 'for' loop. */
1994START_TEST(test_stop_parser_between_char_data_calls) {
1995  /* The sample data must be big enough that there are two calls to
1996     the character data handler from within the inner "for" loop of
1997     the XML_TOK_DATA_CHARS case in doContent(), and the character
1998     handler must stop the parser and clear the character data
1999     handler.
2000  */
2001  const char *text = long_character_data_text;
2002
2003  XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
2004  resumable = XML_FALSE;
2005  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2006      != XML_STATUS_ERROR)
2007    xml_failure(g_parser);
2008  if (XML_GetErrorCode(g_parser) != XML_ERROR_ABORTED)
2009    xml_failure(g_parser);
2010}
2011END_TEST
2012
2013/* Regression test for SF bug #1515266: missing check of stopped
2014   parser in doContext() 'for' loop. */
2015START_TEST(test_suspend_parser_between_char_data_calls) {
2016  /* The sample data must be big enough that there are two calls to
2017     the character data handler from within the inner "for" loop of
2018     the XML_TOK_DATA_CHARS case in doContent(), and the character
2019     handler must stop the parser and clear the character data
2020     handler.
2021  */
2022  const char *text = long_character_data_text;
2023
2024  XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
2025  resumable = XML_TRUE;
2026  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2027      != XML_STATUS_SUSPENDED)
2028    xml_failure(g_parser);
2029  if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
2030    xml_failure(g_parser);
2031  /* Try parsing directly */
2032  if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
2033      != XML_STATUS_ERROR)
2034    fail("Attempt to continue parse while suspended not faulted");
2035  if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
2036    fail("Suspended parse not faulted with correct error");
2037}
2038END_TEST
2039
2040static XML_Bool abortable = XML_FALSE;
2041
2042static void
2043parser_stop_character_handler(void *userData, const XML_Char *s, int len) {
2044  UNUSED_P(userData);
2045  UNUSED_P(s);
2046  UNUSED_P(len);
2047  XML_StopParser(g_parser, resumable);
2048  XML_SetCharacterDataHandler(g_parser, NULL);
2049  if (! resumable) {
2050    /* Check that aborting an aborted parser is faulted */
2051    if (XML_StopParser(g_parser, XML_FALSE) != XML_STATUS_ERROR)
2052      fail("Aborting aborted parser not faulted");
2053    if (XML_GetErrorCode(g_parser) != XML_ERROR_FINISHED)
2054      xml_failure(g_parser);
2055  } else if (abortable) {
2056    /* Check that aborting a suspended parser works */
2057    if (XML_StopParser(g_parser, XML_FALSE) == XML_STATUS_ERROR)
2058      xml_failure(g_parser);
2059  } else {
2060    /* Check that suspending a suspended parser works */
2061    if (XML_StopParser(g_parser, XML_TRUE) != XML_STATUS_ERROR)
2062      fail("Suspending suspended parser not faulted");
2063    if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
2064      xml_failure(g_parser);
2065  }
2066}
2067
2068/* Test repeated calls to XML_StopParser are handled correctly */
2069START_TEST(test_repeated_stop_parser_between_char_data_calls) {
2070  const char *text = long_character_data_text;
2071
2072  XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
2073  resumable = XML_FALSE;
2074  abortable = XML_FALSE;
2075  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2076      != XML_STATUS_ERROR)
2077    fail("Failed to double-stop parser");
2078
2079  XML_ParserReset(g_parser, NULL);
2080  XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
2081  resumable = XML_TRUE;
2082  abortable = XML_FALSE;
2083  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2084      != XML_STATUS_SUSPENDED)
2085    fail("Failed to double-suspend parser");
2086
2087  XML_ParserReset(g_parser, NULL);
2088  XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
2089  resumable = XML_TRUE;
2090  abortable = XML_TRUE;
2091  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2092      != XML_STATUS_ERROR)
2093    fail("Failed to suspend-abort parser");
2094}
2095END_TEST
2096
2097START_TEST(test_good_cdata_ascii) {
2098  const char *text = "<a><![CDATA[<greeting>Hello, world!</greeting>]]></a>";
2099  const XML_Char *expected = XCS("<greeting>Hello, world!</greeting>");
2100
2101  CharData storage;
2102  CharData_Init(&storage);
2103  XML_SetUserData(g_parser, &storage);
2104  XML_SetCharacterDataHandler(g_parser, accumulate_characters);
2105  /* Add start and end handlers for coverage */
2106  XML_SetStartCdataSectionHandler(g_parser, dummy_start_cdata_handler);
2107  XML_SetEndCdataSectionHandler(g_parser, dummy_end_cdata_handler);
2108
2109  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2110      == XML_STATUS_ERROR)
2111    xml_failure(g_parser);
2112  CharData_CheckXMLChars(&storage, expected);
2113
2114  /* Try again, this time with a default handler */
2115  XML_ParserReset(g_parser, NULL);
2116  CharData_Init(&storage);
2117  XML_SetUserData(g_parser, &storage);
2118  XML_SetCharacterDataHandler(g_parser, accumulate_characters);
2119  XML_SetDefaultHandler(g_parser, dummy_default_handler);
2120
2121  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2122      == XML_STATUS_ERROR)
2123    xml_failure(g_parser);
2124  CharData_CheckXMLChars(&storage, expected);
2125}
2126END_TEST
2127
2128START_TEST(test_good_cdata_utf16) {
2129  /* Test data is:
2130   *   <?xml version='1.0' encoding='utf-16'?>
2131   *   <a><![CDATA[hello]]></a>
2132   */
2133  const char text[]
2134      = "\0<\0?\0x\0m\0l\0"
2135        " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
2136        " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
2137        "1\0"
2138        "6\0'"
2139        "\0?\0>\0\n"
2140        "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0[\0h\0e\0l\0l\0o\0]\0]\0>\0<\0/\0a\0>";
2141  const XML_Char *expected = XCS("hello");
2142
2143  CharData storage;
2144  CharData_Init(&storage);
2145  XML_SetUserData(g_parser, &storage);
2146  XML_SetCharacterDataHandler(g_parser, accumulate_characters);
2147
2148  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
2149      == XML_STATUS_ERROR)
2150    xml_failure(g_parser);
2151  CharData_CheckXMLChars(&storage, expected);
2152}
2153END_TEST
2154
2155START_TEST(test_good_cdata_utf16_le) {
2156  /* Test data is:
2157   *   <?xml version='1.0' encoding='utf-16'?>
2158   *   <a><![CDATA[hello]]></a>
2159   */
2160  const char text[]
2161      = "<\0?\0x\0m\0l\0"
2162        " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
2163        " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
2164        "1\0"
2165        "6\0'"
2166        "\0?\0>\0\n"
2167        "\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";
2168  const XML_Char *expected = XCS("hello");
2169
2170  CharData storage;
2171  CharData_Init(&storage);
2172  XML_SetUserData(g_parser, &storage);
2173  XML_SetCharacterDataHandler(g_parser, accumulate_characters);
2174
2175  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
2176      == XML_STATUS_ERROR)
2177    xml_failure(g_parser);
2178  CharData_CheckXMLChars(&storage, expected);
2179}
2180END_TEST
2181
2182/* Test UTF16 conversion of a long cdata string */
2183
2184/* 16 characters: handy macro to reduce visual clutter */
2185#define A_TO_P_IN_UTF16 "\0A\0B\0C\0D\0E\0F\0G\0H\0I\0J\0K\0L\0M\0N\0O\0P"
2186
2187START_TEST(test_long_cdata_utf16) {
2188  /* Test data is:
2189   * <?xlm version='1.0' encoding='utf-16'?>
2190   * <a><![CDATA[
2191   * ABCDEFGHIJKLMNOP
2192   * ]]></a>
2193   */
2194  const char text[]
2195      = "\0<\0?\0x\0m\0l\0 "
2196        "\0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0 "
2197        "\0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0\x31\0\x36\0'\0?\0>"
2198        "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0["
2199      /* 64 characters per line */
2200      /* clang-format off */
2201        A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16  A_TO_P_IN_UTF16
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
2218        /* clang-format on */
2219        "\0]\0]\0>\0<\0/\0a\0>";
2220  const XML_Char *expected =
2221      /* clang-format off */
2222        XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
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("ABCDEFGHIJKLMNOP");
2239  /* clang-format on */
2240  CharData storage;
2241  void *buffer;
2242
2243  CharData_Init(&storage);
2244  XML_SetUserData(g_parser, &storage);
2245  XML_SetCharacterDataHandler(g_parser, accumulate_characters);
2246  buffer = XML_GetBuffer(g_parser, sizeof(text) - 1);
2247  if (buffer == NULL)
2248    fail("Could not allocate parse buffer");
2249  assert(buffer != NULL);
2250  memcpy(buffer, text, sizeof(text) - 1);
2251  if (XML_ParseBuffer(g_parser, sizeof(text) - 1, XML_TRUE) == XML_STATUS_ERROR)
2252    xml_failure(g_parser);
2253  CharData_CheckXMLChars(&storage, expected);
2254}
2255END_TEST
2256
2257/* Test handling of multiple unit UTF-16 characters */
2258START_TEST(test_multichar_cdata_utf16) {
2259  /* Test data is:
2260   *   <?xml version='1.0' encoding='utf-16'?>
2261   *   <a><![CDATA[{MINIM}{CROTCHET}]]></a>
2262   *
2263   * where {MINIM} is U+1d15e (a minim or half-note)
2264   *   UTF-16: 0xd834 0xdd5e
2265   *   UTF-8:  0xf0 0x9d 0x85 0x9e
2266   * and {CROTCHET} is U+1d15f (a crotchet or quarter-note)
2267   *   UTF-16: 0xd834 0xdd5f
2268   *   UTF-8:  0xf0 0x9d 0x85 0x9f
2269   */
2270  const char text[] = "\0<\0?\0x\0m\0l\0"
2271                      " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
2272                      " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
2273                      "1\0"
2274                      "6\0'"
2275                      "\0?\0>\0\n"
2276                      "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0["
2277                      "\xd8\x34\xdd\x5e\xd8\x34\xdd\x5f"
2278                      "\0]\0]\0>\0<\0/\0a\0>";
2279#ifdef XML_UNICODE
2280  const XML_Char *expected = XCS("\xd834\xdd5e\xd834\xdd5f");
2281#else
2282  const XML_Char *expected = XCS("\xf0\x9d\x85\x9e\xf0\x9d\x85\x9f");
2283#endif
2284  CharData storage;
2285
2286  CharData_Init(&storage);
2287  XML_SetUserData(g_parser, &storage);
2288  XML_SetCharacterDataHandler(g_parser, accumulate_characters);
2289
2290  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
2291      == XML_STATUS_ERROR)
2292    xml_failure(g_parser);
2293  CharData_CheckXMLChars(&storage, expected);
2294}
2295END_TEST
2296
2297/* Test that an element name with a UTF-16 surrogate pair is rejected */
2298START_TEST(test_utf16_bad_surrogate_pair) {
2299  /* Test data is:
2300   *   <?xml version='1.0' encoding='utf-16'?>
2301   *   <a><![CDATA[{BADLINB}]]></a>
2302   *
2303   * where {BADLINB} is U+10000 (the first Linear B character)
2304   * with the UTF-16 surrogate pair in the wrong order, i.e.
2305   *   0xdc00 0xd800
2306   */
2307  const char text[] = "\0<\0?\0x\0m\0l\0"
2308                      " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
2309                      " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
2310                      "1\0"
2311                      "6\0'"
2312                      "\0?\0>\0\n"
2313                      "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0["
2314                      "\xdc\x00\xd8\x00"
2315                      "\0]\0]\0>\0<\0/\0a\0>";
2316
2317  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
2318      != XML_STATUS_ERROR)
2319    fail("Reversed UTF-16 surrogate pair not faulted");
2320  if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
2321    xml_failure(g_parser);
2322}
2323END_TEST
2324
2325START_TEST(test_bad_cdata) {
2326  struct CaseData {
2327    const char *text;
2328    enum XML_Error expectedError;
2329  };
2330
2331  struct CaseData cases[]
2332      = {{"<a><", XML_ERROR_UNCLOSED_TOKEN},
2333         {"<a><!", XML_ERROR_UNCLOSED_TOKEN},
2334         {"<a><![", XML_ERROR_UNCLOSED_TOKEN},
2335         {"<a><![C", XML_ERROR_UNCLOSED_TOKEN},
2336         {"<a><![CD", XML_ERROR_UNCLOSED_TOKEN},
2337         {"<a><![CDA", XML_ERROR_UNCLOSED_TOKEN},
2338         {"<a><![CDAT", XML_ERROR_UNCLOSED_TOKEN},
2339         {"<a><![CDATA", XML_ERROR_UNCLOSED_TOKEN},
2340
2341         {"<a><![CDATA[", XML_ERROR_UNCLOSED_CDATA_SECTION},
2342         {"<a><![CDATA[]", XML_ERROR_UNCLOSED_CDATA_SECTION},
2343         {"<a><![CDATA[]]", XML_ERROR_UNCLOSED_CDATA_SECTION},
2344
2345         {"<a><!<a/>", XML_ERROR_INVALID_TOKEN},
2346         {"<a><![<a/>", XML_ERROR_UNCLOSED_TOKEN},  /* ?! */
2347         {"<a><![C<a/>", XML_ERROR_UNCLOSED_TOKEN}, /* ?! */
2348         {"<a><![CD<a/>", XML_ERROR_INVALID_TOKEN},
2349         {"<a><![CDA<a/>", XML_ERROR_INVALID_TOKEN},
2350         {"<a><![CDAT<a/>", XML_ERROR_INVALID_TOKEN},
2351         {"<a><![CDATA<a/>", XML_ERROR_INVALID_TOKEN},
2352
2353         {"<a><![CDATA[<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION},
2354         {"<a><![CDATA[]<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION},
2355         {"<a><![CDATA[]]<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION}};
2356
2357  size_t i = 0;
2358  for (; i < sizeof(cases) / sizeof(struct CaseData); i++) {
2359    const enum XML_Status actualStatus = _XML_Parse_SINGLE_BYTES(
2360        g_parser, cases[i].text, (int)strlen(cases[i].text), XML_TRUE);
2361    const enum XML_Error actualError = XML_GetErrorCode(g_parser);
2362
2363    assert(actualStatus == XML_STATUS_ERROR);
2364
2365    if (actualError != cases[i].expectedError) {
2366      char message[100];
2367      sprintf(message,
2368              "Expected error %d but got error %d for case %u: \"%s\"\n",
2369              cases[i].expectedError, actualError, (unsigned int)i + 1,
2370              cases[i].text);
2371      fail(message);
2372    }
2373
2374    XML_ParserReset(g_parser, NULL);
2375  }
2376}
2377END_TEST
2378
2379/* Test failures in UTF-16 CDATA */
2380START_TEST(test_bad_cdata_utf16) {
2381  struct CaseData {
2382    size_t text_bytes;
2383    const char *text;
2384    enum XML_Error expected_error;
2385  };
2386
2387  const char prolog[] = "\0<\0?\0x\0m\0l\0"
2388                        " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
2389                        " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
2390                        "1\0"
2391                        "6\0'"
2392                        "\0?\0>\0\n"
2393                        "\0<\0a\0>";
2394  struct CaseData cases[] = {
2395      {1, "\0", XML_ERROR_UNCLOSED_TOKEN},
2396      {2, "\0<", XML_ERROR_UNCLOSED_TOKEN},
2397      {3, "\0<\0", XML_ERROR_UNCLOSED_TOKEN},
2398      {4, "\0<\0!", XML_ERROR_UNCLOSED_TOKEN},
2399      {5, "\0<\0!\0", XML_ERROR_UNCLOSED_TOKEN},
2400      {6, "\0<\0!\0[", XML_ERROR_UNCLOSED_TOKEN},
2401      {7, "\0<\0!\0[\0", XML_ERROR_UNCLOSED_TOKEN},
2402      {8, "\0<\0!\0[\0C", XML_ERROR_UNCLOSED_TOKEN},
2403      {9, "\0<\0!\0[\0C\0", XML_ERROR_UNCLOSED_TOKEN},
2404      {10, "\0<\0!\0[\0C\0D", XML_ERROR_UNCLOSED_TOKEN},
2405      {11, "\0<\0!\0[\0C\0D\0", XML_ERROR_UNCLOSED_TOKEN},
2406      {12, "\0<\0!\0[\0C\0D\0A", XML_ERROR_UNCLOSED_TOKEN},
2407      {13, "\0<\0!\0[\0C\0D\0A\0", XML_ERROR_UNCLOSED_TOKEN},
2408      {14, "\0<\0!\0[\0C\0D\0A\0T", XML_ERROR_UNCLOSED_TOKEN},
2409      {15, "\0<\0!\0[\0C\0D\0A\0T\0", XML_ERROR_UNCLOSED_TOKEN},
2410      {16, "\0<\0!\0[\0C\0D\0A\0T\0A", XML_ERROR_UNCLOSED_TOKEN},
2411      {17, "\0<\0!\0[\0C\0D\0A\0T\0A\0", XML_ERROR_UNCLOSED_TOKEN},
2412      {18, "\0<\0!\0[\0C\0D\0A\0T\0A\0[", XML_ERROR_UNCLOSED_CDATA_SECTION},
2413      {19, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0", XML_ERROR_UNCLOSED_CDATA_SECTION},
2414      {20, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z", XML_ERROR_UNCLOSED_CDATA_SECTION},
2415      /* Now add a four-byte UTF-16 character */
2416      {21, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8",
2417       XML_ERROR_UNCLOSED_CDATA_SECTION},
2418      {22, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34", XML_ERROR_PARTIAL_CHAR},
2419      {23, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34\xdd",
2420       XML_ERROR_PARTIAL_CHAR},
2421      {24, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34\xdd\x5e",
2422       XML_ERROR_UNCLOSED_CDATA_SECTION}};
2423  size_t i;
2424
2425  for (i = 0; i < sizeof(cases) / sizeof(struct CaseData); i++) {
2426    enum XML_Status actual_status;
2427    enum XML_Error actual_error;
2428
2429    if (_XML_Parse_SINGLE_BYTES(g_parser, prolog, (int)sizeof(prolog) - 1,
2430                                XML_FALSE)
2431        == XML_STATUS_ERROR)
2432      xml_failure(g_parser);
2433    actual_status = _XML_Parse_SINGLE_BYTES(g_parser, cases[i].text,
2434                                            (int)cases[i].text_bytes, XML_TRUE);
2435    assert(actual_status == XML_STATUS_ERROR);
2436    actual_error = XML_GetErrorCode(g_parser);
2437    if (actual_error != cases[i].expected_error) {
2438      char message[1024];
2439
2440      sprintf(message,
2441              "Expected error %d (%" XML_FMT_STR "), got %d (%" XML_FMT_STR
2442              ") for case %lu\n",
2443              cases[i].expected_error, XML_ErrorString(cases[i].expected_error),
2444              actual_error, XML_ErrorString(actual_error),
2445              (long unsigned)(i + 1));
2446      fail(message);
2447    }
2448    XML_ParserReset(g_parser, NULL);
2449  }
2450}
2451END_TEST
2452
2453static const char *long_cdata_text
2454    = "<s><![CDATA["
2455      "012345678901234567890123456789012345678901234567890123456789"
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      "]]></s>";
2476
2477/* Test stopping the parser in cdata handler */
2478START_TEST(test_stop_parser_between_cdata_calls) {
2479  const char *text = long_cdata_text;
2480
2481  XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
2482  resumable = XML_FALSE;
2483  expect_failure(text, XML_ERROR_ABORTED, "Parse not aborted in CDATA handler");
2484}
2485END_TEST
2486
2487/* Test suspending the parser in cdata handler */
2488START_TEST(test_suspend_parser_between_cdata_calls) {
2489  const char *text = long_cdata_text;
2490  enum XML_Status result;
2491
2492  XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
2493  resumable = XML_TRUE;
2494  result = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
2495  if (result != XML_STATUS_SUSPENDED) {
2496    if (result == XML_STATUS_ERROR)
2497      xml_failure(g_parser);
2498    fail("Parse not suspended in CDATA handler");
2499  }
2500  if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
2501    xml_failure(g_parser);
2502}
2503END_TEST
2504
2505/* Test memory allocation functions */
2506START_TEST(test_memory_allocation) {
2507  char *buffer = (char *)XML_MemMalloc(g_parser, 256);
2508  char *p;
2509
2510  if (buffer == NULL) {
2511    fail("Allocation failed");
2512  } else {
2513    /* Try writing to memory; some OSes try to cheat! */
2514    buffer[0] = 'T';
2515    buffer[1] = 'E';
2516    buffer[2] = 'S';
2517    buffer[3] = 'T';
2518    buffer[4] = '\0';
2519    if (strcmp(buffer, "TEST") != 0) {
2520      fail("Memory not writable");
2521    } else {
2522      p = (char *)XML_MemRealloc(g_parser, buffer, 512);
2523      if (p == NULL) {
2524        fail("Reallocation failed");
2525      } else {
2526        /* Write again, just to be sure */
2527        buffer = p;
2528        buffer[0] = 'V';
2529        if (strcmp(buffer, "VEST") != 0) {
2530          fail("Reallocated memory not writable");
2531        }
2532      }
2533    }
2534    XML_MemFree(g_parser, buffer);
2535  }
2536}
2537END_TEST
2538
2539static void XMLCALL
2540record_default_handler(void *userData, const XML_Char *s, int len) {
2541  UNUSED_P(s);
2542  UNUSED_P(len);
2543  CharData_AppendXMLChars((CharData *)userData, XCS("D"), 1);
2544}
2545
2546static void XMLCALL
2547record_cdata_handler(void *userData, const XML_Char *s, int len) {
2548  UNUSED_P(s);
2549  UNUSED_P(len);
2550  CharData_AppendXMLChars((CharData *)userData, XCS("C"), 1);
2551  XML_DefaultCurrent(g_parser);
2552}
2553
2554static void XMLCALL
2555record_cdata_nodefault_handler(void *userData, const XML_Char *s, int len) {
2556  UNUSED_P(s);
2557  UNUSED_P(len);
2558  CharData_AppendXMLChars((CharData *)userData, XCS("c"), 1);
2559}
2560
2561static void XMLCALL
2562record_skip_handler(void *userData, const XML_Char *entityName,
2563                    int is_parameter_entity) {
2564  UNUSED_P(entityName);
2565  CharData_AppendXMLChars((CharData *)userData,
2566                          is_parameter_entity ? XCS("E") : XCS("e"), 1);
2567}
2568
2569/* Test XML_DefaultCurrent() passes handling on correctly */
2570START_TEST(test_default_current) {
2571  const char *text = "<doc>hell]</doc>";
2572  const char *entity_text = "<!DOCTYPE doc [\n"
2573                            "<!ENTITY entity '&#37;'>\n"
2574                            "]>\n"
2575                            "<doc>&entity;</doc>";
2576  CharData storage;
2577
2578  XML_SetDefaultHandler(g_parser, record_default_handler);
2579  XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
2580  CharData_Init(&storage);
2581  XML_SetUserData(g_parser, &storage);
2582  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2583      == XML_STATUS_ERROR)
2584    xml_failure(g_parser);
2585  CharData_CheckXMLChars(&storage, XCS("DCDCDCDCDCDD"));
2586
2587  /* Again, without the defaulting */
2588  XML_ParserReset(g_parser, NULL);
2589  XML_SetDefaultHandler(g_parser, record_default_handler);
2590  XML_SetCharacterDataHandler(g_parser, record_cdata_nodefault_handler);
2591  CharData_Init(&storage);
2592  XML_SetUserData(g_parser, &storage);
2593  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2594      == XML_STATUS_ERROR)
2595    xml_failure(g_parser);
2596  CharData_CheckXMLChars(&storage, XCS("DcccccD"));
2597
2598  /* Now with an internal entity to complicate matters */
2599  XML_ParserReset(g_parser, NULL);
2600  XML_SetDefaultHandler(g_parser, record_default_handler);
2601  XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
2602  CharData_Init(&storage);
2603  XML_SetUserData(g_parser, &storage);
2604  if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
2605                              XML_TRUE)
2606      == XML_STATUS_ERROR)
2607    xml_failure(g_parser);
2608  /* The default handler suppresses the entity */
2609  CharData_CheckXMLChars(&storage, XCS("DDDDDDDDDDDDDDDDDDD"));
2610
2611  /* Again, with a skip handler */
2612  XML_ParserReset(g_parser, NULL);
2613  XML_SetDefaultHandler(g_parser, record_default_handler);
2614  XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
2615  XML_SetSkippedEntityHandler(g_parser, record_skip_handler);
2616  CharData_Init(&storage);
2617  XML_SetUserData(g_parser, &storage);
2618  if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
2619                              XML_TRUE)
2620      == XML_STATUS_ERROR)
2621    xml_failure(g_parser);
2622  /* The default handler suppresses the entity */
2623  CharData_CheckXMLChars(&storage, XCS("DDDDDDDDDDDDDDDDDeD"));
2624
2625  /* This time, allow the entity through */
2626  XML_ParserReset(g_parser, NULL);
2627  XML_SetDefaultHandlerExpand(g_parser, record_default_handler);
2628  XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
2629  CharData_Init(&storage);
2630  XML_SetUserData(g_parser, &storage);
2631  if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
2632                              XML_TRUE)
2633      == XML_STATUS_ERROR)
2634    xml_failure(g_parser);
2635  CharData_CheckXMLChars(&storage, XCS("DDDDDDDDDDDDDDDDDCDD"));
2636
2637  /* Finally, without passing the cdata to the default handler */
2638  XML_ParserReset(g_parser, NULL);
2639  XML_SetDefaultHandlerExpand(g_parser, record_default_handler);
2640  XML_SetCharacterDataHandler(g_parser, record_cdata_nodefault_handler);
2641  CharData_Init(&storage);
2642  XML_SetUserData(g_parser, &storage);
2643  if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
2644                              XML_TRUE)
2645      == XML_STATUS_ERROR)
2646    xml_failure(g_parser);
2647  CharData_CheckXMLChars(&storage, XCS("DDDDDDDDDDDDDDDDDcD"));
2648}
2649END_TEST
2650
2651/* Test DTD element parsing code paths */
2652START_TEST(test_dtd_elements) {
2653  const char *text = "<!DOCTYPE doc [\n"
2654                     "<!ELEMENT doc (chapter)>\n"
2655                     "<!ELEMENT chapter (#PCDATA)>\n"
2656                     "]>\n"
2657                     "<doc><chapter>Wombats are go</chapter></doc>";
2658
2659  XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
2660  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2661      == XML_STATUS_ERROR)
2662    xml_failure(g_parser);
2663}
2664END_TEST
2665
2666/* Test foreign DTD handling */
2667START_TEST(test_set_foreign_dtd) {
2668  const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n";
2669  const char *text2 = "<doc>&entity;</doc>";
2670  ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
2671
2672  /* Check hash salt is passed through too */
2673  XML_SetHashSalt(g_parser, 0x12345678);
2674  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
2675  XML_SetUserData(g_parser, &test_data);
2676  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
2677  /* Add a default handler to exercise more code paths */
2678  XML_SetDefaultHandler(g_parser, dummy_default_handler);
2679  if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
2680    fail("Could not set foreign DTD");
2681  if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
2682      == XML_STATUS_ERROR)
2683    xml_failure(g_parser);
2684
2685  /* Ensure that trying to set the DTD after parsing has started
2686   * is faulted, even if it's the same setting.
2687   */
2688  if (XML_UseForeignDTD(g_parser, XML_TRUE)
2689      != XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING)
2690    fail("Failed to reject late foreign DTD setting");
2691  /* Ditto for the hash salt */
2692  if (XML_SetHashSalt(g_parser, 0x23456789))
2693    fail("Failed to reject late hash salt change");
2694
2695  /* Now finish the parse */
2696  if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
2697      == XML_STATUS_ERROR)
2698    xml_failure(g_parser);
2699}
2700END_TEST
2701
2702/* Test foreign DTD handling with a failing NotStandalone handler */
2703START_TEST(test_foreign_dtd_not_standalone) {
2704  const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
2705                     "<doc>&entity;</doc>";
2706  ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
2707
2708  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
2709  XML_SetUserData(g_parser, &test_data);
2710  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
2711  XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler);
2712  if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
2713    fail("Could not set foreign DTD");
2714  expect_failure(text, XML_ERROR_NOT_STANDALONE,
2715                 "NotStandalonehandler failed to reject");
2716}
2717END_TEST
2718
2719/* Test invalid character in a foreign DTD is faulted */
2720START_TEST(test_invalid_foreign_dtd) {
2721  const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
2722                     "<doc>&entity;</doc>";
2723  ExtFaults test_data
2724      = {"$", "Dollar not faulted", NULL, XML_ERROR_INVALID_TOKEN};
2725
2726  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
2727  XML_SetUserData(g_parser, &test_data);
2728  XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
2729  XML_UseForeignDTD(g_parser, XML_TRUE);
2730  expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
2731                 "Bad DTD should not have been accepted");
2732}
2733END_TEST
2734
2735/* Test foreign DTD use with a doctype */
2736START_TEST(test_foreign_dtd_with_doctype) {
2737  const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n"
2738                      "<!DOCTYPE doc [<!ENTITY entity 'hello world'>]>\n";
2739  const char *text2 = "<doc>&entity;</doc>";
2740  ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
2741
2742  /* Check hash salt is passed through too */
2743  XML_SetHashSalt(g_parser, 0x12345678);
2744  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
2745  XML_SetUserData(g_parser, &test_data);
2746  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
2747  /* Add a default handler to exercise more code paths */
2748  XML_SetDefaultHandler(g_parser, dummy_default_handler);
2749  if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
2750    fail("Could not set foreign DTD");
2751  if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
2752      == XML_STATUS_ERROR)
2753    xml_failure(g_parser);
2754
2755  /* Ensure that trying to set the DTD after parsing has started
2756   * is faulted, even if it's the same setting.
2757   */
2758  if (XML_UseForeignDTD(g_parser, XML_TRUE)
2759      != XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING)
2760    fail("Failed to reject late foreign DTD setting");
2761  /* Ditto for the hash salt */
2762  if (XML_SetHashSalt(g_parser, 0x23456789))
2763    fail("Failed to reject late hash salt change");
2764
2765  /* Now finish the parse */
2766  if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
2767      == XML_STATUS_ERROR)
2768    xml_failure(g_parser);
2769}
2770END_TEST
2771
2772/* Test XML_UseForeignDTD with no external subset present */
2773static int XMLCALL
2774external_entity_null_loader(XML_Parser parser, const XML_Char *context,
2775                            const XML_Char *base, const XML_Char *systemId,
2776                            const XML_Char *publicId) {
2777  UNUSED_P(parser);
2778  UNUSED_P(context);
2779  UNUSED_P(base);
2780  UNUSED_P(systemId);
2781  UNUSED_P(publicId);
2782  return XML_STATUS_OK;
2783}
2784
2785START_TEST(test_foreign_dtd_without_external_subset) {
2786  const char *text = "<!DOCTYPE doc [<!ENTITY foo 'bar'>]>\n"
2787                     "<doc>&foo;</doc>";
2788
2789  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
2790  XML_SetUserData(g_parser, NULL);
2791  XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader);
2792  XML_UseForeignDTD(g_parser, XML_TRUE);
2793  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2794      == XML_STATUS_ERROR)
2795    xml_failure(g_parser);
2796}
2797END_TEST
2798
2799START_TEST(test_empty_foreign_dtd) {
2800  const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
2801                     "<doc>&entity;</doc>";
2802
2803  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
2804  XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader);
2805  XML_UseForeignDTD(g_parser, XML_TRUE);
2806  expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
2807                 "Undefined entity not faulted");
2808}
2809END_TEST
2810
2811/* Test XML Base is set and unset appropriately */
2812START_TEST(test_set_base) {
2813  const XML_Char *old_base;
2814  const XML_Char *new_base = XCS("/local/file/name.xml");
2815
2816  old_base = XML_GetBase(g_parser);
2817  if (XML_SetBase(g_parser, new_base) != XML_STATUS_OK)
2818    fail("Unable to set base");
2819  if (xcstrcmp(XML_GetBase(g_parser), new_base) != 0)
2820    fail("Base setting not correct");
2821  if (XML_SetBase(g_parser, NULL) != XML_STATUS_OK)
2822    fail("Unable to NULL base");
2823  if (XML_GetBase(g_parser) != NULL)
2824    fail("Base setting not nulled");
2825  XML_SetBase(g_parser, old_base);
2826}
2827END_TEST
2828
2829/* Test attribute counts, indexing, etc */
2830typedef struct attrInfo {
2831  const XML_Char *name;
2832  const XML_Char *value;
2833} AttrInfo;
2834
2835typedef struct elementInfo {
2836  const XML_Char *name;
2837  int attr_count;
2838  const XML_Char *id_name;
2839  AttrInfo *attributes;
2840} ElementInfo;
2841
2842static void XMLCALL
2843counting_start_element_handler(void *userData, const XML_Char *name,
2844                               const XML_Char **atts) {
2845  ElementInfo *info = (ElementInfo *)userData;
2846  AttrInfo *attr;
2847  int count, id, i;
2848
2849  while (info->name != NULL) {
2850    if (! xcstrcmp(name, info->name))
2851      break;
2852    info++;
2853  }
2854  if (info->name == NULL)
2855    fail("Element not recognised");
2856  /* The attribute count is twice what you might expect.  It is a
2857   * count of items in atts, an array which contains alternating
2858   * attribute names and attribute values.  For the naive user this
2859   * is possibly a little unexpected, but it is what the
2860   * documentation in expat.h tells us to expect.
2861   */
2862  count = XML_GetSpecifiedAttributeCount(g_parser);
2863  if (info->attr_count * 2 != count) {
2864    fail("Not got expected attribute count");
2865    return;
2866  }
2867  id = XML_GetIdAttributeIndex(g_parser);
2868  if (id == -1 && info->id_name != NULL) {
2869    fail("ID not present");
2870    return;
2871  }
2872  if (id != -1 && xcstrcmp(atts[id], info->id_name)) {
2873    fail("ID does not have the correct name");
2874    return;
2875  }
2876  for (i = 0; i < info->attr_count; i++) {
2877    attr = info->attributes;
2878    while (attr->name != NULL) {
2879      if (! xcstrcmp(atts[0], attr->name))
2880        break;
2881      attr++;
2882    }
2883    if (attr->name == NULL) {
2884      fail("Attribute not recognised");
2885      return;
2886    }
2887    if (xcstrcmp(atts[1], attr->value)) {
2888      fail("Attribute has wrong value");
2889      return;
2890    }
2891    /* Remember, two entries in atts per attribute (see above) */
2892    atts += 2;
2893  }
2894}
2895
2896START_TEST(test_attributes) {
2897  const char *text = "<!DOCTYPE doc [\n"
2898                     "<!ELEMENT doc (tag)>\n"
2899                     "<!ATTLIST doc id ID #REQUIRED>\n"
2900                     "]>"
2901                     "<doc a='1' id='one' b='2'>"
2902                     "<tag c='3'/>"
2903                     "</doc>";
2904  AttrInfo doc_info[] = {{XCS("a"), XCS("1")},
2905                         {XCS("b"), XCS("2")},
2906                         {XCS("id"), XCS("one")},
2907                         {NULL, NULL}};
2908  AttrInfo tag_info[] = {{XCS("c"), XCS("3")}, {NULL, NULL}};
2909  ElementInfo info[] = {{XCS("doc"), 3, XCS("id"), NULL},
2910                        {XCS("tag"), 1, NULL, NULL},
2911                        {NULL, 0, NULL, NULL}};
2912  info[0].attributes = doc_info;
2913  info[1].attributes = tag_info;
2914
2915  XML_SetStartElementHandler(g_parser, counting_start_element_handler);
2916  XML_SetUserData(g_parser, info);
2917  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2918      == XML_STATUS_ERROR)
2919    xml_failure(g_parser);
2920}
2921END_TEST
2922
2923/* Test reset works correctly in the middle of processing an internal
2924 * entity.  Exercises some obscure code in XML_ParserReset().
2925 */
2926START_TEST(test_reset_in_entity) {
2927  const char *text = "<!DOCTYPE doc [\n"
2928                     "<!ENTITY wombat 'wom'>\n"
2929                     "<!ENTITY entity 'hi &wom; there'>\n"
2930                     "]>\n"
2931                     "<doc>&entity;</doc>";
2932  XML_ParsingStatus status;
2933
2934  resumable = XML_TRUE;
2935  XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
2936  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
2937      == XML_STATUS_ERROR)
2938    xml_failure(g_parser);
2939  XML_GetParsingStatus(g_parser, &status);
2940  if (status.parsing != XML_SUSPENDED)
2941    fail("Parsing status not SUSPENDED");
2942  XML_ParserReset(g_parser, NULL);
2943  XML_GetParsingStatus(g_parser, &status);
2944  if (status.parsing != XML_INITIALIZED)
2945    fail("Parsing status doesn't reset to INITIALIZED");
2946}
2947END_TEST
2948
2949/* Test that resume correctly passes through parse errors */
2950START_TEST(test_resume_invalid_parse) {
2951  const char *text = "<doc>Hello</doc"; /* Missing closing wedge */
2952
2953  resumable = XML_TRUE;
2954  XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
2955  if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
2956      == XML_STATUS_ERROR)
2957    xml_failure(g_parser);
2958  if (XML_ResumeParser(g_parser) == XML_STATUS_OK)
2959    fail("Resumed invalid parse not faulted");
2960  if (XML_GetErrorCode(g_parser) != XML_ERROR_UNCLOSED_TOKEN)
2961    fail("Invalid parse not correctly faulted");
2962}
2963END_TEST
2964
2965/* Test that re-suspended parses are correctly passed through */
2966START_TEST(test_resume_resuspended) {
2967  const char *text = "<doc>Hello<meep/>world</doc>";
2968
2969  resumable = XML_TRUE;
2970  XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
2971  if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
2972      == XML_STATUS_ERROR)
2973    xml_failure(g_parser);
2974  resumable = XML_TRUE;
2975  XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
2976  if (XML_ResumeParser(g_parser) != XML_STATUS_SUSPENDED)
2977    fail("Resumption not suspended");
2978  /* This one should succeed and finish up */
2979  if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
2980    xml_failure(g_parser);
2981}
2982END_TEST
2983
2984/* Test that CDATA shows up correctly through a default handler */
2985START_TEST(test_cdata_default) {
2986  const char *text = "<doc><![CDATA[Hello\nworld]]></doc>";
2987  const XML_Char *expected = XCS("<doc><![CDATA[Hello\nworld]]></doc>");
2988  CharData storage;
2989
2990  CharData_Init(&storage);
2991  XML_SetUserData(g_parser, &storage);
2992  XML_SetDefaultHandler(g_parser, accumulate_characters);
2993
2994  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
2995      == XML_STATUS_ERROR)
2996    xml_failure(g_parser);
2997  CharData_CheckXMLChars(&storage, expected);
2998}
2999END_TEST
3000
3001/* Test resetting a subordinate parser does exactly nothing */
3002static int XMLCALL
3003external_entity_resetter(XML_Parser parser, const XML_Char *context,
3004                         const XML_Char *base, const XML_Char *systemId,
3005                         const XML_Char *publicId) {
3006  const char *text = "<!ELEMENT doc (#PCDATA)*>";
3007  XML_Parser ext_parser;
3008  XML_ParsingStatus status;
3009
3010  UNUSED_P(base);
3011  UNUSED_P(systemId);
3012  UNUSED_P(publicId);
3013  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3014  if (ext_parser == NULL)
3015    fail("Could not create external entity parser");
3016  XML_GetParsingStatus(ext_parser, &status);
3017  if (status.parsing != XML_INITIALIZED) {
3018    fail("Parsing status is not INITIALIZED");
3019    return XML_STATUS_ERROR;
3020  }
3021  if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
3022      == XML_STATUS_ERROR) {
3023    xml_failure(parser);
3024    return XML_STATUS_ERROR;
3025  }
3026  XML_GetParsingStatus(ext_parser, &status);
3027  if (status.parsing != XML_FINISHED) {
3028    fail("Parsing status is not FINISHED");
3029    return XML_STATUS_ERROR;
3030  }
3031  /* Check we can't parse here */
3032  if (XML_Parse(ext_parser, text, (int)strlen(text), XML_TRUE)
3033      != XML_STATUS_ERROR)
3034    fail("Parsing when finished not faulted");
3035  if (XML_GetErrorCode(ext_parser) != XML_ERROR_FINISHED)
3036    fail("Parsing when finished faulted with wrong code");
3037  XML_ParserReset(ext_parser, NULL);
3038  XML_GetParsingStatus(ext_parser, &status);
3039  if (status.parsing != XML_FINISHED) {
3040    fail("Parsing status not still FINISHED");
3041    return XML_STATUS_ERROR;
3042  }
3043  XML_ParserFree(ext_parser);
3044  return XML_STATUS_OK;
3045}
3046
3047START_TEST(test_subordinate_reset) {
3048  const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
3049                     "<!DOCTYPE doc SYSTEM 'foo'>\n"
3050                     "<doc>&entity;</doc>";
3051
3052  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3053  XML_SetExternalEntityRefHandler(g_parser, external_entity_resetter);
3054  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3055      == XML_STATUS_ERROR)
3056    xml_failure(g_parser);
3057}
3058END_TEST
3059
3060/* Test suspending a subordinate parser */
3061
3062static void XMLCALL
3063entity_suspending_decl_handler(void *userData, const XML_Char *name,
3064                               XML_Content *model) {
3065  XML_Parser ext_parser = (XML_Parser)userData;
3066
3067  UNUSED_P(name);
3068  if (XML_StopParser(ext_parser, XML_TRUE) != XML_STATUS_ERROR)
3069    fail("Attempting to suspend a subordinate parser not faulted");
3070  if (XML_GetErrorCode(ext_parser) != XML_ERROR_SUSPEND_PE)
3071    fail("Suspending subordinate parser get wrong code");
3072  XML_SetElementDeclHandler(ext_parser, NULL);
3073  XML_FreeContentModel(g_parser, model);
3074}
3075
3076static int XMLCALL
3077external_entity_suspender(XML_Parser parser, const XML_Char *context,
3078                          const XML_Char *base, const XML_Char *systemId,
3079                          const XML_Char *publicId) {
3080  const char *text = "<!ELEMENT doc (#PCDATA)*>";
3081  XML_Parser ext_parser;
3082
3083  UNUSED_P(base);
3084  UNUSED_P(systemId);
3085  UNUSED_P(publicId);
3086  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3087  if (ext_parser == NULL)
3088    fail("Could not create external entity parser");
3089  XML_SetElementDeclHandler(ext_parser, entity_suspending_decl_handler);
3090  XML_SetUserData(ext_parser, ext_parser);
3091  if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
3092      == XML_STATUS_ERROR) {
3093    xml_failure(ext_parser);
3094    return XML_STATUS_ERROR;
3095  }
3096  XML_ParserFree(ext_parser);
3097  return XML_STATUS_OK;
3098}
3099
3100START_TEST(test_subordinate_suspend) {
3101  const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
3102                     "<!DOCTYPE doc SYSTEM 'foo'>\n"
3103                     "<doc>&entity;</doc>";
3104
3105  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3106  XML_SetExternalEntityRefHandler(g_parser, external_entity_suspender);
3107  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3108      == XML_STATUS_ERROR)
3109    xml_failure(g_parser);
3110}
3111END_TEST
3112
3113/* Test suspending a subordinate parser from an XML declaration */
3114/* Increases code coverage of the tests */
3115static void XMLCALL
3116entity_suspending_xdecl_handler(void *userData, const XML_Char *version,
3117                                const XML_Char *encoding, int standalone) {
3118  XML_Parser ext_parser = (XML_Parser)userData;
3119
3120  UNUSED_P(version);
3121  UNUSED_P(encoding);
3122  UNUSED_P(standalone);
3123  XML_StopParser(ext_parser, resumable);
3124  XML_SetXmlDeclHandler(ext_parser, NULL);
3125}
3126
3127static int XMLCALL
3128external_entity_suspend_xmldecl(XML_Parser parser, const XML_Char *context,
3129                                const XML_Char *base, const XML_Char *systemId,
3130                                const XML_Char *publicId) {
3131  const char *text = "<?xml version='1.0' encoding='us-ascii'?>";
3132  XML_Parser ext_parser;
3133  XML_ParsingStatus status;
3134  enum XML_Status rc;
3135
3136  UNUSED_P(base);
3137  UNUSED_P(systemId);
3138  UNUSED_P(publicId);
3139  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3140  if (ext_parser == NULL)
3141    fail("Could not create external entity parser");
3142  XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler);
3143  XML_SetUserData(ext_parser, ext_parser);
3144  rc = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
3145  XML_GetParsingStatus(ext_parser, &status);
3146  if (resumable) {
3147    if (rc == XML_STATUS_ERROR)
3148      xml_failure(ext_parser);
3149    if (status.parsing != XML_SUSPENDED)
3150      fail("Ext Parsing status not SUSPENDED");
3151  } else {
3152    if (rc != XML_STATUS_ERROR)
3153      fail("Ext parsing not aborted");
3154    if (XML_GetErrorCode(ext_parser) != XML_ERROR_ABORTED)
3155      xml_failure(ext_parser);
3156    if (status.parsing != XML_FINISHED)
3157      fail("Ext Parsing status not FINISHED");
3158  }
3159
3160  XML_ParserFree(ext_parser);
3161  return XML_STATUS_OK;
3162}
3163
3164START_TEST(test_subordinate_xdecl_suspend) {
3165  const char *text
3166      = "<!DOCTYPE doc [\n"
3167        "  <!ENTITY entity SYSTEM 'http://example.org/dummy.ent'>\n"
3168        "]>\n"
3169        "<doc>&entity;</doc>";
3170
3171  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3172  XML_SetExternalEntityRefHandler(g_parser, external_entity_suspend_xmldecl);
3173  resumable = XML_TRUE;
3174  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3175      == XML_STATUS_ERROR)
3176    xml_failure(g_parser);
3177}
3178END_TEST
3179
3180START_TEST(test_subordinate_xdecl_abort) {
3181  const char *text
3182      = "<!DOCTYPE doc [\n"
3183        "  <!ENTITY entity SYSTEM 'http://example.org/dummy.ent'>\n"
3184        "]>\n"
3185        "<doc>&entity;</doc>";
3186
3187  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3188  XML_SetExternalEntityRefHandler(g_parser, external_entity_suspend_xmldecl);
3189  resumable = XML_FALSE;
3190  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3191      == XML_STATUS_ERROR)
3192    xml_failure(g_parser);
3193}
3194END_TEST
3195
3196/* Test external entity fault handling with suspension */
3197static int XMLCALL
3198external_entity_suspending_faulter(XML_Parser parser, const XML_Char *context,
3199                                   const XML_Char *base,
3200                                   const XML_Char *systemId,
3201                                   const XML_Char *publicId) {
3202  XML_Parser ext_parser;
3203  ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser);
3204  void *buffer;
3205  int parse_len = (int)strlen(fault->parse_text);
3206
3207  UNUSED_P(base);
3208  UNUSED_P(systemId);
3209  UNUSED_P(publicId);
3210  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3211  if (ext_parser == NULL)
3212    fail("Could not create external entity parser");
3213  XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler);
3214  XML_SetUserData(ext_parser, ext_parser);
3215  resumable = XML_TRUE;
3216  buffer = XML_GetBuffer(ext_parser, parse_len);
3217  if (buffer == NULL)
3218    fail("Could not allocate parse buffer");
3219  assert(buffer != NULL);
3220  memcpy(buffer, fault->parse_text, parse_len);
3221  if (XML_ParseBuffer(ext_parser, parse_len, XML_FALSE) != XML_STATUS_SUSPENDED)
3222    fail("XML declaration did not suspend");
3223  if (XML_ResumeParser(ext_parser) != XML_STATUS_OK)
3224    xml_failure(ext_parser);
3225  if (XML_ParseBuffer(ext_parser, 0, XML_TRUE) != XML_STATUS_ERROR)
3226    fail(fault->fail_text);
3227  if (XML_GetErrorCode(ext_parser) != fault->error)
3228    xml_failure(ext_parser);
3229
3230  XML_ParserFree(ext_parser);
3231  return XML_STATUS_ERROR;
3232}
3233
3234START_TEST(test_ext_entity_invalid_suspended_parse) {
3235  const char *text = "<!DOCTYPE doc [\n"
3236                     "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
3237                     "]>\n"
3238                     "<doc>&en;</doc>";
3239  ExtFaults faults[]
3240      = {{"<?xml version='1.0' encoding='us-ascii'?><",
3241          "Incomplete element declaration not faulted", NULL,
3242          XML_ERROR_UNCLOSED_TOKEN},
3243         {/* First two bytes of a three-byte char */
3244          "<?xml version='1.0' encoding='utf-8'?>\xe2\x82",
3245          "Incomplete character not faulted", NULL, XML_ERROR_PARTIAL_CHAR},
3246         {NULL, NULL, NULL, XML_ERROR_NONE}};
3247  ExtFaults *fault;
3248
3249  for (fault = &faults[0]; fault->parse_text != NULL; fault++) {
3250    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3251    XML_SetExternalEntityRefHandler(g_parser,
3252                                    external_entity_suspending_faulter);
3253    XML_SetUserData(g_parser, fault);
3254    expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
3255                   "Parser did not report external entity error");
3256    XML_ParserReset(g_parser, NULL);
3257  }
3258}
3259END_TEST
3260
3261/* Test setting an explicit encoding */
3262START_TEST(test_explicit_encoding) {
3263  const char *text1 = "<doc>Hello ";
3264  const char *text2 = " World</doc>";
3265
3266  /* Just check that we can set the encoding to NULL before starting */
3267  if (XML_SetEncoding(g_parser, NULL) != XML_STATUS_OK)
3268    fail("Failed to initialise encoding to NULL");
3269  /* Say we are UTF-8 */
3270  if (XML_SetEncoding(g_parser, XCS("utf-8")) != XML_STATUS_OK)
3271    fail("Failed to set explicit encoding");
3272  if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
3273      == XML_STATUS_ERROR)
3274    xml_failure(g_parser);
3275  /* Try to switch encodings mid-parse */
3276  if (XML_SetEncoding(g_parser, XCS("us-ascii")) != XML_STATUS_ERROR)
3277    fail("Allowed encoding change");
3278  if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
3279      == XML_STATUS_ERROR)
3280    xml_failure(g_parser);
3281  /* Try now the parse is over */
3282  if (XML_SetEncoding(g_parser, NULL) != XML_STATUS_OK)
3283    fail("Failed to unset encoding");
3284}
3285END_TEST
3286
3287/* Test handling of trailing CR (rather than newline) */
3288static void XMLCALL
3289cr_cdata_handler(void *userData, const XML_Char *s, int len) {
3290  int *pfound = (int *)userData;
3291
3292  /* Internal processing turns the CR into a newline for the
3293   * character data handler, but not for the default handler
3294   */
3295  if (len == 1 && (*s == XCS('\n') || *s == XCS('\r')))
3296    *pfound = 1;
3297}
3298
3299START_TEST(test_trailing_cr) {
3300  const char *text = "<doc>\r";
3301  int found_cr;
3302
3303  /* Try with a character handler, for code coverage */
3304  XML_SetCharacterDataHandler(g_parser, cr_cdata_handler);
3305  XML_SetUserData(g_parser, &found_cr);
3306  found_cr = 0;
3307  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3308      == XML_STATUS_OK)
3309    fail("Failed to fault unclosed doc");
3310  if (found_cr == 0)
3311    fail("Did not catch the carriage return");
3312  XML_ParserReset(g_parser, NULL);
3313
3314  /* Now with a default handler instead */
3315  XML_SetDefaultHandler(g_parser, cr_cdata_handler);
3316  XML_SetUserData(g_parser, &found_cr);
3317  found_cr = 0;
3318  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3319      == XML_STATUS_OK)
3320    fail("Failed to fault unclosed doc");
3321  if (found_cr == 0)
3322    fail("Did not catch default carriage return");
3323}
3324END_TEST
3325
3326/* Test trailing CR in an external entity parse */
3327static int XMLCALL
3328external_entity_cr_catcher(XML_Parser parser, const XML_Char *context,
3329                           const XML_Char *base, const XML_Char *systemId,
3330                           const XML_Char *publicId) {
3331  const char *text = "\r";
3332  XML_Parser ext_parser;
3333
3334  UNUSED_P(base);
3335  UNUSED_P(systemId);
3336  UNUSED_P(publicId);
3337  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3338  if (ext_parser == NULL)
3339    fail("Could not create external entity parser");
3340  XML_SetCharacterDataHandler(ext_parser, cr_cdata_handler);
3341  if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
3342      == XML_STATUS_ERROR)
3343    xml_failure(ext_parser);
3344  XML_ParserFree(ext_parser);
3345  return XML_STATUS_OK;
3346}
3347
3348static int XMLCALL
3349external_entity_bad_cr_catcher(XML_Parser parser, const XML_Char *context,
3350                               const XML_Char *base, const XML_Char *systemId,
3351                               const XML_Char *publicId) {
3352  const char *text = "<tag>\r";
3353  XML_Parser ext_parser;
3354
3355  UNUSED_P(base);
3356  UNUSED_P(systemId);
3357  UNUSED_P(publicId);
3358  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3359  if (ext_parser == NULL)
3360    fail("Could not create external entity parser");
3361  XML_SetCharacterDataHandler(ext_parser, cr_cdata_handler);
3362  if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
3363      == XML_STATUS_OK)
3364    fail("Async entity error not caught");
3365  if (XML_GetErrorCode(ext_parser) != XML_ERROR_ASYNC_ENTITY)
3366    xml_failure(ext_parser);
3367  XML_ParserFree(ext_parser);
3368  return XML_STATUS_OK;
3369}
3370
3371START_TEST(test_ext_entity_trailing_cr) {
3372  const char *text = "<!DOCTYPE doc [\n"
3373                     "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
3374                     "]>\n"
3375                     "<doc>&en;</doc>";
3376  int found_cr;
3377
3378  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3379  XML_SetExternalEntityRefHandler(g_parser, external_entity_cr_catcher);
3380  XML_SetUserData(g_parser, &found_cr);
3381  found_cr = 0;
3382  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3383      != XML_STATUS_OK)
3384    xml_failure(g_parser);
3385  if (found_cr == 0)
3386    fail("No carriage return found");
3387  XML_ParserReset(g_parser, NULL);
3388
3389  /* Try again with a different trailing CR */
3390  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3391  XML_SetExternalEntityRefHandler(g_parser, external_entity_bad_cr_catcher);
3392  XML_SetUserData(g_parser, &found_cr);
3393  found_cr = 0;
3394  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3395      != XML_STATUS_OK)
3396    xml_failure(g_parser);
3397  if (found_cr == 0)
3398    fail("No carriage return found");
3399}
3400END_TEST
3401
3402/* Test handling of trailing square bracket */
3403static void XMLCALL
3404rsqb_handler(void *userData, const XML_Char *s, int len) {
3405  int *pfound = (int *)userData;
3406
3407  if (len == 1 && *s == XCS(']'))
3408    *pfound = 1;
3409}
3410
3411START_TEST(test_trailing_rsqb) {
3412  const char *text8 = "<doc>]";
3413  const char text16[] = "\xFF\xFE<\000d\000o\000c\000>\000]\000";
3414  int found_rsqb;
3415  int text8_len = (int)strlen(text8);
3416
3417  XML_SetCharacterDataHandler(g_parser, rsqb_handler);
3418  XML_SetUserData(g_parser, &found_rsqb);
3419  found_rsqb = 0;
3420  if (_XML_Parse_SINGLE_BYTES(g_parser, text8, text8_len, XML_TRUE)
3421      == XML_STATUS_OK)
3422    fail("Failed to fault unclosed doc");
3423  if (found_rsqb == 0)
3424    fail("Did not catch the right square bracket");
3425
3426  /* Try again with a different encoding */
3427  XML_ParserReset(g_parser, NULL);
3428  XML_SetCharacterDataHandler(g_parser, rsqb_handler);
3429  XML_SetUserData(g_parser, &found_rsqb);
3430  found_rsqb = 0;
3431  if (_XML_Parse_SINGLE_BYTES(g_parser, text16, (int)sizeof(text16) - 1,
3432                              XML_TRUE)
3433      == XML_STATUS_OK)
3434    fail("Failed to fault unclosed doc");
3435  if (found_rsqb == 0)
3436    fail("Did not catch the right square bracket");
3437
3438  /* And finally with a default handler */
3439  XML_ParserReset(g_parser, NULL);
3440  XML_SetDefaultHandler(g_parser, rsqb_handler);
3441  XML_SetUserData(g_parser, &found_rsqb);
3442  found_rsqb = 0;
3443  if (_XML_Parse_SINGLE_BYTES(g_parser, text16, (int)sizeof(text16) - 1,
3444                              XML_TRUE)
3445      == XML_STATUS_OK)
3446    fail("Failed to fault unclosed doc");
3447  if (found_rsqb == 0)
3448    fail("Did not catch the right square bracket");
3449}
3450END_TEST
3451
3452/* Test trailing right square bracket in an external entity parse */
3453static int XMLCALL
3454external_entity_rsqb_catcher(XML_Parser parser, const XML_Char *context,
3455                             const XML_Char *base, const XML_Char *systemId,
3456                             const XML_Char *publicId) {
3457  const char *text = "<tag>]";
3458  XML_Parser ext_parser;
3459
3460  UNUSED_P(base);
3461  UNUSED_P(systemId);
3462  UNUSED_P(publicId);
3463  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3464  if (ext_parser == NULL)
3465    fail("Could not create external entity parser");
3466  XML_SetCharacterDataHandler(ext_parser, rsqb_handler);
3467  if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
3468      != XML_STATUS_ERROR)
3469    fail("Async entity error not caught");
3470  if (XML_GetErrorCode(ext_parser) != XML_ERROR_ASYNC_ENTITY)
3471    xml_failure(ext_parser);
3472  XML_ParserFree(ext_parser);
3473  return XML_STATUS_OK;
3474}
3475
3476START_TEST(test_ext_entity_trailing_rsqb) {
3477  const char *text = "<!DOCTYPE doc [\n"
3478                     "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
3479                     "]>\n"
3480                     "<doc>&en;</doc>";
3481  int found_rsqb;
3482
3483  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3484  XML_SetExternalEntityRefHandler(g_parser, external_entity_rsqb_catcher);
3485  XML_SetUserData(g_parser, &found_rsqb);
3486  found_rsqb = 0;
3487  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3488      != XML_STATUS_OK)
3489    xml_failure(g_parser);
3490  if (found_rsqb == 0)
3491    fail("No right square bracket found");
3492}
3493END_TEST
3494
3495/* Test CDATA handling in an external entity */
3496static int XMLCALL
3497external_entity_good_cdata_ascii(XML_Parser parser, const XML_Char *context,
3498                                 const XML_Char *base, const XML_Char *systemId,
3499                                 const XML_Char *publicId) {
3500  const char *text = "<a><![CDATA[<greeting>Hello, world!</greeting>]]></a>";
3501  const XML_Char *expected = XCS("<greeting>Hello, world!</greeting>");
3502  CharData storage;
3503  XML_Parser ext_parser;
3504
3505  UNUSED_P(base);
3506  UNUSED_P(systemId);
3507  UNUSED_P(publicId);
3508  CharData_Init(&storage);
3509  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3510  if (ext_parser == NULL)
3511    fail("Could not create external entity parser");
3512  XML_SetUserData(ext_parser, &storage);
3513  XML_SetCharacterDataHandler(ext_parser, accumulate_characters);
3514
3515  if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
3516      == XML_STATUS_ERROR)
3517    xml_failure(ext_parser);
3518  CharData_CheckXMLChars(&storage, expected);
3519
3520  XML_ParserFree(ext_parser);
3521  return XML_STATUS_OK;
3522}
3523
3524START_TEST(test_ext_entity_good_cdata) {
3525  const char *text = "<!DOCTYPE doc [\n"
3526                     "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
3527                     "]>\n"
3528                     "<doc>&en;</doc>";
3529
3530  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3531  XML_SetExternalEntityRefHandler(g_parser, external_entity_good_cdata_ascii);
3532  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3533      != XML_STATUS_OK)
3534    xml_failure(g_parser);
3535}
3536END_TEST
3537
3538/* Test user parameter settings */
3539/* Variable holding the expected handler userData */
3540static void *handler_data = NULL;
3541/* Count of the number of times the comment handler has been invoked */
3542static int comment_count = 0;
3543/* Count of the number of skipped entities */
3544static int skip_count = 0;
3545/* Count of the number of times the XML declaration handler is invoked */
3546static int xdecl_count = 0;
3547
3548static void XMLCALL
3549xml_decl_handler(void *userData, const XML_Char *version,
3550                 const XML_Char *encoding, int standalone) {
3551  UNUSED_P(version);
3552  UNUSED_P(encoding);
3553  if (userData != handler_data)
3554    fail("User data (xml decl) not correctly set");
3555  if (standalone != -1)
3556    fail("Standalone not flagged as not present in XML decl");
3557  xdecl_count++;
3558}
3559
3560static void XMLCALL
3561param_check_skip_handler(void *userData, const XML_Char *entityName,
3562                         int is_parameter_entity) {
3563  UNUSED_P(entityName);
3564  UNUSED_P(is_parameter_entity);
3565  if (userData != handler_data)
3566    fail("User data (skip) not correctly set");
3567  skip_count++;
3568}
3569
3570static void XMLCALL
3571data_check_comment_handler(void *userData, const XML_Char *data) {
3572  UNUSED_P(data);
3573  /* Check that the userData passed through is what we expect */
3574  if (userData != handler_data)
3575    fail("User data (parser) not correctly set");
3576  /* Check that the user data in the parser is appropriate */
3577  if (XML_GetUserData(userData) != (void *)1)
3578    fail("User data in parser not correctly set");
3579  comment_count++;
3580}
3581
3582static int XMLCALL
3583external_entity_param_checker(XML_Parser parser, const XML_Char *context,
3584                              const XML_Char *base, const XML_Char *systemId,
3585                              const XML_Char *publicId) {
3586  const char *text = "<!-- Subordinate parser -->\n"
3587                     "<!ELEMENT doc (#PCDATA)*>";
3588  XML_Parser ext_parser;
3589
3590  UNUSED_P(base);
3591  UNUSED_P(systemId);
3592  UNUSED_P(publicId);
3593  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3594  if (ext_parser == NULL)
3595    fail("Could not create external entity parser");
3596  handler_data = ext_parser;
3597  if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
3598      == XML_STATUS_ERROR) {
3599    xml_failure(parser);
3600    return XML_STATUS_ERROR;
3601  }
3602  handler_data = parser;
3603  XML_ParserFree(ext_parser);
3604  return XML_STATUS_OK;
3605}
3606
3607START_TEST(test_user_parameters) {
3608  const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
3609                     "<!-- Primary parse -->\n"
3610                     "<!DOCTYPE doc SYSTEM 'foo'>\n"
3611                     "<doc>&entity;";
3612  const char *epilog = "<!-- Back to primary parser -->\n"
3613                       "</doc>";
3614
3615  comment_count = 0;
3616  skip_count = 0;
3617  xdecl_count = 0;
3618  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3619  XML_SetXmlDeclHandler(g_parser, xml_decl_handler);
3620  XML_SetExternalEntityRefHandler(g_parser, external_entity_param_checker);
3621  XML_SetCommentHandler(g_parser, data_check_comment_handler);
3622  XML_SetSkippedEntityHandler(g_parser, param_check_skip_handler);
3623  XML_UseParserAsHandlerArg(g_parser);
3624  XML_SetUserData(g_parser, (void *)1);
3625  handler_data = g_parser;
3626  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
3627      == XML_STATUS_ERROR)
3628    xml_failure(g_parser);
3629  if (comment_count != 2)
3630    fail("Comment handler not invoked enough times");
3631  /* Ensure we can't change policy mid-parse */
3632  if (XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_NEVER))
3633    fail("Changed param entity parsing policy while parsing");
3634  if (_XML_Parse_SINGLE_BYTES(g_parser, epilog, (int)strlen(epilog), XML_TRUE)
3635      == XML_STATUS_ERROR)
3636    xml_failure(g_parser);
3637  if (comment_count != 3)
3638    fail("Comment handler not invoked enough times");
3639  if (skip_count != 1)
3640    fail("Skip handler not invoked enough times");
3641  if (xdecl_count != 1)
3642    fail("XML declaration handler not invoked");
3643}
3644END_TEST
3645
3646/* Test that an explicit external entity handler argument replaces
3647 * the parser as the first argument.
3648 *
3649 * We do not call the first parameter to the external entity handler
3650 * 'parser' for once, since the first time the handler is called it
3651 * will actually be a text string.  We need to be able to access the
3652 * global 'parser' variable to create our external entity parser from,
3653 * since there are code paths we need to ensure get executed.
3654 */
3655static int XMLCALL
3656external_entity_ref_param_checker(XML_Parser parameter, const XML_Char *context,
3657                                  const XML_Char *base,
3658                                  const XML_Char *systemId,
3659                                  const XML_Char *publicId) {
3660  const char *text = "<!ELEMENT doc (#PCDATA)*>";
3661  XML_Parser ext_parser;
3662
3663  UNUSED_P(base);
3664  UNUSED_P(systemId);
3665  UNUSED_P(publicId);
3666  if ((void *)parameter != handler_data)
3667    fail("External entity ref handler parameter not correct");
3668
3669  /* Here we use the global 'parser' variable */
3670  ext_parser = XML_ExternalEntityParserCreate(g_parser, context, NULL);
3671  if (ext_parser == NULL)
3672    fail("Could not create external entity parser");
3673  if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
3674      == XML_STATUS_ERROR)
3675    xml_failure(ext_parser);
3676
3677  XML_ParserFree(ext_parser);
3678  return XML_STATUS_OK;
3679}
3680
3681START_TEST(test_ext_entity_ref_parameter) {
3682  const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
3683                     "<!DOCTYPE doc SYSTEM 'foo'>\n"
3684                     "<doc>&entity;</doc>";
3685
3686  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3687  XML_SetExternalEntityRefHandler(g_parser, external_entity_ref_param_checker);
3688  /* Set a handler arg that is not NULL and not parser (which is
3689   * what NULL would cause to be passed.
3690   */
3691  XML_SetExternalEntityRefHandlerArg(g_parser, (void *)text);
3692  handler_data = (void *)text;
3693  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3694      == XML_STATUS_ERROR)
3695    xml_failure(g_parser);
3696
3697  /* Now try again with unset args */
3698  XML_ParserReset(g_parser, NULL);
3699  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
3700  XML_SetExternalEntityRefHandler(g_parser, external_entity_ref_param_checker);
3701  XML_SetExternalEntityRefHandlerArg(g_parser, NULL);
3702  handler_data = (void *)g_parser;
3703  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3704      == XML_STATUS_ERROR)
3705    xml_failure(g_parser);
3706}
3707END_TEST
3708
3709/* Test the parsing of an empty string */
3710START_TEST(test_empty_parse) {
3711  const char *text = "<doc></doc>";
3712  const char *partial = "<doc>";
3713
3714  if (XML_Parse(g_parser, NULL, 0, XML_FALSE) == XML_STATUS_ERROR)
3715    fail("Parsing empty string faulted");
3716  if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR)
3717    fail("Parsing final empty string not faulted");
3718  if (XML_GetErrorCode(g_parser) != XML_ERROR_NO_ELEMENTS)
3719    fail("Parsing final empty string faulted for wrong reason");
3720
3721  /* Now try with valid text before the empty end */
3722  XML_ParserReset(g_parser, NULL);
3723  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
3724      == XML_STATUS_ERROR)
3725    xml_failure(g_parser);
3726  if (XML_Parse(g_parser, NULL, 0, XML_TRUE) == XML_STATUS_ERROR)
3727    fail("Parsing final empty string faulted");
3728
3729  /* Now try with invalid text before the empty end */
3730  XML_ParserReset(g_parser, NULL);
3731  if (_XML_Parse_SINGLE_BYTES(g_parser, partial, (int)strlen(partial),
3732                              XML_FALSE)
3733      == XML_STATUS_ERROR)
3734    xml_failure(g_parser);
3735  if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR)
3736    fail("Parsing final incomplete empty string not faulted");
3737}
3738END_TEST
3739
3740/* Test odd corners of the XML_GetBuffer interface */
3741static enum XML_Status
3742get_feature(enum XML_FeatureEnum feature_id, long *presult) {
3743  const XML_Feature *feature = XML_GetFeatureList();
3744
3745  if (feature == NULL)
3746    return XML_STATUS_ERROR;
3747  for (; feature->feature != XML_FEATURE_END; feature++) {
3748    if (feature->feature == feature_id) {
3749      *presult = feature->value;
3750      return XML_STATUS_OK;
3751    }
3752  }
3753  return XML_STATUS_ERROR;
3754}
3755
3756/* Having an element name longer than 1024 characters exercises some
3757 * of the pool allocation code in the parser that otherwise does not
3758 * get executed.  The count at the end of the line is the number of
3759 * characters (bytes) in the element name by that point.x
3760 */
3761static const char *get_buffer_test_text
3762    = "<documentwitharidiculouslylongelementnametotease"  /* 0x030 */
3763      "aparticularcorneroftheallocationinXML_GetBuffers"  /* 0x060 */
3764      "othatwecanimprovethecoverageyetagain012345678901"  /* 0x090 */
3765      "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x0c0 */
3766      "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x0f0 */
3767      "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x120 */
3768      "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x150 */
3769      "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x180 */
3770      "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x1b0 */
3771      "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x1e0 */
3772      "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x210 */
3773      "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x240 */
3774      "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x270 */
3775      "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x2a0 */
3776      "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x2d0 */
3777      "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x300 */
3778      "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x330 */
3779      "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x360 */
3780      "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x390 */
3781      "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x3c0 */
3782      "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x3f0 */
3783      "123456789abcdef0123456789abcdef0123456789>\n<ef0"; /* 0x420 */
3784
3785/* Test odd corners of the XML_GetBuffer interface */
3786START_TEST(test_get_buffer_1) {
3787  const char *text = get_buffer_test_text;
3788  void *buffer;
3789  long context_bytes;
3790
3791  /* Attempt to allocate a negative length buffer */
3792  if (XML_GetBuffer(g_parser, -12) != NULL)
3793    fail("Negative length buffer not failed");
3794
3795  /* Now get a small buffer and extend it past valid length */
3796  buffer = XML_GetBuffer(g_parser, 1536);
3797  if (buffer == NULL)
3798    fail("1.5K buffer failed");
3799  assert(buffer != NULL);
3800  memcpy(buffer, text, strlen(text));
3801  if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_FALSE)
3802      == XML_STATUS_ERROR)
3803    xml_failure(g_parser);
3804  if (XML_GetBuffer(g_parser, INT_MAX) != NULL)
3805    fail("INT_MAX buffer not failed");
3806
3807  /* Now try extending it a more reasonable but still too large
3808   * amount.  The allocator in XML_GetBuffer() doubles the buffer
3809   * size until it exceeds the requested amount or INT_MAX.  If it
3810   * exceeds INT_MAX, it rejects the request, so we want a request
3811   * between INT_MAX and INT_MAX/2.  A gap of 1K seems comfortable,
3812   * with an extra byte just to ensure that the request is off any
3813   * boundary.  The request will be inflated internally by
3814   * XML_CONTEXT_BYTES (if defined), so we subtract that from our
3815   * request.
3816   */
3817  if (get_feature(XML_FEATURE_CONTEXT_BYTES, &context_bytes) != XML_STATUS_OK)
3818    context_bytes = 0;
3819  if (XML_GetBuffer(g_parser, INT_MAX - (context_bytes + 1025)) != NULL)
3820    fail("INT_MAX- buffer not failed");
3821
3822  /* Now try extending it a carefully crafted amount */
3823  if (XML_GetBuffer(g_parser, 1000) == NULL)
3824    fail("1000 buffer failed");
3825}
3826END_TEST
3827
3828/* Test more corners of the XML_GetBuffer interface */
3829START_TEST(test_get_buffer_2) {
3830  const char *text = get_buffer_test_text;
3831  void *buffer;
3832
3833  /* Now get a decent buffer */
3834  buffer = XML_GetBuffer(g_parser, 1536);
3835  if (buffer == NULL)
3836    fail("1.5K buffer failed");
3837  assert(buffer != NULL);
3838  memcpy(buffer, text, strlen(text));
3839  if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_FALSE)
3840      == XML_STATUS_ERROR)
3841    xml_failure(g_parser);
3842
3843  /* Extend it, to catch a different code path */
3844  if (XML_GetBuffer(g_parser, 1024) == NULL)
3845    fail("1024 buffer failed");
3846}
3847END_TEST
3848
3849/* Test position information macros */
3850START_TEST(test_byte_info_at_end) {
3851  const char *text = "<doc></doc>";
3852
3853  if (XML_GetCurrentByteIndex(g_parser) != -1
3854      || XML_GetCurrentByteCount(g_parser) != 0)
3855    fail("Byte index/count incorrect at start of parse");
3856  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3857      == XML_STATUS_ERROR)
3858    xml_failure(g_parser);
3859  /* At end, the count will be zero and the index the end of string */
3860  if (XML_GetCurrentByteCount(g_parser) != 0)
3861    fail("Terminal byte count incorrect");
3862  if (XML_GetCurrentByteIndex(g_parser) != (XML_Index)strlen(text))
3863    fail("Terminal byte index incorrect");
3864}
3865END_TEST
3866
3867/* Test position information from errors */
3868#define PRE_ERROR_STR "<doc></"
3869#define POST_ERROR_STR "wombat></doc>"
3870START_TEST(test_byte_info_at_error) {
3871  const char *text = PRE_ERROR_STR POST_ERROR_STR;
3872
3873  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3874      == XML_STATUS_OK)
3875    fail("Syntax error not faulted");
3876  if (XML_GetCurrentByteCount(g_parser) != 0)
3877    fail("Error byte count incorrect");
3878  if (XML_GetCurrentByteIndex(g_parser) != strlen(PRE_ERROR_STR))
3879    fail("Error byte index incorrect");
3880}
3881END_TEST
3882#undef PRE_ERROR_STR
3883#undef POST_ERROR_STR
3884
3885/* Test position information in handler */
3886typedef struct ByteTestData {
3887  int start_element_len;
3888  int cdata_len;
3889  int total_string_len;
3890} ByteTestData;
3891
3892static void
3893byte_character_handler(void *userData, const XML_Char *s, int len) {
3894#ifdef XML_CONTEXT_BYTES
3895  int offset, size;
3896  const char *buffer;
3897  ByteTestData *data = (ByteTestData *)userData;
3898
3899  UNUSED_P(s);
3900  buffer = XML_GetInputContext(g_parser, &offset, &size);
3901  if (buffer == NULL)
3902    fail("Failed to get context buffer");
3903  if (offset != data->start_element_len)
3904    fail("Context offset in unexpected position");
3905  if (len != data->cdata_len)
3906    fail("CDATA length reported incorrectly");
3907  if (size != data->total_string_len)
3908    fail("Context size is not full buffer");
3909  if (XML_GetCurrentByteIndex(g_parser) != offset)
3910    fail("Character byte index incorrect");
3911  if (XML_GetCurrentByteCount(g_parser) != len)
3912    fail("Character byte count incorrect");
3913#else
3914  UNUSED_P(s);
3915  UNUSED_P(userData);
3916  UNUSED_P(len);
3917#endif
3918}
3919
3920#define START_ELEMENT "<e>"
3921#define CDATA_TEXT "Hello"
3922#define END_ELEMENT "</e>"
3923START_TEST(test_byte_info_at_cdata) {
3924  const char *text = START_ELEMENT CDATA_TEXT END_ELEMENT;
3925  int offset, size;
3926  ByteTestData data;
3927
3928  /* Check initial context is empty */
3929  if (XML_GetInputContext(g_parser, &offset, &size) != NULL)
3930    fail("Unexpected context at start of parse");
3931
3932  data.start_element_len = (int)strlen(START_ELEMENT);
3933  data.cdata_len = (int)strlen(CDATA_TEXT);
3934  data.total_string_len = (int)strlen(text);
3935  XML_SetCharacterDataHandler(g_parser, byte_character_handler);
3936  XML_SetUserData(g_parser, &data);
3937  if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) != XML_STATUS_OK)
3938    xml_failure(g_parser);
3939}
3940END_TEST
3941#undef START_ELEMENT
3942#undef CDATA_TEXT
3943#undef END_ELEMENT
3944
3945/* Test predefined entities are correctly recognised */
3946START_TEST(test_predefined_entities) {
3947  const char *text = "<doc>&lt;&gt;&amp;&quot;&apos;</doc>";
3948  const XML_Char *expected = XCS("<doc>&lt;&gt;&amp;&quot;&apos;</doc>");
3949  const XML_Char *result = XCS("<>&\"'");
3950  CharData storage;
3951
3952  XML_SetDefaultHandler(g_parser, accumulate_characters);
3953  /* run_character_check uses XML_SetCharacterDataHandler(), which
3954   * unfortunately heads off a code path that we need to exercise.
3955   */
3956  CharData_Init(&storage);
3957  XML_SetUserData(g_parser, &storage);
3958  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
3959      == XML_STATUS_ERROR)
3960    xml_failure(g_parser);
3961  /* The default handler doesn't translate the entities */
3962  CharData_CheckXMLChars(&storage, expected);
3963
3964  /* Now try again and check the translation */
3965  XML_ParserReset(g_parser, NULL);
3966  run_character_check(text, result);
3967}
3968END_TEST
3969
3970/* Regression test that an invalid tag in an external parameter
3971 * reference in an external DTD is correctly faulted.
3972 *
3973 * Only a few specific tags are legal in DTDs ignoring comments and
3974 * processing instructions, all of which begin with an exclamation
3975 * mark.  "<el/>" is not one of them, so the parser should raise an
3976 * error on encountering it.
3977 */
3978static int XMLCALL
3979external_entity_param(XML_Parser parser, const XML_Char *context,
3980                      const XML_Char *base, const XML_Char *systemId,
3981                      const XML_Char *publicId) {
3982  const char *text1 = "<!ELEMENT doc EMPTY>\n"
3983                      "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
3984                      "<!ENTITY % e2 '%e1;'>\n"
3985                      "%e1;\n";
3986  const char *text2 = "<!ELEMENT el EMPTY>\n"
3987                      "<el/>\n";
3988  XML_Parser ext_parser;
3989
3990  UNUSED_P(base);
3991  UNUSED_P(publicId);
3992  if (systemId == NULL)
3993    return XML_STATUS_OK;
3994
3995  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
3996  if (ext_parser == NULL)
3997    fail("Could not create external entity parser");
3998
3999  if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
4000    if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
4001        != XML_STATUS_ERROR)
4002      fail("Inner DTD with invalid tag not rejected");
4003    if (XML_GetErrorCode(ext_parser) != XML_ERROR_EXTERNAL_ENTITY_HANDLING)
4004      xml_failure(ext_parser);
4005  } else if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
4006    if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
4007        != XML_STATUS_ERROR)
4008      fail("Invalid tag in external param not rejected");
4009    if (XML_GetErrorCode(ext_parser) != XML_ERROR_SYNTAX)
4010      xml_failure(ext_parser);
4011  } else {
4012    fail("Unknown system ID");
4013  }
4014
4015  XML_ParserFree(ext_parser);
4016  return XML_STATUS_ERROR;
4017}
4018
4019START_TEST(test_invalid_tag_in_dtd) {
4020  const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
4021                     "<doc></doc>\n";
4022
4023  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4024  XML_SetExternalEntityRefHandler(g_parser, external_entity_param);
4025  expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
4026                 "Invalid tag IN DTD external param not rejected");
4027}
4028END_TEST
4029
4030/* Test entities not quite the predefined ones are not mis-recognised */
4031START_TEST(test_not_predefined_entities) {
4032  const char *text[] = {"<doc>&pt;</doc>", "<doc>&amo;</doc>",
4033                        "<doc>&quid;</doc>", "<doc>&apod;</doc>", NULL};
4034  int i = 0;
4035
4036  while (text[i] != NULL) {
4037    expect_failure(text[i], XML_ERROR_UNDEFINED_ENTITY,
4038                   "Undefined entity not rejected");
4039    XML_ParserReset(g_parser, NULL);
4040    i++;
4041  }
4042}
4043END_TEST
4044
4045/* Test conditional inclusion (IGNORE) */
4046static int XMLCALL
4047external_entity_load_ignore(XML_Parser parser, const XML_Char *context,
4048                            const XML_Char *base, const XML_Char *systemId,
4049                            const XML_Char *publicId) {
4050  const char *text = "<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>";
4051  XML_Parser ext_parser;
4052
4053  UNUSED_P(base);
4054  UNUSED_P(systemId);
4055  UNUSED_P(publicId);
4056  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
4057  if (ext_parser == NULL)
4058    fail("Could not create external entity parser");
4059  if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
4060      == XML_STATUS_ERROR)
4061    xml_failure(parser);
4062
4063  XML_ParserFree(ext_parser);
4064  return XML_STATUS_OK;
4065}
4066
4067START_TEST(test_ignore_section) {
4068  const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
4069                     "<doc><e>&entity;</e></doc>";
4070  const XML_Char *expected
4071      = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&entity;");
4072  CharData storage;
4073
4074  CharData_Init(&storage);
4075  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4076  XML_SetUserData(g_parser, &storage);
4077  XML_SetExternalEntityRefHandler(g_parser, external_entity_load_ignore);
4078  XML_SetDefaultHandler(g_parser, accumulate_characters);
4079  XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
4080  XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
4081  XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
4082  XML_SetStartElementHandler(g_parser, dummy_start_element);
4083  XML_SetEndElementHandler(g_parser, dummy_end_element);
4084  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4085      == XML_STATUS_ERROR)
4086    xml_failure(g_parser);
4087  CharData_CheckXMLChars(&storage, expected);
4088}
4089END_TEST
4090
4091static int XMLCALL
4092external_entity_load_ignore_utf16(XML_Parser parser, const XML_Char *context,
4093                                  const XML_Char *base,
4094                                  const XML_Char *systemId,
4095                                  const XML_Char *publicId) {
4096  const char text[] =
4097      /* <![IGNORE[<!ELEMENT e (#PCDATA)*>]]> */
4098      "<\0!\0[\0I\0G\0N\0O\0R\0E\0[\0"
4099      "<\0!\0E\0L\0E\0M\0E\0N\0T\0 \0e\0 \0"
4100      "(\0#\0P\0C\0D\0A\0T\0A\0)\0*\0>\0]\0]\0>\0";
4101  XML_Parser ext_parser;
4102
4103  UNUSED_P(base);
4104  UNUSED_P(systemId);
4105  UNUSED_P(publicId);
4106  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
4107  if (ext_parser == NULL)
4108    fail("Could not create external entity parser");
4109  if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)sizeof(text) - 1, XML_TRUE)
4110      == XML_STATUS_ERROR)
4111    xml_failure(parser);
4112
4113  XML_ParserFree(ext_parser);
4114  return XML_STATUS_OK;
4115}
4116
4117START_TEST(test_ignore_section_utf16) {
4118  const char text[] =
4119      /* <!DOCTYPE d SYSTEM 's'> */
4120      "<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 "
4121      "\0S\0Y\0S\0T\0E\0M\0 \0'\0s\0'\0>\0\n\0"
4122      /* <d><e>&en;</e></d> */
4123      "<\0d\0>\0<\0e\0>\0&\0e\0n\0;\0<\0/\0e\0>\0<\0/\0d\0>\0";
4124  const XML_Char *expected = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&en;");
4125  CharData storage;
4126
4127  CharData_Init(&storage);
4128  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4129  XML_SetUserData(g_parser, &storage);
4130  XML_SetExternalEntityRefHandler(g_parser, external_entity_load_ignore_utf16);
4131  XML_SetDefaultHandler(g_parser, accumulate_characters);
4132  XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
4133  XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
4134  XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
4135  XML_SetStartElementHandler(g_parser, dummy_start_element);
4136  XML_SetEndElementHandler(g_parser, dummy_end_element);
4137  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
4138      == XML_STATUS_ERROR)
4139    xml_failure(g_parser);
4140  CharData_CheckXMLChars(&storage, expected);
4141}
4142END_TEST
4143
4144static int XMLCALL
4145external_entity_load_ignore_utf16_be(XML_Parser parser, const XML_Char *context,
4146                                     const XML_Char *base,
4147                                     const XML_Char *systemId,
4148                                     const XML_Char *publicId) {
4149  const char text[] =
4150      /* <![IGNORE[<!ELEMENT e (#PCDATA)*>]]> */
4151      "\0<\0!\0[\0I\0G\0N\0O\0R\0E\0["
4152      "\0<\0!\0E\0L\0E\0M\0E\0N\0T\0 \0e\0 "
4153      "\0(\0#\0P\0C\0D\0A\0T\0A\0)\0*\0>\0]\0]\0>";
4154  XML_Parser ext_parser;
4155
4156  UNUSED_P(base);
4157  UNUSED_P(systemId);
4158  UNUSED_P(publicId);
4159  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
4160  if (ext_parser == NULL)
4161    fail("Could not create external entity parser");
4162  if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)sizeof(text) - 1, XML_TRUE)
4163      == XML_STATUS_ERROR)
4164    xml_failure(parser);
4165
4166  XML_ParserFree(ext_parser);
4167  return XML_STATUS_OK;
4168}
4169
4170START_TEST(test_ignore_section_utf16_be) {
4171  const char text[] =
4172      /* <!DOCTYPE d SYSTEM 's'> */
4173      "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 "
4174      "\0S\0Y\0S\0T\0E\0M\0 \0'\0s\0'\0>\0\n"
4175      /* <d><e>&en;</e></d> */
4176      "\0<\0d\0>\0<\0e\0>\0&\0e\0n\0;\0<\0/\0e\0>\0<\0/\0d\0>";
4177  const XML_Char *expected = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&en;");
4178  CharData storage;
4179
4180  CharData_Init(&storage);
4181  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4182  XML_SetUserData(g_parser, &storage);
4183  XML_SetExternalEntityRefHandler(g_parser,
4184                                  external_entity_load_ignore_utf16_be);
4185  XML_SetDefaultHandler(g_parser, accumulate_characters);
4186  XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
4187  XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
4188  XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
4189  XML_SetStartElementHandler(g_parser, dummy_start_element);
4190  XML_SetEndElementHandler(g_parser, dummy_end_element);
4191  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
4192      == XML_STATUS_ERROR)
4193    xml_failure(g_parser);
4194  CharData_CheckXMLChars(&storage, expected);
4195}
4196END_TEST
4197
4198/* Test mis-formatted conditional exclusion */
4199START_TEST(test_bad_ignore_section) {
4200  const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
4201                     "<doc><e>&entity;</e></doc>";
4202  ExtFaults faults[]
4203      = {{"<![IGNORE[<!ELEM", "Broken-off declaration not faulted", NULL,
4204          XML_ERROR_SYNTAX},
4205         {"<![IGNORE[\x01]]>", "Invalid XML character not faulted", NULL,
4206          XML_ERROR_INVALID_TOKEN},
4207         {/* FIrst two bytes of a three-byte char */
4208          "<![IGNORE[\xe2\x82", "Partial XML character not faulted", NULL,
4209          XML_ERROR_PARTIAL_CHAR},
4210         {NULL, NULL, NULL, XML_ERROR_NONE}};
4211  ExtFaults *fault;
4212
4213  for (fault = &faults[0]; fault->parse_text != NULL; fault++) {
4214    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4215    XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
4216    XML_SetUserData(g_parser, fault);
4217    expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
4218                   "Incomplete IGNORE section not failed");
4219    XML_ParserReset(g_parser, NULL);
4220  }
4221}
4222END_TEST
4223
4224/* Test recursive parsing */
4225static int XMLCALL
4226external_entity_valuer(XML_Parser parser, const XML_Char *context,
4227                       const XML_Char *base, const XML_Char *systemId,
4228                       const XML_Char *publicId) {
4229  const char *text1 = "<!ELEMENT doc EMPTY>\n"
4230                      "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
4231                      "<!ENTITY % e2 '%e1;'>\n"
4232                      "%e1;\n";
4233  XML_Parser ext_parser;
4234
4235  UNUSED_P(base);
4236  UNUSED_P(publicId);
4237  if (systemId == NULL)
4238    return XML_STATUS_OK;
4239  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
4240  if (ext_parser == NULL)
4241    fail("Could not create external entity parser");
4242  if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
4243    if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
4244        == XML_STATUS_ERROR)
4245      xml_failure(ext_parser);
4246  } else if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
4247    ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser);
4248    enum XML_Status status;
4249    enum XML_Error error;
4250
4251    status = _XML_Parse_SINGLE_BYTES(ext_parser, fault->parse_text,
4252                                     (int)strlen(fault->parse_text), XML_TRUE);
4253    if (fault->error == XML_ERROR_NONE) {
4254      if (status == XML_STATUS_ERROR)
4255        xml_failure(ext_parser);
4256    } else {
4257      if (status != XML_STATUS_ERROR)
4258        fail(fault->fail_text);
4259      error = XML_GetErrorCode(ext_parser);
4260      if (error != fault->error
4261          && (fault->error != XML_ERROR_XML_DECL
4262              || error != XML_ERROR_TEXT_DECL))
4263        xml_failure(ext_parser);
4264    }
4265  }
4266
4267  XML_ParserFree(ext_parser);
4268  return XML_STATUS_OK;
4269}
4270
4271START_TEST(test_external_entity_values) {
4272  const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
4273                     "<doc></doc>\n";
4274  ExtFaults data_004_2[] = {
4275      {"<!ATTLIST doc a1 CDATA 'value'>", NULL, NULL, XML_ERROR_NONE},
4276      {"<!ATTLIST $doc a1 CDATA 'value'>", "Invalid token not faulted", NULL,
4277       XML_ERROR_INVALID_TOKEN},
4278      {"'wombat", "Unterminated string not faulted", NULL,
4279       XML_ERROR_UNCLOSED_TOKEN},
4280      {"\xe2\x82", "Partial UTF-8 character not faulted", NULL,
4281       XML_ERROR_PARTIAL_CHAR},
4282      {"<?xml version='1.0' encoding='utf-8'?>\n", NULL, NULL, XML_ERROR_NONE},
4283      {"<?xml?>", "Malformed XML declaration not faulted", NULL,
4284       XML_ERROR_XML_DECL},
4285      {/* UTF-8 BOM */
4286       "\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>", NULL, NULL,
4287       XML_ERROR_NONE},
4288      {"<?xml version='1.0' encoding='utf-8'?>\n$",
4289       "Invalid token after text declaration not faulted", NULL,
4290       XML_ERROR_INVALID_TOKEN},
4291      {"<?xml version='1.0' encoding='utf-8'?>\n'wombat",
4292       "Unterminated string after text decl not faulted", NULL,
4293       XML_ERROR_UNCLOSED_TOKEN},
4294      {"<?xml version='1.0' encoding='utf-8'?>\n\xe2\x82",
4295       "Partial UTF-8 character after text decl not faulted", NULL,
4296       XML_ERROR_PARTIAL_CHAR},
4297      {"%e1;", "Recursive parameter entity not faulted", NULL,
4298       XML_ERROR_RECURSIVE_ENTITY_REF},
4299      {NULL, NULL, NULL, XML_ERROR_NONE}};
4300  int i;
4301
4302  for (i = 0; data_004_2[i].parse_text != NULL; i++) {
4303    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4304    XML_SetExternalEntityRefHandler(g_parser, external_entity_valuer);
4305    XML_SetUserData(g_parser, &data_004_2[i]);
4306    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4307        == XML_STATUS_ERROR)
4308      xml_failure(g_parser);
4309    XML_ParserReset(g_parser, NULL);
4310  }
4311}
4312END_TEST
4313
4314/* Test the recursive parse interacts with a not standalone handler */
4315static int XMLCALL
4316external_entity_not_standalone(XML_Parser parser, const XML_Char *context,
4317                               const XML_Char *base, const XML_Char *systemId,
4318                               const XML_Char *publicId) {
4319  const char *text1 = "<!ELEMENT doc EMPTY>\n"
4320                      "<!ENTITY % e1 SYSTEM 'bar'>\n"
4321                      "%e1;\n";
4322  const char *text2 = "<!ATTLIST doc a1 CDATA 'value'>";
4323  XML_Parser ext_parser;
4324
4325  UNUSED_P(base);
4326  UNUSED_P(publicId);
4327  if (systemId == NULL)
4328    return XML_STATUS_OK;
4329  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
4330  if (ext_parser == NULL)
4331    fail("Could not create external entity parser");
4332  if (! xcstrcmp(systemId, XCS("foo"))) {
4333    XML_SetNotStandaloneHandler(ext_parser, reject_not_standalone_handler);
4334    if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
4335        != XML_STATUS_ERROR)
4336      fail("Expected not standalone rejection");
4337    if (XML_GetErrorCode(ext_parser) != XML_ERROR_NOT_STANDALONE)
4338      xml_failure(ext_parser);
4339    XML_SetNotStandaloneHandler(ext_parser, NULL);
4340    XML_ParserFree(ext_parser);
4341    return XML_STATUS_ERROR;
4342  } else if (! xcstrcmp(systemId, XCS("bar"))) {
4343    if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
4344        == XML_STATUS_ERROR)
4345      xml_failure(ext_parser);
4346  }
4347
4348  XML_ParserFree(ext_parser);
4349  return XML_STATUS_OK;
4350}
4351
4352START_TEST(test_ext_entity_not_standalone) {
4353  const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
4354                     "<doc></doc>";
4355
4356  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4357  XML_SetExternalEntityRefHandler(g_parser, external_entity_not_standalone);
4358  expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
4359                 "Standalone rejection not caught");
4360}
4361END_TEST
4362
4363static int XMLCALL
4364external_entity_value_aborter(XML_Parser parser, const XML_Char *context,
4365                              const XML_Char *base, const XML_Char *systemId,
4366                              const XML_Char *publicId) {
4367  const char *text1 = "<!ELEMENT doc EMPTY>\n"
4368                      "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
4369                      "<!ENTITY % e2 '%e1;'>\n"
4370                      "%e1;\n";
4371  const char *text2 = "<?xml version='1.0' encoding='utf-8'?>";
4372  XML_Parser ext_parser;
4373
4374  UNUSED_P(base);
4375  UNUSED_P(publicId);
4376  if (systemId == NULL)
4377    return XML_STATUS_OK;
4378  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
4379  if (ext_parser == NULL)
4380    fail("Could not create external entity parser");
4381  if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
4382    if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
4383        == XML_STATUS_ERROR)
4384      xml_failure(ext_parser);
4385  }
4386  if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
4387    XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler);
4388    XML_SetUserData(ext_parser, ext_parser);
4389    if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
4390        != XML_STATUS_ERROR)
4391      fail("Aborted parse not faulted");
4392    if (XML_GetErrorCode(ext_parser) != XML_ERROR_ABORTED)
4393      xml_failure(ext_parser);
4394  }
4395
4396  XML_ParserFree(ext_parser);
4397  return XML_STATUS_OK;
4398}
4399
4400START_TEST(test_ext_entity_value_abort) {
4401  const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
4402                     "<doc></doc>\n";
4403
4404  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4405  XML_SetExternalEntityRefHandler(g_parser, external_entity_value_aborter);
4406  resumable = XML_FALSE;
4407  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4408      == XML_STATUS_ERROR)
4409    xml_failure(g_parser);
4410}
4411END_TEST
4412
4413START_TEST(test_bad_public_doctype) {
4414  const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
4415                     "<!DOCTYPE doc PUBLIC '{BadName}' 'test'>\n"
4416                     "<doc></doc>";
4417
4418  /* Setting a handler provokes a particular code path */
4419  XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_handler,
4420                            dummy_end_doctype_handler);
4421  expect_failure(text, XML_ERROR_PUBLICID, "Bad Public ID not failed");
4422}
4423END_TEST
4424
4425/* Test based on ibm/valid/P32/ibm32v04.xml */
4426START_TEST(test_attribute_enum_value) {
4427  const char *text = "<?xml version='1.0' standalone='no'?>\n"
4428                     "<!DOCTYPE animal SYSTEM 'test.dtd'>\n"
4429                     "<animal>This is a \n    <a/>  \n\nyellow tiger</animal>";
4430  ExtTest dtd_data
4431      = {"<!ELEMENT animal (#PCDATA|a)*>\n"
4432         "<!ELEMENT a EMPTY>\n"
4433         "<!ATTLIST animal xml:space (default|preserve) 'preserve'>",
4434         NULL, NULL};
4435  const XML_Char *expected = XCS("This is a \n      \n\nyellow tiger");
4436
4437  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
4438  XML_SetUserData(g_parser, &dtd_data);
4439  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4440  /* An attribute list handler provokes a different code path */
4441  XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
4442  run_ext_character_check(text, &dtd_data, expected);
4443}
4444END_TEST
4445
4446/* Slightly bizarrely, the library seems to silently ignore entity
4447 * definitions for predefined entities, even when they are wrong.  The
4448 * language of the XML 1.0 spec is somewhat unhelpful as to what ought
4449 * to happen, so this is currently treated as acceptable.
4450 */
4451START_TEST(test_predefined_entity_redefinition) {
4452  const char *text = "<!DOCTYPE doc [\n"
4453                     "<!ENTITY apos 'foo'>\n"
4454                     "]>\n"
4455                     "<doc>&apos;</doc>";
4456  run_character_check(text, XCS("'"));
4457}
4458END_TEST
4459
4460/* Test that the parser stops processing the DTD after an unresolved
4461 * parameter entity is encountered.
4462 */
4463START_TEST(test_dtd_stop_processing) {
4464  const char *text = "<!DOCTYPE doc [\n"
4465                     "%foo;\n"
4466                     "<!ENTITY bar 'bas'>\n"
4467                     "]><doc/>";
4468
4469  XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
4470  dummy_handler_flags = 0;
4471  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4472      == XML_STATUS_ERROR)
4473    xml_failure(g_parser);
4474  if (dummy_handler_flags != 0)
4475    fail("DTD processing still going after undefined PE");
4476}
4477END_TEST
4478
4479/* Test public notations with no system ID */
4480START_TEST(test_public_notation_no_sysid) {
4481  const char *text = "<!DOCTYPE doc [\n"
4482                     "<!NOTATION note PUBLIC 'foo'>\n"
4483                     "<!ELEMENT doc EMPTY>\n"
4484                     "]>\n<doc/>";
4485
4486  dummy_handler_flags = 0;
4487  XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
4488  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4489      == XML_STATUS_ERROR)
4490    xml_failure(g_parser);
4491  if (dummy_handler_flags != DUMMY_NOTATION_DECL_HANDLER_FLAG)
4492    fail("Notation declaration handler not called");
4493}
4494END_TEST
4495
4496static void XMLCALL
4497record_element_start_handler(void *userData, const XML_Char *name,
4498                             const XML_Char **atts) {
4499  UNUSED_P(atts);
4500  CharData_AppendXMLChars((CharData *)userData, name, (int)xcstrlen(name));
4501}
4502
4503START_TEST(test_nested_groups) {
4504  const char *text
4505      = "<!DOCTYPE doc [\n"
4506        "<!ELEMENT doc "
4507        /* Sixteen elements per line */
4508        "(e,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,"
4509        "(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?"
4510        "))))))))))))))))))))))))))))))))>\n"
4511        "<!ELEMENT e EMPTY>"
4512        "]>\n"
4513        "<doc><e/></doc>";
4514  CharData storage;
4515
4516  CharData_Init(&storage);
4517  XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
4518  XML_SetStartElementHandler(g_parser, record_element_start_handler);
4519  XML_SetUserData(g_parser, &storage);
4520  dummy_handler_flags = 0;
4521  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4522      == XML_STATUS_ERROR)
4523    xml_failure(g_parser);
4524  CharData_CheckXMLChars(&storage, XCS("doce"));
4525  if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
4526    fail("Element handler not fired");
4527}
4528END_TEST
4529
4530START_TEST(test_group_choice) {
4531  const char *text = "<!DOCTYPE doc [\n"
4532                     "<!ELEMENT doc (a|b|c)+>\n"
4533                     "<!ELEMENT a EMPTY>\n"
4534                     "<!ELEMENT b (#PCDATA)>\n"
4535                     "<!ELEMENT c ANY>\n"
4536                     "]>\n"
4537                     "<doc>\n"
4538                     "<a/>\n"
4539                     "<b attr='foo'>This is a foo</b>\n"
4540                     "<c></c>\n"
4541                     "</doc>\n";
4542
4543  XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
4544  dummy_handler_flags = 0;
4545  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4546      == XML_STATUS_ERROR)
4547    xml_failure(g_parser);
4548  if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
4549    fail("Element handler flag not raised");
4550}
4551END_TEST
4552
4553static int XMLCALL
4554external_entity_public(XML_Parser parser, const XML_Char *context,
4555                       const XML_Char *base, const XML_Char *systemId,
4556                       const XML_Char *publicId) {
4557  const char *text1 = (const char *)XML_GetUserData(parser);
4558  const char *text2 = "<!ATTLIST doc a CDATA 'value'>";
4559  const char *text = NULL;
4560  XML_Parser ext_parser;
4561  int parse_res;
4562
4563  UNUSED_P(base);
4564  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
4565  if (ext_parser == NULL)
4566    return XML_STATUS_ERROR;
4567  if (systemId != NULL && ! xcstrcmp(systemId, XCS("http://example.org/"))) {
4568    text = text1;
4569  } else if (publicId != NULL && ! xcstrcmp(publicId, XCS("foo"))) {
4570    text = text2;
4571  } else
4572    fail("Unexpected parameters to external entity parser");
4573  assert(text != NULL);
4574  parse_res
4575      = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
4576  XML_ParserFree(ext_parser);
4577  return parse_res;
4578}
4579
4580START_TEST(test_standalone_parameter_entity) {
4581  const char *text = "<?xml version='1.0' standalone='yes'?>\n"
4582                     "<!DOCTYPE doc SYSTEM 'http://example.org/' [\n"
4583                     "<!ENTITY % entity '<!ELEMENT doc (#PCDATA)>'>\n"
4584                     "%entity;\n"
4585                     "]>\n"
4586                     "<doc></doc>";
4587  char dtd_data[] = "<!ENTITY % e1 'foo'>\n";
4588
4589  XML_SetUserData(g_parser, dtd_data);
4590  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4591  XML_SetExternalEntityRefHandler(g_parser, external_entity_public);
4592  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4593      == XML_STATUS_ERROR)
4594    xml_failure(g_parser);
4595}
4596END_TEST
4597
4598/* Test skipping of parameter entity in an external DTD */
4599/* Derived from ibm/invalid/P69/ibm69i01.xml */
4600START_TEST(test_skipped_parameter_entity) {
4601  const char *text = "<?xml version='1.0'?>\n"
4602                     "<!DOCTYPE root SYSTEM 'http://example.org/dtd.ent' [\n"
4603                     "<!ELEMENT root (#PCDATA|a)* >\n"
4604                     "]>\n"
4605                     "<root></root>";
4606  ExtTest dtd_data = {"%pe2;", NULL, NULL};
4607
4608  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
4609  XML_SetUserData(g_parser, &dtd_data);
4610  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4611  XML_SetSkippedEntityHandler(g_parser, dummy_skip_handler);
4612  dummy_handler_flags = 0;
4613  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4614      == XML_STATUS_ERROR)
4615    xml_failure(g_parser);
4616  if (dummy_handler_flags != DUMMY_SKIP_HANDLER_FLAG)
4617    fail("Skip handler not executed");
4618}
4619END_TEST
4620
4621/* Test recursive parameter entity definition rejected in external DTD */
4622START_TEST(test_recursive_external_parameter_entity) {
4623  const char *text = "<?xml version='1.0'?>\n"
4624                     "<!DOCTYPE root SYSTEM 'http://example.org/dtd.ent' [\n"
4625                     "<!ELEMENT root (#PCDATA|a)* >\n"
4626                     "]>\n"
4627                     "<root></root>";
4628  ExtFaults dtd_data = {"<!ENTITY % pe2 '&#37;pe2;'>\n%pe2;",
4629                        "Recursive external parameter entity not faulted", NULL,
4630                        XML_ERROR_RECURSIVE_ENTITY_REF};
4631
4632  XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
4633  XML_SetUserData(g_parser, &dtd_data);
4634  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4635  expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
4636                 "Recursive external parameter not spotted");
4637}
4638END_TEST
4639
4640/* Test undefined parameter entity in external entity handler */
4641static int XMLCALL
4642external_entity_devaluer(XML_Parser parser, const XML_Char *context,
4643                         const XML_Char *base, const XML_Char *systemId,
4644                         const XML_Char *publicId) {
4645  const char *text = "<!ELEMENT doc EMPTY>\n"
4646                     "<!ENTITY % e1 SYSTEM 'bar'>\n"
4647                     "%e1;\n";
4648  XML_Parser ext_parser;
4649  intptr_t clear_handler = (intptr_t)XML_GetUserData(parser);
4650
4651  UNUSED_P(base);
4652  UNUSED_P(publicId);
4653  if (systemId == NULL || ! xcstrcmp(systemId, XCS("bar")))
4654    return XML_STATUS_OK;
4655  if (xcstrcmp(systemId, XCS("foo")))
4656    fail("Unexpected system ID");
4657  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
4658  if (ext_parser == NULL)
4659    fail("Could note create external entity parser");
4660  if (clear_handler)
4661    XML_SetExternalEntityRefHandler(ext_parser, NULL);
4662  if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
4663      == XML_STATUS_ERROR)
4664    xml_failure(ext_parser);
4665
4666  XML_ParserFree(ext_parser);
4667  return XML_STATUS_OK;
4668}
4669
4670START_TEST(test_undefined_ext_entity_in_external_dtd) {
4671  const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
4672                     "<doc></doc>\n";
4673
4674  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4675  XML_SetExternalEntityRefHandler(g_parser, external_entity_devaluer);
4676  XML_SetUserData(g_parser, (void *)(intptr_t)XML_FALSE);
4677  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4678      == XML_STATUS_ERROR)
4679    xml_failure(g_parser);
4680
4681  /* Now repeat without the external entity ref handler invoking
4682   * another copy of itself.
4683   */
4684  XML_ParserReset(g_parser, NULL);
4685  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4686  XML_SetExternalEntityRefHandler(g_parser, external_entity_devaluer);
4687  XML_SetUserData(g_parser, (void *)(intptr_t)XML_TRUE);
4688  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4689      == XML_STATUS_ERROR)
4690    xml_failure(g_parser);
4691}
4692END_TEST
4693
4694static void XMLCALL
4695aborting_xdecl_handler(void *userData, const XML_Char *version,
4696                       const XML_Char *encoding, int standalone) {
4697  UNUSED_P(userData);
4698  UNUSED_P(version);
4699  UNUSED_P(encoding);
4700  UNUSED_P(standalone);
4701  XML_StopParser(g_parser, resumable);
4702  XML_SetXmlDeclHandler(g_parser, NULL);
4703}
4704
4705/* Test suspending the parse on receiving an XML declaration works */
4706START_TEST(test_suspend_xdecl) {
4707  const char *text = long_character_data_text;
4708
4709  XML_SetXmlDeclHandler(g_parser, aborting_xdecl_handler);
4710  resumable = XML_TRUE;
4711  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4712      != XML_STATUS_SUSPENDED)
4713    xml_failure(g_parser);
4714  if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
4715    xml_failure(g_parser);
4716  /* Attempt to start a new parse while suspended */
4717  if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
4718      != XML_STATUS_ERROR)
4719    fail("Attempt to parse while suspended not faulted");
4720  if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
4721    fail("Suspended parse not faulted with correct error");
4722}
4723END_TEST
4724
4725/* Test aborting the parse in an epilog works */
4726static void XMLCALL
4727selective_aborting_default_handler(void *userData, const XML_Char *s, int len) {
4728  const XML_Char *match = (const XML_Char *)userData;
4729
4730  if (match == NULL
4731      || (xcstrlen(match) == (unsigned)len && ! xcstrncmp(match, s, len))) {
4732    XML_StopParser(g_parser, resumable);
4733    XML_SetDefaultHandler(g_parser, NULL);
4734  }
4735}
4736
4737START_TEST(test_abort_epilog) {
4738  const char *text = "<doc></doc>\n\r\n";
4739  XML_Char match[] = XCS("\r");
4740
4741  XML_SetDefaultHandler(g_parser, selective_aborting_default_handler);
4742  XML_SetUserData(g_parser, match);
4743  resumable = XML_FALSE;
4744  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4745      != XML_STATUS_ERROR)
4746    fail("Abort not triggered");
4747  if (XML_GetErrorCode(g_parser) != XML_ERROR_ABORTED)
4748    xml_failure(g_parser);
4749}
4750END_TEST
4751
4752/* Test a different code path for abort in the epilog */
4753START_TEST(test_abort_epilog_2) {
4754  const char *text = "<doc></doc>\n";
4755  XML_Char match[] = XCS("\n");
4756
4757  XML_SetDefaultHandler(g_parser, selective_aborting_default_handler);
4758  XML_SetUserData(g_parser, match);
4759  resumable = XML_FALSE;
4760  expect_failure(text, XML_ERROR_ABORTED, "Abort not triggered");
4761}
4762END_TEST
4763
4764/* Test suspension from the epilog */
4765START_TEST(test_suspend_epilog) {
4766  const char *text = "<doc></doc>\n";
4767  XML_Char match[] = XCS("\n");
4768
4769  XML_SetDefaultHandler(g_parser, selective_aborting_default_handler);
4770  XML_SetUserData(g_parser, match);
4771  resumable = XML_TRUE;
4772  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4773      != XML_STATUS_SUSPENDED)
4774    xml_failure(g_parser);
4775}
4776END_TEST
4777
4778static void XMLCALL
4779suspending_end_handler(void *userData, const XML_Char *s) {
4780  UNUSED_P(s);
4781  XML_StopParser((XML_Parser)userData, 1);
4782}
4783
4784START_TEST(test_suspend_in_sole_empty_tag) {
4785  const char *text = "<doc/>";
4786  enum XML_Status rc;
4787
4788  XML_SetEndElementHandler(g_parser, suspending_end_handler);
4789  XML_SetUserData(g_parser, g_parser);
4790  rc = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
4791  if (rc == XML_STATUS_ERROR)
4792    xml_failure(g_parser);
4793  else if (rc != XML_STATUS_SUSPENDED)
4794    fail("Suspend not triggered");
4795  rc = XML_ResumeParser(g_parser);
4796  if (rc == XML_STATUS_ERROR)
4797    xml_failure(g_parser);
4798  else if (rc != XML_STATUS_OK)
4799    fail("Resume failed");
4800}
4801END_TEST
4802
4803START_TEST(test_unfinished_epilog) {
4804  const char *text = "<doc></doc><";
4805
4806  expect_failure(text, XML_ERROR_UNCLOSED_TOKEN,
4807                 "Incomplete epilog entry not faulted");
4808}
4809END_TEST
4810
4811START_TEST(test_partial_char_in_epilog) {
4812  const char *text = "<doc></doc>\xe2\x82";
4813
4814  /* First check that no fault is raised if the parse is not finished */
4815  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
4816      == XML_STATUS_ERROR)
4817    xml_failure(g_parser);
4818  /* Now check that it is faulted once we finish */
4819  if (XML_ParseBuffer(g_parser, 0, XML_TRUE) != XML_STATUS_ERROR)
4820    fail("Partial character in epilog not faulted");
4821  if (XML_GetErrorCode(g_parser) != XML_ERROR_PARTIAL_CHAR)
4822    xml_failure(g_parser);
4823}
4824END_TEST
4825
4826START_TEST(test_hash_collision) {
4827  /* For full coverage of the lookup routine, we need to ensure a
4828   * hash collision even though we can only tell that we have one
4829   * through breakpoint debugging or coverage statistics.  The
4830   * following will cause a hash collision on machines with a 64-bit
4831   * long type; others will have to experiment.  The full coverage
4832   * tests invoked from qa.sh usually provide a hash collision, but
4833   * not always.  This is an attempt to provide insurance.
4834   */
4835#define COLLIDING_HASH_SALT (unsigned long)_SIP_ULL(0xffffffffU, 0xff99fc90U)
4836  const char *text
4837      = "<doc>\n"
4838        "<a1/><a2/><a3/><a4/><a5/><a6/><a7/><a8/>\n"
4839        "<b1></b1><b2 attr='foo'>This is a foo</b2><b3></b3><b4></b4>\n"
4840        "<b5></b5><b6></b6><b7></b7><b8></b8>\n"
4841        "<c1/><c2/><c3/><c4/><c5/><c6/><c7/><c8/>\n"
4842        "<d1/><d2/><d3/><d4/><d5/><d6/><d7/>\n"
4843        "<d8>This triggers the table growth and collides with b2</d8>\n"
4844        "</doc>\n";
4845
4846  XML_SetHashSalt(g_parser, COLLIDING_HASH_SALT);
4847  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4848      == XML_STATUS_ERROR)
4849    xml_failure(g_parser);
4850}
4851END_TEST
4852#undef COLLIDING_HASH_SALT
4853
4854/* Test resuming a parse suspended in entity substitution */
4855static void XMLCALL
4856start_element_suspender(void *userData, const XML_Char *name,
4857                        const XML_Char **atts) {
4858  UNUSED_P(userData);
4859  UNUSED_P(atts);
4860  if (! xcstrcmp(name, XCS("suspend")))
4861    XML_StopParser(g_parser, XML_TRUE);
4862  if (! xcstrcmp(name, XCS("abort")))
4863    XML_StopParser(g_parser, XML_FALSE);
4864}
4865
4866START_TEST(test_suspend_resume_internal_entity) {
4867  const char *text
4868      = "<!DOCTYPE doc [\n"
4869        "<!ENTITY foo '<suspend>Hi<suspend>Ho</suspend></suspend>'>\n"
4870        "]>\n"
4871        "<doc>&foo;</doc>\n";
4872  const XML_Char *expected1 = XCS("Hi");
4873  const XML_Char *expected2 = XCS("HiHo");
4874  CharData storage;
4875
4876  CharData_Init(&storage);
4877  XML_SetStartElementHandler(g_parser, start_element_suspender);
4878  XML_SetCharacterDataHandler(g_parser, accumulate_characters);
4879  XML_SetUserData(g_parser, &storage);
4880  if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
4881      != XML_STATUS_SUSPENDED)
4882    xml_failure(g_parser);
4883  CharData_CheckXMLChars(&storage, XCS(""));
4884  if (XML_ResumeParser(g_parser) != XML_STATUS_SUSPENDED)
4885    xml_failure(g_parser);
4886  CharData_CheckXMLChars(&storage, expected1);
4887  if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
4888    xml_failure(g_parser);
4889  CharData_CheckXMLChars(&storage, expected2);
4890}
4891END_TEST
4892
4893/* Test syntax error is caught at parse resumption */
4894START_TEST(test_resume_entity_with_syntax_error) {
4895  const char *text = "<!DOCTYPE doc [\n"
4896                     "<!ENTITY foo '<suspend>Hi</wombat>'>\n"
4897                     "]>\n"
4898                     "<doc>&foo;</doc>\n";
4899
4900  XML_SetStartElementHandler(g_parser, start_element_suspender);
4901  if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
4902      != XML_STATUS_SUSPENDED)
4903    xml_failure(g_parser);
4904  if (XML_ResumeParser(g_parser) != XML_STATUS_ERROR)
4905    fail("Syntax error in entity not faulted");
4906  if (XML_GetErrorCode(g_parser) != XML_ERROR_TAG_MISMATCH)
4907    xml_failure(g_parser);
4908}
4909END_TEST
4910
4911/* Test suspending and resuming in a parameter entity substitution */
4912static void XMLCALL
4913element_decl_suspender(void *userData, const XML_Char *name,
4914                       XML_Content *model) {
4915  UNUSED_P(userData);
4916  UNUSED_P(name);
4917  XML_StopParser(g_parser, XML_TRUE);
4918  XML_FreeContentModel(g_parser, model);
4919}
4920
4921START_TEST(test_suspend_resume_parameter_entity) {
4922  const char *text = "<!DOCTYPE doc [\n"
4923                     "<!ENTITY % foo '<!ELEMENT doc (#PCDATA)*>'>\n"
4924                     "%foo;\n"
4925                     "]>\n"
4926                     "<doc>Hello, world</doc>";
4927  const XML_Char *expected = XCS("Hello, world");
4928  CharData storage;
4929
4930  CharData_Init(&storage);
4931  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
4932  XML_SetElementDeclHandler(g_parser, element_decl_suspender);
4933  XML_SetCharacterDataHandler(g_parser, accumulate_characters);
4934  XML_SetUserData(g_parser, &storage);
4935  if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
4936      != XML_STATUS_SUSPENDED)
4937    xml_failure(g_parser);
4938  CharData_CheckXMLChars(&storage, XCS(""));
4939  if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
4940    xml_failure(g_parser);
4941  CharData_CheckXMLChars(&storage, expected);
4942}
4943END_TEST
4944
4945/* Test attempting to use parser after an error is faulted */
4946START_TEST(test_restart_on_error) {
4947  const char *text = "<$doc><doc></doc>";
4948
4949  if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
4950      != XML_STATUS_ERROR)
4951    fail("Invalid tag name not faulted");
4952  if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
4953    xml_failure(g_parser);
4954  if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR)
4955    fail("Restarting invalid parse not faulted");
4956  if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
4957    xml_failure(g_parser);
4958}
4959END_TEST
4960
4961/* Test that angle brackets in an attribute default value are faulted */
4962START_TEST(test_reject_lt_in_attribute_value) {
4963  const char *text = "<!DOCTYPE doc [<!ATTLIST doc a CDATA '<bar>'>]>\n"
4964                     "<doc></doc>";
4965
4966  expect_failure(text, XML_ERROR_INVALID_TOKEN,
4967                 "Bad attribute default not faulted");
4968}
4969END_TEST
4970
4971START_TEST(test_reject_unfinished_param_in_att_value) {
4972  const char *text = "<!DOCTYPE doc [<!ATTLIST doc a CDATA '&foo'>]>\n"
4973                     "<doc></doc>";
4974
4975  expect_failure(text, XML_ERROR_INVALID_TOKEN,
4976                 "Bad attribute default not faulted");
4977}
4978END_TEST
4979
4980START_TEST(test_trailing_cr_in_att_value) {
4981  const char *text = "<doc a='value\r'/>";
4982
4983  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
4984      == XML_STATUS_ERROR)
4985    xml_failure(g_parser);
4986}
4987END_TEST
4988
4989/* Try parsing a general entity within a parameter entity in a
4990 * standalone internal DTD.  Covers a corner case in the parser.
4991 */
4992START_TEST(test_standalone_internal_entity) {
4993  const char *text = "<?xml version='1.0' standalone='yes' ?>\n"
4994                     "<!DOCTYPE doc [\n"
4995                     "  <!ELEMENT doc (#PCDATA)>\n"
4996                     "  <!ENTITY % pe '<!ATTLIST doc att2 CDATA \"&ge;\">'>\n"
4997                     "  <!ENTITY ge 'AttDefaultValue'>\n"
4998                     "  %pe;\n"
4999                     "]>\n"
5000                     "<doc att2='any'/>";
5001
5002  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
5003  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5004      == XML_STATUS_ERROR)
5005    xml_failure(g_parser);
5006}
5007END_TEST
5008
5009/* Test that a reference to an unknown external entity is skipped */
5010START_TEST(test_skipped_external_entity) {
5011  const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
5012                     "<doc></doc>\n";
5013  ExtTest test_data = {"<!ELEMENT doc EMPTY>\n"
5014                       "<!ENTITY % e2 '%e1;'>\n",
5015                       NULL, NULL};
5016
5017  XML_SetUserData(g_parser, &test_data);
5018  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
5019  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
5020  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5021      == XML_STATUS_ERROR)
5022    xml_failure(g_parser);
5023}
5024END_TEST
5025
5026/* Test a different form of unknown external entity */
5027typedef struct ext_hdlr_data {
5028  const char *parse_text;
5029  XML_ExternalEntityRefHandler handler;
5030} ExtHdlrData;
5031
5032static int XMLCALL
5033external_entity_oneshot_loader(XML_Parser parser, const XML_Char *context,
5034                               const XML_Char *base, const XML_Char *systemId,
5035                               const XML_Char *publicId) {
5036  ExtHdlrData *test_data = (ExtHdlrData *)XML_GetUserData(parser);
5037  XML_Parser ext_parser;
5038
5039  UNUSED_P(base);
5040  UNUSED_P(systemId);
5041  UNUSED_P(publicId);
5042  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
5043  if (ext_parser == NULL)
5044    fail("Could not create external entity parser.");
5045  /* Use the requested entity parser for further externals */
5046  XML_SetExternalEntityRefHandler(ext_parser, test_data->handler);
5047  if (_XML_Parse_SINGLE_BYTES(ext_parser, test_data->parse_text,
5048                              (int)strlen(test_data->parse_text), XML_TRUE)
5049      == XML_STATUS_ERROR) {
5050    xml_failure(ext_parser);
5051  }
5052
5053  XML_ParserFree(ext_parser);
5054  return XML_STATUS_OK;
5055}
5056
5057START_TEST(test_skipped_null_loaded_ext_entity) {
5058  const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/one.ent'>\n"
5059                     "<doc />";
5060  ExtHdlrData test_data
5061      = {"<!ENTITY % pe1 SYSTEM 'http://example.org/two.ent'>\n"
5062         "<!ENTITY % pe2 '%pe1;'>\n"
5063         "%pe2;\n",
5064         external_entity_null_loader};
5065
5066  XML_SetUserData(g_parser, &test_data);
5067  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
5068  XML_SetExternalEntityRefHandler(g_parser, external_entity_oneshot_loader);
5069  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5070      == XML_STATUS_ERROR)
5071    xml_failure(g_parser);
5072}
5073END_TEST
5074
5075START_TEST(test_skipped_unloaded_ext_entity) {
5076  const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/one.ent'>\n"
5077                     "<doc />";
5078  ExtHdlrData test_data
5079      = {"<!ENTITY % pe1 SYSTEM 'http://example.org/two.ent'>\n"
5080         "<!ENTITY % pe2 '%pe1;'>\n"
5081         "%pe2;\n",
5082         NULL};
5083
5084  XML_SetUserData(g_parser, &test_data);
5085  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
5086  XML_SetExternalEntityRefHandler(g_parser, external_entity_oneshot_loader);
5087  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5088      == XML_STATUS_ERROR)
5089    xml_failure(g_parser);
5090}
5091END_TEST
5092
5093/* Test that a parameter entity value ending with a carriage return
5094 * has it translated internally into a newline.
5095 */
5096START_TEST(test_param_entity_with_trailing_cr) {
5097#define PARAM_ENTITY_NAME "pe"
5098#define PARAM_ENTITY_CORE_VALUE "<!ATTLIST doc att CDATA \"default\">"
5099  const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
5100                     "<doc/>";
5101  ExtTest test_data
5102      = {"<!ENTITY % " PARAM_ENTITY_NAME " '" PARAM_ENTITY_CORE_VALUE "\r'>\n"
5103         "%" PARAM_ENTITY_NAME ";\n",
5104         NULL, NULL};
5105
5106  XML_SetUserData(g_parser, &test_data);
5107  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
5108  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
5109  XML_SetEntityDeclHandler(g_parser, param_entity_match_handler);
5110  entity_name_to_match = XCS(PARAM_ENTITY_NAME);
5111  entity_value_to_match = XCS(PARAM_ENTITY_CORE_VALUE) XCS("\n");
5112  entity_match_flag = ENTITY_MATCH_NOT_FOUND;
5113  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5114      == XML_STATUS_ERROR)
5115    xml_failure(g_parser);
5116  if (entity_match_flag == ENTITY_MATCH_FAIL)
5117    fail("Parameter entity CR->NEWLINE conversion failed");
5118  else if (entity_match_flag == ENTITY_MATCH_NOT_FOUND)
5119    fail("Parameter entity not parsed");
5120}
5121#undef PARAM_ENTITY_NAME
5122#undef PARAM_ENTITY_CORE_VALUE
5123END_TEST
5124
5125START_TEST(test_invalid_character_entity) {
5126  const char *text = "<!DOCTYPE doc [\n"
5127                     "  <!ENTITY entity '&#x110000;'>\n"
5128                     "]>\n"
5129                     "<doc>&entity;</doc>";
5130
5131  expect_failure(text, XML_ERROR_BAD_CHAR_REF,
5132                 "Out of range character reference not faulted");
5133}
5134END_TEST
5135
5136START_TEST(test_invalid_character_entity_2) {
5137  const char *text = "<!DOCTYPE doc [\n"
5138                     "  <!ENTITY entity '&#xg0;'>\n"
5139                     "]>\n"
5140                     "<doc>&entity;</doc>";
5141
5142  expect_failure(text, XML_ERROR_INVALID_TOKEN,
5143                 "Out of range character reference not faulted");
5144}
5145END_TEST
5146
5147START_TEST(test_invalid_character_entity_3) {
5148  const char text[] =
5149      /* <!DOCTYPE doc [\n */
5150      "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0\n"
5151      /* U+0E04 = KHO KHWAI
5152       * U+0E08 = CHO CHAN */
5153      /* <!ENTITY entity '&\u0e04\u0e08;'>\n */
5154      "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0e\0n\0t\0i\0t\0y\0 "
5155      "\0'\0&\x0e\x04\x0e\x08\0;\0'\0>\0\n"
5156      /* ]>\n */
5157      "\0]\0>\0\n"
5158      /* <doc>&entity;</doc> */
5159      "\0<\0d\0o\0c\0>\0&\0e\0n\0t\0i\0t\0y\0;\0<\0/\0d\0o\0c\0>";
5160
5161  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5162      != XML_STATUS_ERROR)
5163    fail("Invalid start of entity name not faulted");
5164  if (XML_GetErrorCode(g_parser) != XML_ERROR_UNDEFINED_ENTITY)
5165    xml_failure(g_parser);
5166}
5167END_TEST
5168
5169START_TEST(test_invalid_character_entity_4) {
5170  const char *text = "<!DOCTYPE doc [\n"
5171                     "  <!ENTITY entity '&#1114112;'>\n" /* = &#x110000 */
5172                     "]>\n"
5173                     "<doc>&entity;</doc>";
5174
5175  expect_failure(text, XML_ERROR_BAD_CHAR_REF,
5176                 "Out of range character reference not faulted");
5177}
5178END_TEST
5179
5180/* Test that processing instructions are picked up by a default handler */
5181START_TEST(test_pi_handled_in_default) {
5182  const char *text = "<?test processing instruction?>\n<doc/>";
5183  const XML_Char *expected = XCS("<?test processing instruction?>\n<doc/>");
5184  CharData storage;
5185
5186  CharData_Init(&storage);
5187  XML_SetDefaultHandler(g_parser, accumulate_characters);
5188  XML_SetUserData(g_parser, &storage);
5189  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5190      == XML_STATUS_ERROR)
5191    xml_failure(g_parser);
5192  CharData_CheckXMLChars(&storage, expected);
5193}
5194END_TEST
5195
5196/* Test that comments are picked up by a default handler */
5197START_TEST(test_comment_handled_in_default) {
5198  const char *text = "<!-- This is a comment -->\n<doc/>";
5199  const XML_Char *expected = XCS("<!-- This is a comment -->\n<doc/>");
5200  CharData storage;
5201
5202  CharData_Init(&storage);
5203  XML_SetDefaultHandler(g_parser, accumulate_characters);
5204  XML_SetUserData(g_parser, &storage);
5205  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5206      == XML_STATUS_ERROR)
5207    xml_failure(g_parser);
5208  CharData_CheckXMLChars(&storage, expected);
5209}
5210END_TEST
5211
5212/* Test PIs that look almost but not quite like XML declarations */
5213static void XMLCALL
5214accumulate_pi_characters(void *userData, const XML_Char *target,
5215                         const XML_Char *data) {
5216  CharData *storage = (CharData *)userData;
5217
5218  CharData_AppendXMLChars(storage, target, -1);
5219  CharData_AppendXMLChars(storage, XCS(": "), 2);
5220  CharData_AppendXMLChars(storage, data, -1);
5221  CharData_AppendXMLChars(storage, XCS("\n"), 1);
5222}
5223
5224START_TEST(test_pi_yml) {
5225  const char *text = "<?yml something like data?><doc/>";
5226  const XML_Char *expected = XCS("yml: something like data\n");
5227  CharData storage;
5228
5229  CharData_Init(&storage);
5230  XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
5231  XML_SetUserData(g_parser, &storage);
5232  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5233      == XML_STATUS_ERROR)
5234    xml_failure(g_parser);
5235  CharData_CheckXMLChars(&storage, expected);
5236}
5237END_TEST
5238
5239START_TEST(test_pi_xnl) {
5240  const char *text = "<?xnl nothing like data?><doc/>";
5241  const XML_Char *expected = XCS("xnl: nothing like data\n");
5242  CharData storage;
5243
5244  CharData_Init(&storage);
5245  XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
5246  XML_SetUserData(g_parser, &storage);
5247  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5248      == XML_STATUS_ERROR)
5249    xml_failure(g_parser);
5250  CharData_CheckXMLChars(&storage, expected);
5251}
5252END_TEST
5253
5254START_TEST(test_pi_xmm) {
5255  const char *text = "<?xmm everything like data?><doc/>";
5256  const XML_Char *expected = XCS("xmm: everything like data\n");
5257  CharData storage;
5258
5259  CharData_Init(&storage);
5260  XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
5261  XML_SetUserData(g_parser, &storage);
5262  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5263      == XML_STATUS_ERROR)
5264    xml_failure(g_parser);
5265  CharData_CheckXMLChars(&storage, expected);
5266}
5267END_TEST
5268
5269START_TEST(test_utf16_pi) {
5270  const char text[] =
5271      /* <?{KHO KHWAI}{CHO CHAN}?>
5272       * where {KHO KHWAI} = U+0E04
5273       * and   {CHO CHAN}  = U+0E08
5274       */
5275      "<\0?\0\x04\x0e\x08\x0e?\0>\0"
5276      /* <q/> */
5277      "<\0q\0/\0>\0";
5278#ifdef XML_UNICODE
5279  const XML_Char *expected = XCS("\x0e04\x0e08: \n");
5280#else
5281  const XML_Char *expected = XCS("\xe0\xb8\x84\xe0\xb8\x88: \n");
5282#endif
5283  CharData storage;
5284
5285  CharData_Init(&storage);
5286  XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
5287  XML_SetUserData(g_parser, &storage);
5288  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5289      == XML_STATUS_ERROR)
5290    xml_failure(g_parser);
5291  CharData_CheckXMLChars(&storage, expected);
5292}
5293END_TEST
5294
5295START_TEST(test_utf16_be_pi) {
5296  const char text[] =
5297      /* <?{KHO KHWAI}{CHO CHAN}?>
5298       * where {KHO KHWAI} = U+0E04
5299       * and   {CHO CHAN}  = U+0E08
5300       */
5301      "\0<\0?\x0e\x04\x0e\x08\0?\0>"
5302      /* <q/> */
5303      "\0<\0q\0/\0>";
5304#ifdef XML_UNICODE
5305  const XML_Char *expected = XCS("\x0e04\x0e08: \n");
5306#else
5307  const XML_Char *expected = XCS("\xe0\xb8\x84\xe0\xb8\x88: \n");
5308#endif
5309  CharData storage;
5310
5311  CharData_Init(&storage);
5312  XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
5313  XML_SetUserData(g_parser, &storage);
5314  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5315      == XML_STATUS_ERROR)
5316    xml_failure(g_parser);
5317  CharData_CheckXMLChars(&storage, expected);
5318}
5319END_TEST
5320
5321/* Test that comments can be picked up and translated */
5322static void XMLCALL
5323accumulate_comment(void *userData, const XML_Char *data) {
5324  CharData *storage = (CharData *)userData;
5325
5326  CharData_AppendXMLChars(storage, data, -1);
5327}
5328
5329START_TEST(test_utf16_be_comment) {
5330  const char text[] =
5331      /* <!-- Comment A --> */
5332      "\0<\0!\0-\0-\0 \0C\0o\0m\0m\0e\0n\0t\0 \0A\0 \0-\0-\0>\0\n"
5333      /* <doc/> */
5334      "\0<\0d\0o\0c\0/\0>";
5335  const XML_Char *expected = XCS(" Comment A ");
5336  CharData storage;
5337
5338  CharData_Init(&storage);
5339  XML_SetCommentHandler(g_parser, accumulate_comment);
5340  XML_SetUserData(g_parser, &storage);
5341  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5342      == XML_STATUS_ERROR)
5343    xml_failure(g_parser);
5344  CharData_CheckXMLChars(&storage, expected);
5345}
5346END_TEST
5347
5348START_TEST(test_utf16_le_comment) {
5349  const char text[] =
5350      /* <!-- Comment B --> */
5351      "<\0!\0-\0-\0 \0C\0o\0m\0m\0e\0n\0t\0 \0B\0 \0-\0-\0>\0\n\0"
5352      /* <doc/> */
5353      "<\0d\0o\0c\0/\0>\0";
5354  const XML_Char *expected = XCS(" Comment B ");
5355  CharData storage;
5356
5357  CharData_Init(&storage);
5358  XML_SetCommentHandler(g_parser, accumulate_comment);
5359  XML_SetUserData(g_parser, &storage);
5360  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
5361      == XML_STATUS_ERROR)
5362    xml_failure(g_parser);
5363  CharData_CheckXMLChars(&storage, expected);
5364}
5365END_TEST
5366
5367/* Test that the unknown encoding handler with map entries that expect
5368 * conversion but no conversion function is faulted
5369 */
5370static int XMLCALL
5371failing_converter(void *data, const char *s) {
5372  UNUSED_P(data);
5373  UNUSED_P(s);
5374  /* Always claim to have failed */
5375  return -1;
5376}
5377
5378static int XMLCALL
5379prefix_converter(void *data, const char *s) {
5380  UNUSED_P(data);
5381  /* If the first byte is 0xff, raise an error */
5382  if (s[0] == (char)-1)
5383    return -1;
5384  /* Just add the low bits of the first byte to the second */
5385  return (s[1] + (s[0] & 0x7f)) & 0x01ff;
5386}
5387
5388static int XMLCALL
5389MiscEncodingHandler(void *data, const XML_Char *encoding, XML_Encoding *info) {
5390  int i;
5391  int high_map = -2; /* Assume a 2-byte sequence */
5392
5393  if (! xcstrcmp(encoding, XCS("invalid-9"))
5394      || ! xcstrcmp(encoding, XCS("ascii-like"))
5395      || ! xcstrcmp(encoding, XCS("invalid-len"))
5396      || ! xcstrcmp(encoding, XCS("invalid-a"))
5397      || ! xcstrcmp(encoding, XCS("invalid-surrogate"))
5398      || ! xcstrcmp(encoding, XCS("invalid-high")))
5399    high_map = -1;
5400
5401  for (i = 0; i < 128; ++i)
5402    info->map[i] = i;
5403  for (; i < 256; ++i)
5404    info->map[i] = high_map;
5405
5406  /* If required, put an invalid value in the ASCII entries */
5407  if (! xcstrcmp(encoding, XCS("invalid-9")))
5408    info->map[9] = 5;
5409  /* If required, have a top-bit set character starts a 5-byte sequence */
5410  if (! xcstrcmp(encoding, XCS("invalid-len")))
5411    info->map[0x81] = -5;
5412  /* If required, make a top-bit set character a valid ASCII character */
5413  if (! xcstrcmp(encoding, XCS("invalid-a")))
5414    info->map[0x82] = 'a';
5415  /* If required, give a top-bit set character a forbidden value,
5416   * what would otherwise be the first of a surrogate pair.
5417   */
5418  if (! xcstrcmp(encoding, XCS("invalid-surrogate")))
5419    info->map[0x83] = 0xd801;
5420  /* If required, give a top-bit set character too high a value */
5421  if (! xcstrcmp(encoding, XCS("invalid-high")))
5422    info->map[0x84] = 0x010101;
5423
5424  info->data = data;
5425  info->release = NULL;
5426  if (! xcstrcmp(encoding, XCS("failing-conv")))
5427    info->convert = failing_converter;
5428  else if (! xcstrcmp(encoding, XCS("prefix-conv")))
5429    info->convert = prefix_converter;
5430  else
5431    info->convert = NULL;
5432  return XML_STATUS_OK;
5433}
5434
5435START_TEST(test_missing_encoding_conversion_fn) {
5436  const char *text = "<?xml version='1.0' encoding='no-conv'?>\n"
5437                     "<doc>\x81</doc>";
5438
5439  XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5440  /* MiscEncodingHandler sets up an encoding with every top-bit-set
5441   * character introducing a two-byte sequence.  For this, it
5442   * requires a convert function.  The above function call doesn't
5443   * pass one through, so when BadEncodingHandler actually gets
5444   * called it should supply an invalid encoding.
5445   */
5446  expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
5447                 "Encoding with missing convert() not faulted");
5448}
5449END_TEST
5450
5451START_TEST(test_failing_encoding_conversion_fn) {
5452  const char *text = "<?xml version='1.0' encoding='failing-conv'?>\n"
5453                     "<doc>\x81</doc>";
5454
5455  XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5456  /* BadEncodingHandler sets up an encoding with every top-bit-set
5457   * character introducing a two-byte sequence.  For this, it
5458   * requires a convert function.  The above function call passes
5459   * one that insists all possible sequences are invalid anyway.
5460   */
5461  expect_failure(text, XML_ERROR_INVALID_TOKEN,
5462                 "Encoding with failing convert() not faulted");
5463}
5464END_TEST
5465
5466/* Test unknown encoding conversions */
5467START_TEST(test_unknown_encoding_success) {
5468  const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
5469                     /* Equivalent to <eoc>Hello, world</eoc> */
5470                     "<\x81\x64\x80oc>Hello, world</\x81\x64\x80oc>";
5471
5472  XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5473  run_character_check(text, XCS("Hello, world"));
5474}
5475END_TEST
5476
5477/* Test bad name character in unknown encoding */
5478START_TEST(test_unknown_encoding_bad_name) {
5479  const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
5480                     "<\xff\x64oc>Hello, world</\xff\x64oc>";
5481
5482  XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5483  expect_failure(text, XML_ERROR_INVALID_TOKEN,
5484                 "Bad name start in unknown encoding not faulted");
5485}
5486END_TEST
5487
5488/* Test bad mid-name character in unknown encoding */
5489START_TEST(test_unknown_encoding_bad_name_2) {
5490  const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
5491                     "<d\xffoc>Hello, world</d\xffoc>";
5492
5493  XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5494  expect_failure(text, XML_ERROR_INVALID_TOKEN,
5495                 "Bad name in unknown encoding not faulted");
5496}
5497END_TEST
5498
5499/* Test element name that is long enough to fill the conversion buffer
5500 * in an unknown encoding, finishing with an encoded character.
5501 */
5502START_TEST(test_unknown_encoding_long_name_1) {
5503  const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
5504                     "<abcdefghabcdefghabcdefghijkl\x80m\x80n\x80o\x80p>"
5505                     "Hi"
5506                     "</abcdefghabcdefghabcdefghijkl\x80m\x80n\x80o\x80p>";
5507  const XML_Char *expected = XCS("abcdefghabcdefghabcdefghijklmnop");
5508  CharData storage;
5509
5510  CharData_Init(&storage);
5511  XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5512  XML_SetStartElementHandler(g_parser, record_element_start_handler);
5513  XML_SetUserData(g_parser, &storage);
5514  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5515      == XML_STATUS_ERROR)
5516    xml_failure(g_parser);
5517  CharData_CheckXMLChars(&storage, expected);
5518}
5519END_TEST
5520
5521/* Test element name that is long enough to fill the conversion buffer
5522 * in an unknown encoding, finishing with an simple character.
5523 */
5524START_TEST(test_unknown_encoding_long_name_2) {
5525  const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
5526                     "<abcdefghabcdefghabcdefghijklmnop>"
5527                     "Hi"
5528                     "</abcdefghabcdefghabcdefghijklmnop>";
5529  const XML_Char *expected = XCS("abcdefghabcdefghabcdefghijklmnop");
5530  CharData storage;
5531
5532  CharData_Init(&storage);
5533  XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5534  XML_SetStartElementHandler(g_parser, record_element_start_handler);
5535  XML_SetUserData(g_parser, &storage);
5536  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5537      == XML_STATUS_ERROR)
5538    xml_failure(g_parser);
5539  CharData_CheckXMLChars(&storage, expected);
5540}
5541END_TEST
5542
5543START_TEST(test_invalid_unknown_encoding) {
5544  const char *text = "<?xml version='1.0' encoding='invalid-9'?>\n"
5545                     "<doc>Hello world</doc>";
5546
5547  XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5548  expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
5549                 "Invalid unknown encoding not faulted");
5550}
5551END_TEST
5552
5553START_TEST(test_unknown_ascii_encoding_ok) {
5554  const char *text = "<?xml version='1.0' encoding='ascii-like'?>\n"
5555                     "<doc>Hello, world</doc>";
5556
5557  XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5558  run_character_check(text, XCS("Hello, world"));
5559}
5560END_TEST
5561
5562START_TEST(test_unknown_ascii_encoding_fail) {
5563  const char *text = "<?xml version='1.0' encoding='ascii-like'?>\n"
5564                     "<doc>Hello, \x80 world</doc>";
5565
5566  XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5567  expect_failure(text, XML_ERROR_INVALID_TOKEN,
5568                 "Invalid character not faulted");
5569}
5570END_TEST
5571
5572START_TEST(test_unknown_encoding_invalid_length) {
5573  const char *text = "<?xml version='1.0' encoding='invalid-len'?>\n"
5574                     "<doc>Hello, world</doc>";
5575
5576  XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5577  expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
5578                 "Invalid unknown encoding not faulted");
5579}
5580END_TEST
5581
5582START_TEST(test_unknown_encoding_invalid_topbit) {
5583  const char *text = "<?xml version='1.0' encoding='invalid-a'?>\n"
5584                     "<doc>Hello, world</doc>";
5585
5586  XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5587  expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
5588                 "Invalid unknown encoding not faulted");
5589}
5590END_TEST
5591
5592START_TEST(test_unknown_encoding_invalid_surrogate) {
5593  const char *text = "<?xml version='1.0' encoding='invalid-surrogate'?>\n"
5594                     "<doc>Hello, \x82 world</doc>";
5595
5596  XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5597  expect_failure(text, XML_ERROR_INVALID_TOKEN,
5598                 "Invalid unknown encoding not faulted");
5599}
5600END_TEST
5601
5602START_TEST(test_unknown_encoding_invalid_high) {
5603  const char *text = "<?xml version='1.0' encoding='invalid-high'?>\n"
5604                     "<doc>Hello, world</doc>";
5605
5606  XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5607  expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
5608                 "Invalid unknown encoding not faulted");
5609}
5610END_TEST
5611
5612START_TEST(test_unknown_encoding_invalid_attr_value) {
5613  const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
5614                     "<doc attr='\xff\x30'/>";
5615
5616  XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
5617  expect_failure(text, XML_ERROR_INVALID_TOKEN,
5618                 "Invalid attribute valid not faulted");
5619}
5620END_TEST
5621
5622/* Test an external entity parser set to use latin-1 detects UTF-16
5623 * BOMs correctly.
5624 */
5625enum ee_parse_flags { EE_PARSE_NONE = 0x00, EE_PARSE_FULL_BUFFER = 0x01 };
5626
5627typedef struct ExtTest2 {
5628  const char *parse_text;
5629  int parse_len;
5630  const XML_Char *encoding;
5631  CharData *storage;
5632  enum ee_parse_flags flags;
5633} ExtTest2;
5634
5635static int XMLCALL
5636external_entity_loader2(XML_Parser parser, const XML_Char *context,
5637                        const XML_Char *base, const XML_Char *systemId,
5638                        const XML_Char *publicId) {
5639  ExtTest2 *test_data = (ExtTest2 *)XML_GetUserData(parser);
5640  XML_Parser extparser;
5641
5642  UNUSED_P(base);
5643  UNUSED_P(systemId);
5644  UNUSED_P(publicId);
5645  extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
5646  if (extparser == NULL)
5647    fail("Coulr not create external entity parser");
5648  if (test_data->encoding != NULL) {
5649    if (! XML_SetEncoding(extparser, test_data->encoding))
5650      fail("XML_SetEncoding() ignored for external entity");
5651  }
5652  if (test_data->flags & EE_PARSE_FULL_BUFFER) {
5653    if (XML_Parse(extparser, test_data->parse_text, test_data->parse_len,
5654                  XML_TRUE)
5655        == XML_STATUS_ERROR) {
5656      xml_failure(extparser);
5657    }
5658  } else if (_XML_Parse_SINGLE_BYTES(extparser, test_data->parse_text,
5659                                     test_data->parse_len, XML_TRUE)
5660             == XML_STATUS_ERROR) {
5661    xml_failure(extparser);
5662  }
5663
5664  XML_ParserFree(extparser);
5665  return XML_STATUS_OK;
5666}
5667
5668/* Test that UTF-16 BOM does not select UTF-16 given explicit encoding */
5669static void XMLCALL
5670ext2_accumulate_characters(void *userData, const XML_Char *s, int len) {
5671  ExtTest2 *test_data = (ExtTest2 *)userData;
5672  accumulate_characters(test_data->storage, s, len);
5673}
5674
5675START_TEST(test_ext_entity_latin1_utf16le_bom) {
5676  const char *text = "<!DOCTYPE doc [\n"
5677                     "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5678                     "]>\n"
5679                     "<doc>&en;</doc>";
5680  ExtTest2 test_data
5681      = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
5682         /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
5683          *   0x4c = L and 0x20 is a space
5684          */
5685         "\xff\xfe\x4c\x20", 4, XCS("iso-8859-1"), NULL, EE_PARSE_NONE};
5686#ifdef XML_UNICODE
5687  const XML_Char *expected = XCS("\x00ff\x00feL ");
5688#else
5689  /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
5690  const XML_Char *expected = XCS("\xc3\xbf\xc3\xbeL ");
5691#endif
5692  CharData storage;
5693
5694  CharData_Init(&storage);
5695  test_data.storage = &storage;
5696  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5697  XML_SetUserData(g_parser, &test_data);
5698  XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5699  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5700      == XML_STATUS_ERROR)
5701    xml_failure(g_parser);
5702  CharData_CheckXMLChars(&storage, expected);
5703}
5704END_TEST
5705
5706START_TEST(test_ext_entity_latin1_utf16be_bom) {
5707  const char *text = "<!DOCTYPE doc [\n"
5708                     "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5709                     "]>\n"
5710                     "<doc>&en;</doc>";
5711  ExtTest2 test_data
5712      = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
5713         /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
5714          *   0x4c = L and 0x20 is a space
5715          */
5716         "\xfe\xff\x20\x4c", 4, XCS("iso-8859-1"), NULL, EE_PARSE_NONE};
5717#ifdef XML_UNICODE
5718  const XML_Char *expected = XCS("\x00fe\x00ff L");
5719#else
5720  /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
5721  const XML_Char *expected = XCS("\xc3\xbe\xc3\xbf L");
5722#endif
5723  CharData storage;
5724
5725  CharData_Init(&storage);
5726  test_data.storage = &storage;
5727  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5728  XML_SetUserData(g_parser, &test_data);
5729  XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5730  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5731      == XML_STATUS_ERROR)
5732    xml_failure(g_parser);
5733  CharData_CheckXMLChars(&storage, expected);
5734}
5735END_TEST
5736
5737/* Parsing the full buffer rather than a byte at a time makes a
5738 * difference to the encoding scanning code, so repeat the above tests
5739 * without breaking them down by byte.
5740 */
5741START_TEST(test_ext_entity_latin1_utf16le_bom2) {
5742  const char *text = "<!DOCTYPE doc [\n"
5743                     "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5744                     "]>\n"
5745                     "<doc>&en;</doc>";
5746  ExtTest2 test_data
5747      = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
5748         /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
5749          *   0x4c = L and 0x20 is a space
5750          */
5751         "\xff\xfe\x4c\x20", 4, XCS("iso-8859-1"), NULL, EE_PARSE_FULL_BUFFER};
5752#ifdef XML_UNICODE
5753  const XML_Char *expected = XCS("\x00ff\x00feL ");
5754#else
5755  /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
5756  const XML_Char *expected = XCS("\xc3\xbf\xc3\xbeL ");
5757#endif
5758  CharData storage;
5759
5760  CharData_Init(&storage);
5761  test_data.storage = &storage;
5762  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5763  XML_SetUserData(g_parser, &test_data);
5764  XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5765  if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
5766      == XML_STATUS_ERROR)
5767    xml_failure(g_parser);
5768  CharData_CheckXMLChars(&storage, expected);
5769}
5770END_TEST
5771
5772START_TEST(test_ext_entity_latin1_utf16be_bom2) {
5773  const char *text = "<!DOCTYPE doc [\n"
5774                     "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5775                     "]>\n"
5776                     "<doc>&en;</doc>";
5777  ExtTest2 test_data
5778      = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
5779         /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
5780          *   0x4c = L and 0x20 is a space
5781          */
5782         "\xfe\xff\x20\x4c", 4, XCS("iso-8859-1"), NULL, EE_PARSE_FULL_BUFFER};
5783#ifdef XML_UNICODE
5784  const XML_Char *expected = XCS("\x00fe\x00ff L");
5785#else
5786  /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
5787  const XML_Char *expected = "\xc3\xbe\xc3\xbf L";
5788#endif
5789  CharData storage;
5790
5791  CharData_Init(&storage);
5792  test_data.storage = &storage;
5793  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5794  XML_SetUserData(g_parser, &test_data);
5795  XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5796  if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
5797      == XML_STATUS_ERROR)
5798    xml_failure(g_parser);
5799  CharData_CheckXMLChars(&storage, expected);
5800}
5801END_TEST
5802
5803/* Test little-endian UTF-16 given an explicit big-endian encoding */
5804START_TEST(test_ext_entity_utf16_be) {
5805  const char *text = "<!DOCTYPE doc [\n"
5806                     "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5807                     "]>\n"
5808                     "<doc>&en;</doc>";
5809  ExtTest2 test_data
5810      = {"<\0e\0/\0>\0", 8, XCS("utf-16be"), NULL, EE_PARSE_NONE};
5811#ifdef XML_UNICODE
5812  const XML_Char *expected = XCS("\x3c00\x6500\x2f00\x3e00");
5813#else
5814  const XML_Char *expected = XCS("\xe3\xb0\x80"   /* U+3C00 */
5815                                 "\xe6\x94\x80"   /* U+6500 */
5816                                 "\xe2\xbc\x80"   /* U+2F00 */
5817                                 "\xe3\xb8\x80"); /* U+3E00 */
5818#endif
5819  CharData storage;
5820
5821  CharData_Init(&storage);
5822  test_data.storage = &storage;
5823  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5824  XML_SetUserData(g_parser, &test_data);
5825  XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5826  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5827      == XML_STATUS_ERROR)
5828    xml_failure(g_parser);
5829  CharData_CheckXMLChars(&storage, expected);
5830}
5831END_TEST
5832
5833/* Test big-endian UTF-16 given an explicit little-endian encoding */
5834START_TEST(test_ext_entity_utf16_le) {
5835  const char *text = "<!DOCTYPE doc [\n"
5836                     "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5837                     "]>\n"
5838                     "<doc>&en;</doc>";
5839  ExtTest2 test_data
5840      = {"\0<\0e\0/\0>", 8, XCS("utf-16le"), NULL, EE_PARSE_NONE};
5841#ifdef XML_UNICODE
5842  const XML_Char *expected = XCS("\x3c00\x6500\x2f00\x3e00");
5843#else
5844  const XML_Char *expected = XCS("\xe3\xb0\x80"   /* U+3C00 */
5845                                 "\xe6\x94\x80"   /* U+6500 */
5846                                 "\xe2\xbc\x80"   /* U+2F00 */
5847                                 "\xe3\xb8\x80"); /* U+3E00 */
5848#endif
5849  CharData storage;
5850
5851  CharData_Init(&storage);
5852  test_data.storage = &storage;
5853  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5854  XML_SetUserData(g_parser, &test_data);
5855  XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5856  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5857      == XML_STATUS_ERROR)
5858    xml_failure(g_parser);
5859  CharData_CheckXMLChars(&storage, expected);
5860}
5861END_TEST
5862
5863/* Test little-endian UTF-16 given no explicit encoding.
5864 * The existing default encoding (UTF-8) is assumed to hold without a
5865 * BOM to contradict it, so the entity value will in fact provoke an
5866 * error because 0x00 is not a valid XML character.  We parse the
5867 * whole buffer in one go rather than feeding it in byte by byte to
5868 * exercise different code paths in the initial scanning routines.
5869 */
5870typedef struct ExtFaults2 {
5871  const char *parse_text;
5872  int parse_len;
5873  const char *fail_text;
5874  const XML_Char *encoding;
5875  enum XML_Error error;
5876} ExtFaults2;
5877
5878static int XMLCALL
5879external_entity_faulter2(XML_Parser parser, const XML_Char *context,
5880                         const XML_Char *base, const XML_Char *systemId,
5881                         const XML_Char *publicId) {
5882  ExtFaults2 *test_data = (ExtFaults2 *)XML_GetUserData(parser);
5883  XML_Parser extparser;
5884
5885  UNUSED_P(base);
5886  UNUSED_P(systemId);
5887  UNUSED_P(publicId);
5888  extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
5889  if (extparser == NULL)
5890    fail("Could not create external entity parser");
5891  if (test_data->encoding != NULL) {
5892    if (! XML_SetEncoding(extparser, test_data->encoding))
5893      fail("XML_SetEncoding() ignored for external entity");
5894  }
5895  if (XML_Parse(extparser, test_data->parse_text, test_data->parse_len,
5896                XML_TRUE)
5897      != XML_STATUS_ERROR)
5898    fail(test_data->fail_text);
5899  if (XML_GetErrorCode(extparser) != test_data->error)
5900    xml_failure(extparser);
5901
5902  XML_ParserFree(extparser);
5903  return XML_STATUS_ERROR;
5904}
5905
5906START_TEST(test_ext_entity_utf16_unknown) {
5907  const char *text = "<!DOCTYPE doc [\n"
5908                     "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5909                     "]>\n"
5910                     "<doc>&en;</doc>";
5911  ExtFaults2 test_data
5912      = {"a\0b\0c\0", 6, "Invalid character in entity not faulted", NULL,
5913         XML_ERROR_INVALID_TOKEN};
5914
5915  XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter2);
5916  XML_SetUserData(g_parser, &test_data);
5917  expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
5918                 "Invalid character should not have been accepted");
5919}
5920END_TEST
5921
5922/* Test not-quite-UTF-8 BOM (0xEF 0xBB 0xBF) */
5923START_TEST(test_ext_entity_utf8_non_bom) {
5924  const char *text = "<!DOCTYPE doc [\n"
5925                     "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
5926                     "]>\n"
5927                     "<doc>&en;</doc>";
5928  ExtTest2 test_data
5929      = {"\xef\xbb\x80", /* Arabic letter DAD medial form, U+FEC0 */
5930         3, NULL, NULL, EE_PARSE_NONE};
5931#ifdef XML_UNICODE
5932  const XML_Char *expected = XCS("\xfec0");
5933#else
5934  const XML_Char *expected = XCS("\xef\xbb\x80");
5935#endif
5936  CharData storage;
5937
5938  CharData_Init(&storage);
5939  test_data.storage = &storage;
5940  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
5941  XML_SetUserData(g_parser, &test_data);
5942  XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
5943  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5944      == XML_STATUS_ERROR)
5945    xml_failure(g_parser);
5946  CharData_CheckXMLChars(&storage, expected);
5947}
5948END_TEST
5949
5950/* Test that UTF-8 in a CDATA section is correctly passed through */
5951START_TEST(test_utf8_in_cdata_section) {
5952  const char *text = "<doc><![CDATA[one \xc3\xa9 two]]></doc>";
5953#ifdef XML_UNICODE
5954  const XML_Char *expected = XCS("one \x00e9 two");
5955#else
5956  const XML_Char *expected = XCS("one \xc3\xa9 two");
5957#endif
5958
5959  run_character_check(text, expected);
5960}
5961END_TEST
5962
5963/* Test that little-endian UTF-16 in a CDATA section is handled */
5964START_TEST(test_utf8_in_cdata_section_2) {
5965  const char *text = "<doc><![CDATA[\xc3\xa9]\xc3\xa9two]]></doc>";
5966#ifdef XML_UNICODE
5967  const XML_Char *expected = XCS("\x00e9]\x00e9two");
5968#else
5969  const XML_Char *expected = XCS("\xc3\xa9]\xc3\xa9two");
5970#endif
5971
5972  run_character_check(text, expected);
5973}
5974END_TEST
5975
5976/* Test trailing spaces in elements are accepted */
5977static void XMLCALL
5978record_element_end_handler(void *userData, const XML_Char *name) {
5979  CharData *storage = (CharData *)userData;
5980
5981  CharData_AppendXMLChars(storage, XCS("/"), 1);
5982  CharData_AppendXMLChars(storage, name, -1);
5983}
5984
5985START_TEST(test_trailing_spaces_in_elements) {
5986  const char *text = "<doc   >Hi</doc >";
5987  const XML_Char *expected = XCS("doc/doc");
5988  CharData storage;
5989
5990  CharData_Init(&storage);
5991  XML_SetElementHandler(g_parser, record_element_start_handler,
5992                        record_element_end_handler);
5993  XML_SetUserData(g_parser, &storage);
5994  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
5995      == XML_STATUS_ERROR)
5996    xml_failure(g_parser);
5997  CharData_CheckXMLChars(&storage, expected);
5998}
5999END_TEST
6000
6001START_TEST(test_utf16_attribute) {
6002  const char text[] =
6003      /* <d {KHO KHWAI}{CHO CHAN}='a'/>
6004       * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
6005       * and   {CHO CHAN}  = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
6006       */
6007      "<\0d\0 \0\x04\x0e\x08\x0e=\0'\0a\0'\0/\0>\0";
6008  const XML_Char *expected = XCS("a");
6009  CharData storage;
6010
6011  CharData_Init(&storage);
6012  XML_SetStartElementHandler(g_parser, accumulate_attribute);
6013  XML_SetUserData(g_parser, &storage);
6014  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6015      == XML_STATUS_ERROR)
6016    xml_failure(g_parser);
6017  CharData_CheckXMLChars(&storage, expected);
6018}
6019END_TEST
6020
6021START_TEST(test_utf16_second_attr) {
6022  /* <d a='1' {KHO KHWAI}{CHO CHAN}='2'/>
6023   * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
6024   * and   {CHO CHAN}  = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
6025   */
6026  const char text[] = "<\0d\0 \0a\0=\0'\0\x31\0'\0 \0"
6027                      "\x04\x0e\x08\x0e=\0'\0\x32\0'\0/\0>\0";
6028  const XML_Char *expected = XCS("1");
6029  CharData storage;
6030
6031  CharData_Init(&storage);
6032  XML_SetStartElementHandler(g_parser, accumulate_attribute);
6033  XML_SetUserData(g_parser, &storage);
6034  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6035      == XML_STATUS_ERROR)
6036    xml_failure(g_parser);
6037  CharData_CheckXMLChars(&storage, expected);
6038}
6039END_TEST
6040
6041START_TEST(test_attr_after_solidus) {
6042  const char *text = "<doc attr1='a' / attr2='b'>";
6043
6044  expect_failure(text, XML_ERROR_INVALID_TOKEN, "Misplaced / not faulted");
6045}
6046END_TEST
6047
6048static void XMLCALL
6049accumulate_entity_decl(void *userData, const XML_Char *entityName,
6050                       int is_parameter_entity, const XML_Char *value,
6051                       int value_length, const XML_Char *base,
6052                       const XML_Char *systemId, const XML_Char *publicId,
6053                       const XML_Char *notationName) {
6054  CharData *storage = (CharData *)userData;
6055
6056  UNUSED_P(is_parameter_entity);
6057  UNUSED_P(base);
6058  UNUSED_P(systemId);
6059  UNUSED_P(publicId);
6060  UNUSED_P(notationName);
6061  CharData_AppendXMLChars(storage, entityName, -1);
6062  CharData_AppendXMLChars(storage, XCS("="), 1);
6063  CharData_AppendXMLChars(storage, value, value_length);
6064  CharData_AppendXMLChars(storage, XCS("\n"), 1);
6065}
6066
6067START_TEST(test_utf16_pe) {
6068  /* <!DOCTYPE doc [
6069   * <!ENTITY % {KHO KHWAI}{CHO CHAN} '<!ELEMENT doc (#PCDATA)>'>
6070   * %{KHO KHWAI}{CHO CHAN};
6071   * ]>
6072   * <doc></doc>
6073   *
6074   * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
6075   * and   {CHO CHAN}  = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
6076   */
6077  const char text[] = "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0\n"
6078                      "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \x0e\x04\x0e\x08\0 "
6079                      "\0'\0<\0!\0E\0L\0E\0M\0E\0N\0T\0 "
6080                      "\0d\0o\0c\0 \0(\0#\0P\0C\0D\0A\0T\0A\0)\0>\0'\0>\0\n"
6081                      "\0%\x0e\x04\x0e\x08\0;\0\n"
6082                      "\0]\0>\0\n"
6083                      "\0<\0d\0o\0c\0>\0<\0/\0d\0o\0c\0>";
6084#ifdef XML_UNICODE
6085  const XML_Char *expected = XCS("\x0e04\x0e08=<!ELEMENT doc (#PCDATA)>\n");
6086#else
6087  const XML_Char *expected
6088      = XCS("\xe0\xb8\x84\xe0\xb8\x88=<!ELEMENT doc (#PCDATA)>\n");
6089#endif
6090  CharData storage;
6091
6092  CharData_Init(&storage);
6093  XML_SetUserData(g_parser, &storage);
6094  XML_SetEntityDeclHandler(g_parser, accumulate_entity_decl);
6095  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6096      == XML_STATUS_ERROR)
6097    xml_failure(g_parser);
6098  CharData_CheckXMLChars(&storage, expected);
6099}
6100END_TEST
6101
6102/* Test that duff attribute description keywords are rejected */
6103START_TEST(test_bad_attr_desc_keyword) {
6104  const char *text = "<!DOCTYPE doc [\n"
6105                     "  <!ATTLIST doc attr CDATA #!IMPLIED>\n"
6106                     "]>\n"
6107                     "<doc />";
6108
6109  expect_failure(text, XML_ERROR_INVALID_TOKEN,
6110                 "Bad keyword !IMPLIED not faulted");
6111}
6112END_TEST
6113
6114/* Test that an invalid attribute description keyword consisting of
6115 * UTF-16 characters with their top bytes non-zero are correctly
6116 * faulted
6117 */
6118START_TEST(test_bad_attr_desc_keyword_utf16) {
6119  /* <!DOCTYPE d [
6120   * <!ATTLIST d a CDATA #{KHO KHWAI}{CHO CHAN}>
6121   * ]><d/>
6122   *
6123   * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
6124   * and   {CHO CHAN}  = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
6125   */
6126  const char text[]
6127      = "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n"
6128        "\0<\0!\0A\0T\0T\0L\0I\0S\0T\0 \0d\0 \0a\0 \0C\0D\0A\0T\0A\0 "
6129        "\0#\x0e\x04\x0e\x08\0>\0\n"
6130        "\0]\0>\0<\0d\0/\0>";
6131
6132  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6133      != XML_STATUS_ERROR)
6134    fail("Invalid UTF16 attribute keyword not faulted");
6135  if (XML_GetErrorCode(g_parser) != XML_ERROR_SYNTAX)
6136    xml_failure(g_parser);
6137}
6138END_TEST
6139
6140/* Test that invalid syntax in a <!DOCTYPE> is rejected.  Do this
6141 * using prefix-encoding (see above) to trigger specific code paths
6142 */
6143START_TEST(test_bad_doctype) {
6144  const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
6145                     "<!DOCTYPE doc [ \x80\x44 ]><doc/>";
6146
6147  XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
6148  expect_failure(text, XML_ERROR_SYNTAX,
6149                 "Invalid bytes in DOCTYPE not faulted");
6150}
6151END_TEST
6152
6153START_TEST(test_bad_doctype_utf16) {
6154  const char text[] =
6155      /* <!DOCTYPE doc [ \x06f2 ]><doc/>
6156       *
6157       * U+06F2 = EXTENDED ARABIC-INDIC DIGIT TWO, a valid number
6158       * (name character) but not a valid letter (name start character)
6159       */
6160      "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0 "
6161      "\x06\xf2"
6162      "\0 \0]\0>\0<\0d\0o\0c\0/\0>";
6163
6164  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6165      != XML_STATUS_ERROR)
6166    fail("Invalid bytes in DOCTYPE not faulted");
6167  if (XML_GetErrorCode(g_parser) != XML_ERROR_SYNTAX)
6168    xml_failure(g_parser);
6169}
6170END_TEST
6171
6172START_TEST(test_bad_doctype_plus) {
6173  const char *text = "<!DOCTYPE 1+ [ <!ENTITY foo 'bar'> ]>\n"
6174                     "<1+>&foo;</1+>";
6175
6176  expect_failure(text, XML_ERROR_INVALID_TOKEN,
6177                 "'+' in document name not faulted");
6178}
6179END_TEST
6180
6181START_TEST(test_bad_doctype_star) {
6182  const char *text = "<!DOCTYPE 1* [ <!ENTITY foo 'bar'> ]>\n"
6183                     "<1*>&foo;</1*>";
6184
6185  expect_failure(text, XML_ERROR_INVALID_TOKEN,
6186                 "'*' in document name not faulted");
6187}
6188END_TEST
6189
6190START_TEST(test_bad_doctype_query) {
6191  const char *text = "<!DOCTYPE 1? [ <!ENTITY foo 'bar'> ]>\n"
6192                     "<1?>&foo;</1?>";
6193
6194  expect_failure(text, XML_ERROR_INVALID_TOKEN,
6195                 "'?' in document name not faulted");
6196}
6197END_TEST
6198
6199START_TEST(test_unknown_encoding_bad_ignore) {
6200  const char *text = "<?xml version='1.0' encoding='prefix-conv'?>"
6201                     "<!DOCTYPE doc SYSTEM 'foo'>"
6202                     "<doc><e>&entity;</e></doc>";
6203  ExtFaults fault = {"<![IGNORE[<!ELEMENT \xffG (#PCDATA)*>]]>",
6204                     "Invalid character not faulted", XCS("prefix-conv"),
6205                     XML_ERROR_INVALID_TOKEN};
6206
6207  XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
6208  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
6209  XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
6210  XML_SetUserData(g_parser, &fault);
6211  expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
6212                 "Bad IGNORE section with unknown encoding not failed");
6213}
6214END_TEST
6215
6216START_TEST(test_entity_in_utf16_be_attr) {
6217  const char text[] =
6218      /* <e a='&#228; &#x00E4;'></e> */
6219      "\0<\0e\0 \0a\0=\0'\0&\0#\0\x32\0\x32\0\x38\0;\0 "
6220      "\0&\0#\0x\0\x30\0\x30\0E\0\x34\0;\0'\0>\0<\0/\0e\0>";
6221#ifdef XML_UNICODE
6222  const XML_Char *expected = XCS("\x00e4 \x00e4");
6223#else
6224  const XML_Char *expected = XCS("\xc3\xa4 \xc3\xa4");
6225#endif
6226  CharData storage;
6227
6228  CharData_Init(&storage);
6229  XML_SetUserData(g_parser, &storage);
6230  XML_SetStartElementHandler(g_parser, accumulate_attribute);
6231  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6232      == XML_STATUS_ERROR)
6233    xml_failure(g_parser);
6234  CharData_CheckXMLChars(&storage, expected);
6235}
6236END_TEST
6237
6238START_TEST(test_entity_in_utf16_le_attr) {
6239  const char text[] =
6240      /* <e a='&#228; &#x00E4;'></e> */
6241      "<\0e\0 \0a\0=\0'\0&\0#\0\x32\0\x32\0\x38\0;\0 \0"
6242      "&\0#\0x\0\x30\0\x30\0E\0\x34\0;\0'\0>\0<\0/\0e\0>\0";
6243#ifdef XML_UNICODE
6244  const XML_Char *expected = XCS("\x00e4 \x00e4");
6245#else
6246  const XML_Char *expected = XCS("\xc3\xa4 \xc3\xa4");
6247#endif
6248  CharData storage;
6249
6250  CharData_Init(&storage);
6251  XML_SetUserData(g_parser, &storage);
6252  XML_SetStartElementHandler(g_parser, accumulate_attribute);
6253  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6254      == XML_STATUS_ERROR)
6255    xml_failure(g_parser);
6256  CharData_CheckXMLChars(&storage, expected);
6257}
6258END_TEST
6259
6260START_TEST(test_entity_public_utf16_be) {
6261  const char text[] =
6262      /* <!DOCTYPE d [ */
6263      "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n"
6264      /* <!ENTITY % e PUBLIC 'foo' 'bar.ent'> */
6265      "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \0e\0 \0P\0U\0B\0L\0I\0C\0 "
6266      "\0'\0f\0o\0o\0'\0 \0'\0b\0a\0r\0.\0e\0n\0t\0'\0>\0\n"
6267      /* %e; */
6268      "\0%\0e\0;\0\n"
6269      /* ]> */
6270      "\0]\0>\0\n"
6271      /* <d>&j;</d> */
6272      "\0<\0d\0>\0&\0j\0;\0<\0/\0d\0>";
6273  ExtTest2 test_data = {/* <!ENTITY j 'baz'> */
6274                        "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0j\0 \0'\0b\0a\0z\0'\0>",
6275                        34, NULL, NULL, EE_PARSE_NONE};
6276  const XML_Char *expected = XCS("baz");
6277  CharData storage;
6278
6279  CharData_Init(&storage);
6280  test_data.storage = &storage;
6281  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
6282  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
6283  XML_SetUserData(g_parser, &test_data);
6284  XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
6285  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6286      == XML_STATUS_ERROR)
6287    xml_failure(g_parser);
6288  CharData_CheckXMLChars(&storage, expected);
6289}
6290END_TEST
6291
6292START_TEST(test_entity_public_utf16_le) {
6293  const char text[] =
6294      /* <!DOCTYPE d [ */
6295      "<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n\0"
6296      /* <!ENTITY % e PUBLIC 'foo' 'bar.ent'> */
6297      "<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \0e\0 \0P\0U\0B\0L\0I\0C\0 \0"
6298      "'\0f\0o\0o\0'\0 \0'\0b\0a\0r\0.\0e\0n\0t\0'\0>\0\n\0"
6299      /* %e; */
6300      "%\0e\0;\0\n\0"
6301      /* ]> */
6302      "]\0>\0\n\0"
6303      /* <d>&j;</d> */
6304      "<\0d\0>\0&\0j\0;\0<\0/\0d\0>\0";
6305  ExtTest2 test_data = {/* <!ENTITY j 'baz'> */
6306                        "<\0!\0E\0N\0T\0I\0T\0Y\0 \0j\0 \0'\0b\0a\0z\0'\0>\0",
6307                        34, NULL, NULL, EE_PARSE_NONE};
6308  const XML_Char *expected = XCS("baz");
6309  CharData storage;
6310
6311  CharData_Init(&storage);
6312  test_data.storage = &storage;
6313  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
6314  XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
6315  XML_SetUserData(g_parser, &test_data);
6316  XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
6317  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
6318      == XML_STATUS_ERROR)
6319    xml_failure(g_parser);
6320  CharData_CheckXMLChars(&storage, expected);
6321}
6322END_TEST
6323
6324/* Test that a doctype with neither an internal nor external subset is
6325 * faulted
6326 */
6327START_TEST(test_short_doctype) {
6328  const char *text = "<!DOCTYPE doc></doc>";
6329  expect_failure(text, XML_ERROR_INVALID_TOKEN,
6330                 "DOCTYPE without subset not rejected");
6331}
6332END_TEST
6333
6334START_TEST(test_short_doctype_2) {
6335  const char *text = "<!DOCTYPE doc PUBLIC></doc>";
6336  expect_failure(text, XML_ERROR_SYNTAX,
6337                 "DOCTYPE without Public ID not rejected");
6338}
6339END_TEST
6340
6341START_TEST(test_short_doctype_3) {
6342  const char *text = "<!DOCTYPE doc SYSTEM></doc>";
6343  expect_failure(text, XML_ERROR_SYNTAX,
6344                 "DOCTYPE without System ID not rejected");
6345}
6346END_TEST
6347
6348START_TEST(test_long_doctype) {
6349  const char *text = "<!DOCTYPE doc PUBLIC 'foo' 'bar' 'baz'></doc>";
6350  expect_failure(text, XML_ERROR_SYNTAX, "DOCTYPE with extra ID not rejected");
6351}
6352END_TEST
6353
6354START_TEST(test_bad_entity) {
6355  const char *text = "<!DOCTYPE doc [\n"
6356                     "  <!ENTITY foo PUBLIC>\n"
6357                     "]>\n"
6358                     "<doc/>";
6359  expect_failure(text, XML_ERROR_SYNTAX,
6360                 "ENTITY without Public ID is not rejected");
6361}
6362END_TEST
6363
6364/* Test unquoted value is faulted */
6365START_TEST(test_bad_entity_2) {
6366  const char *text = "<!DOCTYPE doc [\n"
6367                     "  <!ENTITY % foo bar>\n"
6368                     "]>\n"
6369                     "<doc/>";
6370  expect_failure(text, XML_ERROR_SYNTAX,
6371                 "ENTITY without Public ID is not rejected");
6372}
6373END_TEST
6374
6375START_TEST(test_bad_entity_3) {
6376  const char *text = "<!DOCTYPE doc [\n"
6377                     "  <!ENTITY % foo PUBLIC>\n"
6378                     "]>\n"
6379                     "<doc/>";
6380  expect_failure(text, XML_ERROR_SYNTAX,
6381                 "Parameter ENTITY without Public ID is not rejected");
6382}
6383END_TEST
6384
6385START_TEST(test_bad_entity_4) {
6386  const char *text = "<!DOCTYPE doc [\n"
6387                     "  <!ENTITY % foo SYSTEM>\n"
6388                     "]>\n"
6389                     "<doc/>";
6390  expect_failure(text, XML_ERROR_SYNTAX,
6391                 "Parameter ENTITY without Public ID is not rejected");
6392}
6393END_TEST
6394
6395START_TEST(test_bad_notation) {
6396  const char *text = "<!DOCTYPE doc [\n"
6397                     "  <!NOTATION n SYSTEM>\n"
6398                     "]>\n"
6399                     "<doc/>";
6400  expect_failure(text, XML_ERROR_SYNTAX,
6401                 "Notation without System ID is not rejected");
6402}
6403END_TEST
6404
6405/* Test for issue #11, wrongly suppressed default handler */
6406typedef struct default_check {
6407  const XML_Char *expected;
6408  const int expectedLen;
6409  XML_Bool seen;
6410} DefaultCheck;
6411
6412static void XMLCALL
6413checking_default_handler(void *userData, const XML_Char *s, int len) {
6414  DefaultCheck *data = (DefaultCheck *)userData;
6415  int i;
6416
6417  for (i = 0; data[i].expected != NULL; i++) {
6418    if (data[i].expectedLen == len
6419        && ! memcmp(data[i].expected, s, len * sizeof(XML_Char))) {
6420      data[i].seen = XML_TRUE;
6421      break;
6422    }
6423  }
6424}
6425
6426START_TEST(test_default_doctype_handler) {
6427  const char *text = "<!DOCTYPE doc PUBLIC 'pubname' 'test.dtd' [\n"
6428                     "  <!ENTITY foo 'bar'>\n"
6429                     "]>\n"
6430                     "<doc>&foo;</doc>";
6431  DefaultCheck test_data[] = {{XCS("'pubname'"), 9, XML_FALSE},
6432                              {XCS("'test.dtd'"), 10, XML_FALSE},
6433                              {NULL, 0, XML_FALSE}};
6434  int i;
6435
6436  XML_SetUserData(g_parser, &test_data);
6437  XML_SetDefaultHandler(g_parser, checking_default_handler);
6438  XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
6439  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6440      == XML_STATUS_ERROR)
6441    xml_failure(g_parser);
6442  for (i = 0; test_data[i].expected != NULL; i++)
6443    if (! test_data[i].seen)
6444      fail("Default handler not run for public !DOCTYPE");
6445}
6446END_TEST
6447
6448START_TEST(test_empty_element_abort) {
6449  const char *text = "<abort/>";
6450
6451  XML_SetStartElementHandler(g_parser, start_element_suspender);
6452  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6453      != XML_STATUS_ERROR)
6454    fail("Expected to error on abort");
6455}
6456END_TEST
6457
6458/*
6459 * Namespaces tests.
6460 */
6461
6462static void
6463namespace_setup(void) {
6464  g_parser = XML_ParserCreateNS(NULL, XCS(' '));
6465  if (g_parser == NULL)
6466    fail("Parser not created.");
6467}
6468
6469static void
6470namespace_teardown(void) {
6471  basic_teardown();
6472}
6473
6474/* Check that an element name and attribute name match the expected values.
6475   The expected values are passed as an array reference of string pointers
6476   provided as the userData argument; the first is the expected
6477   element name, and the second is the expected attribute name.
6478*/
6479static int triplet_start_flag = XML_FALSE;
6480static int triplet_end_flag = XML_FALSE;
6481
6482static void XMLCALL
6483triplet_start_checker(void *userData, const XML_Char *name,
6484                      const XML_Char **atts) {
6485  XML_Char **elemstr = (XML_Char **)userData;
6486  char buffer[1024];
6487  if (xcstrcmp(elemstr[0], name) != 0) {
6488    sprintf(buffer, "unexpected start string: '%" XML_FMT_STR "'", name);
6489    fail(buffer);
6490  }
6491  if (xcstrcmp(elemstr[1], atts[0]) != 0) {
6492    sprintf(buffer, "unexpected attribute string: '%" XML_FMT_STR "'", atts[0]);
6493    fail(buffer);
6494  }
6495  triplet_start_flag = XML_TRUE;
6496}
6497
6498/* Check that the element name passed to the end-element handler matches
6499   the expected value.  The expected value is passed as the first element
6500   in an array of strings passed as the userData argument.
6501*/
6502static void XMLCALL
6503triplet_end_checker(void *userData, const XML_Char *name) {
6504  XML_Char **elemstr = (XML_Char **)userData;
6505  if (xcstrcmp(elemstr[0], name) != 0) {
6506    char buffer[1024];
6507    sprintf(buffer, "unexpected end string: '%" XML_FMT_STR "'", name);
6508    fail(buffer);
6509  }
6510  triplet_end_flag = XML_TRUE;
6511}
6512
6513START_TEST(test_return_ns_triplet) {
6514  const char *text = "<foo:e xmlns:foo='http://example.org/' bar:a='12'\n"
6515                     "       xmlns:bar='http://example.org/'>";
6516  const char *epilog = "</foo:e>";
6517  const XML_Char *elemstr[]
6518      = {XCS("http://example.org/ e foo"), XCS("http://example.org/ a bar")};
6519  XML_SetReturnNSTriplet(g_parser, XML_TRUE);
6520  XML_SetUserData(g_parser, (void *)elemstr);
6521  XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
6522  XML_SetNamespaceDeclHandler(g_parser, dummy_start_namespace_decl_handler,
6523                              dummy_end_namespace_decl_handler);
6524  triplet_start_flag = XML_FALSE;
6525  triplet_end_flag = XML_FALSE;
6526  dummy_handler_flags = 0;
6527  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
6528      == XML_STATUS_ERROR)
6529    xml_failure(g_parser);
6530  if (! triplet_start_flag)
6531    fail("triplet_start_checker not invoked");
6532  /* Check that unsetting "return triplets" fails while still parsing */
6533  XML_SetReturnNSTriplet(g_parser, XML_FALSE);
6534  if (_XML_Parse_SINGLE_BYTES(g_parser, epilog, (int)strlen(epilog), XML_TRUE)
6535      == XML_STATUS_ERROR)
6536    xml_failure(g_parser);
6537  if (! triplet_end_flag)
6538    fail("triplet_end_checker not invoked");
6539  if (dummy_handler_flags
6540      != (DUMMY_START_NS_DECL_HANDLER_FLAG | DUMMY_END_NS_DECL_HANDLER_FLAG))
6541    fail("Namespace handlers not called");
6542}
6543END_TEST
6544
6545static void XMLCALL
6546overwrite_start_checker(void *userData, const XML_Char *name,
6547                        const XML_Char **atts) {
6548  CharData *storage = (CharData *)userData;
6549  CharData_AppendXMLChars(storage, XCS("start "), 6);
6550  CharData_AppendXMLChars(storage, name, -1);
6551  while (*atts != NULL) {
6552    CharData_AppendXMLChars(storage, XCS("\nattribute "), 11);
6553    CharData_AppendXMLChars(storage, *atts, -1);
6554    atts += 2;
6555  }
6556  CharData_AppendXMLChars(storage, XCS("\n"), 1);
6557}
6558
6559static void XMLCALL
6560overwrite_end_checker(void *userData, const XML_Char *name) {
6561  CharData *storage = (CharData *)userData;
6562  CharData_AppendXMLChars(storage, XCS("end "), 4);
6563  CharData_AppendXMLChars(storage, name, -1);
6564  CharData_AppendXMLChars(storage, XCS("\n"), 1);
6565}
6566
6567static void
6568run_ns_tagname_overwrite_test(const char *text, const XML_Char *result) {
6569  CharData storage;
6570  CharData_Init(&storage);
6571  XML_SetUserData(g_parser, &storage);
6572  XML_SetElementHandler(g_parser, overwrite_start_checker,
6573                        overwrite_end_checker);
6574  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6575      == XML_STATUS_ERROR)
6576    xml_failure(g_parser);
6577  CharData_CheckXMLChars(&storage, result);
6578}
6579
6580/* Regression test for SF bug #566334. */
6581START_TEST(test_ns_tagname_overwrite) {
6582  const char *text = "<n:e xmlns:n='http://example.org/'>\n"
6583                     "  <n:f n:attr='foo'/>\n"
6584                     "  <n:g n:attr2='bar'/>\n"
6585                     "</n:e>";
6586  const XML_Char *result = XCS("start http://example.org/ e\n")
6587      XCS("start http://example.org/ f\n")
6588          XCS("attribute http://example.org/ attr\n")
6589              XCS("end http://example.org/ f\n")
6590                  XCS("start http://example.org/ g\n")
6591                      XCS("attribute http://example.org/ attr2\n")
6592                          XCS("end http://example.org/ g\n")
6593                              XCS("end http://example.org/ e\n");
6594  run_ns_tagname_overwrite_test(text, result);
6595}
6596END_TEST
6597
6598/* Regression test for SF bug #566334. */
6599START_TEST(test_ns_tagname_overwrite_triplet) {
6600  const char *text = "<n:e xmlns:n='http://example.org/'>\n"
6601                     "  <n:f n:attr='foo'/>\n"
6602                     "  <n:g n:attr2='bar'/>\n"
6603                     "</n:e>";
6604  const XML_Char *result = XCS("start http://example.org/ e n\n")
6605      XCS("start http://example.org/ f n\n")
6606          XCS("attribute http://example.org/ attr n\n")
6607              XCS("end http://example.org/ f n\n")
6608                  XCS("start http://example.org/ g n\n")
6609                      XCS("attribute http://example.org/ attr2 n\n")
6610                          XCS("end http://example.org/ g n\n")
6611                              XCS("end http://example.org/ e n\n");
6612  XML_SetReturnNSTriplet(g_parser, XML_TRUE);
6613  run_ns_tagname_overwrite_test(text, result);
6614}
6615END_TEST
6616
6617/* Regression test for SF bug #620343. */
6618static void XMLCALL
6619start_element_fail(void *userData, const XML_Char *name,
6620                   const XML_Char **atts) {
6621  UNUSED_P(userData);
6622  UNUSED_P(name);
6623  UNUSED_P(atts);
6624
6625  /* We should never get here. */
6626  fail("should never reach start_element_fail()");
6627}
6628
6629static void XMLCALL
6630start_ns_clearing_start_element(void *userData, const XML_Char *prefix,
6631                                const XML_Char *uri) {
6632  UNUSED_P(prefix);
6633  UNUSED_P(uri);
6634  XML_SetStartElementHandler((XML_Parser)userData, NULL);
6635}
6636
6637START_TEST(test_start_ns_clears_start_element) {
6638  /* This needs to use separate start/end tags; using the empty tag
6639     syntax doesn't cause the problematic path through Expat to be
6640     taken.
6641  */
6642  const char *text = "<e xmlns='http://example.org/'></e>";
6643
6644  XML_SetStartElementHandler(g_parser, start_element_fail);
6645  XML_SetStartNamespaceDeclHandler(g_parser, start_ns_clearing_start_element);
6646  XML_SetEndNamespaceDeclHandler(g_parser, dummy_end_namespace_decl_handler);
6647  XML_UseParserAsHandlerArg(g_parser);
6648  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6649      == XML_STATUS_ERROR)
6650    xml_failure(g_parser);
6651}
6652END_TEST
6653
6654/* Regression test for SF bug #616863. */
6655static int XMLCALL
6656external_entity_handler(XML_Parser parser, const XML_Char *context,
6657                        const XML_Char *base, const XML_Char *systemId,
6658                        const XML_Char *publicId) {
6659  intptr_t callno = 1 + (intptr_t)XML_GetUserData(parser);
6660  const char *text;
6661  XML_Parser p2;
6662
6663  UNUSED_P(base);
6664  UNUSED_P(systemId);
6665  UNUSED_P(publicId);
6666  if (callno == 1)
6667    text = ("<!ELEMENT doc (e+)>\n"
6668            "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
6669            "<!ELEMENT e EMPTY>\n");
6670  else
6671    text = ("<?xml version='1.0' encoding='us-ascii'?>"
6672            "<e/>");
6673
6674  XML_SetUserData(parser, (void *)callno);
6675  p2 = XML_ExternalEntityParserCreate(parser, context, NULL);
6676  if (_XML_Parse_SINGLE_BYTES(p2, text, (int)strlen(text), XML_TRUE)
6677      == XML_STATUS_ERROR) {
6678    xml_failure(p2);
6679    return XML_STATUS_ERROR;
6680  }
6681  XML_ParserFree(p2);
6682  return XML_STATUS_OK;
6683}
6684
6685START_TEST(test_default_ns_from_ext_subset_and_ext_ge) {
6686  const char *text = "<?xml version='1.0'?>\n"
6687                     "<!DOCTYPE doc SYSTEM 'http://example.org/doc.dtd' [\n"
6688                     "  <!ENTITY en SYSTEM 'http://example.org/entity.ent'>\n"
6689                     "]>\n"
6690                     "<doc xmlns='http://example.org/ns1'>\n"
6691                     "&en;\n"
6692                     "</doc>";
6693
6694  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
6695  XML_SetExternalEntityRefHandler(g_parser, external_entity_handler);
6696  /* We actually need to set this handler to tickle this bug. */
6697  XML_SetStartElementHandler(g_parser, dummy_start_element);
6698  XML_SetUserData(g_parser, NULL);
6699  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6700      == XML_STATUS_ERROR)
6701    xml_failure(g_parser);
6702}
6703END_TEST
6704
6705/* Regression test #1 for SF bug #673791. */
6706START_TEST(test_ns_prefix_with_empty_uri_1) {
6707  const char *text = "<doc xmlns:prefix='http://example.org/'>\n"
6708                     "  <e xmlns:prefix=''/>\n"
6709                     "</doc>";
6710
6711  expect_failure(text, XML_ERROR_UNDECLARING_PREFIX,
6712                 "Did not report re-setting namespace"
6713                 " URI with prefix to ''.");
6714}
6715END_TEST
6716
6717/* Regression test #2 for SF bug #673791. */
6718START_TEST(test_ns_prefix_with_empty_uri_2) {
6719  const char *text = "<?xml version='1.0'?>\n"
6720                     "<docelem xmlns:pre=''/>";
6721
6722  expect_failure(text, XML_ERROR_UNDECLARING_PREFIX,
6723                 "Did not report setting namespace URI with prefix to ''.");
6724}
6725END_TEST
6726
6727/* Regression test #3 for SF bug #673791. */
6728START_TEST(test_ns_prefix_with_empty_uri_3) {
6729  const char *text = "<!DOCTYPE doc [\n"
6730                     "  <!ELEMENT doc EMPTY>\n"
6731                     "  <!ATTLIST doc\n"
6732                     "    xmlns:prefix CDATA ''>\n"
6733                     "]>\n"
6734                     "<doc/>";
6735
6736  expect_failure(text, XML_ERROR_UNDECLARING_PREFIX,
6737                 "Didn't report attr default setting NS w/ prefix to ''.");
6738}
6739END_TEST
6740
6741/* Regression test #4 for SF bug #673791. */
6742START_TEST(test_ns_prefix_with_empty_uri_4) {
6743  const char *text = "<!DOCTYPE doc [\n"
6744                     "  <!ELEMENT prefix:doc EMPTY>\n"
6745                     "  <!ATTLIST prefix:doc\n"
6746                     "    xmlns:prefix CDATA 'http://example.org/'>\n"
6747                     "]>\n"
6748                     "<prefix:doc/>";
6749  /* Packaged info expected by the end element handler;
6750     the weird structuring lets us re-use the triplet_end_checker()
6751     function also used for another test. */
6752  const XML_Char *elemstr[] = {XCS("http://example.org/ doc prefix")};
6753  XML_SetReturnNSTriplet(g_parser, XML_TRUE);
6754  XML_SetUserData(g_parser, (void *)elemstr);
6755  XML_SetEndElementHandler(g_parser, triplet_end_checker);
6756  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6757      == XML_STATUS_ERROR)
6758    xml_failure(g_parser);
6759}
6760END_TEST
6761
6762/* Test with non-xmlns prefix */
6763START_TEST(test_ns_unbound_prefix) {
6764  const char *text = "<!DOCTYPE doc [\n"
6765                     "  <!ELEMENT prefix:doc EMPTY>\n"
6766                     "  <!ATTLIST prefix:doc\n"
6767                     "    notxmlns:prefix CDATA 'http://example.org/'>\n"
6768                     "]>\n"
6769                     "<prefix:doc/>";
6770
6771  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6772      != XML_STATUS_ERROR)
6773    fail("Unbound prefix incorrectly passed");
6774  if (XML_GetErrorCode(g_parser) != XML_ERROR_UNBOUND_PREFIX)
6775    xml_failure(g_parser);
6776}
6777END_TEST
6778
6779START_TEST(test_ns_default_with_empty_uri) {
6780  const char *text = "<doc xmlns='http://example.org/'>\n"
6781                     "  <e xmlns=''/>\n"
6782                     "</doc>";
6783  /* Add some handlers to exercise extra code paths */
6784  XML_SetStartNamespaceDeclHandler(g_parser,
6785                                   dummy_start_namespace_decl_handler);
6786  XML_SetEndNamespaceDeclHandler(g_parser, dummy_end_namespace_decl_handler);
6787  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6788      == XML_STATUS_ERROR)
6789    xml_failure(g_parser);
6790}
6791END_TEST
6792
6793/* Regression test for SF bug #692964: two prefixes for one namespace. */
6794START_TEST(test_ns_duplicate_attrs_diff_prefixes) {
6795  const char *text = "<doc xmlns:a='http://example.org/a'\n"
6796                     "     xmlns:b='http://example.org/a'\n"
6797                     "     a:a='v' b:a='v' />";
6798  expect_failure(text, XML_ERROR_DUPLICATE_ATTRIBUTE,
6799                 "did not report multiple attributes with same URI+name");
6800}
6801END_TEST
6802
6803START_TEST(test_ns_duplicate_hashes) {
6804  /* The hash of an attribute is calculated as the hash of its URI
6805   * concatenated with a space followed by its name (after the
6806   * colon).  We wish to generate attributes with the same hash
6807   * value modulo the attribute table size so that we can check that
6808   * the attribute hash table works correctly.  The attribute hash
6809   * table size will be the smallest power of two greater than the
6810   * number of attributes, but at least eight.  There is
6811   * unfortunately no programmatic way of getting the hash or the
6812   * table size at user level, but the test code coverage percentage
6813   * will drop if the hashes cease to point to the same row.
6814   *
6815   * The cunning plan is to have few enough attributes to have a
6816   * reliable table size of 8, and have the single letter attribute
6817   * names be 8 characters apart, producing a hash which will be the
6818   * same modulo 8.
6819   */
6820  const char *text = "<doc xmlns:a='http://example.org/a'\n"
6821                     "     a:a='v' a:i='w' />";
6822  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6823      == XML_STATUS_ERROR)
6824    xml_failure(g_parser);
6825}
6826END_TEST
6827
6828/* Regression test for SF bug #695401: unbound prefix. */
6829START_TEST(test_ns_unbound_prefix_on_attribute) {
6830  const char *text = "<doc a:attr=''/>";
6831  expect_failure(text, XML_ERROR_UNBOUND_PREFIX,
6832                 "did not report unbound prefix on attribute");
6833}
6834END_TEST
6835
6836/* Regression test for SF bug #695401: unbound prefix. */
6837START_TEST(test_ns_unbound_prefix_on_element) {
6838  const char *text = "<a:doc/>";
6839  expect_failure(text, XML_ERROR_UNBOUND_PREFIX,
6840                 "did not report unbound prefix on element");
6841}
6842END_TEST
6843
6844/* Test that the parsing status is correctly reset by XML_ParserReset().
6845 * We usE test_return_ns_triplet() for our example parse to improve
6846 * coverage of tidying up code executed.
6847 */
6848START_TEST(test_ns_parser_reset) {
6849  XML_ParsingStatus status;
6850
6851  XML_GetParsingStatus(g_parser, &status);
6852  if (status.parsing != XML_INITIALIZED)
6853    fail("parsing status doesn't start INITIALIZED");
6854  test_return_ns_triplet();
6855  XML_GetParsingStatus(g_parser, &status);
6856  if (status.parsing != XML_FINISHED)
6857    fail("parsing status doesn't end FINISHED");
6858  XML_ParserReset(g_parser, NULL);
6859  XML_GetParsingStatus(g_parser, &status);
6860  if (status.parsing != XML_INITIALIZED)
6861    fail("parsing status doesn't reset to INITIALIZED");
6862}
6863END_TEST
6864
6865/* Test that long element names with namespaces are handled correctly */
6866START_TEST(test_ns_long_element) {
6867  const char *text
6868      = "<foo:thisisalongenoughelementnametotriggerareallocation\n"
6869        " xmlns:foo='http://example.org/' bar:a='12'\n"
6870        " xmlns:bar='http://example.org/'>"
6871        "</foo:thisisalongenoughelementnametotriggerareallocation>";
6872  const XML_Char *elemstr[]
6873      = {XCS("http://example.org/")
6874             XCS(" thisisalongenoughelementnametotriggerareallocation foo"),
6875         XCS("http://example.org/ a bar")};
6876
6877  XML_SetReturnNSTriplet(g_parser, XML_TRUE);
6878  XML_SetUserData(g_parser, (void *)elemstr);
6879  XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
6880  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6881      == XML_STATUS_ERROR)
6882    xml_failure(g_parser);
6883}
6884END_TEST
6885
6886/* Test mixed population of prefixed and unprefixed attributes */
6887START_TEST(test_ns_mixed_prefix_atts) {
6888  const char *text = "<e a='12' bar:b='13'\n"
6889                     " xmlns:bar='http://example.org/'>"
6890                     "</e>";
6891
6892  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6893      == XML_STATUS_ERROR)
6894    xml_failure(g_parser);
6895}
6896END_TEST
6897
6898/* Test having a long namespaced element name inside a short one.
6899 * This exercises some internal buffer reallocation that is shared
6900 * across elements with the same namespace URI.
6901 */
6902START_TEST(test_ns_extend_uri_buffer) {
6903  const char *text = "<foo:e xmlns:foo='http://example.org/'>"
6904                     " <foo:thisisalongenoughnametotriggerallocationaction"
6905                     "   foo:a='12' />"
6906                     "</foo:e>";
6907  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
6908      == XML_STATUS_ERROR)
6909    xml_failure(g_parser);
6910}
6911END_TEST
6912
6913/* Test that xmlns is correctly rejected as an attribute in the xmlns
6914 * namespace, but not in other namespaces
6915 */
6916START_TEST(test_ns_reserved_attributes) {
6917  const char *text1
6918      = "<foo:e xmlns:foo='http://example.org/' xmlns:xmlns='12' />";
6919  const char *text2
6920      = "<foo:e xmlns:foo='http://example.org/' foo:xmlns='12' />";
6921  expect_failure(text1, XML_ERROR_RESERVED_PREFIX_XMLNS,
6922                 "xmlns not rejected as an attribute");
6923  XML_ParserReset(g_parser, NULL);
6924  if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
6925      == XML_STATUS_ERROR)
6926    xml_failure(g_parser);
6927}
6928END_TEST
6929
6930/* Test more reserved attributes */
6931START_TEST(test_ns_reserved_attributes_2) {
6932  const char *text1 = "<foo:e xmlns:foo='http://example.org/'"
6933                      "  xmlns:xml='http://example.org/' />";
6934  const char *text2
6935      = "<foo:e xmlns:foo='http://www.w3.org/XML/1998/namespace' />";
6936  const char *text3 = "<foo:e xmlns:foo='http://www.w3.org/2000/xmlns/' />";
6937
6938  expect_failure(text1, XML_ERROR_RESERVED_PREFIX_XML,
6939                 "xml not rejected as an attribute");
6940  XML_ParserReset(g_parser, NULL);
6941  expect_failure(text2, XML_ERROR_RESERVED_NAMESPACE_URI,
6942                 "Use of w3.org URL not faulted");
6943  XML_ParserReset(g_parser, NULL);
6944  expect_failure(text3, XML_ERROR_RESERVED_NAMESPACE_URI,
6945                 "Use of w3.org xmlns URL not faulted");
6946}
6947END_TEST
6948
6949/* Test string pool handling of namespace names of 2048 characters */
6950/* Exercises a particular string pool growth path */
6951START_TEST(test_ns_extremely_long_prefix) {
6952  /* C99 compilers are only required to support 4095-character
6953   * strings, so the following needs to be split in two to be safe
6954   * for all compilers.
6955   */
6956  const char *text1
6957      = "<doc "
6958        /* 64 character on each line */
6959        /* ...gives a total length of 2048 */
6960        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
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        ":a='12'";
6993  const char *text2
6994      = " xmlns:"
6995        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
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        "='foo'\n>"
7028        "</doc>";
7029
7030  if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
7031      == XML_STATUS_ERROR)
7032    xml_failure(g_parser);
7033  if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
7034      == XML_STATUS_ERROR)
7035    xml_failure(g_parser);
7036}
7037END_TEST
7038
7039/* Test unknown encoding handlers in namespace setup */
7040START_TEST(test_ns_unknown_encoding_success) {
7041  const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
7042                     "<foo:e xmlns:foo='http://example.org/'>Hi</foo:e>";
7043
7044  XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
7045  run_character_check(text, XCS("Hi"));
7046}
7047END_TEST
7048
7049/* Test that too many colons are rejected */
7050START_TEST(test_ns_double_colon) {
7051  const char *text = "<foo:e xmlns:foo='http://example.org/' foo:a:b='bar' />";
7052
7053  expect_failure(text, XML_ERROR_INVALID_TOKEN,
7054                 "Double colon in attribute name not faulted");
7055}
7056END_TEST
7057
7058START_TEST(test_ns_double_colon_element) {
7059  const char *text = "<foo:bar:e xmlns:foo='http://example.org/' />";
7060
7061  expect_failure(text, XML_ERROR_INVALID_TOKEN,
7062                 "Double colon in element name not faulted");
7063}
7064END_TEST
7065
7066/* Test that non-name characters after a colon are rejected */
7067START_TEST(test_ns_bad_attr_leafname) {
7068  const char *text = "<foo:e xmlns:foo='http://example.org/' foo:?ar='baz' />";
7069
7070  expect_failure(text, XML_ERROR_INVALID_TOKEN,
7071                 "Invalid character in leafname not faulted");
7072}
7073END_TEST
7074
7075START_TEST(test_ns_bad_element_leafname) {
7076  const char *text = "<foo:?oc xmlns:foo='http://example.org/' />";
7077
7078  expect_failure(text, XML_ERROR_INVALID_TOKEN,
7079                 "Invalid character in element leafname not faulted");
7080}
7081END_TEST
7082
7083/* Test high-byte-set UTF-16 characters are valid in a leafname */
7084START_TEST(test_ns_utf16_leafname) {
7085  const char text[] =
7086      /* <n:e xmlns:n='URI' n:{KHO KHWAI}='a' />
7087       * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
7088       */
7089      "<\0n\0:\0e\0 \0x\0m\0l\0n\0s\0:\0n\0=\0'\0U\0R\0I\0'\0 \0"
7090      "n\0:\0\x04\x0e=\0'\0a\0'\0 \0/\0>\0";
7091  const XML_Char *expected = XCS("a");
7092  CharData storage;
7093
7094  CharData_Init(&storage);
7095  XML_SetStartElementHandler(g_parser, accumulate_attribute);
7096  XML_SetUserData(g_parser, &storage);
7097  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
7098      == XML_STATUS_ERROR)
7099    xml_failure(g_parser);
7100  CharData_CheckXMLChars(&storage, expected);
7101}
7102END_TEST
7103
7104START_TEST(test_ns_utf16_element_leafname) {
7105  const char text[] =
7106      /* <n:{KHO KHWAI} xmlns:n='URI'/>
7107       * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
7108       */
7109      "\0<\0n\0:\x0e\x04\0 \0x\0m\0l\0n\0s\0:\0n\0=\0'\0U\0R\0I\0'\0/\0>";
7110#ifdef XML_UNICODE
7111  const XML_Char *expected = XCS("URI \x0e04");
7112#else
7113  const XML_Char *expected = XCS("URI \xe0\xb8\x84");
7114#endif
7115  CharData storage;
7116
7117  CharData_Init(&storage);
7118  XML_SetStartElementHandler(g_parser, start_element_event_handler);
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}
7125END_TEST
7126
7127START_TEST(test_ns_utf16_doctype) {
7128  const char text[] =
7129      /* <!DOCTYPE foo:{KHO KHWAI} [ <!ENTITY bar 'baz'> ]>\n
7130       * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
7131       */
7132      "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0f\0o\0o\0:\x0e\x04\0 "
7133      "\0[\0 \0<\0!\0E\0N\0T\0I\0T\0Y\0 \0b\0a\0r\0 \0'\0b\0a\0z\0'\0>\0 "
7134      "\0]\0>\0\n"
7135      /* <foo:{KHO KHWAI} xmlns:foo='URI'>&bar;</foo:{KHO KHWAI}> */
7136      "\0<\0f\0o\0o\0:\x0e\x04\0 "
7137      "\0x\0m\0l\0n\0s\0:\0f\0o\0o\0=\0'\0U\0R\0I\0'\0>"
7138      "\0&\0b\0a\0r\0;"
7139      "\0<\0/\0f\0o\0o\0:\x0e\x04\0>";
7140#ifdef XML_UNICODE
7141  const XML_Char *expected = XCS("URI \x0e04");
7142#else
7143  const XML_Char *expected = XCS("URI \xe0\xb8\x84");
7144#endif
7145  CharData storage;
7146
7147  CharData_Init(&storage);
7148  XML_SetUserData(g_parser, &storage);
7149  XML_SetStartElementHandler(g_parser, start_element_event_handler);
7150  XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
7151  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
7152      == XML_STATUS_ERROR)
7153    xml_failure(g_parser);
7154  CharData_CheckXMLChars(&storage, expected);
7155}
7156END_TEST
7157
7158START_TEST(test_ns_invalid_doctype) {
7159  const char *text = "<!DOCTYPE foo:!bad [ <!ENTITY bar 'baz' ]>\n"
7160                     "<foo:!bad>&bar;</foo:!bad>";
7161
7162  expect_failure(text, XML_ERROR_INVALID_TOKEN,
7163                 "Invalid character in document local name not faulted");
7164}
7165END_TEST
7166
7167START_TEST(test_ns_double_colon_doctype) {
7168  const char *text = "<!DOCTYPE foo:a:doc [ <!ENTITY bar 'baz' ]>\n"
7169                     "<foo:a:doc>&bar;</foo:a:doc>";
7170
7171  expect_failure(text, XML_ERROR_SYNTAX,
7172                 "Double colon in document name not faulted");
7173}
7174END_TEST
7175
7176/* Control variable; the number of times duff_allocator() will successfully
7177 * allocate */
7178#define ALLOC_ALWAYS_SUCCEED (-1)
7179#define REALLOC_ALWAYS_SUCCEED (-1)
7180
7181static intptr_t allocation_count = ALLOC_ALWAYS_SUCCEED;
7182static intptr_t reallocation_count = REALLOC_ALWAYS_SUCCEED;
7183
7184/* Crocked allocator for allocation failure tests */
7185static void *
7186duff_allocator(size_t size) {
7187  if (allocation_count == 0)
7188    return NULL;
7189  if (allocation_count != ALLOC_ALWAYS_SUCCEED)
7190    allocation_count--;
7191  return malloc(size);
7192}
7193
7194/* Crocked reallocator for allocation failure tests */
7195static void *
7196duff_reallocator(void *ptr, size_t size) {
7197  if (reallocation_count == 0)
7198    return NULL;
7199  if (reallocation_count != REALLOC_ALWAYS_SUCCEED)
7200    reallocation_count--;
7201  return realloc(ptr, size);
7202}
7203
7204/* Test that a failure to allocate the parser structure fails gracefully */
7205START_TEST(test_misc_alloc_create_parser) {
7206  XML_Memory_Handling_Suite memsuite = {duff_allocator, realloc, free};
7207  unsigned int i;
7208  const unsigned int max_alloc_count = 10;
7209
7210  /* Something this simple shouldn't need more than 10 allocations */
7211  for (i = 0; i < max_alloc_count; i++) {
7212    allocation_count = i;
7213    g_parser = XML_ParserCreate_MM(NULL, &memsuite, NULL);
7214    if (g_parser != NULL)
7215      break;
7216  }
7217  if (i == 0)
7218    fail("Parser unexpectedly ignored failing allocator");
7219  else if (i == max_alloc_count)
7220    fail("Parser not created with max allocation count");
7221}
7222END_TEST
7223
7224/* Test memory allocation failures for a parser with an encoding */
7225START_TEST(test_misc_alloc_create_parser_with_encoding) {
7226  XML_Memory_Handling_Suite memsuite = {duff_allocator, realloc, free};
7227  unsigned int i;
7228  const unsigned int max_alloc_count = 10;
7229
7230  /* Try several levels of allocation */
7231  for (i = 0; i < max_alloc_count; i++) {
7232    allocation_count = i;
7233    g_parser = XML_ParserCreate_MM(XCS("us-ascii"), &memsuite, NULL);
7234    if (g_parser != NULL)
7235      break;
7236  }
7237  if (i == 0)
7238    fail("Parser ignored failing allocator");
7239  else if (i == max_alloc_count)
7240    fail("Parser not created with max allocation count");
7241}
7242END_TEST
7243
7244/* Test that freeing a NULL parser doesn't cause an explosion.
7245 * (Not actually tested anywhere else)
7246 */
7247START_TEST(test_misc_null_parser) {
7248  XML_ParserFree(NULL);
7249}
7250END_TEST
7251
7252/* Test that XML_ErrorString rejects out-of-range codes */
7253START_TEST(test_misc_error_string) {
7254  if (XML_ErrorString((enum XML_Error) - 1) != NULL)
7255    fail("Negative error code not rejected");
7256  if (XML_ErrorString((enum XML_Error)100) != NULL)
7257    fail("Large error code not rejected");
7258}
7259END_TEST
7260
7261/* Test the version information is consistent */
7262
7263/* Since we are working in XML_LChars (potentially 16-bits), we
7264 * can't use the standard C library functions for character
7265 * manipulation and have to roll our own.
7266 */
7267static int
7268parse_version(const XML_LChar *version_text,
7269              XML_Expat_Version *version_struct) {
7270  if (! version_text)
7271    return XML_FALSE;
7272
7273  while (*version_text != 0x00) {
7274    if (*version_text >= ASCII_0 && *version_text <= ASCII_9)
7275      break;
7276    version_text++;
7277  }
7278  if (*version_text == 0x00)
7279    return XML_FALSE;
7280
7281  /* version_struct->major = strtoul(version_text, 10, &version_text) */
7282  version_struct->major = 0;
7283  while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
7284    version_struct->major
7285        = 10 * version_struct->major + (*version_text++ - ASCII_0);
7286  }
7287  if (*version_text++ != ASCII_PERIOD)
7288    return XML_FALSE;
7289
7290  /* Now for the minor version number */
7291  version_struct->minor = 0;
7292  while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
7293    version_struct->minor
7294        = 10 * version_struct->minor + (*version_text++ - ASCII_0);
7295  }
7296  if (*version_text++ != ASCII_PERIOD)
7297    return XML_FALSE;
7298
7299  /* Finally the micro version number */
7300  version_struct->micro = 0;
7301  while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
7302    version_struct->micro
7303        = 10 * version_struct->micro + (*version_text++ - ASCII_0);
7304  }
7305  if (*version_text != 0x00)
7306    return XML_FALSE;
7307  return XML_TRUE;
7308}
7309
7310static int
7311versions_equal(const XML_Expat_Version *first,
7312               const XML_Expat_Version *second) {
7313  return (first->major == second->major && first->minor == second->minor
7314          && first->micro == second->micro);
7315}
7316
7317START_TEST(test_misc_version) {
7318  XML_Expat_Version read_version = XML_ExpatVersionInfo();
7319  /* Silence compiler warning with the following assignment */
7320  XML_Expat_Version parsed_version = {0, 0, 0};
7321  const XML_LChar *version_text = XML_ExpatVersion();
7322
7323  if (version_text == NULL)
7324    fail("Could not obtain version text");
7325  assert(version_text != NULL);
7326  if (! parse_version(version_text, &parsed_version))
7327    fail("Unable to parse version text");
7328  if (! versions_equal(&read_version, &parsed_version))
7329    fail("Version mismatch");
7330
7331#if ! defined(XML_UNICODE) || defined(XML_UNICODE_WCHAR_T)
7332  if (xcstrcmp(version_text, XCS("expat_2.2.9"))) /* needs bump on releases */
7333    fail("XML_*_VERSION in expat.h out of sync?\n");
7334#else
7335  /* If we have XML_UNICODE defined but not XML_UNICODE_WCHAR_T
7336   * then XML_LChar is defined as char, for some reason.
7337   */
7338  if (strcmp(version_text, "expat_2.2.5")) /* needs bump on releases */
7339    fail("XML_*_VERSION in expat.h out of sync?\n");
7340#endif /* ! defined(XML_UNICODE) || defined(XML_UNICODE_WCHAR_T) */
7341}
7342END_TEST
7343
7344/* Test feature information */
7345START_TEST(test_misc_features) {
7346  const XML_Feature *features = XML_GetFeatureList();
7347
7348  /* Prevent problems with double-freeing parsers */
7349  g_parser = NULL;
7350  if (features == NULL) {
7351    fail("Failed to get feature information");
7352  } else {
7353    /* Loop through the features checking what we can */
7354    while (features->feature != XML_FEATURE_END) {
7355      switch (features->feature) {
7356      case XML_FEATURE_SIZEOF_XML_CHAR:
7357        if (features->value != sizeof(XML_Char))
7358          fail("Incorrect size of XML_Char");
7359        break;
7360      case XML_FEATURE_SIZEOF_XML_LCHAR:
7361        if (features->value != sizeof(XML_LChar))
7362          fail("Incorrect size of XML_LChar");
7363        break;
7364      default:
7365        break;
7366      }
7367      features++;
7368    }
7369  }
7370}
7371END_TEST
7372
7373/* Regression test for GitHub Issue #17: memory leak parsing attribute
7374 * values with mixed bound and unbound namespaces.
7375 */
7376START_TEST(test_misc_attribute_leak) {
7377  const char *text = "<D xmlns:L=\"D\" l:a='' L:a=''/>";
7378  XML_Memory_Handling_Suite memsuite
7379      = {tracking_malloc, tracking_realloc, tracking_free};
7380
7381  g_parser = XML_ParserCreate_MM(XCS("UTF-8"), &memsuite, XCS("\n"));
7382  expect_failure(text, XML_ERROR_UNBOUND_PREFIX, "Unbound prefixes not found");
7383  XML_ParserFree(g_parser);
7384  /* Prevent the teardown trying to double free */
7385  g_parser = NULL;
7386
7387  if (! tracking_report())
7388    fail("Memory leak found");
7389}
7390END_TEST
7391
7392/* Test parser created for UTF-16LE is successful */
7393START_TEST(test_misc_utf16le) {
7394  const char text[] =
7395      /* <?xml version='1.0'?><q>Hi</q> */
7396      "<\0?\0x\0m\0l\0 \0"
7397      "v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0?\0>\0"
7398      "<\0q\0>\0H\0i\0<\0/\0q\0>\0";
7399  const XML_Char *expected = XCS("Hi");
7400  CharData storage;
7401
7402  g_parser = XML_ParserCreate(XCS("UTF-16LE"));
7403  if (g_parser == NULL)
7404    fail("Parser not created");
7405
7406  CharData_Init(&storage);
7407  XML_SetUserData(g_parser, &storage);
7408  XML_SetCharacterDataHandler(g_parser, accumulate_characters);
7409  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
7410      == XML_STATUS_ERROR)
7411    xml_failure(g_parser);
7412  CharData_CheckXMLChars(&storage, expected);
7413}
7414END_TEST
7415
7416typedef struct {
7417  XML_Parser parser;
7418  int deep;
7419} DataIssue240;
7420
7421static void
7422start_element_issue_240(void *userData, const XML_Char *name,
7423                        const XML_Char **atts) {
7424  DataIssue240 *mydata = (DataIssue240 *)userData;
7425  UNUSED_P(name);
7426  UNUSED_P(atts);
7427  mydata->deep++;
7428}
7429
7430static void
7431end_element_issue_240(void *userData, const XML_Char *name) {
7432  DataIssue240 *mydata = (DataIssue240 *)userData;
7433
7434  UNUSED_P(name);
7435  mydata->deep--;
7436  if (mydata->deep == 0) {
7437    XML_StopParser(mydata->parser, 0);
7438  }
7439}
7440
7441START_TEST(test_misc_stop_during_end_handler_issue_240_1) {
7442  XML_Parser parser;
7443  DataIssue240 *mydata;
7444  enum XML_Status result;
7445  const char *const doc1 = "<doc><e1/><e><foo/></e></doc>";
7446
7447  parser = XML_ParserCreate(NULL);
7448  XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240);
7449  mydata = (DataIssue240 *)malloc(sizeof(DataIssue240));
7450  mydata->parser = parser;
7451  mydata->deep = 0;
7452  XML_SetUserData(parser, mydata);
7453
7454  result = XML_Parse(parser, doc1, (int)strlen(doc1), 1);
7455  XML_ParserFree(parser);
7456  free(mydata);
7457  if (result != XML_STATUS_ERROR)
7458    fail("Stopping the parser did not work as expected");
7459}
7460END_TEST
7461
7462START_TEST(test_misc_stop_during_end_handler_issue_240_2) {
7463  XML_Parser parser;
7464  DataIssue240 *mydata;
7465  enum XML_Status result;
7466  const char *const doc2 = "<doc><elem/></doc>";
7467
7468  parser = XML_ParserCreate(NULL);
7469  XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240);
7470  mydata = (DataIssue240 *)malloc(sizeof(DataIssue240));
7471  mydata->parser = parser;
7472  mydata->deep = 0;
7473  XML_SetUserData(parser, mydata);
7474
7475  result = XML_Parse(parser, doc2, (int)strlen(doc2), 1);
7476  XML_ParserFree(parser);
7477  free(mydata);
7478  if (result != XML_STATUS_ERROR)
7479    fail("Stopping the parser did not work as expected");
7480}
7481END_TEST
7482
7483#ifdef XML_DTD
7484START_TEST(test_misc_deny_internal_entity_closing_doctype_issue_317) {
7485  const char *const inputOne = "<!DOCTYPE d [\n"
7486                               "<!ENTITY % e ']><d/>'>\n"
7487                               "\n"
7488                               "%e;";
7489  const char *const inputTwo = "<!DOCTYPE d [\n"
7490                               "<!ENTITY % e1 ']><d/>'><!ENTITY % e2 '&e1;'>\n"
7491                               "\n"
7492                               "%e2;";
7493  const char *const inputThree = "<!DOCTYPE d [\n"
7494                                 "<!ENTITY % e ']><d'>\n"
7495                                 "\n"
7496                                 "%e;";
7497  const char *const inputIssue317 = "<!DOCTYPE doc [\n"
7498                                    "<!ENTITY % foo ']>\n"
7499                                    "<doc>Hell<oc (#PCDATA)*>'>\n"
7500                                    "%foo;\n"
7501                                    "]>\n"
7502                                    "<doc>Hello, world</dVc>";
7503
7504  const char *const inputs[] = {inputOne, inputTwo, inputThree, inputIssue317};
7505  size_t inputIndex = 0;
7506
7507  for (; inputIndex < sizeof(inputs) / sizeof(inputs[0]); inputIndex++) {
7508    XML_Parser parser;
7509    enum XML_Status parseResult;
7510    int setParamEntityResult;
7511    XML_Size lineNumber;
7512    XML_Size columnNumber;
7513    const char *const input = inputs[inputIndex];
7514
7515    parser = XML_ParserCreate(NULL);
7516    setParamEntityResult
7517        = XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
7518    if (setParamEntityResult != 1)
7519      fail("Failed to set XML_PARAM_ENTITY_PARSING_ALWAYS.");
7520
7521    parseResult = XML_Parse(parser, input, (int)strlen(input), 0);
7522    if (parseResult != XML_STATUS_ERROR) {
7523      parseResult = XML_Parse(parser, "", 0, 1);
7524      if (parseResult != XML_STATUS_ERROR) {
7525        fail("Parsing was expected to fail but succeeded.");
7526      }
7527    }
7528
7529    if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
7530      fail("Error code does not match XML_ERROR_INVALID_TOKEN");
7531
7532    lineNumber = XML_GetCurrentLineNumber(parser);
7533    if (lineNumber != 4)
7534      fail("XML_GetCurrentLineNumber does not work as expected.");
7535
7536    columnNumber = XML_GetCurrentColumnNumber(parser);
7537    if (columnNumber != 0)
7538      fail("XML_GetCurrentColumnNumber does not work as expected.");
7539
7540    XML_ParserFree(parser);
7541  }
7542}
7543END_TEST
7544#endif
7545
7546static void
7547alloc_setup(void) {
7548  XML_Memory_Handling_Suite memsuite = {duff_allocator, duff_reallocator, free};
7549
7550  /* Ensure the parser creation will go through */
7551  allocation_count = ALLOC_ALWAYS_SUCCEED;
7552  reallocation_count = REALLOC_ALWAYS_SUCCEED;
7553  g_parser = XML_ParserCreate_MM(NULL, &memsuite, NULL);
7554  if (g_parser == NULL)
7555    fail("Parser not created");
7556}
7557
7558static void
7559alloc_teardown(void) {
7560  basic_teardown();
7561}
7562
7563/* Test the effects of allocation failures on xml declaration processing */
7564START_TEST(test_alloc_parse_xdecl) {
7565  const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
7566                     "<doc>Hello, world</doc>";
7567  int i;
7568  const int max_alloc_count = 15;
7569
7570  for (i = 0; i < max_alloc_count; i++) {
7571    allocation_count = i;
7572    XML_SetXmlDeclHandler(g_parser, dummy_xdecl_handler);
7573    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7574        != XML_STATUS_ERROR)
7575      break;
7576    /* Resetting the parser is insufficient, because some memory
7577     * allocations are cached within the parser.  Instead we use
7578     * the teardown and setup routines to ensure that we have the
7579     * right sort of parser back in our hands.
7580     */
7581    alloc_teardown();
7582    alloc_setup();
7583  }
7584  if (i == 0)
7585    fail("Parse succeeded despite failing allocator");
7586  if (i == max_alloc_count)
7587    fail("Parse failed with max allocations");
7588}
7589END_TEST
7590
7591/* As above, but with an encoding big enough to cause storing the
7592 * version information to expand the string pool being used.
7593 */
7594static int XMLCALL
7595long_encoding_handler(void *userData, const XML_Char *encoding,
7596                      XML_Encoding *info) {
7597  int i;
7598
7599  UNUSED_P(userData);
7600  UNUSED_P(encoding);
7601  for (i = 0; i < 256; i++)
7602    info->map[i] = i;
7603  info->data = NULL;
7604  info->convert = NULL;
7605  info->release = NULL;
7606  return XML_STATUS_OK;
7607}
7608
7609START_TEST(test_alloc_parse_xdecl_2) {
7610  const char *text
7611      = "<?xml version='1.0' encoding='"
7612        /* Each line is 64 characters */
7613        "ThisIsAStupidlyLongEncodingNameIntendedToTriggerPoolGrowth123456"
7614        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7615        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7616        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7617        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7618        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7619        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7620        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7621        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7622        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7623        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7624        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7625        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7626        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7627        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7628        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMN"
7629        "'?>"
7630        "<doc>Hello, world</doc>";
7631  int i;
7632  const int max_alloc_count = 20;
7633
7634  for (i = 0; i < max_alloc_count; i++) {
7635    allocation_count = i;
7636    XML_SetXmlDeclHandler(g_parser, dummy_xdecl_handler);
7637    XML_SetUnknownEncodingHandler(g_parser, long_encoding_handler, NULL);
7638    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7639        != XML_STATUS_ERROR)
7640      break;
7641    /* See comment in test_alloc_parse_xdecl() */
7642    alloc_teardown();
7643    alloc_setup();
7644  }
7645  if (i == 0)
7646    fail("Parse succeeded despite failing allocator");
7647  if (i == max_alloc_count)
7648    fail("Parse failed with max allocations");
7649}
7650END_TEST
7651
7652/* Test the effects of allocation failures on a straightforward parse */
7653START_TEST(test_alloc_parse_pi) {
7654  const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
7655                     "<?pi unknown?>\n"
7656                     "<doc>"
7657                     "Hello, world"
7658                     "</doc>";
7659  int i;
7660  const int max_alloc_count = 15;
7661
7662  for (i = 0; i < max_alloc_count; i++) {
7663    allocation_count = i;
7664    XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
7665    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7666        != XML_STATUS_ERROR)
7667      break;
7668    /* See comment in test_alloc_parse_xdecl() */
7669    alloc_teardown();
7670    alloc_setup();
7671  }
7672  if (i == 0)
7673    fail("Parse succeeded despite failing allocator");
7674  if (i == max_alloc_count)
7675    fail("Parse failed with max allocations");
7676}
7677END_TEST
7678
7679START_TEST(test_alloc_parse_pi_2) {
7680  const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
7681                     "<doc>"
7682                     "Hello, world"
7683                     "<?pi unknown?>\n"
7684                     "</doc>";
7685  int i;
7686  const int max_alloc_count = 15;
7687
7688  for (i = 0; i < max_alloc_count; i++) {
7689    allocation_count = i;
7690    XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
7691    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7692        != XML_STATUS_ERROR)
7693      break;
7694    /* See comment in test_alloc_parse_xdecl() */
7695    alloc_teardown();
7696    alloc_setup();
7697  }
7698  if (i == 0)
7699    fail("Parse succeeded despite failing allocator");
7700  if (i == max_alloc_count)
7701    fail("Parse failed with max allocations");
7702}
7703END_TEST
7704
7705START_TEST(test_alloc_parse_pi_3) {
7706  const char *text
7707      = "<?"
7708        /* 64 characters per line */
7709        "This processing instruction should be long enough to ensure that"
7710        "it triggers the growth of an internal string pool when the      "
7711        "allocator fails at a cruicial moment FGHIJKLMNOPABCDEFGHIJKLMNOP"
7712        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7713        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7714        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7715        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7716        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7717        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7718        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7719        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7720        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7721        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7722        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7723        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7724        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
7725        "Q?><doc/>";
7726  int i;
7727  const int max_alloc_count = 20;
7728
7729  for (i = 0; i < max_alloc_count; i++) {
7730    allocation_count = i;
7731    XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
7732    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7733        != XML_STATUS_ERROR)
7734      break;
7735    /* See comment in test_alloc_parse_xdecl() */
7736    alloc_teardown();
7737    alloc_setup();
7738  }
7739  if (i == 0)
7740    fail("Parse succeeded despite failing allocator");
7741  if (i == max_alloc_count)
7742    fail("Parse failed with max allocations");
7743}
7744END_TEST
7745
7746START_TEST(test_alloc_parse_comment) {
7747  const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
7748                     "<!-- Test parsing this comment -->"
7749                     "<doc>Hi</doc>";
7750  int i;
7751  const int max_alloc_count = 15;
7752
7753  for (i = 0; i < max_alloc_count; i++) {
7754    allocation_count = i;
7755    XML_SetCommentHandler(g_parser, dummy_comment_handler);
7756    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7757        != XML_STATUS_ERROR)
7758      break;
7759    /* See comment in test_alloc_parse_xdecl() */
7760    alloc_teardown();
7761    alloc_setup();
7762  }
7763  if (i == 0)
7764    fail("Parse succeeded despite failing allocator");
7765  if (i == max_alloc_count)
7766    fail("Parse failed with max allocations");
7767}
7768END_TEST
7769
7770START_TEST(test_alloc_parse_comment_2) {
7771  const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
7772                     "<doc>"
7773                     "Hello, world"
7774                     "<!-- Parse this comment too -->"
7775                     "</doc>";
7776  int i;
7777  const int max_alloc_count = 15;
7778
7779  for (i = 0; i < max_alloc_count; i++) {
7780    allocation_count = i;
7781    XML_SetCommentHandler(g_parser, dummy_comment_handler);
7782    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7783        != XML_STATUS_ERROR)
7784      break;
7785    /* See comment in test_alloc_parse_xdecl() */
7786    alloc_teardown();
7787    alloc_setup();
7788  }
7789  if (i == 0)
7790    fail("Parse succeeded despite failing allocator");
7791  if (i == max_alloc_count)
7792    fail("Parse failed with max allocations");
7793}
7794END_TEST
7795
7796static int XMLCALL
7797external_entity_duff_loader(XML_Parser parser, const XML_Char *context,
7798                            const XML_Char *base, const XML_Char *systemId,
7799                            const XML_Char *publicId) {
7800  XML_Parser new_parser;
7801  unsigned int i;
7802  const unsigned int max_alloc_count = 10;
7803
7804  UNUSED_P(base);
7805  UNUSED_P(systemId);
7806  UNUSED_P(publicId);
7807  /* Try a few different allocation levels */
7808  for (i = 0; i < max_alloc_count; i++) {
7809    allocation_count = i;
7810    new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
7811    if (new_parser != NULL) {
7812      XML_ParserFree(new_parser);
7813      break;
7814    }
7815  }
7816  if (i == 0)
7817    fail("External parser creation ignored failing allocator");
7818  else if (i == max_alloc_count)
7819    fail("Extern parser not created with max allocation count");
7820
7821  /* Make sure other random allocation doesn't now fail */
7822  allocation_count = ALLOC_ALWAYS_SUCCEED;
7823
7824  /* Make sure the failure code path is executed too */
7825  return XML_STATUS_ERROR;
7826}
7827
7828/* Test that external parser creation running out of memory is
7829 * correctly reported.  Based on the external entity test cases.
7830 */
7831START_TEST(test_alloc_create_external_parser) {
7832  const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
7833                     "<!DOCTYPE doc SYSTEM 'foo'>\n"
7834                     "<doc>&entity;</doc>";
7835  char foo_text[] = "<!ELEMENT doc (#PCDATA)*>";
7836
7837  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
7838  XML_SetUserData(g_parser, foo_text);
7839  XML_SetExternalEntityRefHandler(g_parser, external_entity_duff_loader);
7840  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7841      != XML_STATUS_ERROR) {
7842    fail("External parser allocator returned success incorrectly");
7843  }
7844}
7845END_TEST
7846
7847/* More external parser memory allocation testing */
7848START_TEST(test_alloc_run_external_parser) {
7849  const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
7850                     "<!DOCTYPE doc SYSTEM 'foo'>\n"
7851                     "<doc>&entity;</doc>";
7852  char foo_text[] = "<!ELEMENT doc (#PCDATA)*>";
7853  unsigned int i;
7854  const unsigned int max_alloc_count = 15;
7855
7856  for (i = 0; i < max_alloc_count; i++) {
7857    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
7858    XML_SetUserData(g_parser, foo_text);
7859    XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader);
7860    allocation_count = i;
7861    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7862        != XML_STATUS_ERROR)
7863      break;
7864    /* See comment in test_alloc_parse_xdecl() */
7865    alloc_teardown();
7866    alloc_setup();
7867  }
7868  if (i == 0)
7869    fail("Parsing ignored failing allocator");
7870  else if (i == max_alloc_count)
7871    fail("Parsing failed with allocation count 10");
7872}
7873END_TEST
7874
7875static int XMLCALL
7876external_entity_dbl_handler(XML_Parser parser, const XML_Char *context,
7877                            const XML_Char *base, const XML_Char *systemId,
7878                            const XML_Char *publicId) {
7879  intptr_t callno = (intptr_t)XML_GetUserData(parser);
7880  const char *text;
7881  XML_Parser new_parser;
7882  int i;
7883  const int max_alloc_count = 20;
7884
7885  UNUSED_P(base);
7886  UNUSED_P(systemId);
7887  UNUSED_P(publicId);
7888  if (callno == 0) {
7889    /* First time through, check how many calls to malloc occur */
7890    text = ("<!ELEMENT doc (e+)>\n"
7891            "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
7892            "<!ELEMENT e EMPTY>\n");
7893    allocation_count = 10000;
7894    new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
7895    if (new_parser == NULL) {
7896      fail("Unable to allocate first external parser");
7897      return XML_STATUS_ERROR;
7898    }
7899    /* Stash the number of calls in the user data */
7900    XML_SetUserData(parser, (void *)(intptr_t)(10000 - allocation_count));
7901  } else {
7902    text = ("<?xml version='1.0' encoding='us-ascii'?>"
7903            "<e/>");
7904    /* Try at varying levels to exercise more code paths */
7905    for (i = 0; i < max_alloc_count; i++) {
7906      allocation_count = callno + i;
7907      new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
7908      if (new_parser != NULL)
7909        break;
7910    }
7911    if (i == 0) {
7912      fail("Second external parser unexpectedly created");
7913      XML_ParserFree(new_parser);
7914      return XML_STATUS_ERROR;
7915    } else if (i == max_alloc_count) {
7916      fail("Second external parser not created");
7917      return XML_STATUS_ERROR;
7918    }
7919  }
7920
7921  allocation_count = ALLOC_ALWAYS_SUCCEED;
7922  if (_XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE)
7923      == XML_STATUS_ERROR) {
7924    xml_failure(new_parser);
7925    return XML_STATUS_ERROR;
7926  }
7927  XML_ParserFree(new_parser);
7928  return XML_STATUS_OK;
7929}
7930
7931/* Test that running out of memory in dtdCopy is correctly reported.
7932 * Based on test_default_ns_from_ext_subset_and_ext_ge()
7933 */
7934START_TEST(test_alloc_dtd_copy_default_atts) {
7935  const char *text = "<?xml version='1.0'?>\n"
7936                     "<!DOCTYPE doc SYSTEM 'http://example.org/doc.dtd' [\n"
7937                     "  <!ENTITY en SYSTEM 'http://example.org/entity.ent'>\n"
7938                     "]>\n"
7939                     "<doc xmlns='http://example.org/ns1'>\n"
7940                     "&en;\n"
7941                     "</doc>";
7942
7943  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
7944  XML_SetExternalEntityRefHandler(g_parser, external_entity_dbl_handler);
7945  XML_SetUserData(g_parser, NULL);
7946  if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
7947      == XML_STATUS_ERROR)
7948    xml_failure(g_parser);
7949}
7950END_TEST
7951
7952static int XMLCALL
7953external_entity_dbl_handler_2(XML_Parser parser, const XML_Char *context,
7954                              const XML_Char *base, const XML_Char *systemId,
7955                              const XML_Char *publicId) {
7956  intptr_t callno = (intptr_t)XML_GetUserData(parser);
7957  const char *text;
7958  XML_Parser new_parser;
7959  enum XML_Status rv;
7960
7961  UNUSED_P(base);
7962  UNUSED_P(systemId);
7963  UNUSED_P(publicId);
7964  if (callno == 0) {
7965    /* Try different allocation levels for whole exercise */
7966    text = ("<!ELEMENT doc (e+)>\n"
7967            "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
7968            "<!ELEMENT e EMPTY>\n");
7969    XML_SetUserData(parser, (void *)(intptr_t)1);
7970    new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
7971    if (new_parser == NULL)
7972      return XML_STATUS_ERROR;
7973    rv = _XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE);
7974  } else {
7975    /* Just run through once */
7976    text = ("<?xml version='1.0' encoding='us-ascii'?>"
7977            "<e/>");
7978    new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
7979    if (new_parser == NULL)
7980      return XML_STATUS_ERROR;
7981    rv = _XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE);
7982  }
7983  XML_ParserFree(new_parser);
7984  if (rv == XML_STATUS_ERROR)
7985    return XML_STATUS_ERROR;
7986  return XML_STATUS_OK;
7987}
7988
7989/* Test more external entity allocation failure paths */
7990START_TEST(test_alloc_external_entity) {
7991  const char *text = "<?xml version='1.0'?>\n"
7992                     "<!DOCTYPE doc SYSTEM 'http://example.org/doc.dtd' [\n"
7993                     "  <!ENTITY en SYSTEM 'http://example.org/entity.ent'>\n"
7994                     "]>\n"
7995                     "<doc xmlns='http://example.org/ns1'>\n"
7996                     "&en;\n"
7997                     "</doc>";
7998  int i;
7999  const int alloc_test_max_repeats = 50;
8000
8001  for (i = 0; i < alloc_test_max_repeats; i++) {
8002    allocation_count = -1;
8003    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
8004    XML_SetExternalEntityRefHandler(g_parser, external_entity_dbl_handler_2);
8005    XML_SetUserData(g_parser, NULL);
8006    allocation_count = i;
8007    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8008        == XML_STATUS_OK)
8009      break;
8010    /* See comment in test_alloc_parse_xdecl() */
8011    alloc_teardown();
8012    alloc_setup();
8013  }
8014  allocation_count = -1;
8015  if (i == 0)
8016    fail("External entity parsed despite duff allocator");
8017  if (i == alloc_test_max_repeats)
8018    fail("External entity not parsed at max allocation count");
8019}
8020END_TEST
8021
8022/* Test more allocation failure paths */
8023static int XMLCALL
8024external_entity_alloc_set_encoding(XML_Parser parser, const XML_Char *context,
8025                                   const XML_Char *base,
8026                                   const XML_Char *systemId,
8027                                   const XML_Char *publicId) {
8028  /* As for external_entity_loader() */
8029  const char *text = "<?xml encoding='iso-8859-3'?>"
8030                     "\xC3\xA9";
8031  XML_Parser ext_parser;
8032  enum XML_Status status;
8033
8034  UNUSED_P(base);
8035  UNUSED_P(systemId);
8036  UNUSED_P(publicId);
8037  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
8038  if (ext_parser == NULL)
8039    return XML_STATUS_ERROR;
8040  if (! XML_SetEncoding(ext_parser, XCS("utf-8"))) {
8041    XML_ParserFree(ext_parser);
8042    return XML_STATUS_ERROR;
8043  }
8044  status
8045      = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
8046  XML_ParserFree(ext_parser);
8047  if (status == XML_STATUS_ERROR)
8048    return XML_STATUS_ERROR;
8049  return XML_STATUS_OK;
8050}
8051
8052START_TEST(test_alloc_ext_entity_set_encoding) {
8053  const char *text = "<!DOCTYPE doc [\n"
8054                     "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
8055                     "]>\n"
8056                     "<doc>&en;</doc>";
8057  int i;
8058  const int max_allocation_count = 30;
8059
8060  for (i = 0; i < max_allocation_count; i++) {
8061    XML_SetExternalEntityRefHandler(g_parser,
8062                                    external_entity_alloc_set_encoding);
8063    allocation_count = i;
8064    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8065        == XML_STATUS_OK)
8066      break;
8067    allocation_count = -1;
8068    /* See comment in test_alloc_parse_xdecl() */
8069    alloc_teardown();
8070    alloc_setup();
8071  }
8072  if (i == 0)
8073    fail("Encoding check succeeded despite failing allocator");
8074  if (i == max_allocation_count)
8075    fail("Encoding failed at max allocation count");
8076}
8077END_TEST
8078
8079static int XMLCALL
8080unknown_released_encoding_handler(void *data, const XML_Char *encoding,
8081                                  XML_Encoding *info) {
8082  UNUSED_P(data);
8083  if (! xcstrcmp(encoding, XCS("unsupported-encoding"))) {
8084    int i;
8085
8086    for (i = 0; i < 256; i++)
8087      info->map[i] = i;
8088    info->data = NULL;
8089    info->convert = NULL;
8090    info->release = dummy_release;
8091    return XML_STATUS_OK;
8092  }
8093  return XML_STATUS_ERROR;
8094}
8095
8096/* Test the effects of allocation failure in internal entities.
8097 * Based on test_unknown_encoding_internal_entity
8098 */
8099START_TEST(test_alloc_internal_entity) {
8100  const char *text = "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
8101                     "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
8102                     "<test a='&foo;'/>";
8103  unsigned int i;
8104  const unsigned int max_alloc_count = 20;
8105
8106  for (i = 0; i < max_alloc_count; i++) {
8107    allocation_count = i;
8108    XML_SetUnknownEncodingHandler(g_parser, unknown_released_encoding_handler,
8109                                  NULL);
8110    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8111        != XML_STATUS_ERROR)
8112      break;
8113    /* See comment in test_alloc_parse_xdecl() */
8114    alloc_teardown();
8115    alloc_setup();
8116  }
8117  if (i == 0)
8118    fail("Internal entity worked despite failing allocations");
8119  else if (i == max_alloc_count)
8120    fail("Internal entity failed at max allocation count");
8121}
8122END_TEST
8123
8124/* Test the robustness against allocation failure of element handling
8125 * Based on test_dtd_default_handling().
8126 */
8127START_TEST(test_alloc_dtd_default_handling) {
8128  const char *text = "<!DOCTYPE doc [\n"
8129                     "<!ENTITY e SYSTEM 'http://example.org/e'>\n"
8130                     "<!NOTATION n SYSTEM 'http://example.org/n'>\n"
8131                     "<!ENTITY e1 SYSTEM 'http://example.org/e' NDATA n>\n"
8132                     "<!ELEMENT doc (#PCDATA)>\n"
8133                     "<!ATTLIST doc a CDATA #IMPLIED>\n"
8134                     "<?pi in dtd?>\n"
8135                     "<!--comment in dtd-->\n"
8136                     "]>\n"
8137                     "<doc><![CDATA[text in doc]]></doc>";
8138  const XML_Char *expected = XCS("\n\n\n\n\n\n\n\n\n<doc>text in doc</doc>");
8139  CharData storage;
8140  int i;
8141  const int max_alloc_count = 25;
8142
8143  for (i = 0; i < max_alloc_count; i++) {
8144    allocation_count = i;
8145    dummy_handler_flags = 0;
8146    XML_SetDefaultHandler(g_parser, accumulate_characters);
8147    XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_handler,
8148                              dummy_end_doctype_handler);
8149    XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
8150    XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
8151    XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
8152    XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
8153    XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
8154    XML_SetCommentHandler(g_parser, dummy_comment_handler);
8155    XML_SetCdataSectionHandler(g_parser, dummy_start_cdata_handler,
8156                               dummy_end_cdata_handler);
8157    XML_SetUnparsedEntityDeclHandler(g_parser,
8158                                     dummy_unparsed_entity_decl_handler);
8159    CharData_Init(&storage);
8160    XML_SetUserData(g_parser, &storage);
8161    XML_SetCharacterDataHandler(g_parser, accumulate_characters);
8162    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8163        != XML_STATUS_ERROR)
8164      break;
8165    /* See comment in test_alloc_parse_xdecl() */
8166    alloc_teardown();
8167    alloc_setup();
8168  }
8169  if (i == 0)
8170    fail("Default DTD parsed despite allocation failures");
8171  if (i == max_alloc_count)
8172    fail("Default DTD not parsed with maximum alloc count");
8173  CharData_CheckXMLChars(&storage, expected);
8174  if (dummy_handler_flags
8175      != (DUMMY_START_DOCTYPE_HANDLER_FLAG | DUMMY_END_DOCTYPE_HANDLER_FLAG
8176          | DUMMY_ENTITY_DECL_HANDLER_FLAG | DUMMY_NOTATION_DECL_HANDLER_FLAG
8177          | DUMMY_ELEMENT_DECL_HANDLER_FLAG | DUMMY_ATTLIST_DECL_HANDLER_FLAG
8178          | DUMMY_COMMENT_HANDLER_FLAG | DUMMY_PI_HANDLER_FLAG
8179          | DUMMY_START_CDATA_HANDLER_FLAG | DUMMY_END_CDATA_HANDLER_FLAG
8180          | DUMMY_UNPARSED_ENTITY_DECL_HANDLER_FLAG))
8181    fail("Not all handlers were called");
8182}
8183END_TEST
8184
8185/* Test robustness of XML_SetEncoding() with a failing allocator */
8186START_TEST(test_alloc_explicit_encoding) {
8187  int i;
8188  const int max_alloc_count = 5;
8189
8190  for (i = 0; i < max_alloc_count; i++) {
8191    allocation_count = i;
8192    if (XML_SetEncoding(g_parser, XCS("us-ascii")) == XML_STATUS_OK)
8193      break;
8194  }
8195  if (i == 0)
8196    fail("Encoding set despite failing allocator");
8197  else if (i == max_alloc_count)
8198    fail("Encoding not set at max allocation count");
8199}
8200END_TEST
8201
8202/* Test robustness of XML_SetBase against a failing allocator */
8203START_TEST(test_alloc_set_base) {
8204  const XML_Char *new_base = XCS("/local/file/name.xml");
8205  int i;
8206  const int max_alloc_count = 5;
8207
8208  for (i = 0; i < max_alloc_count; i++) {
8209    allocation_count = i;
8210    if (XML_SetBase(g_parser, new_base) == XML_STATUS_OK)
8211      break;
8212  }
8213  if (i == 0)
8214    fail("Base set despite failing allocator");
8215  else if (i == max_alloc_count)
8216    fail("Base not set with max allocation count");
8217}
8218END_TEST
8219
8220/* Test buffer extension in the face of a duff reallocator */
8221START_TEST(test_alloc_realloc_buffer) {
8222  const char *text = get_buffer_test_text;
8223  void *buffer;
8224  int i;
8225  const int max_realloc_count = 10;
8226
8227  /* Get a smallish buffer */
8228  for (i = 0; i < max_realloc_count; i++) {
8229    reallocation_count = i;
8230    buffer = XML_GetBuffer(g_parser, 1536);
8231    if (buffer == NULL)
8232      fail("1.5K buffer reallocation failed");
8233    assert(buffer != NULL);
8234    memcpy(buffer, text, strlen(text));
8235    if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_FALSE)
8236        == XML_STATUS_OK)
8237      break;
8238    /* See comment in test_alloc_parse_xdecl() */
8239    alloc_teardown();
8240    alloc_setup();
8241  }
8242  reallocation_count = -1;
8243  if (i == 0)
8244    fail("Parse succeeded with no reallocation");
8245  else if (i == max_realloc_count)
8246    fail("Parse failed with max reallocation count");
8247}
8248END_TEST
8249
8250/* Same test for external entity parsers */
8251static int XMLCALL
8252external_entity_reallocator(XML_Parser parser, const XML_Char *context,
8253                            const XML_Char *base, const XML_Char *systemId,
8254                            const XML_Char *publicId) {
8255  const char *text = get_buffer_test_text;
8256  XML_Parser ext_parser;
8257  void *buffer;
8258  enum XML_Status status;
8259
8260  UNUSED_P(base);
8261  UNUSED_P(systemId);
8262  UNUSED_P(publicId);
8263  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
8264  if (ext_parser == NULL)
8265    fail("Could not create external entity parser");
8266
8267  reallocation_count = (intptr_t)XML_GetUserData(parser);
8268  buffer = XML_GetBuffer(ext_parser, 1536);
8269  if (buffer == NULL)
8270    fail("Buffer allocation failed");
8271  assert(buffer != NULL);
8272  memcpy(buffer, text, strlen(text));
8273  status = XML_ParseBuffer(ext_parser, (int)strlen(text), XML_FALSE);
8274  reallocation_count = -1;
8275  XML_ParserFree(ext_parser);
8276  return (status == XML_STATUS_OK) ? XML_STATUS_OK : XML_STATUS_ERROR;
8277}
8278
8279START_TEST(test_alloc_ext_entity_realloc_buffer) {
8280  const char *text = "<!DOCTYPE doc [\n"
8281                     "  <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
8282                     "]>\n"
8283                     "<doc>&en;</doc>";
8284  int i;
8285  const int max_realloc_count = 10;
8286
8287  for (i = 0; i < max_realloc_count; i++) {
8288    XML_SetExternalEntityRefHandler(g_parser, external_entity_reallocator);
8289    XML_SetUserData(g_parser, (void *)(intptr_t)i);
8290    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8291        == XML_STATUS_OK)
8292      break;
8293    /* See comment in test_alloc_parse_xdecl() */
8294    alloc_teardown();
8295    alloc_setup();
8296  }
8297  if (i == 0)
8298    fail("Succeeded with no reallocations");
8299  if (i == max_realloc_count)
8300    fail("Failed with max reallocations");
8301}
8302END_TEST
8303
8304/* Test elements with many attributes are handled correctly */
8305START_TEST(test_alloc_realloc_many_attributes) {
8306  const char *text = "<!DOCTYPE doc [\n"
8307                     "<!ATTLIST doc za CDATA 'default'>\n"
8308                     "<!ATTLIST doc zb CDATA 'def2'>\n"
8309                     "<!ATTLIST doc zc CDATA 'def3'>\n"
8310                     "]>\n"
8311                     "<doc a='1'"
8312                     "     b='2'"
8313                     "     c='3'"
8314                     "     d='4'"
8315                     "     e='5'"
8316                     "     f='6'"
8317                     "     g='7'"
8318                     "     h='8'"
8319                     "     i='9'"
8320                     "     j='10'"
8321                     "     k='11'"
8322                     "     l='12'"
8323                     "     m='13'"
8324                     "     n='14'"
8325                     "     p='15'"
8326                     "     q='16'"
8327                     "     r='17'"
8328                     "     s='18'>"
8329                     "</doc>";
8330  int i;
8331  const int max_realloc_count = 10;
8332
8333  for (i = 0; i < max_realloc_count; i++) {
8334    reallocation_count = i;
8335    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8336        != XML_STATUS_ERROR)
8337      break;
8338    /* See comment in test_alloc_parse_xdecl() */
8339    alloc_teardown();
8340    alloc_setup();
8341  }
8342  if (i == 0)
8343    fail("Parse succeeded despite no reallocations");
8344  if (i == max_realloc_count)
8345    fail("Parse failed at max reallocations");
8346}
8347END_TEST
8348
8349/* Test handling of a public entity with failing allocator */
8350START_TEST(test_alloc_public_entity_value) {
8351  const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
8352                     "<doc></doc>\n";
8353  char dtd_text[]
8354      = "<!ELEMENT doc EMPTY>\n"
8355        "<!ENTITY % e1 PUBLIC 'foo' 'bar.ent'>\n"
8356        "<!ENTITY % "
8357        /* Each line is 64 characters */
8358        "ThisIsAStupidlyLongParameterNameIntendedToTriggerPoolGrowth12345"
8359        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8360        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8361        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8362        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8363        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8364        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8365        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8366        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8367        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8368        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8369        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8370        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8371        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8372        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8373        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8374        " '%e1;'>\n"
8375        "%e1;\n";
8376  int i;
8377  const int max_alloc_count = 50;
8378
8379  for (i = 0; i < max_alloc_count; i++) {
8380    allocation_count = i;
8381    dummy_handler_flags = 0;
8382    XML_SetUserData(g_parser, dtd_text);
8383    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
8384    XML_SetExternalEntityRefHandler(g_parser, external_entity_public);
8385    /* Provoke a particular code path */
8386    XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
8387    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8388        != XML_STATUS_ERROR)
8389      break;
8390    /* See comment in test_alloc_parse_xdecl() */
8391    alloc_teardown();
8392    alloc_setup();
8393  }
8394  if (i == 0)
8395    fail("Parsing worked despite failing allocation");
8396  if (i == max_alloc_count)
8397    fail("Parsing failed at max allocation count");
8398  if (dummy_handler_flags != DUMMY_ENTITY_DECL_HANDLER_FLAG)
8399    fail("Entity declaration handler not called");
8400}
8401END_TEST
8402
8403START_TEST(test_alloc_realloc_subst_public_entity_value) {
8404  const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
8405                     "<doc></doc>\n";
8406  char dtd_text[]
8407      = "<!ELEMENT doc EMPTY>\n"
8408        "<!ENTITY % "
8409        /* Each line is 64 characters */
8410        "ThisIsAStupidlyLongParameterNameIntendedToTriggerPoolGrowth12345"
8411        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8412        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8413        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8414        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8415        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8416        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8417        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8418        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8419        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8420        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8421        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8422        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8423        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8424        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8425        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8426        " PUBLIC 'foo' 'bar.ent'>\n"
8427        "%ThisIsAStupidlyLongParameterNameIntendedToTriggerPoolGrowth12345"
8428        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8429        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8430        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8431        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8432        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8433        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8434        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8435        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8436        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8437        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8438        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8439        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8440        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8441        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8442        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP;";
8443  int i;
8444  const int max_realloc_count = 10;
8445
8446  for (i = 0; i < max_realloc_count; i++) {
8447    reallocation_count = i;
8448    XML_SetUserData(g_parser, dtd_text);
8449    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
8450    XML_SetExternalEntityRefHandler(g_parser, external_entity_public);
8451    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8452        != XML_STATUS_ERROR)
8453      break;
8454    /* See comment in test_alloc_parse_xdecl() */
8455    alloc_teardown();
8456    alloc_setup();
8457  }
8458  if (i == 0)
8459    fail("Parsing worked despite failing reallocation");
8460  if (i == max_realloc_count)
8461    fail("Parsing failed at max reallocation count");
8462}
8463END_TEST
8464
8465START_TEST(test_alloc_parse_public_doctype) {
8466  const char *text
8467      = "<?xml version='1.0' encoding='utf-8'?>\n"
8468        "<!DOCTYPE doc PUBLIC '"
8469        /* 64 characters per line */
8470        "http://example.com/a/long/enough/name/to/trigger/pool/growth/zz/"
8471        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8472        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8473        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8474        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8475        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8476        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8477        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8478        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8479        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8480        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8481        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8482        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8483        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8484        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8485        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8486        "' 'test'>\n"
8487        "<doc></doc>";
8488  int i;
8489  const int max_alloc_count = 25;
8490
8491  for (i = 0; i < max_alloc_count; i++) {
8492    allocation_count = i;
8493    dummy_handler_flags = 0;
8494    XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_decl_handler,
8495                              dummy_end_doctype_decl_handler);
8496    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8497        != XML_STATUS_ERROR)
8498      break;
8499    /* See comment in test_alloc_parse_xdecl() */
8500    alloc_teardown();
8501    alloc_setup();
8502  }
8503  if (i == 0)
8504    fail("Parse succeeded despite failing allocator");
8505  if (i == max_alloc_count)
8506    fail("Parse failed at maximum allocation count");
8507  if (dummy_handler_flags
8508      != (DUMMY_START_DOCTYPE_DECL_HANDLER_FLAG
8509          | DUMMY_END_DOCTYPE_DECL_HANDLER_FLAG))
8510    fail("Doctype handler functions not called");
8511}
8512END_TEST
8513
8514START_TEST(test_alloc_parse_public_doctype_long_name) {
8515  const char *text
8516      = "<?xml version='1.0' encoding='utf-8'?>\n"
8517        "<!DOCTYPE doc PUBLIC 'http://example.com/foo' '"
8518        /* 64 characters per line */
8519        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8520        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8521        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8522        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8523        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8524        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8525        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8526        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8527        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8528        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8529        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8530        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8531        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8532        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8533        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8534        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
8535        "'>\n"
8536        "<doc></doc>";
8537  int i;
8538  const int max_alloc_count = 25;
8539
8540  for (i = 0; i < max_alloc_count; i++) {
8541    allocation_count = i;
8542    XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_decl_handler,
8543                              dummy_end_doctype_decl_handler);
8544    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8545        != XML_STATUS_ERROR)
8546      break;
8547    /* See comment in test_alloc_parse_xdecl() */
8548    alloc_teardown();
8549    alloc_setup();
8550  }
8551  if (i == 0)
8552    fail("Parse succeeded despite failing allocator");
8553  if (i == max_alloc_count)
8554    fail("Parse failed at maximum allocation count");
8555}
8556END_TEST
8557
8558static int XMLCALL
8559external_entity_alloc(XML_Parser parser, const XML_Char *context,
8560                      const XML_Char *base, const XML_Char *systemId,
8561                      const XML_Char *publicId) {
8562  const char *text = (const char *)XML_GetUserData(parser);
8563  XML_Parser ext_parser;
8564  int parse_res;
8565
8566  UNUSED_P(base);
8567  UNUSED_P(systemId);
8568  UNUSED_P(publicId);
8569  ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
8570  if (ext_parser == NULL)
8571    return XML_STATUS_ERROR;
8572  parse_res
8573      = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
8574  XML_ParserFree(ext_parser);
8575  return parse_res;
8576}
8577
8578/* Test foreign DTD handling */
8579START_TEST(test_alloc_set_foreign_dtd) {
8580  const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n"
8581                      "<doc>&entity;</doc>";
8582  char text2[] = "<!ELEMENT doc (#PCDATA)*>";
8583  int i;
8584  const int max_alloc_count = 25;
8585
8586  for (i = 0; i < max_alloc_count; i++) {
8587    allocation_count = i;
8588    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
8589    XML_SetUserData(g_parser, &text2);
8590    XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
8591    if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
8592      fail("Could not set foreign DTD");
8593    if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_TRUE)
8594        != XML_STATUS_ERROR)
8595      break;
8596    /* See comment in test_alloc_parse_xdecl() */
8597    alloc_teardown();
8598    alloc_setup();
8599  }
8600  if (i == 0)
8601    fail("Parse succeeded despite failing allocator");
8602  if (i == max_alloc_count)
8603    fail("Parse failed at maximum allocation count");
8604}
8605END_TEST
8606
8607/* Test based on ibm/valid/P32/ibm32v04.xml */
8608START_TEST(test_alloc_attribute_enum_value) {
8609  const char *text = "<?xml version='1.0' standalone='no'?>\n"
8610                     "<!DOCTYPE animal SYSTEM 'test.dtd'>\n"
8611                     "<animal>This is a \n    <a/>  \n\nyellow tiger</animal>";
8612  char dtd_text[] = "<!ELEMENT animal (#PCDATA|a)*>\n"
8613                    "<!ELEMENT a EMPTY>\n"
8614                    "<!ATTLIST animal xml:space (default|preserve) 'preserve'>";
8615  int i;
8616  const int max_alloc_count = 30;
8617
8618  for (i = 0; i < max_alloc_count; i++) {
8619    allocation_count = i;
8620    XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
8621    XML_SetUserData(g_parser, dtd_text);
8622    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
8623    /* An attribute list handler provokes a different code path */
8624    XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
8625    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8626        != XML_STATUS_ERROR)
8627      break;
8628    /* See comment in test_alloc_parse_xdecl() */
8629    alloc_teardown();
8630    alloc_setup();
8631  }
8632  if (i == 0)
8633    fail("Parse succeeded despite failing allocator");
8634  if (i == max_alloc_count)
8635    fail("Parse failed at maximum allocation count");
8636}
8637END_TEST
8638
8639/* Test attribute enums sufficient to overflow the string pool */
8640START_TEST(test_alloc_realloc_attribute_enum_value) {
8641  const char *text = "<?xml version='1.0' standalone='no'?>\n"
8642                     "<!DOCTYPE animal SYSTEM 'test.dtd'>\n"
8643                     "<animal>This is a yellow tiger</animal>";
8644  /* We wish to define a collection of attribute enums that will
8645   * cause the string pool storing them to have to expand.  This
8646   * means more than 1024 bytes, including the parentheses and
8647   * separator bars.
8648   */
8649  char dtd_text[]
8650      = "<!ELEMENT animal (#PCDATA)*>\n"
8651        "<!ATTLIST animal thing "
8652        "(default"
8653        /* Each line is 64 characters */
8654        "|ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8655        "|BBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8656        "|CBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8657        "|DBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8658        "|EBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8659        "|FBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8660        "|GBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8661        "|HBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8662        "|IBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8663        "|JBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8664        "|KBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8665        "|LBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8666        "|MBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8667        "|NBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8668        "|OBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8669        "|PBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO)"
8670        " 'default'>";
8671  int i;
8672  const int max_realloc_count = 10;
8673
8674  for (i = 0; i < max_realloc_count; i++) {
8675    reallocation_count = i;
8676    XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
8677    XML_SetUserData(g_parser, dtd_text);
8678    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
8679    /* An attribute list handler provokes a different code path */
8680    XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
8681    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8682        != XML_STATUS_ERROR)
8683      break;
8684    /* See comment in test_alloc_parse_xdecl() */
8685    alloc_teardown();
8686    alloc_setup();
8687  }
8688  if (i == 0)
8689    fail("Parse succeeded despite failing reallocator");
8690  if (i == max_realloc_count)
8691    fail("Parse failed at maximum reallocation count");
8692}
8693END_TEST
8694
8695/* Test attribute enums in a #IMPLIED attribute forcing pool growth */
8696START_TEST(test_alloc_realloc_implied_attribute) {
8697  /* Forcing this particular code path is a balancing act.  The
8698   * addition of the closing parenthesis and terminal NUL must be
8699   * what pushes the string of enums over the 1024-byte limit,
8700   * otherwise a different code path will pick up the realloc.
8701   */
8702  const char *text
8703      = "<!DOCTYPE doc [\n"
8704        "<!ELEMENT doc EMPTY>\n"
8705        "<!ATTLIST doc a "
8706        /* Each line is 64 characters */
8707        "(ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8708        "|BBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8709        "|CBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8710        "|DBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8711        "|EBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8712        "|FBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8713        "|GBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8714        "|HBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8715        "|IBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8716        "|JBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8717        "|KBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8718        "|LBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8719        "|MBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8720        "|NBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8721        "|OBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8722        "|PBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMN)"
8723        " #IMPLIED>\n"
8724        "]><doc/>";
8725  int i;
8726  const int max_realloc_count = 10;
8727
8728  for (i = 0; i < max_realloc_count; i++) {
8729    reallocation_count = i;
8730    XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
8731    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8732        != XML_STATUS_ERROR)
8733      break;
8734    /* See comment in test_alloc_parse_xdecl() */
8735    alloc_teardown();
8736    alloc_setup();
8737  }
8738  if (i == 0)
8739    fail("Parse succeeded despite failing reallocator");
8740  if (i == max_realloc_count)
8741    fail("Parse failed at maximum reallocation count");
8742}
8743END_TEST
8744
8745/* Test attribute enums in a defaulted attribute forcing pool growth */
8746START_TEST(test_alloc_realloc_default_attribute) {
8747  /* Forcing this particular code path is a balancing act.  The
8748   * addition of the closing parenthesis and terminal NUL must be
8749   * what pushes the string of enums over the 1024-byte limit,
8750   * otherwise a different code path will pick up the realloc.
8751   */
8752  const char *text
8753      = "<!DOCTYPE doc [\n"
8754        "<!ELEMENT doc EMPTY>\n"
8755        "<!ATTLIST doc a "
8756        /* Each line is 64 characters */
8757        "(ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8758        "|BBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8759        "|CBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8760        "|DBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8761        "|EBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8762        "|FBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8763        "|GBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8764        "|HBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8765        "|IBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8766        "|JBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8767        "|KBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8768        "|LBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8769        "|MBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8770        "|NBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8771        "|OBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
8772        "|PBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMN)"
8773        " 'ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO'"
8774        ">\n]><doc/>";
8775  int i;
8776  const int max_realloc_count = 10;
8777
8778  for (i = 0; i < max_realloc_count; i++) {
8779    reallocation_count = i;
8780    XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
8781    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8782        != XML_STATUS_ERROR)
8783      break;
8784    /* See comment in test_alloc_parse_xdecl() */
8785    alloc_teardown();
8786    alloc_setup();
8787  }
8788  if (i == 0)
8789    fail("Parse succeeded despite failing reallocator");
8790  if (i == max_realloc_count)
8791    fail("Parse failed at maximum reallocation count");
8792}
8793END_TEST
8794
8795/* Test long notation name with dodgy allocator */
8796START_TEST(test_alloc_notation) {
8797  const char *text
8798      = "<!DOCTYPE doc [\n"
8799        "<!NOTATION "
8800        /* Each line is 64 characters */
8801        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8802        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8803        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8804        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8805        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8806        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8807        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8808        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8809        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8810        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8811        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8812        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8813        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8814        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8815        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8816        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8817        " SYSTEM 'http://example.org/n'>\n"
8818        "<!ENTITY e SYSTEM 'http://example.org/e' NDATA "
8819        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8820        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
8821        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
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        ">\n"
8836        "<!ELEMENT doc EMPTY>\n"
8837        "]>\n<doc/>";
8838  int i;
8839  const int max_alloc_count = 20;
8840
8841  for (i = 0; i < max_alloc_count; i++) {
8842    allocation_count = i;
8843    dummy_handler_flags = 0;
8844    XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
8845    XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
8846    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8847        != XML_STATUS_ERROR)
8848      break;
8849    /* See comment in test_alloc_parse_xdecl() */
8850    alloc_teardown();
8851    alloc_setup();
8852  }
8853  if (i == 0)
8854    fail("Parse succeeded despite allocation failures");
8855  if (i == max_alloc_count)
8856    fail("Parse failed at maximum allocation count");
8857  if (dummy_handler_flags
8858      != (DUMMY_ENTITY_DECL_HANDLER_FLAG | DUMMY_NOTATION_DECL_HANDLER_FLAG))
8859    fail("Entity declaration handler not called");
8860}
8861END_TEST
8862
8863/* Test public notation with dodgy allocator */
8864START_TEST(test_alloc_public_notation) {
8865  const char *text
8866      = "<!DOCTYPE doc [\n"
8867        "<!NOTATION note PUBLIC '"
8868        /* 64 characters per line */
8869        "http://example.com/a/long/enough/name/to/trigger/pool/growth/zz/"
8870        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8871        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8872        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8873        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8874        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8875        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8876        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8877        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8878        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8879        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8880        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8881        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8882        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8883        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8884        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8885        "' 'foo'>\n"
8886        "<!ENTITY e SYSTEM 'http://example.com/e' NDATA note>\n"
8887        "<!ELEMENT doc EMPTY>\n"
8888        "]>\n<doc/>";
8889  int i;
8890  const int max_alloc_count = 20;
8891
8892  for (i = 0; i < max_alloc_count; i++) {
8893    allocation_count = i;
8894    dummy_handler_flags = 0;
8895    XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
8896    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8897        != XML_STATUS_ERROR)
8898      break;
8899    /* See comment in test_alloc_parse_xdecl() */
8900    alloc_teardown();
8901    alloc_setup();
8902  }
8903  if (i == 0)
8904    fail("Parse succeeded despite allocation failures");
8905  if (i == max_alloc_count)
8906    fail("Parse failed at maximum allocation count");
8907  if (dummy_handler_flags != DUMMY_NOTATION_DECL_HANDLER_FLAG)
8908    fail("Notation handler not called");
8909}
8910END_TEST
8911
8912/* Test public notation with dodgy allocator */
8913START_TEST(test_alloc_system_notation) {
8914  const char *text
8915      = "<!DOCTYPE doc [\n"
8916        "<!NOTATION note SYSTEM '"
8917        /* 64 characters per line */
8918        "http://example.com/a/long/enough/name/to/trigger/pool/growth/zz/"
8919        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8920        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8921        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8922        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8923        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8924        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8925        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8926        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8927        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8928        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8929        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8930        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8931        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8932        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8933        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
8934        "'>\n"
8935        "<!ENTITY e SYSTEM 'http://example.com/e' NDATA note>\n"
8936        "<!ELEMENT doc EMPTY>\n"
8937        "]>\n<doc/>";
8938  int i;
8939  const int max_alloc_count = 20;
8940
8941  for (i = 0; i < max_alloc_count; i++) {
8942    allocation_count = i;
8943    dummy_handler_flags = 0;
8944    XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
8945    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8946        != XML_STATUS_ERROR)
8947      break;
8948    /* See comment in test_alloc_parse_xdecl() */
8949    alloc_teardown();
8950    alloc_setup();
8951  }
8952  if (i == 0)
8953    fail("Parse succeeded despite allocation failures");
8954  if (i == max_alloc_count)
8955    fail("Parse failed at maximum allocation count");
8956  if (dummy_handler_flags != DUMMY_NOTATION_DECL_HANDLER_FLAG)
8957    fail("Notation handler not called");
8958}
8959END_TEST
8960
8961START_TEST(test_alloc_nested_groups) {
8962  const char *text
8963      = "<!DOCTYPE doc [\n"
8964        "<!ELEMENT doc "
8965        /* Sixteen elements per line */
8966        "(e,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,"
8967        "(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?"
8968        "))))))))))))))))))))))))))))))))>\n"
8969        "<!ELEMENT e EMPTY>"
8970        "]>\n"
8971        "<doc><e/></doc>";
8972  CharData storage;
8973  int i;
8974  const int max_alloc_count = 20;
8975
8976  for (i = 0; i < max_alloc_count; i++) {
8977    allocation_count = i;
8978    CharData_Init(&storage);
8979    XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
8980    XML_SetStartElementHandler(g_parser, record_element_start_handler);
8981    XML_SetUserData(g_parser, &storage);
8982    dummy_handler_flags = 0;
8983    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
8984        != XML_STATUS_ERROR)
8985      break;
8986    /* See comment in test_alloc_parse_xdecl() */
8987    alloc_teardown();
8988    alloc_setup();
8989  }
8990
8991  if (i == 0)
8992    fail("Parse succeeded despite failing reallocator");
8993  if (i == max_alloc_count)
8994    fail("Parse failed at maximum reallocation count");
8995  CharData_CheckXMLChars(&storage, XCS("doce"));
8996  if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
8997    fail("Element handler not fired");
8998}
8999END_TEST
9000
9001START_TEST(test_alloc_realloc_nested_groups) {
9002  const char *text
9003      = "<!DOCTYPE doc [\n"
9004        "<!ELEMENT doc "
9005        /* Sixteen elements per line */
9006        "(e,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,"
9007        "(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?"
9008        "))))))))))))))))))))))))))))))))>\n"
9009        "<!ELEMENT e EMPTY>"
9010        "]>\n"
9011        "<doc><e/></doc>";
9012  CharData storage;
9013  int i;
9014  const int max_realloc_count = 10;
9015
9016  for (i = 0; i < max_realloc_count; i++) {
9017    reallocation_count = i;
9018    CharData_Init(&storage);
9019    XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
9020    XML_SetStartElementHandler(g_parser, record_element_start_handler);
9021    XML_SetUserData(g_parser, &storage);
9022    dummy_handler_flags = 0;
9023    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9024        != XML_STATUS_ERROR)
9025      break;
9026    /* See comment in test_alloc_parse_xdecl() */
9027    alloc_teardown();
9028    alloc_setup();
9029  }
9030
9031  if (i == 0)
9032    fail("Parse succeeded despite failing reallocator");
9033  if (i == max_realloc_count)
9034    fail("Parse failed at maximum reallocation count");
9035  CharData_CheckXMLChars(&storage, XCS("doce"));
9036  if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
9037    fail("Element handler not fired");
9038}
9039END_TEST
9040
9041START_TEST(test_alloc_large_group) {
9042  const char *text = "<!DOCTYPE doc [\n"
9043                     "<!ELEMENT doc ("
9044                     "a1|a2|a3|a4|a5|a6|a7|a8|"
9045                     "b1|b2|b3|b4|b5|b6|b7|b8|"
9046                     "c1|c2|c3|c4|c5|c6|c7|c8|"
9047                     "d1|d2|d3|d4|d5|d6|d7|d8|"
9048                     "e1"
9049                     ")+>\n"
9050                     "]>\n"
9051                     "<doc>\n"
9052                     "<a1/>\n"
9053                     "</doc>\n";
9054  int i;
9055  const int max_alloc_count = 50;
9056
9057  for (i = 0; i < max_alloc_count; i++) {
9058    allocation_count = i;
9059    XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
9060    dummy_handler_flags = 0;
9061    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9062        != XML_STATUS_ERROR)
9063      break;
9064    /* See comment in test_alloc_parse_xdecl() */
9065    alloc_teardown();
9066    alloc_setup();
9067  }
9068  if (i == 0)
9069    fail("Parse succeeded despite failing allocator");
9070  if (i == max_alloc_count)
9071    fail("Parse failed at maximum allocation count");
9072  if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
9073    fail("Element handler flag not raised");
9074}
9075END_TEST
9076
9077START_TEST(test_alloc_realloc_group_choice) {
9078  const char *text = "<!DOCTYPE doc [\n"
9079                     "<!ELEMENT doc ("
9080                     "a1|a2|a3|a4|a5|a6|a7|a8|"
9081                     "b1|b2|b3|b4|b5|b6|b7|b8|"
9082                     "c1|c2|c3|c4|c5|c6|c7|c8|"
9083                     "d1|d2|d3|d4|d5|d6|d7|d8|"
9084                     "e1"
9085                     ")+>\n"
9086                     "]>\n"
9087                     "<doc>\n"
9088                     "<a1/>\n"
9089                     "<b2 attr='foo'>This is a foo</b2>\n"
9090                     "<c3></c3>\n"
9091                     "</doc>\n";
9092  int i;
9093  const int max_realloc_count = 10;
9094
9095  for (i = 0; i < max_realloc_count; i++) {
9096    reallocation_count = i;
9097    XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
9098    dummy_handler_flags = 0;
9099    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9100        != XML_STATUS_ERROR)
9101      break;
9102    /* See comment in test_alloc_parse_xdecl() */
9103    alloc_teardown();
9104    alloc_setup();
9105  }
9106  if (i == 0)
9107    fail("Parse succeeded despite failing reallocator");
9108  if (i == max_realloc_count)
9109    fail("Parse failed at maximum reallocation count");
9110  if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
9111    fail("Element handler flag not raised");
9112}
9113END_TEST
9114
9115START_TEST(test_alloc_pi_in_epilog) {
9116  const char *text = "<doc></doc>\n"
9117                     "<?pi in epilog?>";
9118  int i;
9119  const int max_alloc_count = 15;
9120
9121  for (i = 0; i < max_alloc_count; i++) {
9122    allocation_count = i;
9123    XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
9124    dummy_handler_flags = 0;
9125    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9126        != XML_STATUS_ERROR)
9127      break;
9128    /* See comment in test_alloc_parse_xdecl() */
9129    alloc_teardown();
9130    alloc_setup();
9131  }
9132  if (i == 0)
9133    fail("Parse completed despite failing allocator");
9134  if (i == max_alloc_count)
9135    fail("Parse failed at maximum allocation count");
9136  if (dummy_handler_flags != DUMMY_PI_HANDLER_FLAG)
9137    fail("Processing instruction handler not invoked");
9138}
9139END_TEST
9140
9141START_TEST(test_alloc_comment_in_epilog) {
9142  const char *text = "<doc></doc>\n"
9143                     "<!-- comment in epilog -->";
9144  int i;
9145  const int max_alloc_count = 15;
9146
9147  for (i = 0; i < max_alloc_count; i++) {
9148    allocation_count = i;
9149    XML_SetCommentHandler(g_parser, dummy_comment_handler);
9150    dummy_handler_flags = 0;
9151    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9152        != XML_STATUS_ERROR)
9153      break;
9154    /* See comment in test_alloc_parse_xdecl() */
9155    alloc_teardown();
9156    alloc_setup();
9157  }
9158  if (i == 0)
9159    fail("Parse completed despite failing allocator");
9160  if (i == max_alloc_count)
9161    fail("Parse failed at maximum allocation count");
9162  if (dummy_handler_flags != DUMMY_COMMENT_HANDLER_FLAG)
9163    fail("Processing instruction handler not invoked");
9164}
9165END_TEST
9166
9167START_TEST(test_alloc_realloc_long_attribute_value) {
9168  const char *text
9169      = "<!DOCTYPE doc [<!ENTITY foo '"
9170        /* Each line is 64 characters */
9171        "This entity will be substituted as an attribute value, and is   "
9172        "calculated to be exactly long enough that the terminating NUL   "
9173        "that the library adds internally will trigger the string pool to"
9174        "grow. GHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9175        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9176        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9177        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9178        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9179        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9180        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9181        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9182        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9183        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9184        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9185        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9186        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9187        "'>]>\n"
9188        "<doc a='&foo;'></doc>";
9189  int i;
9190  const int max_realloc_count = 10;
9191
9192  for (i = 0; i < max_realloc_count; i++) {
9193    reallocation_count = i;
9194    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9195        != XML_STATUS_ERROR)
9196      break;
9197    /* See comment in test_alloc_parse_xdecl() */
9198    alloc_teardown();
9199    alloc_setup();
9200  }
9201  if (i == 0)
9202    fail("Parse succeeded despite failing reallocator");
9203  if (i == max_realloc_count)
9204    fail("Parse failed at maximum reallocation count");
9205}
9206END_TEST
9207
9208START_TEST(test_alloc_attribute_whitespace) {
9209  const char *text = "<doc a=' '></doc>";
9210  int i;
9211  const int max_alloc_count = 15;
9212
9213  for (i = 0; i < max_alloc_count; i++) {
9214    allocation_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 allocator");
9224  if (i == max_alloc_count)
9225    fail("Parse failed at maximum allocation count");
9226}
9227END_TEST
9228
9229START_TEST(test_alloc_attribute_predefined_entity) {
9230  const char *text = "<doc a='&amp;'></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}
9248END_TEST
9249
9250/* Test that a character reference at the end of a suitably long
9251 * default value for an attribute can trigger pool growth, and recovers
9252 * if the allocator fails on it.
9253 */
9254START_TEST(test_alloc_long_attr_default_with_char_ref) {
9255  const char *text
9256      = "<!DOCTYPE doc [<!ATTLIST doc a CDATA '"
9257        /* 64 characters per line */
9258        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9259        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9260        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9261        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9262        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9263        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9264        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9265        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9266        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9267        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9268        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9269        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9270        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9271        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9272        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9273        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHI"
9274        "&#x31;'>]>\n"
9275        "<doc/>";
9276  int i;
9277  const int max_alloc_count = 20;
9278
9279  for (i = 0; i < max_alloc_count; i++) {
9280    allocation_count = i;
9281    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9282        != XML_STATUS_ERROR)
9283      break;
9284    /* See comment in test_alloc_parse_xdecl() */
9285    alloc_teardown();
9286    alloc_setup();
9287  }
9288  if (i == 0)
9289    fail("Parse succeeded despite failing allocator");
9290  if (i == max_alloc_count)
9291    fail("Parse failed at maximum allocation count");
9292}
9293END_TEST
9294
9295/* Test that a long character reference substitution triggers a pool
9296 * expansion correctly for an attribute value.
9297 */
9298START_TEST(test_alloc_long_attr_value) {
9299  const char *text
9300      = "<!DOCTYPE test [<!ENTITY foo '\n"
9301        /* 64 characters per line */
9302        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9303        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9304        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9305        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9306        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9307        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9308        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9309        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9310        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9311        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9312        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9313        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9314        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9315        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9316        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9317        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9318        "'>]>\n"
9319        "<test a='&foo;'/>";
9320  int i;
9321  const int max_alloc_count = 25;
9322
9323  for (i = 0; i < max_alloc_count; i++) {
9324    allocation_count = i;
9325    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9326        != XML_STATUS_ERROR)
9327      break;
9328    /* See comment in test_alloc_parse_xdecl() */
9329    alloc_teardown();
9330    alloc_setup();
9331  }
9332  if (i == 0)
9333    fail("Parse succeeded despite failing allocator");
9334  if (i == max_alloc_count)
9335    fail("Parse failed at maximum allocation count");
9336}
9337END_TEST
9338
9339/* Test that an error in a nested parameter entity substitution is
9340 * handled correctly.  It seems unlikely that the code path being
9341 * exercised can be reached purely by carefully crafted XML, but an
9342 * allocation error in the right place will definitely do it.
9343 */
9344START_TEST(test_alloc_nested_entities) {
9345  const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/one.ent'>\n"
9346                     "<doc />";
9347  ExtFaults test_data
9348      = {"<!ENTITY % pe1 '"
9349         /* 64 characters per line */
9350         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9351         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9352         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9353         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9354         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9355         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9356         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9357         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9358         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9359         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9360         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9361         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9362         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9363         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9364         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9365         "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9366         "'>\n"
9367         "<!ENTITY % pe2 '%pe1;'>\n"
9368         "%pe2;",
9369         "Memory Fail not faulted", NULL, XML_ERROR_NO_MEMORY};
9370
9371  /* Causes an allocation error in a nested storeEntityValue() */
9372  allocation_count = 12;
9373  XML_SetUserData(g_parser, &test_data);
9374  XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
9375  XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
9376  expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
9377                 "Entity allocation failure not noted");
9378}
9379END_TEST
9380
9381START_TEST(test_alloc_realloc_param_entity_newline) {
9382  const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
9383                     "<doc/>";
9384  char dtd_text[]
9385      = "<!ENTITY % pe '<!ATTLIST doc att CDATA \""
9386        /* 64 characters per line */
9387        "This default value is carefully crafted so that the carriage    "
9388        "return right at the end of the entity string causes an internal "
9389        "string pool to have to grow.  This allows us to test the alloc  "
9390        "failure path from that point. OPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9391        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9392        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9393        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9394        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9395        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9396        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9397        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9398        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9399        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9400        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9401        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9402        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDE"
9403        "\">\n'>"
9404        "%pe;\n";
9405  int i;
9406  const int max_realloc_count = 5;
9407
9408  for (i = 0; i < max_realloc_count; i++) {
9409    reallocation_count = i;
9410    XML_SetUserData(g_parser, dtd_text);
9411    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
9412    XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
9413    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9414        != XML_STATUS_ERROR)
9415      break;
9416    /* See comment in test_alloc_parse_xdecl() */
9417    alloc_teardown();
9418    alloc_setup();
9419  }
9420  if (i == 0)
9421    fail("Parse succeeded despite failing reallocator");
9422  if (i == max_realloc_count)
9423    fail("Parse failed at maximum reallocation count");
9424}
9425END_TEST
9426
9427START_TEST(test_alloc_realloc_ce_extends_pe) {
9428  const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
9429                     "<doc/>";
9430  char dtd_text[]
9431      = "<!ENTITY % pe '<!ATTLIST doc att CDATA \""
9432        /* 64 characters per line */
9433        "This default value is carefully crafted so that the character   "
9434        "entity at the end causes an internal string pool to have to     "
9435        "grow.  This allows us to test the allocation failure path from  "
9436        "that point onwards. EFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9437        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9438        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9439        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9440        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9441        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9442        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9443        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9444        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9445        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9446        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9447        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
9448        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFG&#x51;"
9449        "\">\n'>"
9450        "%pe;\n";
9451  int i;
9452  const int max_realloc_count = 5;
9453
9454  for (i = 0; i < max_realloc_count; i++) {
9455    reallocation_count = i;
9456    XML_SetUserData(g_parser, dtd_text);
9457    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
9458    XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
9459    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9460        != XML_STATUS_ERROR)
9461      break;
9462    /* See comment in test_alloc_parse_xdecl() */
9463    alloc_teardown();
9464    alloc_setup();
9465  }
9466  if (i == 0)
9467    fail("Parse succeeded despite failing reallocator");
9468  if (i == max_realloc_count)
9469    fail("Parse failed at maximum reallocation count");
9470}
9471END_TEST
9472
9473START_TEST(test_alloc_realloc_attributes) {
9474  const char *text = "<!DOCTYPE doc [\n"
9475                     "  <!ATTLIST doc\n"
9476                     "    a1  (a|b|c)   'a'\n"
9477                     "    a2  (foo|bar) #IMPLIED\n"
9478                     "    a3  NMTOKEN   #IMPLIED\n"
9479                     "    a4  NMTOKENS  #IMPLIED\n"
9480                     "    a5  ID        #IMPLIED\n"
9481                     "    a6  IDREF     #IMPLIED\n"
9482                     "    a7  IDREFS    #IMPLIED\n"
9483                     "    a8  ENTITY    #IMPLIED\n"
9484                     "    a9  ENTITIES  #IMPLIED\n"
9485                     "    a10 CDATA     #IMPLIED\n"
9486                     "  >]>\n"
9487                     "<doc>wombat</doc>\n";
9488  int i;
9489  const int max_realloc_count = 5;
9490
9491  for (i = 0; i < max_realloc_count; i++) {
9492    reallocation_count = i;
9493    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9494        != XML_STATUS_ERROR)
9495      break;
9496    /* See comment in test_alloc_parse_xdecl() */
9497    alloc_teardown();
9498    alloc_setup();
9499  }
9500
9501  if (i == 0)
9502    fail("Parse succeeded despite failing reallocator");
9503  if (i == max_realloc_count)
9504    fail("Parse failed at maximum reallocation count");
9505}
9506END_TEST
9507
9508START_TEST(test_alloc_long_doc_name) {
9509  const char *text =
9510      /* 64 characters per line */
9511      "<LongRootElementNameThatWillCauseTheNextAllocationToExpandTheStr"
9512      "ingPoolForTheDTDQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9513      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9514      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9515      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9516      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9517      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9518      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9519      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9520      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9521      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9522      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9523      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9524      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9525      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9526      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9527      " a='1'/>";
9528  int i;
9529  const int max_alloc_count = 20;
9530
9531  for (i = 0; i < max_alloc_count; i++) {
9532    allocation_count = i;
9533    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9534        != XML_STATUS_ERROR)
9535      break;
9536    /* See comment in test_alloc_parse_xdecl() */
9537    alloc_teardown();
9538    alloc_setup();
9539  }
9540  if (i == 0)
9541    fail("Parsing worked despite failing reallocations");
9542  else if (i == max_alloc_count)
9543    fail("Parsing failed even at max reallocation count");
9544}
9545END_TEST
9546
9547START_TEST(test_alloc_long_base) {
9548  const char *text = "<!DOCTYPE doc [\n"
9549                     "  <!ENTITY e SYSTEM 'foo'>\n"
9550                     "]>\n"
9551                     "<doc>&e;</doc>";
9552  char entity_text[] = "Hello world";
9553  const XML_Char *base =
9554      /* 64 characters per line */
9555      /* clang-format off */
9556        XCS("LongBaseURI/that/will/overflow/an/internal/buffer/and/cause/it/t")
9557        XCS("o/have/to/grow/PQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9558        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9559        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9560        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9561        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9562        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9563        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9564        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9565        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9566        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9567        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9568        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9569        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9570        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
9571        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/");
9572  /* clang-format on */
9573  int i;
9574  const int max_alloc_count = 25;
9575
9576  for (i = 0; i < max_alloc_count; i++) {
9577    allocation_count = i;
9578    XML_SetUserData(g_parser, entity_text);
9579    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
9580    XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
9581    if (XML_SetBase(g_parser, base) == XML_STATUS_ERROR) {
9582      XML_ParserReset(g_parser, NULL);
9583      continue;
9584    }
9585    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9586        != XML_STATUS_ERROR)
9587      break;
9588    /* See comment in test_alloc_parse_xdecl() */
9589    alloc_teardown();
9590    alloc_setup();
9591  }
9592  if (i == 0)
9593    fail("Parsing worked despite failing allocations");
9594  else if (i == max_alloc_count)
9595    fail("Parsing failed even at max allocation count");
9596}
9597END_TEST
9598
9599START_TEST(test_alloc_long_public_id) {
9600  const char *text
9601      = "<!DOCTYPE doc [\n"
9602        "  <!ENTITY e PUBLIC '"
9603        /* 64 characters per line */
9604        "LongPublicIDThatShouldResultInAnInternalStringPoolGrowingAtASpec"
9605        "ificMomentKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9606        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9607        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9608        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9609        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9610        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9611        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9612        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9613        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9614        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9615        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9616        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9617        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9618        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9619        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9620        "' 'bar'>\n"
9621        "]>\n"
9622        "<doc>&e;</doc>";
9623  char entity_text[] = "Hello world";
9624  int i;
9625  const int max_alloc_count = 40;
9626
9627  for (i = 0; i < max_alloc_count; i++) {
9628    allocation_count = i;
9629    XML_SetUserData(g_parser, entity_text);
9630    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
9631    XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
9632    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9633        != XML_STATUS_ERROR)
9634      break;
9635    /* See comment in test_alloc_parse_xdecl() */
9636    alloc_teardown();
9637    alloc_setup();
9638  }
9639  if (i == 0)
9640    fail("Parsing worked despite failing allocations");
9641  else if (i == max_alloc_count)
9642    fail("Parsing failed even at max allocation count");
9643}
9644END_TEST
9645
9646START_TEST(test_alloc_long_entity_value) {
9647  const char *text
9648      = "<!DOCTYPE doc [\n"
9649        "  <!ENTITY e1 '"
9650        /* 64 characters per line */
9651        "Long entity value that should provoke a string pool to grow whil"
9652        "e setting up to parse the external entity below. xyz0123456789AB"
9653        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9654        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9655        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9656        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9657        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9658        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9659        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9660        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9661        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9662        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9663        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9664        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9665        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9666        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9667        "'>\n"
9668        "  <!ENTITY e2 SYSTEM 'bar'>\n"
9669        "]>\n"
9670        "<doc>&e2;</doc>";
9671  char entity_text[] = "Hello world";
9672  int i;
9673  const int max_alloc_count = 40;
9674
9675  for (i = 0; i < max_alloc_count; i++) {
9676    allocation_count = i;
9677    XML_SetUserData(g_parser, entity_text);
9678    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
9679    XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
9680    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9681        != XML_STATUS_ERROR)
9682      break;
9683    /* See comment in test_alloc_parse_xdecl() */
9684    alloc_teardown();
9685    alloc_setup();
9686  }
9687  if (i == 0)
9688    fail("Parsing worked despite failing allocations");
9689  else if (i == max_alloc_count)
9690    fail("Parsing failed even at max allocation count");
9691}
9692END_TEST
9693
9694START_TEST(test_alloc_long_notation) {
9695  const char *text
9696      = "<!DOCTYPE doc [\n"
9697        "  <!NOTATION note SYSTEM '"
9698        /* 64 characters per line */
9699        "ALongNotationNameThatShouldProvokeStringPoolGrowthWhileCallingAn"
9700        "ExternalEntityParserUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9701        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9702        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9703        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9704        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9705        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9706        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9707        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9708        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9709        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9710        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9711        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9712        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9713        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9714        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9715        "'>\n"
9716        "  <!ENTITY e1 SYSTEM 'foo' NDATA "
9717        /* 64 characters per line */
9718        "ALongNotationNameThatShouldProvokeStringPoolGrowthWhileCallingAn"
9719        "ExternalEntityParserUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9720        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
9721        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
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        ">\n"
9735        "  <!ENTITY e2 SYSTEM 'bar'>\n"
9736        "]>\n"
9737        "<doc>&e2;</doc>";
9738  ExtOption options[]
9739      = {{XCS("foo"), "Entity Foo"}, {XCS("bar"), "Entity Bar"}, {NULL, NULL}};
9740  int i;
9741  const int max_alloc_count = 40;
9742
9743  for (i = 0; i < max_alloc_count; i++) {
9744    allocation_count = i;
9745    XML_SetUserData(g_parser, options);
9746    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
9747    XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
9748    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9749        != XML_STATUS_ERROR)
9750      break;
9751
9752    /* See comment in test_alloc_parse_xdecl() */
9753    alloc_teardown();
9754    alloc_setup();
9755  }
9756  if (i == 0)
9757    fail("Parsing worked despite failing allocations");
9758  else if (i == max_alloc_count)
9759    fail("Parsing failed even at max allocation count");
9760}
9761END_TEST
9762
9763static void
9764nsalloc_setup(void) {
9765  XML_Memory_Handling_Suite memsuite = {duff_allocator, duff_reallocator, free};
9766  XML_Char ns_sep[2] = {' ', '\0'};
9767
9768  /* Ensure the parser creation will go through */
9769  allocation_count = ALLOC_ALWAYS_SUCCEED;
9770  reallocation_count = REALLOC_ALWAYS_SUCCEED;
9771  g_parser = XML_ParserCreate_MM(NULL, &memsuite, ns_sep);
9772  if (g_parser == NULL)
9773    fail("Parser not created");
9774}
9775
9776static void
9777nsalloc_teardown(void) {
9778  basic_teardown();
9779}
9780
9781/* Test the effects of allocation failure in simple namespace parsing.
9782 * Based on test_ns_default_with_empty_uri()
9783 */
9784START_TEST(test_nsalloc_xmlns) {
9785  const char *text = "<doc xmlns='http://example.org/'>\n"
9786                     "  <e xmlns=''/>\n"
9787                     "</doc>";
9788  unsigned int i;
9789  const unsigned int max_alloc_count = 30;
9790
9791  for (i = 0; i < max_alloc_count; i++) {
9792    allocation_count = i;
9793    /* Exercise more code paths with a default handler */
9794    XML_SetDefaultHandler(g_parser, dummy_default_handler);
9795    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9796        != XML_STATUS_ERROR)
9797      break;
9798    /* Resetting the parser is insufficient, because some memory
9799     * allocations are cached within the parser.  Instead we use
9800     * the teardown and setup routines to ensure that we have the
9801     * right sort of parser back in our hands.
9802     */
9803    nsalloc_teardown();
9804    nsalloc_setup();
9805  }
9806  if (i == 0)
9807    fail("Parsing worked despite failing allocations");
9808  else if (i == max_alloc_count)
9809    fail("Parsing failed even at maximum allocation count");
9810}
9811END_TEST
9812
9813/* Test XML_ParseBuffer interface with namespace and a dicky allocator */
9814START_TEST(test_nsalloc_parse_buffer) {
9815  const char *text = "<doc>Hello</doc>";
9816  void *buffer;
9817
9818  /* Try a parse before the start of the world */
9819  /* (Exercises new code path) */
9820  allocation_count = 0;
9821  if (XML_ParseBuffer(g_parser, 0, XML_FALSE) != XML_STATUS_ERROR)
9822    fail("Pre-init XML_ParseBuffer not faulted");
9823  if (XML_GetErrorCode(g_parser) != XML_ERROR_NO_MEMORY)
9824    fail("Pre-init XML_ParseBuffer faulted for wrong reason");
9825
9826  /* Now with actual memory allocation */
9827  allocation_count = ALLOC_ALWAYS_SUCCEED;
9828  if (XML_ParseBuffer(g_parser, 0, XML_FALSE) != XML_STATUS_OK)
9829    xml_failure(g_parser);
9830
9831  /* Check that resuming an unsuspended parser is faulted */
9832  if (XML_ResumeParser(g_parser) != XML_STATUS_ERROR)
9833    fail("Resuming unsuspended parser not faulted");
9834  if (XML_GetErrorCode(g_parser) != XML_ERROR_NOT_SUSPENDED)
9835    xml_failure(g_parser);
9836
9837  /* Get the parser into suspended state */
9838  XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
9839  resumable = XML_TRUE;
9840  buffer = XML_GetBuffer(g_parser, (int)strlen(text));
9841  if (buffer == NULL)
9842    fail("Could not acquire parse buffer");
9843  assert(buffer != NULL);
9844  memcpy(buffer, text, strlen(text));
9845  if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_TRUE)
9846      != XML_STATUS_SUSPENDED)
9847    xml_failure(g_parser);
9848  if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
9849    xml_failure(g_parser);
9850  if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_TRUE)
9851      != XML_STATUS_ERROR)
9852    fail("Suspended XML_ParseBuffer not faulted");
9853  if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
9854    xml_failure(g_parser);
9855  if (XML_GetBuffer(g_parser, (int)strlen(text)) != NULL)
9856    fail("Suspended XML_GetBuffer not faulted");
9857
9858  /* Get it going again and complete the world */
9859  XML_SetCharacterDataHandler(g_parser, NULL);
9860  if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
9861    xml_failure(g_parser);
9862  if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_TRUE)
9863      != XML_STATUS_ERROR)
9864    fail("Post-finishing XML_ParseBuffer not faulted");
9865  if (XML_GetErrorCode(g_parser) != XML_ERROR_FINISHED)
9866    xml_failure(g_parser);
9867  if (XML_GetBuffer(g_parser, (int)strlen(text)) != NULL)
9868    fail("Post-finishing XML_GetBuffer not faulted");
9869}
9870END_TEST
9871
9872/* Check handling of long prefix names (pool growth) */
9873START_TEST(test_nsalloc_long_prefix) {
9874  const char *text
9875      = "<"
9876        /* 64 characters per line */
9877        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9878        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9879        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9880        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9881        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9882        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9883        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9884        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9885        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9886        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9887        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9888        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9889        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9890        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9891        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9892        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9893        ":foo xmlns:"
9894        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9895        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9896        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9897        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9898        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9899        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9900        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9901        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9902        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9903        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9904        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9905        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9906        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9907        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9908        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9909        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9910        "='http://example.org/'>"
9911        "</"
9912        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9913        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9914        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9915        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9916        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9917        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9918        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9919        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9920        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9921        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9922        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9923        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9924        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9925        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9926        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9927        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
9928        ":foo>";
9929  int i;
9930  const int max_alloc_count = 40;
9931
9932  for (i = 0; i < max_alloc_count; i++) {
9933    allocation_count = i;
9934    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9935        != XML_STATUS_ERROR)
9936      break;
9937    /* See comment in test_nsalloc_xmlns() */
9938    nsalloc_teardown();
9939    nsalloc_setup();
9940  }
9941  if (i == 0)
9942    fail("Parsing worked despite failing allocations");
9943  else if (i == max_alloc_count)
9944    fail("Parsing failed even at max allocation count");
9945}
9946END_TEST
9947
9948/* Check handling of long uri names (pool growth) */
9949START_TEST(test_nsalloc_long_uri) {
9950  const char *text
9951      = "<foo:e xmlns:foo='http://example.org/"
9952        /* 64 characters per line */
9953        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9954        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9955        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9956        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9957        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9958        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9959        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9960        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9961        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9962        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9963        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9964        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9965        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9966        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9967        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9968        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9969        "' bar:a='12'\n"
9970        "xmlns:bar='http://example.org/"
9971        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9972        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9973        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9974        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9975        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9976        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9977        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9978        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9979        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9980        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9981        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9982        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9983        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9984        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9985        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9986        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
9987        "'>"
9988        "</foo:e>";
9989  int i;
9990  const int max_alloc_count = 40;
9991
9992  for (i = 0; i < max_alloc_count; i++) {
9993    allocation_count = i;
9994    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
9995        != XML_STATUS_ERROR)
9996      break;
9997    /* See comment in test_nsalloc_xmlns() */
9998    nsalloc_teardown();
9999    nsalloc_setup();
10000  }
10001  if (i == 0)
10002    fail("Parsing worked despite failing allocations");
10003  else if (i == max_alloc_count)
10004    fail("Parsing failed even at max allocation count");
10005}
10006END_TEST
10007
10008/* Test handling of long attribute names with prefixes */
10009START_TEST(test_nsalloc_long_attr) {
10010  const char *text
10011      = "<foo:e xmlns:foo='http://example.org/' bar:"
10012        /* 64 characters per line */
10013        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10014        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10015        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10016        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10017        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10018        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10019        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10020        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10021        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10022        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10023        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10024        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10025        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10026        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10027        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10028        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10029        "='12'\n"
10030        "xmlns:bar='http://example.org/'>"
10031        "</foo:e>";
10032  int i;
10033  const int max_alloc_count = 40;
10034
10035  for (i = 0; i < max_alloc_count; i++) {
10036    allocation_count = i;
10037    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10038        != XML_STATUS_ERROR)
10039      break;
10040    /* See comment in test_nsalloc_xmlns() */
10041    nsalloc_teardown();
10042    nsalloc_setup();
10043  }
10044  if (i == 0)
10045    fail("Parsing worked despite failing allocations");
10046  else if (i == max_alloc_count)
10047    fail("Parsing failed even at max allocation count");
10048}
10049END_TEST
10050
10051/* Test handling of an attribute name with a long namespace prefix */
10052START_TEST(test_nsalloc_long_attr_prefix) {
10053  const char *text
10054      = "<foo:e xmlns:foo='http://example.org/' "
10055        /* 64 characters per line */
10056        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10057        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10058        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10059        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10060        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10061        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10062        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10063        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10064        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10065        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10066        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10067        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10068        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10069        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10070        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10071        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10072        ":a='12'\n"
10073        "xmlns:"
10074        /* 64 characters per line */
10075        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10076        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10077        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10078        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10079        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10080        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10081        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10082        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10083        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10084        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10085        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10086        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10087        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10088        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10089        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10090        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10091        "='http://example.org/'>"
10092        "</foo:e>";
10093  const XML_Char *elemstr[] = {
10094      /* clang-format off */
10095        XCS("http://example.org/ e foo"),
10096        XCS("http://example.org/ a ")
10097        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10098        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10099        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10100        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10101        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10102        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10103        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10104        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10105        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10106        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10107        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10108        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10109        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10110        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10111        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10112        XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
10113      /* clang-format on */
10114  };
10115  int i;
10116  const int max_alloc_count = 40;
10117
10118  for (i = 0; i < max_alloc_count; i++) {
10119    allocation_count = i;
10120    XML_SetReturnNSTriplet(g_parser, XML_TRUE);
10121    XML_SetUserData(g_parser, (void *)elemstr);
10122    XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
10123    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10124        != XML_STATUS_ERROR)
10125      break;
10126    /* See comment in test_nsalloc_xmlns() */
10127    nsalloc_teardown();
10128    nsalloc_setup();
10129  }
10130  if (i == 0)
10131    fail("Parsing worked despite failing allocations");
10132  else if (i == max_alloc_count)
10133    fail("Parsing failed even at max allocation count");
10134}
10135END_TEST
10136
10137/* Test attribute handling in the face of a dodgy reallocator */
10138START_TEST(test_nsalloc_realloc_attributes) {
10139  const char *text = "<foo:e xmlns:foo='http://example.org/' bar:a='12'\n"
10140                     "       xmlns:bar='http://example.org/'>"
10141                     "</foo:e>";
10142  int i;
10143  const int max_realloc_count = 10;
10144
10145  for (i = 0; i < max_realloc_count; i++) {
10146    reallocation_count = i;
10147    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10148        != XML_STATUS_ERROR)
10149      break;
10150    /* See comment in test_nsalloc_xmlns() */
10151    nsalloc_teardown();
10152    nsalloc_setup();
10153  }
10154  if (i == 0)
10155    fail("Parsing worked despite failing reallocations");
10156  else if (i == max_realloc_count)
10157    fail("Parsing failed at max reallocation count");
10158}
10159END_TEST
10160
10161/* Test long element names with namespaces under a failing allocator */
10162START_TEST(test_nsalloc_long_element) {
10163  const char *text
10164      = "<foo:thisisalongenoughelementnametotriggerareallocation\n"
10165        " xmlns:foo='http://example.org/' bar:a='12'\n"
10166        " xmlns:bar='http://example.org/'>"
10167        "</foo:thisisalongenoughelementnametotriggerareallocation>";
10168  const XML_Char *elemstr[]
10169      = {XCS("http://example.org/")
10170             XCS(" thisisalongenoughelementnametotriggerareallocation foo"),
10171         XCS("http://example.org/ a bar")};
10172  int i;
10173  const int max_alloc_count = 30;
10174
10175  for (i = 0; i < max_alloc_count; i++) {
10176    allocation_count = i;
10177    XML_SetReturnNSTriplet(g_parser, XML_TRUE);
10178    XML_SetUserData(g_parser, (void *)elemstr);
10179    XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
10180    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10181        != XML_STATUS_ERROR)
10182      break;
10183    /* See comment in test_nsalloc_xmlns() */
10184    nsalloc_teardown();
10185    nsalloc_setup();
10186  }
10187  if (i == 0)
10188    fail("Parsing worked despite failing reallocations");
10189  else if (i == max_alloc_count)
10190    fail("Parsing failed at max reallocation count");
10191}
10192END_TEST
10193
10194/* Test the effects of reallocation failure when reassigning a
10195 * binding.
10196 *
10197 * XML_ParserReset does not free the BINDING structures used by a
10198 * parser, but instead adds them to an internal free list to be reused
10199 * as necessary.  Likewise the URI buffers allocated for the binding
10200 * aren't freed, but kept attached to their existing binding.  If the
10201 * new binding has a longer URI, it will need reallocation.  This test
10202 * provokes that reallocation, and tests the control path if it fails.
10203 */
10204START_TEST(test_nsalloc_realloc_binding_uri) {
10205  const char *first = "<doc xmlns='http://example.org/'>\n"
10206                      "  <e xmlns='' />\n"
10207                      "</doc>";
10208  const char *second
10209      = "<doc xmlns='http://example.org/long/enough/URI/to/reallocate/'>\n"
10210        "  <e xmlns='' />\n"
10211        "</doc>";
10212  unsigned i;
10213  const unsigned max_realloc_count = 10;
10214
10215  /* First, do a full parse that will leave bindings around */
10216  if (_XML_Parse_SINGLE_BYTES(g_parser, first, (int)strlen(first), XML_TRUE)
10217      == XML_STATUS_ERROR)
10218    xml_failure(g_parser);
10219
10220  /* Now repeat with a longer URI and a duff reallocator */
10221  for (i = 0; i < max_realloc_count; i++) {
10222    XML_ParserReset(g_parser, NULL);
10223    reallocation_count = i;
10224    if (_XML_Parse_SINGLE_BYTES(g_parser, second, (int)strlen(second), XML_TRUE)
10225        != XML_STATUS_ERROR)
10226      break;
10227  }
10228  if (i == 0)
10229    fail("Parsing worked despite failing reallocation");
10230  else if (i == max_realloc_count)
10231    fail("Parsing failed at max reallocation count");
10232}
10233END_TEST
10234
10235/* Check handling of long prefix names (pool growth) */
10236START_TEST(test_nsalloc_realloc_long_prefix) {
10237  const char *text
10238      = "<"
10239        /* 64 characters per line */
10240        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10241        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10242        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10243        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10244        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10245        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10246        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10247        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10248        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10249        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10250        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10251        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10252        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10253        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10254        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10255        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10256        ":foo xmlns:"
10257        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10258        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10259        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10260        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10261        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10262        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10263        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10264        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10265        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10266        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10267        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10268        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10269        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10270        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10271        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10272        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10273        "='http://example.org/'>"
10274        "</"
10275        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10276        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10277        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10278        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10279        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10280        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10281        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10282        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10283        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10284        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10285        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10286        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10287        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10288        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10289        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10290        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10291        ":foo>";
10292  int i;
10293  const int max_realloc_count = 12;
10294
10295  for (i = 0; i < max_realloc_count; i++) {
10296    reallocation_count = i;
10297    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10298        != XML_STATUS_ERROR)
10299      break;
10300    /* See comment in test_nsalloc_xmlns() */
10301    nsalloc_teardown();
10302    nsalloc_setup();
10303  }
10304  if (i == 0)
10305    fail("Parsing worked despite failing reallocations");
10306  else if (i == max_realloc_count)
10307    fail("Parsing failed even at max reallocation count");
10308}
10309END_TEST
10310
10311/* Check handling of even long prefix names (different code path) */
10312START_TEST(test_nsalloc_realloc_longer_prefix) {
10313  const char *text
10314      = "<"
10315        /* 64 characters per line */
10316        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10317        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10318        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10319        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10320        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10321        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10322        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10323        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10324        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10325        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10326        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10327        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10328        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10329        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10330        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10331        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10332        "Q:foo xmlns:"
10333        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10334        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10335        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10336        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10337        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10338        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10339        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10340        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10341        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10342        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10343        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10344        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10345        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10346        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10347        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10348        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10349        "Q='http://example.org/'>"
10350        "</"
10351        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10352        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10353        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10354        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10355        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10356        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10357        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10358        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10359        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10360        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10361        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10362        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10363        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10364        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10365        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10366        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10367        "Q:foo>";
10368  int i;
10369  const int max_realloc_count = 12;
10370
10371  for (i = 0; i < max_realloc_count; i++) {
10372    reallocation_count = i;
10373    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10374        != XML_STATUS_ERROR)
10375      break;
10376    /* See comment in test_nsalloc_xmlns() */
10377    nsalloc_teardown();
10378    nsalloc_setup();
10379  }
10380  if (i == 0)
10381    fail("Parsing worked despite failing reallocations");
10382  else if (i == max_realloc_count)
10383    fail("Parsing failed even at max reallocation count");
10384}
10385END_TEST
10386
10387START_TEST(test_nsalloc_long_namespace) {
10388  const char *text1
10389      = "<"
10390        /* 64 characters per line */
10391        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10392        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10393        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10394        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10395        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10396        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10397        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10398        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10399        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10400        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10401        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10402        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10403        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10404        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10405        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10406        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10407        ":e xmlns:"
10408        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10409        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10410        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10411        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10412        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10413        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10414        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10415        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10416        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10417        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10418        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10419        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10420        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10421        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10422        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10423        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10424        "='http://example.org/'>\n";
10425  const char *text2
10426      = "<"
10427        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10428        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10429        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10430        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10431        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10432        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10433        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10434        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10435        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10436        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10437        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10438        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10439        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10440        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10441        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10442        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10443        ":f "
10444        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10445        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10446        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10447        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10448        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10449        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10450        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10451        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10452        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10453        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10454        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10455        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10456        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10457        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10458        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10459        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10460        ":attr='foo'/>\n"
10461        "</"
10462        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10463        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10464        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10465        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10466        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10467        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10468        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10469        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10470        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10471        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10472        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10473        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10474        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10475        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10476        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10477        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10478        ":e>";
10479  int i;
10480  const int max_alloc_count = 40;
10481
10482  for (i = 0; i < max_alloc_count; i++) {
10483    allocation_count = i;
10484    if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
10485            != XML_STATUS_ERROR
10486        && _XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2),
10487                                   XML_TRUE)
10488               != XML_STATUS_ERROR)
10489      break;
10490    /* See comment in test_nsalloc_xmlns() */
10491    nsalloc_teardown();
10492    nsalloc_setup();
10493  }
10494  if (i == 0)
10495    fail("Parsing worked despite failing allocations");
10496  else if (i == max_alloc_count)
10497    fail("Parsing failed even at max allocation count");
10498}
10499END_TEST
10500
10501/* Using a slightly shorter namespace name provokes allocations in
10502 * slightly different places in the code.
10503 */
10504START_TEST(test_nsalloc_less_long_namespace) {
10505  const char *text
10506      = "<"
10507        /* 64 characters per line */
10508        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10509        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10510        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10511        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10512        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10513        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10514        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10515        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
10516        ":e xmlns:"
10517        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10518        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10519        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10520        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10521        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10522        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10523        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10524        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
10525        "='http://example.org/'>\n"
10526        "<"
10527        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10528        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10529        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10530        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10531        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10532        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10533        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10534        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
10535        ":f "
10536        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10537        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10538        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10539        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10540        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10541        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10542        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10543        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
10544        ":att='foo'/>\n"
10545        "</"
10546        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10547        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10548        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10549        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10550        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10551        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10552        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
10553        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
10554        ":e>";
10555  int i;
10556  const int max_alloc_count = 40;
10557
10558  for (i = 0; i < max_alloc_count; i++) {
10559    allocation_count = i;
10560    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10561        != XML_STATUS_ERROR)
10562      break;
10563    /* See comment in test_nsalloc_xmlns() */
10564    nsalloc_teardown();
10565    nsalloc_setup();
10566  }
10567  if (i == 0)
10568    fail("Parsing worked despite failing allocations");
10569  else if (i == max_alloc_count)
10570    fail("Parsing failed even at max allocation count");
10571}
10572END_TEST
10573
10574START_TEST(test_nsalloc_long_context) {
10575  const char *text
10576      = "<!DOCTYPE doc SYSTEM 'foo' [\n"
10577        "  <!ATTLIST doc baz ID #REQUIRED>\n"
10578        "  <!ENTITY en SYSTEM 'bar'>\n"
10579        "]>\n"
10580        "<doc xmlns='http://example.org/"
10581        /* 64 characters per line */
10582        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10583        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10584        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10585        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10586        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10587        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10588        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10589        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10590        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10591        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10592        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10593        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10594        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10595        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10596        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10597        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKL"
10598        "' baz='2'>\n"
10599        "&en;"
10600        "</doc>";
10601  ExtOption options[] = {
10602      {XCS("foo"), "<!ELEMENT e EMPTY>"}, {XCS("bar"), "<e/>"}, {NULL, NULL}};
10603  int i;
10604  const int max_alloc_count = 70;
10605
10606  for (i = 0; i < max_alloc_count; i++) {
10607    allocation_count = i;
10608    XML_SetUserData(g_parser, options);
10609    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
10610    XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
10611    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10612        != XML_STATUS_ERROR)
10613      break;
10614
10615    /* See comment in test_nsalloc_xmlns() */
10616    nsalloc_teardown();
10617    nsalloc_setup();
10618  }
10619  if (i == 0)
10620    fail("Parsing worked despite failing allocations");
10621  else if (i == max_alloc_count)
10622    fail("Parsing failed even at max allocation count");
10623}
10624END_TEST
10625
10626/* This function is void; it will throw a fail() on error, so if it
10627 * returns normally it must have succeeded.
10628 */
10629static void
10630context_realloc_test(const char *text) {
10631  ExtOption options[] = {
10632      {XCS("foo"), "<!ELEMENT e EMPTY>"}, {XCS("bar"), "<e/>"}, {NULL, NULL}};
10633  int i;
10634  const int max_realloc_count = 6;
10635
10636  for (i = 0; i < max_realloc_count; i++) {
10637    reallocation_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    /* See comment in test_nsalloc_xmlns() */
10645    nsalloc_teardown();
10646    nsalloc_setup();
10647  }
10648  if (i == 0)
10649    fail("Parsing worked despite failing reallocations");
10650  else if (i == max_realloc_count)
10651    fail("Parsing failed even at max reallocation count");
10652}
10653
10654START_TEST(test_nsalloc_realloc_long_context) {
10655  const char *text
10656      = "<!DOCTYPE doc SYSTEM 'foo' [\n"
10657        "  <!ENTITY en SYSTEM 'bar'>\n"
10658        "]>\n"
10659        "<doc xmlns='http://example.org/"
10660        /* 64 characters per line */
10661        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10662        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10663        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10664        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10665        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10666        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10667        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10668        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10669        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10670        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10671        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10672        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10673        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10674        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10675        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10676        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKL"
10677        "'>\n"
10678        "&en;"
10679        "</doc>";
10680
10681  context_realloc_test(text);
10682}
10683END_TEST
10684
10685START_TEST(test_nsalloc_realloc_long_context_2) {
10686  const char *text
10687      = "<!DOCTYPE doc SYSTEM 'foo' [\n"
10688        "  <!ENTITY en SYSTEM 'bar'>\n"
10689        "]>\n"
10690        "<doc xmlns='http://example.org/"
10691        /* 64 characters per line */
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/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10707        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJK"
10708        "'>\n"
10709        "&en;"
10710        "</doc>";
10711
10712  context_realloc_test(text);
10713}
10714END_TEST
10715
10716START_TEST(test_nsalloc_realloc_long_context_3) {
10717  const char *text
10718      = "<!DOCTYPE doc SYSTEM 'foo' [\n"
10719        "  <!ENTITY en SYSTEM 'bar'>\n"
10720        "]>\n"
10721        "<doc xmlns='http://example.org/"
10722        /* 64 characters per line */
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/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10738        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGH"
10739        "'>\n"
10740        "&en;"
10741        "</doc>";
10742
10743  context_realloc_test(text);
10744}
10745END_TEST
10746
10747START_TEST(test_nsalloc_realloc_long_context_4) {
10748  const char *text
10749      = "<!DOCTYPE doc SYSTEM 'foo' [\n"
10750        "  <!ENTITY en SYSTEM 'bar'>\n"
10751        "]>\n"
10752        "<doc xmlns='http://example.org/"
10753        /* 64 characters per line */
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/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10769        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO"
10770        "'>\n"
10771        "&en;"
10772        "</doc>";
10773
10774  context_realloc_test(text);
10775}
10776END_TEST
10777
10778START_TEST(test_nsalloc_realloc_long_context_5) {
10779  const char *text
10780      = "<!DOCTYPE doc SYSTEM 'foo' [\n"
10781        "  <!ENTITY en SYSTEM 'bar'>\n"
10782        "]>\n"
10783        "<doc xmlns='http://example.org/"
10784        /* 64 characters per line */
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/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
10800        "ABC"
10801        "'>\n"
10802        "&en;"
10803        "</doc>";
10804
10805  context_realloc_test(text);
10806}
10807END_TEST
10808
10809START_TEST(test_nsalloc_realloc_long_context_6) {
10810  const char *text
10811      = "<!DOCTYPE doc SYSTEM 'foo' [\n"
10812        "  <!ENTITY en SYSTEM 'bar'>\n"
10813        "]>\n"
10814        "<doc xmlns='http://example.org/"
10815        /* 64 characters per line */
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        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
10831        "'>\n"
10832        "&en;"
10833        "</doc>";
10834
10835  context_realloc_test(text);
10836}
10837END_TEST
10838
10839START_TEST(test_nsalloc_realloc_long_context_7) {
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/ABCDEFGHIJKLMNO/"
10861        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLM"
10862        "'>\n"
10863        "&en;"
10864        "</doc>";
10865
10866  context_realloc_test(text);
10867}
10868END_TEST
10869
10870START_TEST(test_nsalloc_realloc_long_ge_name) {
10871  const char *text
10872      = "<!DOCTYPE doc SYSTEM 'foo' [\n"
10873        "  <!ENTITY "
10874        /* 64 characters per line */
10875        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10876        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10877        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10878        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10879        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10880        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10881        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10882        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10883        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10884        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10885        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10886        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10887        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10888        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10889        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10890        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10891        " SYSTEM 'bar'>\n"
10892        "]>\n"
10893        "<doc xmlns='http://example.org/baz'>\n"
10894        "&"
10895        /* 64 characters per line */
10896        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10897        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10898        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10899        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10900        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10901        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10902        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10903        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10904        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10905        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10906        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10907        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10908        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10909        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10910        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10911        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10912        ";"
10913        "</doc>";
10914  ExtOption options[] = {
10915      {XCS("foo"), "<!ELEMENT el EMPTY>"}, {XCS("bar"), "<el/>"}, {NULL, NULL}};
10916  int i;
10917  const int max_realloc_count = 10;
10918
10919  for (i = 0; i < max_realloc_count; i++) {
10920    reallocation_count = i;
10921    XML_SetUserData(g_parser, options);
10922    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
10923    XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
10924    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
10925        != XML_STATUS_ERROR)
10926      break;
10927    /* See comment in test_nsalloc_xmlns() */
10928    nsalloc_teardown();
10929    nsalloc_setup();
10930  }
10931  if (i == 0)
10932    fail("Parsing worked despite failing reallocations");
10933  else if (i == max_realloc_count)
10934    fail("Parsing failed even at max reallocation count");
10935}
10936END_TEST
10937
10938/* Test that when a namespace is passed through the context mechanism
10939 * to an external entity parser, the parsers handle reallocation
10940 * failures correctly.  The prefix is exactly the right length to
10941 * provoke particular uncommon code paths.
10942 */
10943START_TEST(test_nsalloc_realloc_long_context_in_dtd) {
10944  const char *text1
10945      = "<!DOCTYPE "
10946        /* 64 characters per line */
10947        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10948        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10949        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10950        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10951        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10952        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10953        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10954        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10955        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10956        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10957        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10958        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10959        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10960        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10961        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10962        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10963        ":doc [\n"
10964        "  <!ENTITY First SYSTEM 'foo/First'>\n"
10965        "]>\n"
10966        "<"
10967        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10968        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10969        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10970        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10971        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10972        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10973        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10974        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10975        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10976        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10977        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10978        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10979        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10980        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10981        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10982        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10983        ":doc xmlns:"
10984        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10985        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10986        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10987        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10988        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10989        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10990        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10991        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10992        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10993        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10994        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10995        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10996        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10997        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10998        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
10999        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11000        "='foo/Second'>&First;";
11001  const char *text2
11002      = "</"
11003        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11004        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11005        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11006        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11007        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11008        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11009        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11010        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11011        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11012        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11013        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11014        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11015        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11016        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11017        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11018        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11019        ":doc>";
11020  ExtOption options[] = {{XCS("foo/First"), "Hello world"}, {NULL, NULL}};
11021  int i;
11022  const int max_realloc_count = 20;
11023
11024  for (i = 0; i < max_realloc_count; i++) {
11025    reallocation_count = i;
11026    XML_SetUserData(g_parser, options);
11027    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
11028    XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
11029    if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
11030            != XML_STATUS_ERROR
11031        && _XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2),
11032                                   XML_TRUE)
11033               != XML_STATUS_ERROR)
11034      break;
11035    /* See comment in test_nsalloc_xmlns() */
11036    nsalloc_teardown();
11037    nsalloc_setup();
11038  }
11039  if (i == 0)
11040    fail("Parsing worked despite failing reallocations");
11041  else if (i == max_realloc_count)
11042    fail("Parsing failed even at max reallocation count");
11043}
11044END_TEST
11045
11046START_TEST(test_nsalloc_long_default_in_ext) {
11047  const char *text
11048      = "<!DOCTYPE doc [\n"
11049        "  <!ATTLIST e a1 CDATA '"
11050        /* 64 characters per line */
11051        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11052        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11053        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11054        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11055        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11056        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11057        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11058        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11059        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11060        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11061        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11062        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11063        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11064        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11065        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11066        "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
11067        "'>\n"
11068        "  <!ENTITY x SYSTEM 'foo'>\n"
11069        "]>\n"
11070        "<doc>&x;</doc>";
11071  ExtOption options[] = {{XCS("foo"), "<e/>"}, {NULL, NULL}};
11072  int i;
11073  const int max_alloc_count = 50;
11074
11075  for (i = 0; i < max_alloc_count; i++) {
11076    allocation_count = i;
11077    XML_SetUserData(g_parser, options);
11078    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
11079    XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
11080    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
11081        != XML_STATUS_ERROR)
11082      break;
11083
11084    /* See comment in test_nsalloc_xmlns() */
11085    nsalloc_teardown();
11086    nsalloc_setup();
11087  }
11088  if (i == 0)
11089    fail("Parsing worked despite failing allocations");
11090  else if (i == max_alloc_count)
11091    fail("Parsing failed even at max allocation count");
11092}
11093END_TEST
11094
11095START_TEST(test_nsalloc_long_systemid_in_ext) {
11096  const char *text
11097      = "<!DOCTYPE doc SYSTEM 'foo' [\n"
11098        "  <!ENTITY en SYSTEM '"
11099        /* 64 characters per line */
11100        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11101        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11102        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11103        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11104        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11105        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11106        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11107        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11108        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11109        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11110        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11111        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11112        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11113        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11114        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11115        "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
11116        "'>\n"
11117        "]>\n"
11118        "<doc>&en;</doc>";
11119  ExtOption options[] = {
11120      {XCS("foo"), "<!ELEMENT e EMPTY>"},
11121      {/* clang-format off */
11122            XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11123            XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11124            XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11125            XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11126            XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11127            XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11128            XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11129            XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11130            XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11131            XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11132            XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11133            XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11134            XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11135            XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11136            XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
11137            XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"),
11138       /* clang-format on */
11139       "<e/>"},
11140      {NULL, NULL}};
11141  int i;
11142  const int max_alloc_count = 55;
11143
11144  for (i = 0; i < max_alloc_count; i++) {
11145    allocation_count = i;
11146    XML_SetUserData(g_parser, options);
11147    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
11148    XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
11149    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
11150        != XML_STATUS_ERROR)
11151      break;
11152
11153    /* See comment in test_nsalloc_xmlns() */
11154    nsalloc_teardown();
11155    nsalloc_setup();
11156  }
11157  if (i == 0)
11158    fail("Parsing worked despite failing allocations");
11159  else if (i == max_alloc_count)
11160    fail("Parsing failed even at max allocation count");
11161}
11162END_TEST
11163
11164/* Test the effects of allocation failure on parsing an element in a
11165 * namespace.  Based on test_nsalloc_long_context.
11166 */
11167START_TEST(test_nsalloc_prefixed_element) {
11168  const char *text = "<!DOCTYPE pfx:element SYSTEM 'foo' [\n"
11169                     "  <!ATTLIST pfx:element baz ID #REQUIRED>\n"
11170                     "  <!ENTITY en SYSTEM 'bar'>\n"
11171                     "]>\n"
11172                     "<pfx:element xmlns:pfx='http://example.org/' baz='2'>\n"
11173                     "&en;"
11174                     "</pfx:element>";
11175  ExtOption options[] = {
11176      {XCS("foo"), "<!ELEMENT e EMPTY>"}, {XCS("bar"), "<e/>"}, {NULL, NULL}};
11177  int i;
11178  const int max_alloc_count = 70;
11179
11180  for (i = 0; i < max_alloc_count; i++) {
11181    allocation_count = i;
11182    XML_SetUserData(g_parser, options);
11183    XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
11184    XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
11185    if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
11186        != XML_STATUS_ERROR)
11187      break;
11188
11189    /* See comment in test_nsalloc_xmlns() */
11190    nsalloc_teardown();
11191    nsalloc_setup();
11192  }
11193  if (i == 0)
11194    fail("Success despite failing allocator");
11195  else if (i == max_alloc_count)
11196    fail("Failed even at full allocation count");
11197}
11198END_TEST
11199
11200static Suite *
11201make_suite(void) {
11202  Suite *s = suite_create("basic");
11203  TCase *tc_basic = tcase_create("basic tests");
11204  TCase *tc_namespace = tcase_create("XML namespaces");
11205  TCase *tc_misc = tcase_create("miscellaneous tests");
11206  TCase *tc_alloc = tcase_create("allocation tests");
11207  TCase *tc_nsalloc = tcase_create("namespace allocation tests");
11208
11209  suite_add_tcase(s, tc_basic);
11210  tcase_add_checked_fixture(tc_basic, basic_setup, basic_teardown);
11211  tcase_add_test(tc_basic, test_nul_byte);
11212  tcase_add_test(tc_basic, test_u0000_char);
11213  tcase_add_test(tc_basic, test_siphash_self);
11214  tcase_add_test(tc_basic, test_siphash_spec);
11215  tcase_add_test(tc_basic, test_bom_utf8);
11216  tcase_add_test(tc_basic, test_bom_utf16_be);
11217  tcase_add_test(tc_basic, test_bom_utf16_le);
11218  tcase_add_test(tc_basic, test_nobom_utf16_le);
11219  tcase_add_test(tc_basic, test_illegal_utf8);
11220  tcase_add_test(tc_basic, test_utf8_auto_align);
11221  tcase_add_test(tc_basic, test_utf16);
11222  tcase_add_test(tc_basic, test_utf16_le_epilog_newline);
11223  tcase_add_test(tc_basic, test_not_utf16);
11224  tcase_add_test(tc_basic, test_bad_encoding);
11225  tcase_add_test(tc_basic, test_latin1_umlauts);
11226  tcase_add_test(tc_basic, test_long_utf8_character);
11227  tcase_add_test(tc_basic, test_long_latin1_attribute);
11228  tcase_add_test(tc_basic, test_long_ascii_attribute);
11229  /* Regression test for SF bug #491986. */
11230  tcase_add_test(tc_basic, test_danish_latin1);
11231  /* Regression test for SF bug #514281. */
11232  tcase_add_test(tc_basic, test_french_charref_hexidecimal);
11233  tcase_add_test(tc_basic, test_french_charref_decimal);
11234  tcase_add_test(tc_basic, test_french_latin1);
11235  tcase_add_test(tc_basic, test_french_utf8);
11236  tcase_add_test(tc_basic, test_utf8_false_rejection);
11237  tcase_add_test(tc_basic, test_line_number_after_parse);
11238  tcase_add_test(tc_basic, test_column_number_after_parse);
11239  tcase_add_test(tc_basic, test_line_and_column_numbers_inside_handlers);
11240  tcase_add_test(tc_basic, test_line_number_after_error);
11241  tcase_add_test(tc_basic, test_column_number_after_error);
11242  tcase_add_test(tc_basic, test_really_long_lines);
11243  tcase_add_test(tc_basic, test_really_long_encoded_lines);
11244  tcase_add_test(tc_basic, test_end_element_events);
11245  tcase_add_test(tc_basic, test_attr_whitespace_normalization);
11246  tcase_add_test(tc_basic, test_xmldecl_misplaced);
11247  tcase_add_test(tc_basic, test_xmldecl_invalid);
11248  tcase_add_test(tc_basic, test_xmldecl_missing_attr);
11249  tcase_add_test(tc_basic, test_xmldecl_missing_value);
11250  tcase_add_test(tc_basic, test_unknown_encoding_internal_entity);
11251  tcase_add_test(tc_basic, test_unrecognised_encoding_internal_entity);
11252  tcase_add_test(tc_basic, test_wfc_undeclared_entity_unread_external_subset);
11253  tcase_add_test(tc_basic, test_wfc_undeclared_entity_no_external_subset);
11254  tcase_add_test(tc_basic, test_wfc_undeclared_entity_standalone);
11255  tcase_add_test(tc_basic, test_wfc_undeclared_entity_with_external_subset);
11256  tcase_add_test(tc_basic, test_not_standalone_handler_reject);
11257  tcase_add_test(tc_basic, test_not_standalone_handler_accept);
11258  tcase_add_test(tc_basic,
11259                 test_wfc_undeclared_entity_with_external_subset_standalone);
11260  tcase_add_test(tc_basic, test_entity_with_external_subset_unless_standalone);
11261  tcase_add_test(tc_basic, test_wfc_no_recursive_entity_refs);
11262  tcase_add_test(tc_basic, test_ext_entity_set_encoding);
11263  tcase_add_test(tc_basic, test_ext_entity_no_handler);
11264  tcase_add_test(tc_basic, test_ext_entity_set_bom);
11265  tcase_add_test(tc_basic, test_ext_entity_bad_encoding);
11266  tcase_add_test(tc_basic, test_ext_entity_bad_encoding_2);
11267  tcase_add_test(tc_basic, test_ext_entity_invalid_parse);
11268  tcase_add_test(tc_basic, test_ext_entity_invalid_suspended_parse);
11269  tcase_add_test(tc_basic, test_dtd_default_handling);
11270  tcase_add_test(tc_basic, test_dtd_attr_handling);
11271  tcase_add_test(tc_basic, test_empty_ns_without_namespaces);
11272  tcase_add_test(tc_basic, test_ns_in_attribute_default_without_namespaces);
11273  tcase_add_test(tc_basic, test_stop_parser_between_char_data_calls);
11274  tcase_add_test(tc_basic, test_suspend_parser_between_char_data_calls);
11275  tcase_add_test(tc_basic, test_repeated_stop_parser_between_char_data_calls);
11276  tcase_add_test(tc_basic, test_good_cdata_ascii);
11277  tcase_add_test(tc_basic, test_good_cdata_utf16);
11278  tcase_add_test(tc_basic, test_good_cdata_utf16_le);
11279  tcase_add_test(tc_basic, test_long_cdata_utf16);
11280#ifndef XML_MIN_SIZE /* FIXME workaround -DXML_MIN_SIZE + ASan (issue #332) */
11281  tcase_add_test(tc_basic, test_multichar_cdata_utf16);
11282#endif
11283  tcase_add_test(tc_basic, test_utf16_bad_surrogate_pair);
11284  tcase_add_test(tc_basic, test_bad_cdata);
11285#ifndef XML_MIN_SIZE /* FIXME workaround -DXML_MIN_SIZE + ASan (issue #332) */
11286  tcase_add_test(tc_basic, test_bad_cdata_utf16);
11287#endif
11288  tcase_add_test(tc_basic, test_stop_parser_between_cdata_calls);
11289  tcase_add_test(tc_basic, test_suspend_parser_between_cdata_calls);
11290  tcase_add_test(tc_basic, test_memory_allocation);
11291  tcase_add_test(tc_basic, test_default_current);
11292  tcase_add_test(tc_basic, test_dtd_elements);
11293  tcase_add_test(tc_basic, test_set_foreign_dtd);
11294  tcase_add_test(tc_basic, test_foreign_dtd_not_standalone);
11295  tcase_add_test(tc_basic, test_invalid_foreign_dtd);
11296  tcase_add_test(tc_basic, test_foreign_dtd_with_doctype);
11297  tcase_add_test(tc_basic, test_foreign_dtd_without_external_subset);
11298  tcase_add_test(tc_basic, test_empty_foreign_dtd);
11299  tcase_add_test(tc_basic, test_set_base);
11300  tcase_add_test(tc_basic, test_attributes);
11301  tcase_add_test(tc_basic, test_reset_in_entity);
11302  tcase_add_test(tc_basic, test_resume_invalid_parse);
11303  tcase_add_test(tc_basic, test_resume_resuspended);
11304  tcase_add_test(tc_basic, test_cdata_default);
11305  tcase_add_test(tc_basic, test_subordinate_reset);
11306  tcase_add_test(tc_basic, test_subordinate_suspend);
11307  tcase_add_test(tc_basic, test_subordinate_xdecl_suspend);
11308  tcase_add_test(tc_basic, test_subordinate_xdecl_abort);
11309  tcase_add_test(tc_basic, test_explicit_encoding);
11310  tcase_add_test(tc_basic, test_trailing_cr);
11311  tcase_add_test(tc_basic, test_ext_entity_trailing_cr);
11312  tcase_add_test(tc_basic, test_trailing_rsqb);
11313  tcase_add_test(tc_basic, test_ext_entity_trailing_rsqb);
11314  tcase_add_test(tc_basic, test_ext_entity_good_cdata);
11315  tcase_add_test(tc_basic, test_user_parameters);
11316  tcase_add_test(tc_basic, test_ext_entity_ref_parameter);
11317  tcase_add_test(tc_basic, test_empty_parse);
11318  tcase_add_test(tc_basic, test_get_buffer_1);
11319  tcase_add_test(tc_basic, test_get_buffer_2);
11320  tcase_add_test(tc_basic, test_byte_info_at_end);
11321  tcase_add_test(tc_basic, test_byte_info_at_error);
11322  tcase_add_test(tc_basic, test_byte_info_at_cdata);
11323  tcase_add_test(tc_basic, test_predefined_entities);
11324  tcase_add_test(tc_basic, test_invalid_tag_in_dtd);
11325  tcase_add_test(tc_basic, test_not_predefined_entities);
11326  tcase_add_test(tc_basic, test_ignore_section);
11327  tcase_add_test(tc_basic, test_ignore_section_utf16);
11328  tcase_add_test(tc_basic, test_ignore_section_utf16_be);
11329  tcase_add_test(tc_basic, test_bad_ignore_section);
11330  tcase_add_test(tc_basic, test_external_entity_values);
11331  tcase_add_test(tc_basic, test_ext_entity_not_standalone);
11332  tcase_add_test(tc_basic, test_ext_entity_value_abort);
11333  tcase_add_test(tc_basic, test_bad_public_doctype);
11334  tcase_add_test(tc_basic, test_attribute_enum_value);
11335  tcase_add_test(tc_basic, test_predefined_entity_redefinition);
11336  tcase_add_test(tc_basic, test_dtd_stop_processing);
11337  tcase_add_test(tc_basic, test_public_notation_no_sysid);
11338  tcase_add_test(tc_basic, test_nested_groups);
11339  tcase_add_test(tc_basic, test_group_choice);
11340  tcase_add_test(tc_basic, test_standalone_parameter_entity);
11341  tcase_add_test(tc_basic, test_skipped_parameter_entity);
11342  tcase_add_test(tc_basic, test_recursive_external_parameter_entity);
11343  tcase_add_test(tc_basic, test_undefined_ext_entity_in_external_dtd);
11344  tcase_add_test(tc_basic, test_suspend_xdecl);
11345  tcase_add_test(tc_basic, test_abort_epilog);
11346  tcase_add_test(tc_basic, test_abort_epilog_2);
11347  tcase_add_test(tc_basic, test_suspend_epilog);
11348  tcase_add_test(tc_basic, test_suspend_in_sole_empty_tag);
11349  tcase_add_test(tc_basic, test_unfinished_epilog);
11350  tcase_add_test(tc_basic, test_partial_char_in_epilog);
11351  tcase_add_test(tc_basic, test_hash_collision);
11352  tcase_add_test(tc_basic, test_suspend_resume_internal_entity);
11353  tcase_add_test(tc_basic, test_resume_entity_with_syntax_error);
11354  tcase_add_test(tc_basic, test_suspend_resume_parameter_entity);
11355  tcase_add_test(tc_basic, test_restart_on_error);
11356  tcase_add_test(tc_basic, test_reject_lt_in_attribute_value);
11357  tcase_add_test(tc_basic, test_reject_unfinished_param_in_att_value);
11358  tcase_add_test(tc_basic, test_trailing_cr_in_att_value);
11359  tcase_add_test(tc_basic, test_standalone_internal_entity);
11360  tcase_add_test(tc_basic, test_skipped_external_entity);
11361  tcase_add_test(tc_basic, test_skipped_null_loaded_ext_entity);
11362  tcase_add_test(tc_basic, test_skipped_unloaded_ext_entity);
11363  tcase_add_test(tc_basic, test_param_entity_with_trailing_cr);
11364  tcase_add_test(tc_basic, test_invalid_character_entity);
11365  tcase_add_test(tc_basic, test_invalid_character_entity_2);
11366  tcase_add_test(tc_basic, test_invalid_character_entity_3);
11367  tcase_add_test(tc_basic, test_invalid_character_entity_4);
11368  tcase_add_test(tc_basic, test_pi_handled_in_default);
11369  tcase_add_test(tc_basic, test_comment_handled_in_default);
11370  tcase_add_test(tc_basic, test_pi_yml);
11371  tcase_add_test(tc_basic, test_pi_xnl);
11372  tcase_add_test(tc_basic, test_pi_xmm);
11373  tcase_add_test(tc_basic, test_utf16_pi);
11374  tcase_add_test(tc_basic, test_utf16_be_pi);
11375  tcase_add_test(tc_basic, test_utf16_be_comment);
11376  tcase_add_test(tc_basic, test_utf16_le_comment);
11377  tcase_add_test(tc_basic, test_missing_encoding_conversion_fn);
11378  tcase_add_test(tc_basic, test_failing_encoding_conversion_fn);
11379  tcase_add_test(tc_basic, test_unknown_encoding_success);
11380  tcase_add_test(tc_basic, test_unknown_encoding_bad_name);
11381  tcase_add_test(tc_basic, test_unknown_encoding_bad_name_2);
11382  tcase_add_test(tc_basic, test_unknown_encoding_long_name_1);
11383  tcase_add_test(tc_basic, test_unknown_encoding_long_name_2);
11384  tcase_add_test(tc_basic, test_invalid_unknown_encoding);
11385  tcase_add_test(tc_basic, test_unknown_ascii_encoding_ok);
11386  tcase_add_test(tc_basic, test_unknown_ascii_encoding_fail);
11387  tcase_add_test(tc_basic, test_unknown_encoding_invalid_length);
11388  tcase_add_test(tc_basic, test_unknown_encoding_invalid_topbit);
11389  tcase_add_test(tc_basic, test_unknown_encoding_invalid_surrogate);
11390  tcase_add_test(tc_basic, test_unknown_encoding_invalid_high);
11391  tcase_add_test(tc_basic, test_unknown_encoding_invalid_attr_value);
11392  tcase_add_test(tc_basic, test_ext_entity_latin1_utf16le_bom);
11393  tcase_add_test(tc_basic, test_ext_entity_latin1_utf16be_bom);
11394  tcase_add_test(tc_basic, test_ext_entity_latin1_utf16le_bom2);
11395  tcase_add_test(tc_basic, test_ext_entity_latin1_utf16be_bom2);
11396  tcase_add_test(tc_basic, test_ext_entity_utf16_be);
11397  tcase_add_test(tc_basic, test_ext_entity_utf16_le);
11398  tcase_add_test(tc_basic, test_ext_entity_utf16_unknown);
11399  tcase_add_test(tc_basic, test_ext_entity_utf8_non_bom);
11400  tcase_add_test(tc_basic, test_utf8_in_cdata_section);
11401  tcase_add_test(tc_basic, test_utf8_in_cdata_section_2);
11402  tcase_add_test(tc_basic, test_trailing_spaces_in_elements);
11403  tcase_add_test(tc_basic, test_utf16_attribute);
11404  tcase_add_test(tc_basic, test_utf16_second_attr);
11405  tcase_add_test(tc_basic, test_attr_after_solidus);
11406  tcase_add_test(tc_basic, test_utf16_pe);
11407  tcase_add_test(tc_basic, test_bad_attr_desc_keyword);
11408  tcase_add_test(tc_basic, test_bad_attr_desc_keyword_utf16);
11409  tcase_add_test(tc_basic, test_bad_doctype);
11410  tcase_add_test(tc_basic, test_bad_doctype_utf16);
11411  tcase_add_test(tc_basic, test_bad_doctype_plus);
11412  tcase_add_test(tc_basic, test_bad_doctype_star);
11413  tcase_add_test(tc_basic, test_bad_doctype_query);
11414  tcase_add_test(tc_basic, test_unknown_encoding_bad_ignore);
11415  tcase_add_test(tc_basic, test_entity_in_utf16_be_attr);
11416  tcase_add_test(tc_basic, test_entity_in_utf16_le_attr);
11417  tcase_add_test(tc_basic, test_entity_public_utf16_be);
11418  tcase_add_test(tc_basic, test_entity_public_utf16_le);
11419  tcase_add_test(tc_basic, test_short_doctype);
11420  tcase_add_test(tc_basic, test_short_doctype_2);
11421  tcase_add_test(tc_basic, test_short_doctype_3);
11422  tcase_add_test(tc_basic, test_long_doctype);
11423  tcase_add_test(tc_basic, test_bad_entity);
11424  tcase_add_test(tc_basic, test_bad_entity_2);
11425  tcase_add_test(tc_basic, test_bad_entity_3);
11426  tcase_add_test(tc_basic, test_bad_entity_4);
11427  tcase_add_test(tc_basic, test_bad_notation);
11428  tcase_add_test(tc_basic, test_default_doctype_handler);
11429  tcase_add_test(tc_basic, test_empty_element_abort);
11430
11431  suite_add_tcase(s, tc_namespace);
11432  tcase_add_checked_fixture(tc_namespace, namespace_setup, namespace_teardown);
11433  tcase_add_test(tc_namespace, test_return_ns_triplet);
11434  tcase_add_test(tc_namespace, test_ns_tagname_overwrite);
11435  tcase_add_test(tc_namespace, test_ns_tagname_overwrite_triplet);
11436  tcase_add_test(tc_namespace, test_start_ns_clears_start_element);
11437  tcase_add_test(tc_namespace, test_default_ns_from_ext_subset_and_ext_ge);
11438  tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_1);
11439  tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_2);
11440  tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_3);
11441  tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_4);
11442  tcase_add_test(tc_namespace, test_ns_unbound_prefix);
11443  tcase_add_test(tc_namespace, test_ns_default_with_empty_uri);
11444  tcase_add_test(tc_namespace, test_ns_duplicate_attrs_diff_prefixes);
11445  tcase_add_test(tc_namespace, test_ns_duplicate_hashes);
11446  tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_attribute);
11447  tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_element);
11448  tcase_add_test(tc_namespace, test_ns_parser_reset);
11449  tcase_add_test(tc_namespace, test_ns_long_element);
11450  tcase_add_test(tc_namespace, test_ns_mixed_prefix_atts);
11451  tcase_add_test(tc_namespace, test_ns_extend_uri_buffer);
11452  tcase_add_test(tc_namespace, test_ns_reserved_attributes);
11453  tcase_add_test(tc_namespace, test_ns_reserved_attributes_2);
11454  tcase_add_test(tc_namespace, test_ns_extremely_long_prefix);
11455  tcase_add_test(tc_namespace, test_ns_unknown_encoding_success);
11456  tcase_add_test(tc_namespace, test_ns_double_colon);
11457  tcase_add_test(tc_namespace, test_ns_double_colon_element);
11458  tcase_add_test(tc_namespace, test_ns_bad_attr_leafname);
11459  tcase_add_test(tc_namespace, test_ns_bad_element_leafname);
11460  tcase_add_test(tc_namespace, test_ns_utf16_leafname);
11461  tcase_add_test(tc_namespace, test_ns_utf16_element_leafname);
11462  tcase_add_test(tc_namespace, test_ns_utf16_doctype);
11463  tcase_add_test(tc_namespace, test_ns_invalid_doctype);
11464  tcase_add_test(tc_namespace, test_ns_double_colon_doctype);
11465
11466  suite_add_tcase(s, tc_misc);
11467  tcase_add_checked_fixture(tc_misc, NULL, basic_teardown);
11468  tcase_add_test(tc_misc, test_misc_alloc_create_parser);
11469  tcase_add_test(tc_misc, test_misc_alloc_create_parser_with_encoding);
11470  tcase_add_test(tc_misc, test_misc_null_parser);
11471  tcase_add_test(tc_misc, test_misc_error_string);
11472  tcase_add_test(tc_misc, test_misc_version);
11473  tcase_add_test(tc_misc, test_misc_features);
11474  tcase_add_test(tc_misc, test_misc_attribute_leak);
11475  tcase_add_test(tc_misc, test_misc_utf16le);
11476  tcase_add_test(tc_misc, test_misc_stop_during_end_handler_issue_240_1);
11477  tcase_add_test(tc_misc, test_misc_stop_during_end_handler_issue_240_2);
11478#ifdef XML_DTD
11479  tcase_add_test(tc_misc,
11480                 test_misc_deny_internal_entity_closing_doctype_issue_317);
11481#endif
11482
11483  suite_add_tcase(s, tc_alloc);
11484  tcase_add_checked_fixture(tc_alloc, alloc_setup, alloc_teardown);
11485  tcase_add_test(tc_alloc, test_alloc_parse_xdecl);
11486  tcase_add_test(tc_alloc, test_alloc_parse_xdecl_2);
11487  tcase_add_test(tc_alloc, test_alloc_parse_pi);
11488  tcase_add_test(tc_alloc, test_alloc_parse_pi_2);
11489  tcase_add_test(tc_alloc, test_alloc_parse_pi_3);
11490  tcase_add_test(tc_alloc, test_alloc_parse_comment);
11491  tcase_add_test(tc_alloc, test_alloc_parse_comment_2);
11492  tcase_add_test(tc_alloc, test_alloc_create_external_parser);
11493  tcase_add_test(tc_alloc, test_alloc_run_external_parser);
11494  tcase_add_test(tc_alloc, test_alloc_dtd_copy_default_atts);
11495  tcase_add_test(tc_alloc, test_alloc_external_entity);
11496  tcase_add_test(tc_alloc, test_alloc_ext_entity_set_encoding);
11497  tcase_add_test(tc_alloc, test_alloc_internal_entity);
11498  tcase_add_test(tc_alloc, test_alloc_dtd_default_handling);
11499  tcase_add_test(tc_alloc, test_alloc_explicit_encoding);
11500  tcase_add_test(tc_alloc, test_alloc_set_base);
11501  tcase_add_test(tc_alloc, test_alloc_realloc_buffer);
11502  tcase_add_test(tc_alloc, test_alloc_ext_entity_realloc_buffer);
11503  tcase_add_test(tc_alloc, test_alloc_realloc_many_attributes);
11504  tcase_add_test(tc_alloc, test_alloc_public_entity_value);
11505  tcase_add_test(tc_alloc, test_alloc_realloc_subst_public_entity_value);
11506  tcase_add_test(tc_alloc, test_alloc_parse_public_doctype);
11507  tcase_add_test(tc_alloc, test_alloc_parse_public_doctype_long_name);
11508  tcase_add_test(tc_alloc, test_alloc_set_foreign_dtd);
11509  tcase_add_test(tc_alloc, test_alloc_attribute_enum_value);
11510  tcase_add_test(tc_alloc, test_alloc_realloc_attribute_enum_value);
11511  tcase_add_test(tc_alloc, test_alloc_realloc_implied_attribute);
11512  tcase_add_test(tc_alloc, test_alloc_realloc_default_attribute);
11513  tcase_add_test(tc_alloc, test_alloc_notation);
11514  tcase_add_test(tc_alloc, test_alloc_public_notation);
11515  tcase_add_test(tc_alloc, test_alloc_system_notation);
11516  tcase_add_test(tc_alloc, test_alloc_nested_groups);
11517  tcase_add_test(tc_alloc, test_alloc_realloc_nested_groups);
11518  tcase_add_test(tc_alloc, test_alloc_large_group);
11519  tcase_add_test(tc_alloc, test_alloc_realloc_group_choice);
11520  tcase_add_test(tc_alloc, test_alloc_pi_in_epilog);
11521  tcase_add_test(tc_alloc, test_alloc_comment_in_epilog);
11522  tcase_add_test(tc_alloc, test_alloc_realloc_long_attribute_value);
11523  tcase_add_test(tc_alloc, test_alloc_attribute_whitespace);
11524  tcase_add_test(tc_alloc, test_alloc_attribute_predefined_entity);
11525  tcase_add_test(tc_alloc, test_alloc_long_attr_default_with_char_ref);
11526  tcase_add_test(tc_alloc, test_alloc_long_attr_value);
11527  tcase_add_test(tc_alloc, test_alloc_nested_entities);
11528  tcase_add_test(tc_alloc, test_alloc_realloc_param_entity_newline);
11529  tcase_add_test(tc_alloc, test_alloc_realloc_ce_extends_pe);
11530  tcase_add_test(tc_alloc, test_alloc_realloc_attributes);
11531  tcase_add_test(tc_alloc, test_alloc_long_doc_name);
11532  tcase_add_test(tc_alloc, test_alloc_long_base);
11533  tcase_add_test(tc_alloc, test_alloc_long_public_id);
11534  tcase_add_test(tc_alloc, test_alloc_long_entity_value);
11535  tcase_add_test(tc_alloc, test_alloc_long_notation);
11536
11537  suite_add_tcase(s, tc_nsalloc);
11538  tcase_add_checked_fixture(tc_nsalloc, nsalloc_setup, nsalloc_teardown);
11539  tcase_add_test(tc_nsalloc, test_nsalloc_xmlns);
11540  tcase_add_test(tc_nsalloc, test_nsalloc_parse_buffer);
11541  tcase_add_test(tc_nsalloc, test_nsalloc_long_prefix);
11542  tcase_add_test(tc_nsalloc, test_nsalloc_long_uri);
11543  tcase_add_test(tc_nsalloc, test_nsalloc_long_attr);
11544  tcase_add_test(tc_nsalloc, test_nsalloc_long_attr_prefix);
11545  tcase_add_test(tc_nsalloc, test_nsalloc_realloc_attributes);
11546  tcase_add_test(tc_nsalloc, test_nsalloc_long_element);
11547  tcase_add_test(tc_nsalloc, test_nsalloc_realloc_binding_uri);
11548  tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_prefix);
11549  tcase_add_test(tc_nsalloc, test_nsalloc_realloc_longer_prefix);
11550  tcase_add_test(tc_nsalloc, test_nsalloc_long_namespace);
11551  tcase_add_test(tc_nsalloc, test_nsalloc_less_long_namespace);
11552  tcase_add_test(tc_nsalloc, test_nsalloc_long_context);
11553  tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context);
11554  tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_2);
11555  tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_3);
11556  tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_4);
11557  tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_5);
11558  tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_6);
11559  tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_7);
11560  tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_ge_name);
11561  tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_in_dtd);
11562  tcase_add_test(tc_nsalloc, test_nsalloc_long_default_in_ext);
11563  tcase_add_test(tc_nsalloc, test_nsalloc_long_systemid_in_ext);
11564  tcase_add_test(tc_nsalloc, test_nsalloc_prefixed_element);
11565
11566  return s;
11567}
11568
11569int
11570main(int argc, char *argv[]) {
11571  int i, nf;
11572  int verbosity = CK_NORMAL;
11573  Suite *s = make_suite();
11574  SRunner *sr = srunner_create(s);
11575
11576  /* run the tests for internal helper functions */
11577  testhelper_is_whitespace_normalized();
11578
11579  for (i = 1; i < argc; ++i) {
11580    char *opt = argv[i];
11581    if (strcmp(opt, "-v") == 0 || strcmp(opt, "--verbose") == 0)
11582      verbosity = CK_VERBOSE;
11583    else if (strcmp(opt, "-q") == 0 || strcmp(opt, "--quiet") == 0)
11584      verbosity = CK_SILENT;
11585    else {
11586      fprintf(stderr, "runtests: unknown option '%s'\n", opt);
11587      return 2;
11588    }
11589  }
11590  if (verbosity != CK_SILENT)
11591    printf("Expat version: %" XML_FMT_STR "\n", XML_ExpatVersion());
11592  srunner_run_all(sr, verbosity);
11593  nf = srunner_ntests_failed(sr);
11594  srunner_free(sr);
11595
11596  return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
11597}
11598