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