xref: /freebsd/contrib/expat/tests/handlers.c (revision 22c3edb31297a79ec3c7bf8f906be2df11b472d2)
1 /* XML handler functions for the Expat test suite
2                             __  __            _
3                          ___\ \/ /_ __   __ _| |_
4                         / _ \\  /| '_ \ / _` | __|
5                        |  __//  \| |_) | (_| | |_
6                         \___/_/\_\ .__/ \__,_|\__|
7                                  |_| XML parser
8 
9    Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
10    Copyright (c) 2003      Greg Stein <gstein@users.sourceforge.net>
11    Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
12    Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
13    Copyright (c) 2016-2026 Sebastian Pipping <sebastian@pipping.org>
14    Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
15    Copyright (c) 2017      Joe Orton <jorton@redhat.com>
16    Copyright (c) 2017      José Gutiérrez de la Concha <jose@zeroc.com>
17    Copyright (c) 2018      Marco Maggi <marco.maggi-ipsu@poste.it>
18    Copyright (c) 2019      David Loffredo <loffredo@steptools.com>
19    Copyright (c) 2020      Tim Gates <tim.gates@iress.com>
20    Copyright (c) 2021      Donghee Na <donghee.na@python.org>
21    Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
22    Copyright (c) 2026      Matthew Fernandez <matthew.fernandez@gmail.com>
23    Copyright (c) 2026      Berkay Eren Ürün <berkay.ueruen@siemens.com>
24    Copyright (c) 2026      Kartik Kenchi <netliomax25@gmail.com>
25    Licensed under the MIT license:
26 
27    Permission is  hereby granted,  free of charge,  to any  person obtaining
28    a  copy  of  this  software   and  associated  documentation  files  (the
29    "Software"),  to  deal in  the  Software  without restriction,  including
30    without  limitation the  rights  to use,  copy,  modify, merge,  publish,
31    distribute, sublicense, and/or sell copies of the Software, and to permit
32    persons  to whom  the Software  is  furnished to  do so,  subject to  the
33    following conditions:
34 
35    The above copyright  notice and this permission notice  shall be included
36    in all copies or substantial portions of the Software.
37 
38    THE  SOFTWARE  IS  PROVIDED  "AS  IS",  WITHOUT  WARRANTY  OF  ANY  KIND,
39    EXPRESS  OR IMPLIED,  INCLUDING  BUT  NOT LIMITED  TO  THE WARRANTIES  OF
40    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
41    NO EVENT SHALL THE AUTHORS OR  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
42    DAMAGES OR  OTHER LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT,  TORT OR
43    OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
44    USE OR OTHER DEALINGS IN THE SOFTWARE.
45 
46    SPDX-License-Identifier: MIT
47 */
48 
49 #if defined(NDEBUG)
50 #  undef NDEBUG /* because test suite relies on assert(...) at the moment */
51 #endif
52 
53 #include "expat_config.h"
54 
55 #include <stdint.h>
56 #include <stdio.h>
57 #include <string.h>
58 #include <assert.h>
59 
60 #include "expat.h"
61 #include "internal.h"
62 #include "chardata.h"
63 #include "structdata.h"
64 #include "common.h"
65 #include "handlers.h"
66 #include "../lib/xcs.h"
67 
68 /* Global variables for user parameter settings tests */
69 /* Variable holding the expected handler userData */
70 const void *g_handler_data = NULL;
71 /* Count of the number of times the comment handler has been invoked */
72 int g_comment_count = 0;
73 /* Count of the number of skipped entities */
74 int g_skip_count = 0;
75 /* Count of the number of times the XML declaration handler is invoked */
76 int g_xdecl_count = 0;
77 
78 /* Start/End Element Handlers */
79 
80 void XMLCALL
81 start_element_event_handler(void *userData, const XML_Char *name,
82                             const XML_Char **atts) {
83   UNUSED_P(atts);
84   CharData_AppendXMLChars((CharData *)userData, name, -1);
85 }
86 
87 void XMLCALL
88 end_element_event_handler(void *userData, const XML_Char *name) {
89   CharData *storage = (CharData *)userData;
90   CharData_AppendXMLChars(storage, XCS("/"), 1);
91   CharData_AppendXMLChars(storage, name, -1);
92 }
93 
94 void XMLCALL
95 start_element_event_handler2(void *userData, const XML_Char *name,
96                              const XML_Char **attr) {
97   StructData *storage = (StructData *)userData;
98   UNUSED_P(attr);
99   StructData_AddItem(storage, name, (int)XML_GetCurrentColumnNumber64(g_parser),
100                      (int)XML_GetCurrentLineNumber64(g_parser),
101                      STRUCT_START_TAG);
102 }
103 
104 void XMLCALL
105 end_element_event_handler2(void *userData, const XML_Char *name) {
106   StructData *storage = (StructData *)userData;
107   StructData_AddItem(storage, name, (int)XML_GetCurrentColumnNumber64(g_parser),
108                      (int)XML_GetCurrentLineNumber64(g_parser), STRUCT_END_TAG);
109 }
110 
111 void XMLCALL
112 counting_start_element_handler(void *userData, const XML_Char *name,
113                                const XML_Char **atts) {
114   ParserAndElementInfo *const parserAndElementInfos
115       = (ParserAndElementInfo *)userData;
116   ElementInfo *info = parserAndElementInfos->info;
117   AttrInfo *attr;
118   int count, id, i;
119 
120   while (info->name != NULL) {
121     if (! xcscmp(name, info->name))
122       break;
123     info++;
124   }
125   if (info->name == NULL)
126     fail("Element not recognised");
127   /* The attribute count is twice what you might expect.  It is a
128    * count of items in atts, an array which contains alternating
129    * attribute names and attribute values.  For the naive user this
130    * is possibly a little unexpected, but it is what the
131    * documentation in expat.h tells us to expect.
132    */
133   count = XML_GetSpecifiedAttributeCount(parserAndElementInfos->parser);
134   if (info->attr_count * 2 != count) {
135     fail("Not got expected attribute count");
136     return;
137   }
138   id = XML_GetIdAttributeIndex(parserAndElementInfos->parser);
139   if (id == -1 && info->id_name != NULL) {
140     fail("ID not present");
141     return;
142   }
143   if (id != -1 && xcscmp(atts[id], info->id_name) != 0) {
144     fail("ID does not have the correct name");
145     return;
146   }
147   for (i = 0; i < info->attr_count + info->default_attr_count; i++) {
148     attr = info->attributes;
149     while (attr->name != NULL) {
150       if (! xcscmp(atts[0], attr->name))
151         break;
152       attr++;
153     }
154     if (attr->name == NULL) {
155       fail("Attribute not recognised");
156       return;
157     }
158     if (xcscmp(atts[1], attr->value) != 0) {
159       fail("Attribute has wrong value");
160       return;
161     }
162     /* Remember, two entries in atts per attribute (see above) */
163     atts += 2;
164   }
165 
166   // Self-test that the test case's list of expected attributes is complete
167   assert_true(atts[0] == NULL);
168 }
169 
170 void XMLCALL
171 suspending_end_handler(void *userData, const XML_Char *s) {
172   UNUSED_P(s);
173   XML_StopParser((XML_Parser)userData, 1);
174 }
175 
176 void XMLCALL
177 start_element_suspender(void *userData, const XML_Char *name,
178                         const XML_Char **atts) {
179   UNUSED_P(userData);
180   UNUSED_P(atts);
181   if (! xcscmp(name, XCS("suspend")))
182     XML_StopParser(g_parser, XML_TRUE);
183   if (! xcscmp(name, XCS("abort")))
184     XML_StopParser(g_parser, XML_FALSE);
185 }
186 
187 /* Check that an element name and attribute name match the expected values.
188    The expected values are passed as an array reference of string pointers
189    provided as the userData argument; the first is the expected
190    element name, and the second is the expected attribute name.
191 */
192 int g_triplet_start_flag = XML_FALSE;
193 int g_triplet_end_flag = XML_FALSE;
194 
195 void XMLCALL
196 triplet_start_checker(void *userData, const XML_Char *name,
197                       const XML_Char **atts) {
198   XML_Char **elemstr = (XML_Char **)userData;
199   char buffer[1024];
200   if (xcscmp(elemstr[0], name) != 0) {
201     snprintf(buffer, sizeof(buffer),
202              "unexpected start string: '%" XML_FMT_STR "'", name);
203     fail(buffer);
204   }
205   if (xcscmp(elemstr[1], atts[0]) != 0) {
206     snprintf(buffer, sizeof(buffer),
207              "unexpected attribute string: '%" XML_FMT_STR "'", atts[0]);
208     fail(buffer);
209   }
210   g_triplet_start_flag = XML_TRUE;
211 }
212 
213 /* Check that the element name passed to the end-element handler matches
214    the expected value.  The expected value is passed as the first element
215    in an array of strings passed as the userData argument.
216 */
217 void XMLCALL
218 triplet_end_checker(void *userData, const XML_Char *name) {
219   XML_Char **elemstr = (XML_Char **)userData;
220   if (xcscmp(elemstr[0], name) != 0) {
221     char buffer[1024];
222     snprintf(buffer, sizeof(buffer),
223              "unexpected end string: '%" XML_FMT_STR "'", name);
224     fail(buffer);
225   }
226   g_triplet_end_flag = XML_TRUE;
227 }
228 
229 void XMLCALL
230 overwrite_start_checker(void *userData, const XML_Char *name,
231                         const XML_Char **atts) {
232   CharData *storage = (CharData *)userData;
233   CharData_AppendXMLChars(storage, XCS("start "), 6);
234   CharData_AppendXMLChars(storage, name, -1);
235   while (*atts != NULL) {
236     CharData_AppendXMLChars(storage, XCS("\nattribute "), 11);
237     CharData_AppendXMLChars(storage, *atts, -1);
238     atts += 2;
239   }
240   CharData_AppendXMLChars(storage, XCS("\n"), 1);
241 }
242 
243 void XMLCALL
244 overwrite_end_checker(void *userData, const XML_Char *name) {
245   CharData *storage = (CharData *)userData;
246   CharData_AppendXMLChars(storage, XCS("end "), 4);
247   CharData_AppendXMLChars(storage, name, -1);
248   CharData_AppendXMLChars(storage, XCS("\n"), 1);
249 }
250 
251 void XMLCALL
252 start_element_fail(void *userData, const XML_Char *name,
253                    const XML_Char **atts) {
254   UNUSED_P(userData);
255   UNUSED_P(name);
256   UNUSED_P(atts);
257 
258   /* We should never get here. */
259   fail("should never reach start_element_fail()");
260 }
261 
262 void XMLCALL
263 start_ns_clearing_start_element(void *userData, const XML_Char *prefix,
264                                 const XML_Char *uri) {
265   UNUSED_P(prefix);
266   UNUSED_P(uri);
267   XML_SetStartElementHandler((XML_Parser)userData, NULL);
268 }
269 
270 void XMLCALL
271 start_element_issue_240(void *userData, const XML_Char *name,
272                         const XML_Char **atts) {
273   DataIssue240 *mydata = (DataIssue240 *)userData;
274   UNUSED_P(name);
275   UNUSED_P(atts);
276   mydata->deep++;
277 }
278 
279 void XMLCALL
280 end_element_issue_240(void *userData, const XML_Char *name) {
281   DataIssue240 *mydata = (DataIssue240 *)userData;
282 
283   UNUSED_P(name);
284   mydata->deep--;
285   if (mydata->deep == 0) {
286     XML_StopParser(mydata->parser, 0);
287   }
288 }
289 
290 /* Text encoding handlers */
291 
292 int XMLCALL
293 UnknownEncodingHandler(void *data, const XML_Char *encoding,
294                        XML_Encoding *info) {
295   UNUSED_P(data);
296   if (xcscmp(encoding, XCS("unsupported-encoding")) == 0) {
297     int i;
298     for (i = 0; i < 256; ++i)
299       info->map[i] = i;
300     info->data = NULL;
301     info->convert = NULL;
302     info->release = NULL;
303     return XML_STATUS_OK;
304   }
305   return XML_STATUS_ERROR;
306 }
307 
308 static void
309 dummy_release(void *data) {
310   UNUSED_P(data);
311 }
312 
313 int XMLCALL
314 UnrecognisedEncodingHandler(void *data, const XML_Char *encoding,
315                             XML_Encoding *info) {
316   UNUSED_P(data);
317   UNUSED_P(encoding);
318   info->data = NULL;
319   info->convert = NULL;
320   info->release = dummy_release;
321   return XML_STATUS_ERROR;
322 }
323 
324 int XMLCALL
325 unknown_released_encoding_handler(void *data, const XML_Char *encoding,
326                                   XML_Encoding *info) {
327   UNUSED_P(data);
328   if (! xcscmp(encoding, XCS("unsupported-encoding"))) {
329     int i;
330 
331     for (i = 0; i < 256; i++)
332       info->map[i] = i;
333     info->data = NULL;
334     info->convert = NULL;
335     info->release = dummy_release;
336     return XML_STATUS_OK;
337   }
338   return XML_STATUS_ERROR;
339 }
340 
341 static int XMLCALL
342 failing_converter(void *data, const char *s) {
343   UNUSED_P(data);
344   UNUSED_P(s);
345   /* Always claim to have failed */
346   return -1;
347 }
348 
349 static int XMLCALL
350 prefix_converter(void *data, const char *s) {
351   UNUSED_P(data);
352   /* If the first byte is 0xff, raise an error */
353   if (s[0] == (char)-1)
354     return -1;
355   /* Just add the low bits of the first byte to the second */
356   return (s[1] + (s[0] & 0x7f)) & 0x01ff;
357 }
358 
359 int XMLCALL
360 MiscEncodingHandler(void *data, const XML_Char *encoding, XML_Encoding *info) {
361   int i;
362   int high_map = -2; /* Assume a 2-byte sequence */
363 
364   if (! xcscmp(encoding, XCS("invalid-9"))
365       || ! xcscmp(encoding, XCS("ascii-like"))
366       || ! xcscmp(encoding, XCS("invalid-len"))
367       || ! xcscmp(encoding, XCS("invalid-a"))
368       || ! xcscmp(encoding, XCS("invalid-surrogate"))
369       || ! xcscmp(encoding, XCS("invalid-high")))
370     high_map = -1;
371 
372   for (i = 0; i < 128; ++i)
373     info->map[i] = i;
374   for (; i < 256; ++i)
375     info->map[i] = high_map;
376 
377   /* If required, put an invalid value in the ASCII entries */
378   if (! xcscmp(encoding, XCS("invalid-9")))
379     info->map[9] = 5;
380   /* If required, have a top-bit set character starts a 5-byte sequence */
381   if (! xcscmp(encoding, XCS("invalid-len")))
382     info->map[0x81] = -5;
383   /* If required, make a top-bit set character a valid ASCII character */
384   if (! xcscmp(encoding, XCS("invalid-a")))
385     info->map[0x82] = 'a';
386   /* If required, give a top-bit set character a forbidden value,
387    * what would otherwise be the first of a surrogate pair.
388    */
389   if (! xcscmp(encoding, XCS("invalid-surrogate")))
390     info->map[0x83] = 0xd801;
391   /* If required, give a top-bit set character too high a value */
392   if (! xcscmp(encoding, XCS("invalid-high")))
393     info->map[0x84] = 0x010101;
394 
395   info->data = data;
396   info->release = NULL;
397   if (! xcscmp(encoding, XCS("failing-conv")))
398     info->convert = failing_converter;
399   else if (! xcscmp(encoding, XCS("prefix-conv")))
400     info->convert = prefix_converter;
401   else
402     info->convert = NULL;
403   return XML_STATUS_OK;
404 }
405 
406 int XMLCALL
407 long_encoding_handler(void *userData, const XML_Char *encoding,
408                       XML_Encoding *info) {
409   int i;
410 
411   UNUSED_P(userData);
412   UNUSED_P(encoding);
413   for (i = 0; i < 256; i++)
414     info->map[i] = i;
415   info->data = NULL;
416   info->convert = NULL;
417   info->release = NULL;
418   return XML_STATUS_OK;
419 }
420 
421 int XMLCALL
422 user_data_checking_unknown_encoding_handler(void *userData,
423                                             const XML_Char *encoding,
424                                             XML_Encoding *info) {
425   const intptr_t number = (intptr_t)userData;
426   assert_true(number == 0xC0FFEE);
427   return long_encoding_handler(userData, encoding, info);
428 }
429 
430 /* External Entity Handlers */
431 
432 int XMLCALL
433 external_entity_optioner(XML_Parser parser, const XML_Char *context,
434                          const XML_Char *base, const XML_Char *systemId,
435                          const XML_Char *publicId) {
436   ExtOption *options = XML_GetUserData(parser);
437   XML_Parser ext_parser;
438 
439   UNUSED_P(base);
440   UNUSED_P(publicId);
441   while (options->parse_text != NULL) {
442     if (! xcscmp(systemId, options->system_id)) {
443       enum XML_Status rc;
444       ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
445       if (ext_parser == NULL)
446         return XML_STATUS_ERROR;
447       rc = _XML_Parse_SINGLE_BYTES(ext_parser, options->parse_text,
448                                    (int)strlen(options->parse_text), XML_TRUE);
449       XML_ParserFree(ext_parser);
450       return rc;
451     }
452     options++;
453   }
454   fail("No suitable option found");
455   return XML_STATUS_ERROR;
456 }
457 
458 int XMLCALL
459 external_entity_loader(XML_Parser parser, const XML_Char *context,
460                        const XML_Char *base, const XML_Char *systemId,
461                        const XML_Char *publicId) {
462   ExtTest *test_data = XML_GetUserData(parser);
463   XML_Parser extparser;
464 
465   UNUSED_P(base);
466   UNUSED_P(systemId);
467   UNUSED_P(publicId);
468   extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
469   if (extparser == NULL)
470     fail("Could not create external entity parser.");
471   if (test_data->encoding != NULL) {
472     if (! XML_SetEncoding(extparser, test_data->encoding))
473       fail("XML_SetEncoding() ignored for external entity");
474   }
475   if (_XML_Parse_SINGLE_BYTES(extparser, test_data->parse_text,
476                               (int)strlen(test_data->parse_text), XML_TRUE)
477       == XML_STATUS_ERROR) {
478     xml_failure(extparser);
479     return XML_STATUS_ERROR;
480   }
481   XML_ParserFree(extparser);
482   return XML_STATUS_OK;
483 }
484 
485 int XMLCALL
486 external_entity_faulter(XML_Parser parser, const XML_Char *context,
487                         const XML_Char *base, const XML_Char *systemId,
488                         const XML_Char *publicId) {
489   XML_Parser ext_parser;
490   ExtFaults *fault = XML_GetUserData(parser);
491 
492   UNUSED_P(base);
493   UNUSED_P(systemId);
494   UNUSED_P(publicId);
495   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
496   if (ext_parser == NULL)
497     fail("Could not create external entity parser");
498   if (fault->encoding != NULL) {
499     if (! XML_SetEncoding(ext_parser, fault->encoding))
500       fail("XML_SetEncoding failed");
501   }
502   if (_XML_Parse_SINGLE_BYTES(ext_parser, fault->parse_text,
503                               (int)strlen(fault->parse_text), XML_TRUE)
504       != XML_STATUS_ERROR)
505     fail(fault->fail_text);
506   if (XML_GetErrorCode(ext_parser) != fault->error)
507     xml_failure(ext_parser);
508 
509   XML_ParserFree(ext_parser);
510   return XML_STATUS_ERROR;
511 }
512 
513 int XMLCALL
514 external_entity_null_loader(XML_Parser parser, const XML_Char *context,
515                             const XML_Char *base, const XML_Char *systemId,
516                             const XML_Char *publicId) {
517   UNUSED_P(parser);
518   UNUSED_P(context);
519   UNUSED_P(base);
520   UNUSED_P(systemId);
521   UNUSED_P(publicId);
522   return XML_STATUS_OK;
523 }
524 
525 int XMLCALL
526 external_entity_resetter(XML_Parser parser, const XML_Char *context,
527                          const XML_Char *base, const XML_Char *systemId,
528                          const XML_Char *publicId) {
529   const char *text = "<!ELEMENT doc (#PCDATA)*>";
530   XML_Parser ext_parser;
531   XML_ParsingStatus status;
532 
533   UNUSED_P(base);
534   UNUSED_P(systemId);
535   UNUSED_P(publicId);
536   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
537   if (ext_parser == NULL)
538     fail("Could not create external entity parser");
539   XML_GetParsingStatus(ext_parser, &status);
540   if (status.parsing != XML_INITIALIZED) {
541     fail("Parsing status is not INITIALIZED");
542     return XML_STATUS_ERROR;
543   }
544   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
545       == XML_STATUS_ERROR) {
546     xml_failure(parser);
547     return XML_STATUS_ERROR;
548   }
549   XML_GetParsingStatus(ext_parser, &status);
550   if (status.parsing != XML_FINISHED) {
551     fail("Parsing status is not FINISHED");
552     return XML_STATUS_ERROR;
553   }
554   /* Check we can't parse here */
555   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
556       != XML_STATUS_ERROR)
557     fail("Parsing when finished not faulted");
558   if (XML_GetErrorCode(ext_parser) != XML_ERROR_FINISHED)
559     fail("Parsing when finished faulted with wrong code");
560   XML_ParserReset(ext_parser, NULL);
561   XML_GetParsingStatus(ext_parser, &status);
562   if (status.parsing != XML_FINISHED) {
563     fail("Parsing status not still FINISHED");
564     return XML_STATUS_ERROR;
565   }
566   XML_ParserFree(ext_parser);
567   return XML_STATUS_OK;
568 }
569 
570 void XMLCALL
571 entity_suspending_decl_handler(void *userData, const XML_Char *name,
572                                XML_Content *model) {
573   XML_Parser ext_parser = (XML_Parser)userData;
574 
575   UNUSED_P(name);
576   if (XML_StopParser(ext_parser, XML_TRUE) != XML_STATUS_ERROR)
577     fail("Attempting to suspend a subordinate parser not faulted");
578   if (XML_GetErrorCode(ext_parser) != XML_ERROR_SUSPEND_PE)
579     fail("Suspending subordinate parser get wrong code");
580   XML_SetElementDeclHandler(ext_parser, NULL);
581   XML_FreeContentModel(g_parser, model);
582 }
583 
584 int XMLCALL
585 external_entity_suspender(XML_Parser parser, const XML_Char *context,
586                           const XML_Char *base, const XML_Char *systemId,
587                           const XML_Char *publicId) {
588   const char *text = "<!ELEMENT doc (#PCDATA)*>";
589   XML_Parser ext_parser;
590 
591   UNUSED_P(base);
592   UNUSED_P(systemId);
593   UNUSED_P(publicId);
594   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
595   if (ext_parser == NULL)
596     fail("Could not create external entity parser");
597   XML_SetElementDeclHandler(ext_parser, entity_suspending_decl_handler);
598   XML_SetUserData(ext_parser, ext_parser);
599   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
600       == XML_STATUS_ERROR) {
601     xml_failure(ext_parser);
602     return XML_STATUS_ERROR;
603   }
604   XML_ParserFree(ext_parser);
605   return XML_STATUS_OK;
606 }
607 
608 void XMLCALL
609 entity_suspending_xdecl_handler(void *userData, const XML_Char *version,
610                                 const XML_Char *encoding, int standalone) {
611   XML_Parser ext_parser = (XML_Parser)userData;
612 
613   UNUSED_P(version);
614   UNUSED_P(encoding);
615   UNUSED_P(standalone);
616   XML_StopParser(ext_parser, g_resumable);
617   XML_SetXmlDeclHandler(ext_parser, NULL);
618 }
619 
620 int XMLCALL
621 external_entity_suspend_xmldecl(XML_Parser parser, const XML_Char *context,
622                                 const XML_Char *base, const XML_Char *systemId,
623                                 const XML_Char *publicId) {
624   const char *text = "<?xml version='1.0' encoding='us-ascii'?>";
625   XML_Parser ext_parser;
626   XML_ParsingStatus status;
627   enum XML_Status rc;
628 
629   UNUSED_P(base);
630   UNUSED_P(systemId);
631   UNUSED_P(publicId);
632   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
633   if (ext_parser == NULL)
634     fail("Could not create external entity parser");
635   XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler);
636   XML_SetUserData(ext_parser, ext_parser);
637   rc = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
638   XML_GetParsingStatus(ext_parser, &status);
639   if (g_resumable) {
640     if (rc == XML_STATUS_ERROR)
641       xml_failure(ext_parser);
642     if (status.parsing != XML_SUSPENDED)
643       fail("Ext Parsing status not SUSPENDED");
644   } else {
645     if (rc != XML_STATUS_ERROR)
646       fail("Ext parsing not aborted");
647     if (XML_GetErrorCode(ext_parser) != XML_ERROR_ABORTED)
648       xml_failure(ext_parser);
649     if (status.parsing != XML_FINISHED)
650       fail("Ext Parsing status not FINISHED");
651   }
652 
653   XML_ParserFree(ext_parser);
654   return XML_STATUS_OK;
655 }
656 
657 int XMLCALL
658 external_entity_suspending_faulter(XML_Parser parser, const XML_Char *context,
659                                    const XML_Char *base,
660                                    const XML_Char *systemId,
661                                    const XML_Char *publicId) {
662   XML_Parser ext_parser;
663   ExtFaults *fault = XML_GetUserData(parser);
664   void *buffer;
665   int parse_len = (int)strlen(fault->parse_text);
666 
667   UNUSED_P(base);
668   UNUSED_P(systemId);
669   UNUSED_P(publicId);
670   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
671   if (ext_parser == NULL)
672     fail("Could not create external entity parser");
673   XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler);
674   XML_SetUserData(ext_parser, ext_parser);
675   g_resumable = XML_TRUE;
676   buffer = XML_GetBuffer(ext_parser, parse_len);
677   if (buffer == NULL)
678     fail("Could not allocate parse buffer");
679   assert(buffer != NULL);
680   memcpy(buffer, fault->parse_text, parse_len);
681   if (XML_ParseBuffer(ext_parser, parse_len, XML_FALSE) != XML_STATUS_SUSPENDED)
682     fail("XML declaration did not suspend");
683   if (XML_ResumeParser(ext_parser) != XML_STATUS_OK)
684     xml_failure(ext_parser);
685   if (XML_ParseBuffer(ext_parser, 0, XML_TRUE) != XML_STATUS_ERROR)
686     fail(fault->fail_text);
687   if (XML_GetErrorCode(ext_parser) != fault->error)
688     xml_failure(ext_parser);
689 
690   XML_ParserFree(ext_parser);
691   return XML_STATUS_ERROR;
692 }
693 
694 int XMLCALL
695 external_entity_failer__if_not_xml_ge(XML_Parser parser,
696                                       const XML_Char *context,
697                                       const XML_Char *base,
698                                       const XML_Char *systemId,
699                                       const XML_Char *publicId) {
700   UNUSED_P(parser);
701   UNUSED_P(context);
702   UNUSED_P(base);
703   UNUSED_P(systemId);
704   UNUSED_P(publicId);
705 #if XML_GE == 0
706   fail(
707       "Function external_entity_suspending_failer was called despite XML_GE==0.");
708 #endif
709   return XML_STATUS_OK;
710 }
711 
712 int XMLCALL
713 external_entity_cr_catcher(XML_Parser parser, const XML_Char *context,
714                            const XML_Char *base, const XML_Char *systemId,
715                            const XML_Char *publicId) {
716   const char *text = "\r";
717   XML_Parser ext_parser;
718 
719   UNUSED_P(base);
720   UNUSED_P(systemId);
721   UNUSED_P(publicId);
722   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
723   if (ext_parser == NULL)
724     fail("Could not create external entity parser");
725   XML_SetCharacterDataHandler(ext_parser, cr_cdata_handler);
726   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
727       == XML_STATUS_ERROR)
728     xml_failure(ext_parser);
729   XML_ParserFree(ext_parser);
730   return XML_STATUS_OK;
731 }
732 
733 int XMLCALL
734 external_entity_bad_cr_catcher(XML_Parser parser, const XML_Char *context,
735                                const XML_Char *base, const XML_Char *systemId,
736                                const XML_Char *publicId) {
737   const char *text = "<tag>\r";
738   XML_Parser ext_parser;
739 
740   UNUSED_P(base);
741   UNUSED_P(systemId);
742   UNUSED_P(publicId);
743   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
744   if (ext_parser == NULL)
745     fail("Could not create external entity parser");
746   XML_SetCharacterDataHandler(ext_parser, cr_cdata_handler);
747   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
748       == XML_STATUS_OK)
749     fail("Async entity error not caught");
750   if (XML_GetErrorCode(ext_parser) != XML_ERROR_ASYNC_ENTITY)
751     xml_failure(ext_parser);
752   XML_ParserFree(ext_parser);
753   return XML_STATUS_OK;
754 }
755 
756 int XMLCALL
757 external_entity_rsqb_catcher(XML_Parser parser, const XML_Char *context,
758                              const XML_Char *base, const XML_Char *systemId,
759                              const XML_Char *publicId) {
760   const char *text = "<tag>]";
761   XML_Parser ext_parser;
762 
763   UNUSED_P(base);
764   UNUSED_P(systemId);
765   UNUSED_P(publicId);
766   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
767   if (ext_parser == NULL)
768     fail("Could not create external entity parser");
769   XML_SetCharacterDataHandler(ext_parser, rsqb_handler);
770   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
771       != XML_STATUS_ERROR)
772     fail("Async entity error not caught");
773   if (XML_GetErrorCode(ext_parser) != XML_ERROR_ASYNC_ENTITY)
774     xml_failure(ext_parser);
775   XML_ParserFree(ext_parser);
776   return XML_STATUS_OK;
777 }
778 
779 int XMLCALL
780 external_entity_good_cdata_ascii(XML_Parser parser, const XML_Char *context,
781                                  const XML_Char *base, const XML_Char *systemId,
782                                  const XML_Char *publicId) {
783   const char *text = "<a><![CDATA[<greeting>Hello, world!</greeting>]]></a>";
784   const XML_Char *expected = XCS("<greeting>Hello, world!</greeting>");
785   CharData storage;
786   XML_Parser ext_parser;
787 
788   UNUSED_P(base);
789   UNUSED_P(systemId);
790   UNUSED_P(publicId);
791   CharData_Init(&storage);
792   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
793   if (ext_parser == NULL)
794     fail("Could not create external entity parser");
795   XML_SetUserData(ext_parser, &storage);
796   XML_SetCharacterDataHandler(ext_parser, accumulate_characters);
797 
798   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
799       == XML_STATUS_ERROR)
800     xml_failure(ext_parser);
801   CharData_CheckXMLChars(&storage, expected);
802 
803   XML_ParserFree(ext_parser);
804   return XML_STATUS_OK;
805 }
806 
807 int XMLCALL
808 external_entity_param_checker(XML_Parser parser, const XML_Char *context,
809                               const XML_Char *base, const XML_Char *systemId,
810                               const XML_Char *publicId) {
811   const char *text = "<!-- Subordinate parser -->\n"
812                      "<!ELEMENT doc (#PCDATA)*>";
813   XML_Parser ext_parser;
814 
815   UNUSED_P(base);
816   UNUSED_P(systemId);
817   UNUSED_P(publicId);
818   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
819   if (ext_parser == NULL)
820     fail("Could not create external entity parser");
821   g_handler_data = ext_parser;
822   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
823       == XML_STATUS_ERROR) {
824     xml_failure(parser);
825     return XML_STATUS_ERROR;
826   }
827   g_handler_data = parser;
828   XML_ParserFree(ext_parser);
829   return XML_STATUS_OK;
830 }
831 
832 int XMLCALL
833 external_entity_ref_param_checker(XML_Parser parameter, const XML_Char *context,
834                                   const XML_Char *base,
835                                   const XML_Char *systemId,
836                                   const XML_Char *publicId) {
837   const char *text = "<!ELEMENT doc (#PCDATA)*>";
838   XML_Parser ext_parser;
839 
840   UNUSED_P(base);
841   UNUSED_P(systemId);
842   UNUSED_P(publicId);
843   if ((void *)parameter != g_handler_data)
844     fail("External entity ref handler parameter not correct");
845 
846   /* Here we use the global 'parser' variable */
847   ext_parser = XML_ExternalEntityParserCreate(g_parser, context, NULL);
848   if (ext_parser == NULL)
849     fail("Could not create external entity parser");
850   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
851       == XML_STATUS_ERROR)
852     xml_failure(ext_parser);
853 
854   XML_ParserFree(ext_parser);
855   return XML_STATUS_OK;
856 }
857 
858 int XMLCALL
859 external_entity_param(XML_Parser parser, const XML_Char *context,
860                       const XML_Char *base, const XML_Char *systemId,
861                       const XML_Char *publicId) {
862   const char *text1 = "<!ELEMENT doc EMPTY>\n"
863                       "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
864                       "<!ENTITY % e2 '%e1;'>\n"
865                       "%e1;\n";
866   const char *text2 = "<!ELEMENT el EMPTY>\n"
867                       "<el/>\n";
868   XML_Parser ext_parser;
869 
870   UNUSED_P(base);
871   UNUSED_P(publicId);
872   if (systemId == NULL)
873     return XML_STATUS_OK;
874 
875   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
876   if (ext_parser == NULL)
877     fail("Could not create external entity parser");
878 
879   if (! xcscmp(systemId, XCS("004-1.ent"))) {
880     if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
881         != XML_STATUS_ERROR)
882       fail("Inner DTD with invalid tag not rejected");
883     if (XML_GetErrorCode(ext_parser) != XML_ERROR_EXTERNAL_ENTITY_HANDLING)
884       xml_failure(ext_parser);
885   } else if (! xcscmp(systemId, XCS("004-2.ent"))) {
886     if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
887         != XML_STATUS_ERROR)
888       fail("Invalid tag in external param not rejected");
889     if (XML_GetErrorCode(ext_parser) != XML_ERROR_SYNTAX)
890       xml_failure(ext_parser);
891   } else {
892     fail("Unknown system ID");
893   }
894 
895   XML_ParserFree(ext_parser);
896   return XML_STATUS_ERROR;
897 }
898 
899 int XMLCALL
900 external_entity_load_ignore(XML_Parser parser, const XML_Char *context,
901                             const XML_Char *base, const XML_Char *systemId,
902                             const XML_Char *publicId) {
903   const char *text = "<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>";
904   XML_Parser ext_parser;
905 
906   UNUSED_P(base);
907   UNUSED_P(systemId);
908   UNUSED_P(publicId);
909   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
910   if (ext_parser == NULL)
911     fail("Could not create external entity parser");
912   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
913       == XML_STATUS_ERROR)
914     xml_failure(parser);
915 
916   XML_ParserFree(ext_parser);
917   return XML_STATUS_OK;
918 }
919 
920 int XMLCALL
921 external_entity_load_ignore_utf16(XML_Parser parser, const XML_Char *context,
922                                   const XML_Char *base,
923                                   const XML_Char *systemId,
924                                   const XML_Char *publicId) {
925   const char text[] =
926       /* <![IGNORE[<!ELEMENT e (#PCDATA)*>]]> */
927       "<\0!\0[\0I\0G\0N\0O\0R\0E\0[\0"
928       "<\0!\0E\0L\0E\0M\0E\0N\0T\0 \0e\0 \0"
929       "(\0#\0P\0C\0D\0A\0T\0A\0)\0*\0>\0]\0]\0>\0";
930   XML_Parser ext_parser;
931 
932   UNUSED_P(base);
933   UNUSED_P(systemId);
934   UNUSED_P(publicId);
935   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
936   if (ext_parser == NULL)
937     fail("Could not create external entity parser");
938   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)sizeof(text) - 1, XML_TRUE)
939       == XML_STATUS_ERROR)
940     xml_failure(parser);
941 
942   XML_ParserFree(ext_parser);
943   return XML_STATUS_OK;
944 }
945 
946 int XMLCALL
947 external_entity_load_ignore_utf16_be(XML_Parser parser, const XML_Char *context,
948                                      const XML_Char *base,
949                                      const XML_Char *systemId,
950                                      const XML_Char *publicId) {
951   const char text[] =
952       /* <![IGNORE[<!ELEMENT e (#PCDATA)*>]]> */
953       "\0<\0!\0[\0I\0G\0N\0O\0R\0E\0["
954       "\0<\0!\0E\0L\0E\0M\0E\0N\0T\0 \0e\0 "
955       "\0(\0#\0P\0C\0D\0A\0T\0A\0)\0*\0>\0]\0]\0>";
956   XML_Parser ext_parser;
957 
958   UNUSED_P(base);
959   UNUSED_P(systemId);
960   UNUSED_P(publicId);
961   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
962   if (ext_parser == NULL)
963     fail("Could not create external entity parser");
964   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)sizeof(text) - 1, XML_TRUE)
965       == XML_STATUS_ERROR)
966     xml_failure(parser);
967 
968   XML_ParserFree(ext_parser);
969   return XML_STATUS_OK;
970 }
971 
972 int XMLCALL
973 external_entity_valuer(XML_Parser parser, const XML_Char *context,
974                        const XML_Char *base, const XML_Char *systemId,
975                        const XML_Char *publicId) {
976   const char *text1 = "<!ELEMENT doc EMPTY>\n"
977                       "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
978                       "<!ENTITY % e2 '%e1;'>\n"
979                       "%e1;\n";
980   XML_Parser ext_parser;
981 
982   UNUSED_P(base);
983   UNUSED_P(publicId);
984   if (systemId == NULL)
985     return XML_STATUS_OK;
986   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
987   if (ext_parser == NULL)
988     fail("Could not create external entity parser");
989   if (! xcscmp(systemId, XCS("004-1.ent"))) {
990     if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
991         == XML_STATUS_ERROR)
992       xml_failure(ext_parser);
993   } else if (! xcscmp(systemId, XCS("004-2.ent"))) {
994     ExtFaults *fault = XML_GetUserData(parser);
995     enum XML_Status status;
996     enum XML_Error error;
997 
998     status = _XML_Parse_SINGLE_BYTES(ext_parser, fault->parse_text,
999                                      (int)strlen(fault->parse_text), XML_TRUE);
1000     if (fault->error == XML_ERROR_NONE) {
1001       if (status == XML_STATUS_ERROR)
1002         xml_failure(ext_parser);
1003     } else {
1004       if (status != XML_STATUS_ERROR)
1005         fail(fault->fail_text);
1006       error = XML_GetErrorCode(ext_parser);
1007       if (error != fault->error
1008           && (fault->error != XML_ERROR_XML_DECL
1009               || error != XML_ERROR_TEXT_DECL))
1010         xml_failure(ext_parser);
1011     }
1012   }
1013 
1014   XML_ParserFree(ext_parser);
1015   return XML_STATUS_OK;
1016 }
1017 
1018 int XMLCALL
1019 external_entity_not_standalone(XML_Parser parser, const XML_Char *context,
1020                                const XML_Char *base, const XML_Char *systemId,
1021                                const XML_Char *publicId) {
1022   const char *text1 = "<!ELEMENT doc EMPTY>\n"
1023                       "<!ENTITY % e1 SYSTEM 'bar'>\n"
1024                       "%e1;\n";
1025   const char *text2 = "<!ATTLIST doc a1 CDATA 'value'>";
1026   XML_Parser ext_parser;
1027 
1028   UNUSED_P(base);
1029   UNUSED_P(publicId);
1030   if (systemId == NULL)
1031     return XML_STATUS_OK;
1032   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
1033   if (ext_parser == NULL)
1034     fail("Could not create external entity parser");
1035   if (! xcscmp(systemId, XCS("foo"))) {
1036     XML_SetNotStandaloneHandler(ext_parser, reject_not_standalone_handler);
1037     if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
1038         != XML_STATUS_ERROR)
1039       fail("Expected not standalone rejection");
1040     if (XML_GetErrorCode(ext_parser) != XML_ERROR_NOT_STANDALONE)
1041       xml_failure(ext_parser);
1042     XML_SetNotStandaloneHandler(ext_parser, NULL);
1043     XML_ParserFree(ext_parser);
1044     return XML_STATUS_ERROR;
1045   } else if (! xcscmp(systemId, XCS("bar"))) {
1046     if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
1047         == XML_STATUS_ERROR)
1048       xml_failure(ext_parser);
1049   }
1050 
1051   XML_ParserFree(ext_parser);
1052   return XML_STATUS_OK;
1053 }
1054 
1055 int XMLCALL
1056 external_entity_value_aborter(XML_Parser parser, const XML_Char *context,
1057                               const XML_Char *base, const XML_Char *systemId,
1058                               const XML_Char *publicId) {
1059   const char *text1 = "<!ELEMENT doc EMPTY>\n"
1060                       "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
1061                       "<!ENTITY % e2 '%e1;'>\n"
1062                       "%e1;\n";
1063   const char *text2 = "<?xml version='1.0' encoding='utf-8'?>";
1064   XML_Parser ext_parser;
1065 
1066   UNUSED_P(base);
1067   UNUSED_P(publicId);
1068   if (systemId == NULL)
1069     return XML_STATUS_OK;
1070   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
1071   if (ext_parser == NULL)
1072     fail("Could not create external entity parser");
1073   if (! xcscmp(systemId, XCS("004-1.ent"))) {
1074     if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
1075         == XML_STATUS_ERROR)
1076       xml_failure(ext_parser);
1077   }
1078   if (! xcscmp(systemId, XCS("004-2.ent"))) {
1079     XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler);
1080     XML_SetUserData(ext_parser, ext_parser);
1081     if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
1082         != XML_STATUS_ERROR)
1083       fail("Aborted parse not faulted");
1084     if (XML_GetErrorCode(ext_parser) != XML_ERROR_ABORTED)
1085       xml_failure(ext_parser);
1086   }
1087 
1088   XML_ParserFree(ext_parser);
1089   return XML_STATUS_OK;
1090 }
1091 
1092 int XMLCALL
1093 external_entity_public(XML_Parser parser, const XML_Char *context,
1094                        const XML_Char *base, const XML_Char *systemId,
1095                        const XML_Char *publicId) {
1096   const char *text1 = XML_GetUserData(parser);
1097   const char *text2 = "<!ATTLIST doc a CDATA 'value'>";
1098   const char *text = NULL;
1099   XML_Parser ext_parser;
1100   int parse_res;
1101 
1102   UNUSED_P(base);
1103   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
1104   if (ext_parser == NULL)
1105     return XML_STATUS_ERROR;
1106   if (systemId != NULL && ! xcscmp(systemId, XCS("http://example.org/"))) {
1107     text = text1;
1108   } else if (publicId != NULL && ! xcscmp(publicId, XCS("foo"))) {
1109     text = text2;
1110   } else
1111     fail("Unexpected parameters to external entity parser");
1112   assert(text != NULL);
1113   parse_res
1114       = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
1115   XML_ParserFree(ext_parser);
1116   return parse_res;
1117 }
1118 
1119 int XMLCALL
1120 external_entity_devaluer(XML_Parser parser, const XML_Char *context,
1121                          const XML_Char *base, const XML_Char *systemId,
1122                          const XML_Char *publicId) {
1123   const char *text = "<!ELEMENT doc EMPTY>\n"
1124                      "<!ENTITY % e1 SYSTEM 'bar'>\n"
1125                      "%e1;\n";
1126   XML_Parser ext_parser;
1127   int clear_handler_flag = (XML_GetUserData(parser) != NULL);
1128 
1129   UNUSED_P(base);
1130   UNUSED_P(publicId);
1131   if (systemId == NULL || ! xcscmp(systemId, XCS("bar")))
1132     return XML_STATUS_OK;
1133   if (xcscmp(systemId, XCS("foo")) != 0)
1134     fail("Unexpected system ID");
1135   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
1136   if (ext_parser == NULL)
1137     fail("Could note create external entity parser");
1138   if (clear_handler_flag)
1139     XML_SetExternalEntityRefHandler(ext_parser, NULL);
1140   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
1141       == XML_STATUS_ERROR)
1142     xml_failure(ext_parser);
1143 
1144   XML_ParserFree(ext_parser);
1145   return XML_STATUS_OK;
1146 }
1147 
1148 int XMLCALL
1149 external_entity_oneshot_loader(XML_Parser parser, const XML_Char *context,
1150                                const XML_Char *base, const XML_Char *systemId,
1151                                const XML_Char *publicId) {
1152   ExtHdlrData *test_data = XML_GetUserData(parser);
1153   XML_Parser ext_parser;
1154 
1155   UNUSED_P(base);
1156   UNUSED_P(systemId);
1157   UNUSED_P(publicId);
1158   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
1159   if (ext_parser == NULL)
1160     fail("Could not create external entity parser.");
1161   /* Use the requested entity parser for further externals */
1162   XML_SetExternalEntityRefHandler(ext_parser, test_data->handler);
1163   if (_XML_Parse_SINGLE_BYTES(ext_parser, test_data->parse_text,
1164                               (int)strlen(test_data->parse_text), XML_TRUE)
1165       == XML_STATUS_ERROR) {
1166     xml_failure(ext_parser);
1167   }
1168 
1169   XML_ParserFree(ext_parser);
1170   return XML_STATUS_OK;
1171 }
1172 
1173 int XMLCALL
1174 external_entity_loader2(XML_Parser parser, const XML_Char *context,
1175                         const XML_Char *base, const XML_Char *systemId,
1176                         const XML_Char *publicId) {
1177   ExtTest2 *test_data = XML_GetUserData(parser);
1178   XML_Parser extparser;
1179 
1180   UNUSED_P(base);
1181   UNUSED_P(systemId);
1182   UNUSED_P(publicId);
1183   extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
1184   if (extparser == NULL)
1185     fail("Coulr not create external entity parser");
1186   if (test_data->encoding != NULL) {
1187     if (! XML_SetEncoding(extparser, test_data->encoding))
1188       fail("XML_SetEncoding() ignored for external entity");
1189   }
1190   if (_XML_Parse_SINGLE_BYTES(extparser, test_data->parse_text,
1191                               test_data->parse_len, XML_TRUE)
1192       == XML_STATUS_ERROR) {
1193     xml_failure(extparser);
1194   }
1195 
1196   XML_ParserFree(extparser);
1197   return XML_STATUS_OK;
1198 }
1199 
1200 int XMLCALL
1201 external_entity_faulter2(XML_Parser parser, const XML_Char *context,
1202                          const XML_Char *base, const XML_Char *systemId,
1203                          const XML_Char *publicId) {
1204   ExtFaults2 *test_data = XML_GetUserData(parser);
1205   XML_Parser extparser;
1206 
1207   UNUSED_P(base);
1208   UNUSED_P(systemId);
1209   UNUSED_P(publicId);
1210   extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
1211   if (extparser == NULL)
1212     fail("Could not create external entity parser");
1213   if (test_data->encoding != NULL) {
1214     if (! XML_SetEncoding(extparser, test_data->encoding))
1215       fail("XML_SetEncoding() ignored for external entity");
1216   }
1217   if (_XML_Parse_SINGLE_BYTES(extparser, test_data->parse_text,
1218                               test_data->parse_len, XML_TRUE)
1219       != XML_STATUS_ERROR)
1220     fail(test_data->fail_text);
1221   if (XML_GetErrorCode(extparser) != test_data->error)
1222     xml_failure(extparser);
1223 
1224   XML_ParserFree(extparser);
1225   return XML_STATUS_ERROR;
1226 }
1227 
1228 int XMLCALL
1229 external_entity_unfinished_attlist(XML_Parser parser, const XML_Char *context,
1230                                    const XML_Char *base,
1231                                    const XML_Char *systemId,
1232                                    const XML_Char *publicId) {
1233   const char *text = "<!ELEMENT barf ANY>\n"
1234                      "<!ATTLIST barf my_attr (blah|%blah;a|foo) #REQUIRED>\n"
1235                      "<!--COMMENT-->\n";
1236   XML_Parser ext_parser;
1237 
1238   UNUSED_P(base);
1239   UNUSED_P(publicId);
1240   if (systemId == NULL)
1241     return XML_STATUS_OK;
1242 
1243   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
1244   if (ext_parser == NULL)
1245     fail("Could not create external entity parser");
1246 
1247   if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
1248       == XML_STATUS_ERROR)
1249     xml_failure(ext_parser);
1250 
1251   XML_ParserFree(ext_parser);
1252   return XML_STATUS_OK;
1253 }
1254 
1255 int XMLCALL
1256 external_entity_handler(XML_Parser parser, const XML_Char *context,
1257                         const XML_Char *base, const XML_Char *systemId,
1258                         const XML_Char *publicId) {
1259   void *user_data = XML_GetUserData(parser);
1260   const char *text;
1261   XML_Parser p2;
1262 
1263   UNUSED_P(base);
1264   UNUSED_P(systemId);
1265   UNUSED_P(publicId);
1266   if (user_data == NULL)
1267     text = ("<!ELEMENT doc (e+)>\n"
1268             "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
1269             "<!ELEMENT e EMPTY>\n");
1270   else
1271     text = ("<?xml version='1.0' encoding='us-ascii'?>"
1272             "<e/>");
1273 
1274   /* Set user data to any non-NULL value */
1275   XML_SetUserData(parser, parser);
1276   p2 = XML_ExternalEntityParserCreate(parser, context, NULL);
1277   if (_XML_Parse_SINGLE_BYTES(p2, text, (int)strlen(text), XML_TRUE)
1278       == XML_STATUS_ERROR) {
1279     xml_failure(p2);
1280     return XML_STATUS_ERROR;
1281   }
1282   XML_ParserFree(p2);
1283   return XML_STATUS_OK;
1284 }
1285 
1286 int XMLCALL
1287 external_entity_duff_loader(XML_Parser parser, const XML_Char *context,
1288                             const XML_Char *base, const XML_Char *systemId,
1289                             const XML_Char *publicId) {
1290   XML_Parser new_parser;
1291   unsigned int i;
1292   const unsigned int max_alloc_count = 10;
1293 
1294   UNUSED_P(base);
1295   UNUSED_P(systemId);
1296   UNUSED_P(publicId);
1297   /* Try a few different allocation levels */
1298   for (i = 0; i < max_alloc_count; i++) {
1299     g_allocation_count = (int)i;
1300     new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
1301     if (new_parser != NULL) {
1302       XML_ParserFree(new_parser);
1303       break;
1304     }
1305   }
1306   if (i == 0)
1307     fail("External parser creation ignored failing allocator");
1308   else if (i == max_alloc_count)
1309     fail("Extern parser not created with max allocation count");
1310 
1311   /* Make sure other random allocation doesn't now fail */
1312   g_allocation_count = ALLOC_ALWAYS_SUCCEED;
1313 
1314   /* Make sure the failure code path is executed too */
1315   return XML_STATUS_ERROR;
1316 }
1317 
1318 int XMLCALL
1319 external_entity_dbl_handler(XML_Parser parser, const XML_Char *context,
1320                             const XML_Char *base, const XML_Char *systemId,
1321                             const XML_Char *publicId) {
1322   int *pcallno = XML_GetUserData(parser);
1323   int callno = *pcallno;
1324   const char *text;
1325   XML_Parser new_parser = NULL;
1326   int i;
1327   const int max_alloc_count = 20;
1328 
1329   UNUSED_P(base);
1330   UNUSED_P(systemId);
1331   UNUSED_P(publicId);
1332   if (callno == 0) {
1333     /* First time through, check how many calls to malloc occur */
1334     text = ("<!ELEMENT doc (e+)>\n"
1335             "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
1336             "<!ELEMENT e EMPTY>\n");
1337     g_allocation_count = 10000;
1338     new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
1339     if (new_parser == NULL) {
1340       fail("Unable to allocate first external parser");
1341       return XML_STATUS_ERROR;
1342     }
1343     /* Stash the number of calls in the user data */
1344     *pcallno = 10000 - g_allocation_count;
1345   } else {
1346     text = ("<?xml version='1.0' encoding='us-ascii'?>"
1347             "<e/>");
1348     /* Try at varying levels to exercise more code paths */
1349     for (i = 0; i < max_alloc_count; i++) {
1350       g_allocation_count = callno + i;
1351       new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
1352       if (new_parser != NULL)
1353         break;
1354     }
1355     if (i == 0) {
1356       fail("Second external parser unexpectedly created");
1357       XML_ParserFree(new_parser);
1358       return XML_STATUS_ERROR;
1359     } else if (i == max_alloc_count) {
1360       fail("Second external parser not created");
1361       return XML_STATUS_ERROR;
1362     }
1363   }
1364 
1365   g_allocation_count = ALLOC_ALWAYS_SUCCEED;
1366   if (_XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE)
1367       == XML_STATUS_ERROR) {
1368     xml_failure(new_parser);
1369     return XML_STATUS_ERROR;
1370   }
1371   XML_ParserFree(new_parser);
1372   return XML_STATUS_OK;
1373 }
1374 
1375 int XMLCALL
1376 external_entity_dbl_handler_2(XML_Parser parser, const XML_Char *context,
1377                               const XML_Char *base, const XML_Char *systemId,
1378                               const XML_Char *publicId) {
1379   int *pcallno = XML_GetUserData(parser);
1380   int callno = *pcallno;
1381   const char *text;
1382   XML_Parser new_parser;
1383   enum XML_Status rv;
1384 
1385   UNUSED_P(base);
1386   UNUSED_P(systemId);
1387   UNUSED_P(publicId);
1388   if (callno == 0) {
1389     /* Try different allocation levels for whole exercise */
1390     text = ("<!ELEMENT doc (e+)>\n"
1391             "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
1392             "<!ELEMENT e EMPTY>\n");
1393     *pcallno = 1;
1394     new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
1395     if (new_parser == NULL)
1396       return XML_STATUS_ERROR;
1397     rv = _XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE);
1398   } else {
1399     /* Just run through once */
1400     text = ("<?xml version='1.0' encoding='us-ascii'?>"
1401             "<e/>");
1402     new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
1403     if (new_parser == NULL)
1404       return XML_STATUS_ERROR;
1405     rv = _XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE);
1406   }
1407   XML_ParserFree(new_parser);
1408   if (rv == XML_STATUS_ERROR)
1409     return XML_STATUS_ERROR;
1410   return XML_STATUS_OK;
1411 }
1412 
1413 int XMLCALL
1414 external_entity_alloc_set_encoding(XML_Parser parser, const XML_Char *context,
1415                                    const XML_Char *base,
1416                                    const XML_Char *systemId,
1417                                    const XML_Char *publicId) {
1418   /* As for external_entity_loader() */
1419   const char *text = "<?xml encoding='iso-8859-3'?>"
1420                      "\xC3\xA9";
1421   XML_Parser ext_parser;
1422   enum XML_Status status;
1423 
1424   UNUSED_P(base);
1425   UNUSED_P(systemId);
1426   UNUSED_P(publicId);
1427   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
1428   if (ext_parser == NULL)
1429     return XML_STATUS_ERROR;
1430   if (! XML_SetEncoding(ext_parser, XCS("utf-8"))) {
1431     XML_ParserFree(ext_parser);
1432     return XML_STATUS_ERROR;
1433   }
1434   status
1435       = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
1436   XML_ParserFree(ext_parser);
1437   if (status == XML_STATUS_ERROR)
1438     return XML_STATUS_ERROR;
1439   return XML_STATUS_OK;
1440 }
1441 
1442 int XMLCALL
1443 external_entity_reallocator(XML_Parser parser, const XML_Char *context,
1444                             const XML_Char *base, const XML_Char *systemId,
1445                             const XML_Char *publicId) {
1446   const char *text = get_buffer_test_text;
1447   XML_Parser ext_parser;
1448   void *buffer;
1449   enum XML_Status status;
1450 
1451   UNUSED_P(base);
1452   UNUSED_P(systemId);
1453   UNUSED_P(publicId);
1454   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
1455   if (ext_parser == NULL)
1456     fail("Could not create external entity parser");
1457 
1458   g_reallocation_count = *(int *)XML_GetUserData(parser);
1459   buffer = XML_GetBuffer(ext_parser, 1536);
1460   if (buffer == NULL)
1461     fail("Buffer allocation failed");
1462   assert(buffer != NULL);
1463   memcpy(buffer, text, strlen(text));
1464   status = XML_ParseBuffer(ext_parser, (int)strlen(text), XML_FALSE);
1465   g_reallocation_count = -1;
1466   XML_ParserFree(ext_parser);
1467   return (status == XML_STATUS_OK) ? XML_STATUS_OK : XML_STATUS_ERROR;
1468 }
1469 
1470 int XMLCALL
1471 external_entity_alloc(XML_Parser parser, const XML_Char *context,
1472                       const XML_Char *base, const XML_Char *systemId,
1473                       const XML_Char *publicId) {
1474   const char *text = XML_GetUserData(parser);
1475   XML_Parser ext_parser;
1476   int parse_res;
1477 
1478   UNUSED_P(base);
1479   UNUSED_P(systemId);
1480   UNUSED_P(publicId);
1481   ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
1482   if (ext_parser == NULL)
1483     return XML_STATUS_ERROR;
1484   parse_res
1485       = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
1486   XML_ParserFree(ext_parser);
1487   return parse_res;
1488 }
1489 
1490 int XMLCALL
1491 external_entity_parser_create_alloc_fail_handler(XML_Parser parser,
1492                                                  const XML_Char *context,
1493                                                  const XML_Char *base,
1494                                                  const XML_Char *systemId,
1495                                                  const XML_Char *publicId) {
1496   UNUSED_P(base);
1497   UNUSED_P(systemId);
1498   UNUSED_P(publicId);
1499 
1500   if (context != NULL)
1501     fail("Unexpected non-NULL context");
1502 
1503   // The following number intends to fail the upcoming allocation in line
1504   // "parser->m_protocolEncodingName = copyString(encodingName,
1505   // &(parser->m_mem));" in function parserInit.
1506   g_allocation_count = 3;
1507 
1508   const XML_Char *const encodingName = XCS("UTF-8"); // needs something non-NULL
1509   const XML_Parser ext_parser
1510       = XML_ExternalEntityParserCreate(parser, context, encodingName);
1511   if (ext_parser != NULL)
1512     fail(
1513         "Call to XML_ExternalEntityParserCreate was expected to fail out-of-memory");
1514 
1515   g_allocation_count = ALLOC_ALWAYS_SUCCEED;
1516   return XML_STATUS_ERROR;
1517 }
1518 
1519 #if XML_GE == 1
1520 int
1521 accounting_external_entity_ref_handler(XML_Parser parser,
1522                                        const XML_Char *context,
1523                                        const XML_Char *base,
1524                                        const XML_Char *systemId,
1525                                        const XML_Char *publicId) {
1526   UNUSED_P(base);
1527   UNUSED_P(publicId);
1528 
1529   const struct AccountingTestCase *const testCase = XML_GetUserData(parser);
1530 
1531   const char *externalText = NULL;
1532   if (xcscmp(systemId, XCS("first.ent")) == 0) {
1533     externalText = testCase->firstExternalText;
1534   } else if (xcscmp(systemId, XCS("second.ent")) == 0) {
1535     externalText = testCase->secondExternalText;
1536   } else {
1537     assert(! "systemId is neither \"first.ent\" nor \"second.ent\"");
1538   }
1539   assert(externalText);
1540 
1541   XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0);
1542   assert(entParser);
1543 
1544   const enum XML_Status status = _XML_Parse_SINGLE_BYTES(
1545       entParser, externalText, (int)strlen(externalText), XML_TRUE);
1546 
1547   XML_ParserFree(entParser);
1548   return status;
1549 }
1550 #endif /* XML_GE == 1 */
1551 
1552 /* NotStandalone handlers */
1553 
1554 int XMLCALL
1555 reject_not_standalone_handler(void *userData) {
1556   UNUSED_P(userData);
1557   return XML_STATUS_ERROR;
1558 }
1559 
1560 int XMLCALL
1561 accept_not_standalone_handler(void *userData) {
1562   UNUSED_P(userData);
1563   return XML_STATUS_OK;
1564 }
1565 
1566 /* Attribute List handlers */
1567 void XMLCALL
1568 verify_attlist_decl_handler(void *userData, const XML_Char *element_name,
1569                             const XML_Char *attr_name,
1570                             const XML_Char *attr_type,
1571                             const XML_Char *default_value, int is_required) {
1572   AttTest *at = (AttTest *)userData;
1573 
1574   if (xcscmp(element_name, at->element_name) != 0)
1575     fail("Unexpected element name in attribute declaration");
1576   if (xcscmp(attr_name, at->attr_name) != 0)
1577     fail("Unexpected attribute name in attribute declaration");
1578   if (xcscmp(attr_type, at->attr_type) != 0)
1579     fail("Unexpected attribute type in attribute declaration");
1580   if ((default_value == NULL && at->default_value != NULL)
1581       || (default_value != NULL && at->default_value == NULL)
1582       || (default_value != NULL
1583           && xcscmp(default_value, at->default_value) != 0))
1584     fail("Unexpected default value in attribute declaration");
1585   if (is_required != at->is_required)
1586     fail("Requirement mismatch in attribute declaration");
1587 }
1588 
1589 /* Character Data handlers */
1590 
1591 void XMLCALL
1592 clearing_aborting_character_handler(void *userData, const XML_Char *s,
1593                                     int len) {
1594   UNUSED_P(userData);
1595   UNUSED_P(s);
1596   UNUSED_P(len);
1597   XML_StopParser(g_parser, g_resumable);
1598   XML_SetCharacterDataHandler(g_parser, NULL);
1599 }
1600 
1601 void XMLCALL
1602 parser_stop_character_handler(void *userData, const XML_Char *s, int len) {
1603   UNUSED_P(userData);
1604   UNUSED_P(s);
1605   UNUSED_P(len);
1606   XML_ParsingStatus status;
1607   XML_GetParsingStatus(g_parser, &status);
1608   if (status.parsing == XML_FINISHED) {
1609     return; // the parser was stopped by a previous call to this handler.
1610   }
1611   XML_StopParser(g_parser, g_resumable);
1612   XML_SetCharacterDataHandler(g_parser, NULL);
1613   if (! g_resumable) {
1614     /* Check that aborting an aborted parser is faulted */
1615     if (XML_StopParser(g_parser, XML_FALSE) != XML_STATUS_ERROR)
1616       fail("Aborting aborted parser not faulted");
1617     if (XML_GetErrorCode(g_parser) != XML_ERROR_FINISHED)
1618       xml_failure(g_parser);
1619   } else if (g_abortable) {
1620     /* Check that aborting a suspended parser works */
1621     if (XML_StopParser(g_parser, XML_FALSE) == XML_STATUS_ERROR)
1622       xml_failure(g_parser);
1623   } else {
1624     /* Check that suspending a suspended parser works */
1625     if (XML_StopParser(g_parser, XML_TRUE) != XML_STATUS_ERROR)
1626       fail("Suspending suspended parser not faulted");
1627     if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
1628       xml_failure(g_parser);
1629   }
1630 }
1631 
1632 void XMLCALL
1633 cr_cdata_handler(void *userData, const XML_Char *s, int len) {
1634   int *pfound = (int *)userData;
1635 
1636   /* Internal processing turns the CR into a newline for the
1637    * character data handler, but not for the default handler
1638    */
1639   if (len == 1 && (*s == XCS('\n') || *s == XCS('\r')))
1640     *pfound = 1;
1641 }
1642 
1643 void XMLCALL
1644 rsqb_handler(void *userData, const XML_Char *s, int len) {
1645   int *pfound = (int *)userData;
1646 
1647   if (len == 1 && *s == XCS(']'))
1648     *pfound = 1;
1649 }
1650 
1651 void XMLCALL
1652 byte_character_handler(void *userData, const XML_Char *s, int len) {
1653 #if XML_CONTEXT_BYTES > 0
1654   int64_t offset;
1655   uint64_t size;
1656   const char *buffer;
1657   ByteTestData *data = (ByteTestData *)userData;
1658 
1659   UNUSED_P(s);
1660   buffer = XML_GetInputContext64(g_parser, &offset, &size);
1661   if (buffer == NULL)
1662     fail("Failed to get context buffer");
1663   if (offset != data->start_element_len)
1664     fail("Context offset in unexpected position");
1665   if (len != data->cdata_len)
1666     fail("CDATA length reported incorrectly");
1667   if (size != (uint64_t)data->total_string_len)
1668     fail("Context size is not full buffer");
1669   if (XML_GetCurrentByteIndex64(g_parser) != offset)
1670     fail("Character byte index incorrect");
1671   if (XML_GetCurrentByteCount64(g_parser) != (uint64_t)len)
1672     fail("Character byte count incorrect");
1673 #else
1674   UNUSED_P(s);
1675   UNUSED_P(userData);
1676   UNUSED_P(len);
1677 #endif
1678 }
1679 
1680 void XMLCALL
1681 ext2_accumulate_characters(void *userData, const XML_Char *s, int len) {
1682   ExtTest2 *test_data = (ExtTest2 *)userData;
1683   accumulate_characters(test_data->storage, s, len);
1684 }
1685 
1686 /* Handlers that record their function name and int arg. */
1687 
1688 static void
1689 record_call(struct handler_record_list *const rec, const char *funcname,
1690             const int arg) {
1691   const int max_entries = sizeof(rec->entries) / sizeof(rec->entries[0]);
1692   assert_true(rec->count < max_entries);
1693   struct handler_record_entry *const e = &rec->entries[rec->count++];
1694   e->name = funcname;
1695   e->arg = arg;
1696 }
1697 
1698 void XMLCALL
1699 record_default_handler(void *userData, const XML_Char *s, int len) {
1700   UNUSED_P(s);
1701   record_call((struct handler_record_list *)userData, __func__, len);
1702 }
1703 
1704 void XMLCALL
1705 record_cdata_handler(void *userData, const XML_Char *s, int len) {
1706   UNUSED_P(s);
1707   record_call((struct handler_record_list *)userData, __func__, len);
1708   XML_DefaultCurrent(g_parser);
1709 }
1710 
1711 void XMLCALL
1712 record_cdata_nodefault_handler(void *userData, const XML_Char *s, int len) {
1713   UNUSED_P(s);
1714   record_call((struct handler_record_list *)userData, __func__, len);
1715 }
1716 
1717 void XMLCALL
1718 record_skip_handler(void *userData, const XML_Char *entityName,
1719                     int is_parameter_entity) {
1720   UNUSED_P(entityName);
1721   record_call((struct handler_record_list *)userData, __func__,
1722               is_parameter_entity);
1723 }
1724 
1725 void XMLCALL
1726 record_element_start_handler(void *userData, const XML_Char *name,
1727                              const XML_Char **atts) {
1728   UNUSED_P(atts);
1729   CharData_AppendXMLChars((CharData *)userData, name, (int)xcslen(name));
1730 }
1731 
1732 void XMLCALL
1733 record_element_end_handler(void *userData, const XML_Char *name) {
1734   CharData *storage = (CharData *)userData;
1735 
1736   CharData_AppendXMLChars(storage, XCS("/"), 1);
1737   CharData_AppendXMLChars(storage, name, -1);
1738 }
1739 
1740 const struct handler_record_entry *
1741 _handler_record_get(const struct handler_record_list *storage, int index,
1742                     const char *file, int line) {
1743   if (storage->count <= index) {
1744     _fail(file, line, "too few handler calls");
1745   }
1746   return &storage->entries[index];
1747 }
1748 
1749 /* Entity Declaration Handlers */
1750 static const XML_Char *entity_name_to_match = NULL;
1751 static const XML_Char *entity_value_to_match = NULL;
1752 static int entity_match_flag = ENTITY_MATCH_NOT_FOUND;
1753 
1754 void XMLCALL
1755 param_entity_match_handler(void *userData, const XML_Char *entityName,
1756                            int is_parameter_entity, const XML_Char *value,
1757                            int value_length, const XML_Char *base,
1758                            const XML_Char *systemId, const XML_Char *publicId,
1759                            const XML_Char *notationName) {
1760   UNUSED_P(userData);
1761   UNUSED_P(base);
1762   UNUSED_P(systemId);
1763   UNUSED_P(publicId);
1764   UNUSED_P(notationName);
1765   if (! is_parameter_entity || entity_name_to_match == NULL
1766       || entity_value_to_match == NULL) {
1767     return;
1768   }
1769   if (! xcscmp(entityName, entity_name_to_match)) {
1770     /* The cast here is safe because we control the horizontal and
1771      * the vertical, and we therefore know our strings are never
1772      * going to overflow an int.
1773      */
1774     if (value_length != (int)xcslen(entity_value_to_match)
1775         || xcsncmp(value, entity_value_to_match, value_length) != 0) {
1776       entity_match_flag = ENTITY_MATCH_FAIL;
1777     } else {
1778       entity_match_flag = ENTITY_MATCH_SUCCESS;
1779     }
1780   }
1781   /* Else leave the match flag alone */
1782 }
1783 
1784 void
1785 param_entity_match_init(const XML_Char *name, const XML_Char *value) {
1786   entity_name_to_match = name;
1787   entity_value_to_match = value;
1788   entity_match_flag = ENTITY_MATCH_NOT_FOUND;
1789 }
1790 
1791 int
1792 get_param_entity_match_flag(void) {
1793   return entity_match_flag;
1794 }
1795 
1796 /* Misc handlers */
1797 
1798 void XMLCALL
1799 xml_decl_handler(void *userData, const XML_Char *version,
1800                  const XML_Char *encoding, int standalone) {
1801   UNUSED_P(version);
1802   UNUSED_P(encoding);
1803   if (userData != g_handler_data)
1804     fail("User data (xml decl) not correctly set");
1805   if (standalone != -1)
1806     fail("Standalone not flagged as not present in XML decl");
1807   g_xdecl_count++;
1808 }
1809 
1810 void XMLCALL
1811 param_check_skip_handler(void *userData, const XML_Char *entityName,
1812                          int is_parameter_entity) {
1813   UNUSED_P(entityName);
1814   UNUSED_P(is_parameter_entity);
1815   if (userData != g_handler_data)
1816     fail("User data (skip) not correctly set");
1817   g_skip_count++;
1818 }
1819 
1820 void XMLCALL
1821 data_check_comment_handler(void *userData, const XML_Char *data) {
1822   UNUSED_P(data);
1823   /* Check that the userData passed through is what we expect */
1824   if (userData != g_handler_data)
1825     fail("User data (parser) not correctly set");
1826   /* Check that the user data in the parser is appropriate */
1827   if (XML_GetUserData(userData) != (void *)1)
1828     fail("User data in parser not correctly set");
1829   g_comment_count++;
1830 }
1831 
1832 void XMLCALL
1833 selective_aborting_default_handler(void *userData, const XML_Char *s, int len) {
1834   const XML_Char trigger_char = *(const XML_Char *)userData;
1835 
1836   int found = 0;
1837   for (int i = 0; i < len; ++i) {
1838     if (s[i] == trigger_char) {
1839       found = 1;
1840       break;
1841     }
1842   }
1843 
1844   if (found) {
1845     XML_StopParser(g_parser, g_resumable);
1846     XML_SetDefaultHandler(g_parser, NULL);
1847   }
1848 }
1849 
1850 void XMLCALL
1851 suspending_comment_handler(void *userData, const XML_Char *data) {
1852   UNUSED_P(data);
1853   XML_Parser parser = (XML_Parser)userData;
1854   XML_StopParser(parser, XML_TRUE);
1855 }
1856 
1857 void XMLCALL
1858 element_decl_suspender(void *userData, const XML_Char *name,
1859                        XML_Content *model) {
1860   UNUSED_P(userData);
1861   UNUSED_P(name);
1862   XML_StopParser(g_parser, XML_TRUE);
1863   XML_FreeContentModel(g_parser, model);
1864 }
1865 
1866 void XMLCALL
1867 suspend_after_element_declaration(void *userData, const XML_Char *name,
1868                                   XML_Content *model) {
1869   UNUSED_P(name);
1870   XML_Parser parser = (XML_Parser)userData;
1871   assert_true(XML_StopParser(parser, /*resumable*/ XML_TRUE) == XML_STATUS_OK);
1872   XML_FreeContentModel(parser, model);
1873 }
1874 
1875 void XMLCALL
1876 accumulate_pi_characters(void *userData, const XML_Char *target,
1877                          const XML_Char *data) {
1878   CharData *storage = (CharData *)userData;
1879 
1880   CharData_AppendXMLChars(storage, target, -1);
1881   CharData_AppendXMLChars(storage, XCS(": "), 2);
1882   CharData_AppendXMLChars(storage, data, -1);
1883   CharData_AppendXMLChars(storage, XCS("\n"), 1);
1884 }
1885 
1886 void XMLCALL
1887 accumulate_comment(void *userData, const XML_Char *data) {
1888   CharData *storage = (CharData *)userData;
1889 
1890   CharData_AppendXMLChars(storage, data, -1);
1891 }
1892 
1893 void XMLCALL
1894 accumulate_entity_decl(void *userData, const XML_Char *entityName,
1895                        int is_parameter_entity, const XML_Char *value,
1896                        int value_length, const XML_Char *base,
1897                        const XML_Char *systemId, const XML_Char *publicId,
1898                        const XML_Char *notationName) {
1899   CharData *storage = (CharData *)userData;
1900 
1901   UNUSED_P(is_parameter_entity);
1902   UNUSED_P(base);
1903   UNUSED_P(systemId);
1904   UNUSED_P(publicId);
1905   UNUSED_P(notationName);
1906   CharData_AppendXMLChars(storage, entityName, -1);
1907   CharData_AppendXMLChars(storage, XCS("="), 1);
1908   if (value == NULL)
1909     CharData_AppendXMLChars(storage, XCS("(null)"), -1);
1910   else
1911     CharData_AppendXMLChars(storage, value, value_length);
1912   CharData_AppendXMLChars(storage, XCS("\n"), 1);
1913 }
1914 
1915 void XMLCALL
1916 accumulate_char_data_and_suspend(void *userData, const XML_Char *s, int len) {
1917   ParserPlusStorage *const parserPlusStorage = (ParserPlusStorage *)userData;
1918 
1919   CharData_AppendXMLChars(parserPlusStorage->storage, s, len);
1920 
1921   for (int i = 0; i < len; i++) {
1922     if (s[i] == 'Z') {
1923       XML_StopParser(parserPlusStorage->parser, /*resumable=*/XML_TRUE);
1924       break;
1925     }
1926   }
1927 }
1928 
1929 void XMLCALL
1930 accumulate_start_element(void *userData, const XML_Char *name,
1931                          const XML_Char **atts) {
1932   CharData *const storage = (CharData *)userData;
1933   CharData_AppendXMLChars(storage, XCS("("), 1);
1934   CharData_AppendXMLChars(storage, name, -1);
1935 
1936   if ((atts != NULL) && (atts[0] != NULL)) {
1937     CharData_AppendXMLChars(storage, XCS("("), 1);
1938     while (atts[0] != NULL) {
1939       CharData_AppendXMLChars(storage, atts[0], -1);
1940       CharData_AppendXMLChars(storage, XCS("="), 1);
1941       CharData_AppendXMLChars(storage, atts[1], -1);
1942       atts += 2;
1943       if (atts[0] != NULL) {
1944         CharData_AppendXMLChars(storage, XCS(","), 1);
1945       }
1946     }
1947     CharData_AppendXMLChars(storage, XCS(")"), 1);
1948   }
1949 
1950   CharData_AppendXMLChars(storage, XCS(")\n"), 2);
1951 }
1952 
1953 void XMLCALL
1954 accumulate_characters(void *userData, const XML_Char *s, int len) {
1955   CharData *const storage = (CharData *)userData;
1956   CharData_AppendXMLChars(storage, s, len);
1957 }
1958 
1959 void XMLCALL
1960 accumulate_attribute(void *userData, const XML_Char *name,
1961                      const XML_Char **atts) {
1962   CharData *const storage = (CharData *)userData;
1963   UNUSED_P(name);
1964   /* Check there are attributes to deal with */
1965   if (atts == NULL)
1966     return;
1967 
1968   while (storage->count < 0 && atts[0] != NULL) {
1969     /* "accumulate" the value of the first attribute we see */
1970     CharData_AppendXMLChars(storage, atts[1], -1);
1971     atts += 2;
1972   }
1973 }
1974 
1975 void XMLCALL
1976 ext_accumulate_characters(void *userData, const XML_Char *s, int len) {
1977   ExtTest *const test_data = (ExtTest *)userData;
1978   accumulate_characters(test_data->storage, s, len);
1979 }
1980 
1981 void XMLCALL
1982 checking_default_handler(void *userData, const XML_Char *s, int len) {
1983   DefaultCheck *data = (DefaultCheck *)userData;
1984   int i;
1985 
1986   for (i = 0; data[i].expected != NULL; i++) {
1987     if (data[i].expectedLen == len
1988         && ! memcmp(data[i].expected, s, len * sizeof(XML_Char))) {
1989       data[i].seen = XML_TRUE;
1990       break;
1991     }
1992   }
1993 }
1994 
1995 void XMLCALL
1996 accumulate_and_suspend_comment_handler(void *userData, const XML_Char *data) {
1997   ParserPlusStorage *const parserPlusStorage = (ParserPlusStorage *)userData;
1998   accumulate_comment(parserPlusStorage->storage, data);
1999   XML_StopParser(parserPlusStorage->parser, XML_TRUE);
2000 }
2001 
2002 void XMLCALL
2003 forbidden_calls_character_handler(void *userData, const XML_Char *s, int len) {
2004   UNUSED_P(s);
2005   UNUSED_P(len);
2006   XML_Parser parser = userData;
2007 
2008   assert_true(parser != NULL); // self-test
2009 
2010   assert_true(XML_GetBuffer(parser, 123) == NULL); // i.e. rejected
2011 
2012   assert_true(XML_Parse(parser, "", 0, /*isFinal=*/XML_FALSE)
2013               == XML_STATUS_ERROR); // i.e. rejected
2014 
2015   assert_true(XML_ParseBuffer(parser, 0, /*isFinal=*/XML_FALSE)
2016               == XML_STATUS_ERROR); // i.e. rejected
2017 
2018   XML_ParserFree(parser); // rejected
2019 
2020   assert_true(XML_ParserReset(parser, /*encodingName=*/NULL)
2021               == XML_FALSE); // i.e. rejected
2022 
2023   assert_true(XML_GetErrorCode(parser) == XML_ERROR_NONE);
2024 }
2025 
2026 void XMLCALL
2027 suspend_then_resume_character_handler(void *userData, const XML_Char *s,
2028                                       int len) {
2029   UNUSED_P(s);
2030   UNUSED_P(len);
2031   ResumeFromHandlerData *const data = (ResumeFromHandlerData *)userData;
2032 
2033   data->callCount++;
2034   if (data->callCount > 1) {
2035     // Reached only if the guard under test is missing: XML_ResumeParser would
2036     // then have driven the parser re-entrantly and called us again.  Bail out
2037     // so the test fails by assertion below rather than recursing without bound.
2038     return;
2039   }
2040 
2041   // Put the parser into XML_SUSPENDED so that, without the guard,
2042   // XML_ResumeParser would proceed into a re-entrant parse.
2043   assert_true(XML_StopParser(data->parser, /*resumable=*/XML_TRUE)
2044               == XML_STATUS_OK);
2045 
2046   // Resuming the parser from inside a handler must be rejected.
2047   assert_true(XML_ResumeParser(data->parser) == XML_STATUS_ERROR);
2048 }
2049