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