/* XML handler functions for the Expat test suite __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| | __// \| |_) | (_| | |_ \___/_/\_\ .__/ \__,_|\__| |_| XML parser Copyright (c) 2001-2006 Fred L. Drake, Jr. Copyright (c) 2003 Greg Stein Copyright (c) 2005-2007 Steven Solie Copyright (c) 2005-2012 Karl Waclawek Copyright (c) 2016-2024 Sebastian Pipping Copyright (c) 2017-2022 Rhodri James Copyright (c) 2017 Joe Orton Copyright (c) 2017 José Gutiérrez de la Concha Copyright (c) 2018 Marco Maggi Copyright (c) 2019 David Loffredo Copyright (c) 2020 Tim Gates Copyright (c) 2021 Donghee Na Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #if defined(NDEBUG) # undef NDEBUG /* because test suite relies on assert(...) at the moment */ #endif #include #include #include #include "expat_config.h" #include "expat.h" #include "internal.h" #include "chardata.h" #include "structdata.h" #include "common.h" #include "handlers.h" /* Global variables for user parameter settings tests */ /* Variable holding the expected handler userData */ const void *g_handler_data = NULL; /* Count of the number of times the comment handler has been invoked */ int g_comment_count = 0; /* Count of the number of skipped entities */ int g_skip_count = 0; /* Count of the number of times the XML declaration handler is invoked */ int g_xdecl_count = 0; /* Start/End Element Handlers */ void XMLCALL start_element_event_handler(void *userData, const XML_Char *name, const XML_Char **atts) { UNUSED_P(atts); CharData_AppendXMLChars((CharData *)userData, name, -1); } void XMLCALL end_element_event_handler(void *userData, const XML_Char *name) { CharData *storage = (CharData *)userData; CharData_AppendXMLChars(storage, XCS("/"), 1); CharData_AppendXMLChars(storage, name, -1); } void XMLCALL start_element_event_handler2(void *userData, const XML_Char *name, const XML_Char **attr) { StructData *storage = (StructData *)userData; UNUSED_P(attr); StructData_AddItem(storage, name, XML_GetCurrentColumnNumber(g_parser), XML_GetCurrentLineNumber(g_parser), STRUCT_START_TAG); } void XMLCALL end_element_event_handler2(void *userData, const XML_Char *name) { StructData *storage = (StructData *)userData; StructData_AddItem(storage, name, XML_GetCurrentColumnNumber(g_parser), XML_GetCurrentLineNumber(g_parser), STRUCT_END_TAG); } void XMLCALL counting_start_element_handler(void *userData, const XML_Char *name, const XML_Char **atts) { ParserAndElementInfo *const parserAndElementInfos = (ParserAndElementInfo *)userData; ElementInfo *info = parserAndElementInfos->info; AttrInfo *attr; int count, id, i; while (info->name != NULL) { if (! xcstrcmp(name, info->name)) break; info++; } if (info->name == NULL) fail("Element not recognised"); /* The attribute count is twice what you might expect. It is a * count of items in atts, an array which contains alternating * attribute names and attribute values. For the naive user this * is possibly a little unexpected, but it is what the * documentation in expat.h tells us to expect. */ count = XML_GetSpecifiedAttributeCount(parserAndElementInfos->parser); if (info->attr_count * 2 != count) { fail("Not got expected attribute count"); return; } id = XML_GetIdAttributeIndex(parserAndElementInfos->parser); if (id == -1 && info->id_name != NULL) { fail("ID not present"); return; } if (id != -1 && xcstrcmp(atts[id], info->id_name)) { fail("ID does not have the correct name"); return; } for (i = 0; i < info->attr_count; i++) { attr = info->attributes; while (attr->name != NULL) { if (! xcstrcmp(atts[0], attr->name)) break; attr++; } if (attr->name == NULL) { fail("Attribute not recognised"); return; } if (xcstrcmp(atts[1], attr->value)) { fail("Attribute has wrong value"); return; } /* Remember, two entries in atts per attribute (see above) */ atts += 2; } } void XMLCALL suspending_end_handler(void *userData, const XML_Char *s) { UNUSED_P(s); XML_StopParser((XML_Parser)userData, 1); } void XMLCALL start_element_suspender(void *userData, const XML_Char *name, const XML_Char **atts) { UNUSED_P(userData); UNUSED_P(atts); if (! xcstrcmp(name, XCS("suspend"))) XML_StopParser(g_parser, XML_TRUE); if (! xcstrcmp(name, XCS("abort"))) XML_StopParser(g_parser, XML_FALSE); } /* Check that an element name and attribute name match the expected values. The expected values are passed as an array reference of string pointers provided as the userData argument; the first is the expected element name, and the second is the expected attribute name. */ int g_triplet_start_flag = XML_FALSE; int g_triplet_end_flag = XML_FALSE; void XMLCALL triplet_start_checker(void *userData, const XML_Char *name, const XML_Char **atts) { XML_Char **elemstr = (XML_Char **)userData; char buffer[1024]; if (xcstrcmp(elemstr[0], name) != 0) { snprintf(buffer, sizeof(buffer), "unexpected start string: '%" XML_FMT_STR "'", name); fail(buffer); } if (xcstrcmp(elemstr[1], atts[0]) != 0) { snprintf(buffer, sizeof(buffer), "unexpected attribute string: '%" XML_FMT_STR "'", atts[0]); fail(buffer); } g_triplet_start_flag = XML_TRUE; } /* Check that the element name passed to the end-element handler matches the expected value. The expected value is passed as the first element in an array of strings passed as the userData argument. */ void XMLCALL triplet_end_checker(void *userData, const XML_Char *name) { XML_Char **elemstr = (XML_Char **)userData; if (xcstrcmp(elemstr[0], name) != 0) { char buffer[1024]; snprintf(buffer, sizeof(buffer), "unexpected end string: '%" XML_FMT_STR "'", name); fail(buffer); } g_triplet_end_flag = XML_TRUE; } void XMLCALL overwrite_start_checker(void *userData, const XML_Char *name, const XML_Char **atts) { CharData *storage = (CharData *)userData; CharData_AppendXMLChars(storage, XCS("start "), 6); CharData_AppendXMLChars(storage, name, -1); while (*atts != NULL) { CharData_AppendXMLChars(storage, XCS("\nattribute "), 11); CharData_AppendXMLChars(storage, *atts, -1); atts += 2; } CharData_AppendXMLChars(storage, XCS("\n"), 1); } void XMLCALL overwrite_end_checker(void *userData, const XML_Char *name) { CharData *storage = (CharData *)userData; CharData_AppendXMLChars(storage, XCS("end "), 4); CharData_AppendXMLChars(storage, name, -1); CharData_AppendXMLChars(storage, XCS("\n"), 1); } void XMLCALL start_element_fail(void *userData, const XML_Char *name, const XML_Char **atts) { UNUSED_P(userData); UNUSED_P(name); UNUSED_P(atts); /* We should never get here. */ fail("should never reach start_element_fail()"); } void XMLCALL start_ns_clearing_start_element(void *userData, const XML_Char *prefix, const XML_Char *uri) { UNUSED_P(prefix); UNUSED_P(uri); XML_SetStartElementHandler((XML_Parser)userData, NULL); } void XMLCALL start_element_issue_240(void *userData, const XML_Char *name, const XML_Char **atts) { DataIssue240 *mydata = (DataIssue240 *)userData; UNUSED_P(name); UNUSED_P(atts); mydata->deep++; } void XMLCALL end_element_issue_240(void *userData, const XML_Char *name) { DataIssue240 *mydata = (DataIssue240 *)userData; UNUSED_P(name); mydata->deep--; if (mydata->deep == 0) { XML_StopParser(mydata->parser, 0); } } /* Text encoding handlers */ int XMLCALL UnknownEncodingHandler(void *data, const XML_Char *encoding, XML_Encoding *info) { UNUSED_P(data); if (xcstrcmp(encoding, XCS("unsupported-encoding")) == 0) { int i; for (i = 0; i < 256; ++i) info->map[i] = i; info->data = NULL; info->convert = NULL; info->release = NULL; return XML_STATUS_OK; } return XML_STATUS_ERROR; } static void dummy_release(void *data) { UNUSED_P(data); } int XMLCALL UnrecognisedEncodingHandler(void *data, const XML_Char *encoding, XML_Encoding *info) { UNUSED_P(data); UNUSED_P(encoding); info->data = NULL; info->convert = NULL; info->release = dummy_release; return XML_STATUS_ERROR; } int XMLCALL unknown_released_encoding_handler(void *data, const XML_Char *encoding, XML_Encoding *info) { UNUSED_P(data); if (! xcstrcmp(encoding, XCS("unsupported-encoding"))) { int i; for (i = 0; i < 256; i++) info->map[i] = i; info->data = NULL; info->convert = NULL; info->release = dummy_release; return XML_STATUS_OK; } return XML_STATUS_ERROR; } static int XMLCALL failing_converter(void *data, const char *s) { UNUSED_P(data); UNUSED_P(s); /* Always claim to have failed */ return -1; } static int XMLCALL prefix_converter(void *data, const char *s) { UNUSED_P(data); /* If the first byte is 0xff, raise an error */ if (s[0] == (char)-1) return -1; /* Just add the low bits of the first byte to the second */ return (s[1] + (s[0] & 0x7f)) & 0x01ff; } int XMLCALL MiscEncodingHandler(void *data, const XML_Char *encoding, XML_Encoding *info) { int i; int high_map = -2; /* Assume a 2-byte sequence */ if (! xcstrcmp(encoding, XCS("invalid-9")) || ! xcstrcmp(encoding, XCS("ascii-like")) || ! xcstrcmp(encoding, XCS("invalid-len")) || ! xcstrcmp(encoding, XCS("invalid-a")) || ! xcstrcmp(encoding, XCS("invalid-surrogate")) || ! xcstrcmp(encoding, XCS("invalid-high"))) high_map = -1; for (i = 0; i < 128; ++i) info->map[i] = i; for (; i < 256; ++i) info->map[i] = high_map; /* If required, put an invalid value in the ASCII entries */ if (! xcstrcmp(encoding, XCS("invalid-9"))) info->map[9] = 5; /* If required, have a top-bit set character starts a 5-byte sequence */ if (! xcstrcmp(encoding, XCS("invalid-len"))) info->map[0x81] = -5; /* If required, make a top-bit set character a valid ASCII character */ if (! xcstrcmp(encoding, XCS("invalid-a"))) info->map[0x82] = 'a'; /* If required, give a top-bit set character a forbidden value, * what would otherwise be the first of a surrogate pair. */ if (! xcstrcmp(encoding, XCS("invalid-surrogate"))) info->map[0x83] = 0xd801; /* If required, give a top-bit set character too high a value */ if (! xcstrcmp(encoding, XCS("invalid-high"))) info->map[0x84] = 0x010101; info->data = data; info->release = NULL; if (! xcstrcmp(encoding, XCS("failing-conv"))) info->convert = failing_converter; else if (! xcstrcmp(encoding, XCS("prefix-conv"))) info->convert = prefix_converter; else info->convert = NULL; return XML_STATUS_OK; } int XMLCALL long_encoding_handler(void *userData, const XML_Char *encoding, XML_Encoding *info) { int i; UNUSED_P(userData); UNUSED_P(encoding); for (i = 0; i < 256; i++) info->map[i] = i; info->data = NULL; info->convert = NULL; info->release = NULL; return XML_STATUS_OK; } /* External Entity Handlers */ int XMLCALL external_entity_optioner(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { ExtOption *options = (ExtOption *)XML_GetUserData(parser); XML_Parser ext_parser; UNUSED_P(base); UNUSED_P(publicId); while (options->parse_text != NULL) { if (! xcstrcmp(systemId, options->system_id)) { enum XML_Status rc; ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) return XML_STATUS_ERROR; rc = _XML_Parse_SINGLE_BYTES(ext_parser, options->parse_text, (int)strlen(options->parse_text), XML_TRUE); XML_ParserFree(ext_parser); return rc; } options++; } fail("No suitable option found"); return XML_STATUS_ERROR; } int XMLCALL external_entity_loader(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { ExtTest *test_data = (ExtTest *)XML_GetUserData(parser); XML_Parser extparser; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); extparser = XML_ExternalEntityParserCreate(parser, context, NULL); if (extparser == NULL) fail("Could not create external entity parser."); if (test_data->encoding != NULL) { if (! XML_SetEncoding(extparser, test_data->encoding)) fail("XML_SetEncoding() ignored for external entity"); } if (_XML_Parse_SINGLE_BYTES(extparser, test_data->parse_text, (int)strlen(test_data->parse_text), XML_TRUE) == XML_STATUS_ERROR) { xml_failure(extparser); return XML_STATUS_ERROR; } XML_ParserFree(extparser); return XML_STATUS_OK; } int XMLCALL external_entity_faulter(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { XML_Parser ext_parser; ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser); UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); if (fault->encoding != NULL) { if (! XML_SetEncoding(ext_parser, fault->encoding)) fail("XML_SetEncoding failed"); } if (_XML_Parse_SINGLE_BYTES(ext_parser, fault->parse_text, (int)strlen(fault->parse_text), XML_TRUE) != XML_STATUS_ERROR) fail(fault->fail_text); if (XML_GetErrorCode(ext_parser) != fault->error) xml_failure(ext_parser); XML_ParserFree(ext_parser); return XML_STATUS_ERROR; } int XMLCALL external_entity_null_loader(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { UNUSED_P(parser); UNUSED_P(context); UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); return XML_STATUS_OK; } int XMLCALL external_entity_resetter(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char *text = ""; XML_Parser ext_parser; XML_ParsingStatus status; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); XML_GetParsingStatus(ext_parser, &status); if (status.parsing != XML_INITIALIZED) { fail("Parsing status is not INITIALIZED"); return XML_STATUS_ERROR; } if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE) == XML_STATUS_ERROR) { xml_failure(parser); return XML_STATUS_ERROR; } XML_GetParsingStatus(ext_parser, &status); if (status.parsing != XML_FINISHED) { fail("Parsing status is not FINISHED"); return XML_STATUS_ERROR; } /* Check we can't parse here */ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE) != XML_STATUS_ERROR) fail("Parsing when finished not faulted"); if (XML_GetErrorCode(ext_parser) != XML_ERROR_FINISHED) fail("Parsing when finished faulted with wrong code"); XML_ParserReset(ext_parser, NULL); XML_GetParsingStatus(ext_parser, &status); if (status.parsing != XML_FINISHED) { fail("Parsing status not still FINISHED"); return XML_STATUS_ERROR; } XML_ParserFree(ext_parser); return XML_STATUS_OK; } void XMLCALL entity_suspending_decl_handler(void *userData, const XML_Char *name, XML_Content *model) { XML_Parser ext_parser = (XML_Parser)userData; UNUSED_P(name); if (XML_StopParser(ext_parser, XML_TRUE) != XML_STATUS_ERROR) fail("Attempting to suspend a subordinate parser not faulted"); if (XML_GetErrorCode(ext_parser) != XML_ERROR_SUSPEND_PE) fail("Suspending subordinate parser get wrong code"); XML_SetElementDeclHandler(ext_parser, NULL); XML_FreeContentModel(g_parser, model); } int XMLCALL external_entity_suspender(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char *text = ""; XML_Parser ext_parser; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); XML_SetElementDeclHandler(ext_parser, entity_suspending_decl_handler); XML_SetUserData(ext_parser, ext_parser); if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE) == XML_STATUS_ERROR) { xml_failure(ext_parser); return XML_STATUS_ERROR; } XML_ParserFree(ext_parser); return XML_STATUS_OK; } void XMLCALL entity_suspending_xdecl_handler(void *userData, const XML_Char *version, const XML_Char *encoding, int standalone) { XML_Parser ext_parser = (XML_Parser)userData; UNUSED_P(version); UNUSED_P(encoding); UNUSED_P(standalone); XML_StopParser(ext_parser, g_resumable); XML_SetXmlDeclHandler(ext_parser, NULL); } int XMLCALL external_entity_suspend_xmldecl(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char *text = ""; XML_Parser ext_parser; XML_ParsingStatus status; enum XML_Status rc; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler); XML_SetUserData(ext_parser, ext_parser); rc = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE); XML_GetParsingStatus(ext_parser, &status); if (g_resumable) { if (rc == XML_STATUS_ERROR) xml_failure(ext_parser); if (status.parsing != XML_SUSPENDED) fail("Ext Parsing status not SUSPENDED"); } else { if (rc != XML_STATUS_ERROR) fail("Ext parsing not aborted"); if (XML_GetErrorCode(ext_parser) != XML_ERROR_ABORTED) xml_failure(ext_parser); if (status.parsing != XML_FINISHED) fail("Ext Parsing status not FINISHED"); } XML_ParserFree(ext_parser); return XML_STATUS_OK; } int XMLCALL external_entity_suspending_faulter(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { XML_Parser ext_parser; ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser); void *buffer; int parse_len = (int)strlen(fault->parse_text); UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler); XML_SetUserData(ext_parser, ext_parser); g_resumable = XML_TRUE; buffer = XML_GetBuffer(ext_parser, parse_len); if (buffer == NULL) fail("Could not allocate parse buffer"); assert(buffer != NULL); memcpy(buffer, fault->parse_text, parse_len); if (XML_ParseBuffer(ext_parser, parse_len, XML_FALSE) != XML_STATUS_SUSPENDED) fail("XML declaration did not suspend"); if (XML_ResumeParser(ext_parser) != XML_STATUS_OK) xml_failure(ext_parser); if (XML_ParseBuffer(ext_parser, 0, XML_TRUE) != XML_STATUS_ERROR) fail(fault->fail_text); if (XML_GetErrorCode(ext_parser) != fault->error) xml_failure(ext_parser); XML_ParserFree(ext_parser); return XML_STATUS_ERROR; } int XMLCALL external_entity_failer__if_not_xml_ge(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { UNUSED_P(parser); UNUSED_P(context); UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); #if XML_GE == 0 fail( "Function external_entity_suspending_failer was called despite XML_GE==0."); #endif return XML_STATUS_OK; } int XMLCALL external_entity_cr_catcher(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char *text = "\r"; XML_Parser ext_parser; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); XML_SetCharacterDataHandler(ext_parser, cr_cdata_handler); if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE) == XML_STATUS_ERROR) xml_failure(ext_parser); XML_ParserFree(ext_parser); return XML_STATUS_OK; } int XMLCALL external_entity_bad_cr_catcher(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char *text = "\r"; XML_Parser ext_parser; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); XML_SetCharacterDataHandler(ext_parser, cr_cdata_handler); if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE) == XML_STATUS_OK) fail("Async entity error not caught"); if (XML_GetErrorCode(ext_parser) != XML_ERROR_ASYNC_ENTITY) xml_failure(ext_parser); XML_ParserFree(ext_parser); return XML_STATUS_OK; } int XMLCALL external_entity_rsqb_catcher(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char *text = "]"; XML_Parser ext_parser; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); XML_SetCharacterDataHandler(ext_parser, rsqb_handler); if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE) != XML_STATUS_ERROR) fail("Async entity error not caught"); if (XML_GetErrorCode(ext_parser) != XML_ERROR_ASYNC_ENTITY) xml_failure(ext_parser); XML_ParserFree(ext_parser); return XML_STATUS_OK; } int XMLCALL external_entity_good_cdata_ascii(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char *text = "Hello, world!]]>"; const XML_Char *expected = XCS("Hello, world!"); CharData storage; XML_Parser ext_parser; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); CharData_Init(&storage); ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); XML_SetUserData(ext_parser, &storage); XML_SetCharacterDataHandler(ext_parser, accumulate_characters); if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE) == XML_STATUS_ERROR) xml_failure(ext_parser); CharData_CheckXMLChars(&storage, expected); XML_ParserFree(ext_parser); return XML_STATUS_OK; } int XMLCALL external_entity_param_checker(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char *text = "\n" ""; XML_Parser ext_parser; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); g_handler_data = ext_parser; if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE) == XML_STATUS_ERROR) { xml_failure(parser); return XML_STATUS_ERROR; } g_handler_data = parser; XML_ParserFree(ext_parser); return XML_STATUS_OK; } int XMLCALL external_entity_ref_param_checker(XML_Parser parameter, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char *text = ""; XML_Parser ext_parser; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); if ((void *)parameter != g_handler_data) fail("External entity ref handler parameter not correct"); /* Here we use the global 'parser' variable */ ext_parser = XML_ExternalEntityParserCreate(g_parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE) == XML_STATUS_ERROR) xml_failure(ext_parser); XML_ParserFree(ext_parser); return XML_STATUS_OK; } int XMLCALL external_entity_param(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char *text1 = "\n" "\n" "\n" "%e1;\n"; const char *text2 = "\n" "\n"; XML_Parser ext_parser; UNUSED_P(base); UNUSED_P(publicId); if (systemId == NULL) return XML_STATUS_OK; ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); if (! xcstrcmp(systemId, XCS("004-1.ent"))) { if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE) != XML_STATUS_ERROR) fail("Inner DTD with invalid tag not rejected"); if (XML_GetErrorCode(ext_parser) != XML_ERROR_EXTERNAL_ENTITY_HANDLING) xml_failure(ext_parser); } else if (! xcstrcmp(systemId, XCS("004-2.ent"))) { if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE) != XML_STATUS_ERROR) fail("Invalid tag in external param not rejected"); if (XML_GetErrorCode(ext_parser) != XML_ERROR_SYNTAX) xml_failure(ext_parser); } else { fail("Unknown system ID"); } XML_ParserFree(ext_parser); return XML_STATUS_ERROR; } int XMLCALL external_entity_load_ignore(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char *text = "]]>"; XML_Parser ext_parser; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE) == XML_STATUS_ERROR) xml_failure(parser); XML_ParserFree(ext_parser); return XML_STATUS_OK; } int XMLCALL external_entity_load_ignore_utf16(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char text[] = /* ]]> */ "<\0!\0[\0I\0G\0N\0O\0R\0E\0[\0" "<\0!\0E\0L\0E\0M\0E\0N\0T\0 \0e\0 \0" "(\0#\0P\0C\0D\0A\0T\0A\0)\0*\0>\0]\0]\0>\0"; XML_Parser ext_parser; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)sizeof(text) - 1, XML_TRUE) == XML_STATUS_ERROR) xml_failure(parser); XML_ParserFree(ext_parser); return XML_STATUS_OK; } int XMLCALL external_entity_load_ignore_utf16_be(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char text[] = /* ]]> */ "\0<\0!\0[\0I\0G\0N\0O\0R\0E\0[" "\0<\0!\0E\0L\0E\0M\0E\0N\0T\0 \0e\0 " "\0(\0#\0P\0C\0D\0A\0T\0A\0)\0*\0>\0]\0]\0>"; XML_Parser ext_parser; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)sizeof(text) - 1, XML_TRUE) == XML_STATUS_ERROR) xml_failure(parser); XML_ParserFree(ext_parser); return XML_STATUS_OK; } int XMLCALL external_entity_valuer(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char *text1 = "\n" "\n" "\n" "%e1;\n"; XML_Parser ext_parser; UNUSED_P(base); UNUSED_P(publicId); if (systemId == NULL) return XML_STATUS_OK; ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); if (! xcstrcmp(systemId, XCS("004-1.ent"))) { if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE) == XML_STATUS_ERROR) xml_failure(ext_parser); } else if (! xcstrcmp(systemId, XCS("004-2.ent"))) { ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser); enum XML_Status status; enum XML_Error error; status = _XML_Parse_SINGLE_BYTES(ext_parser, fault->parse_text, (int)strlen(fault->parse_text), XML_TRUE); if (fault->error == XML_ERROR_NONE) { if (status == XML_STATUS_ERROR) xml_failure(ext_parser); } else { if (status != XML_STATUS_ERROR) fail(fault->fail_text); error = XML_GetErrorCode(ext_parser); if (error != fault->error && (fault->error != XML_ERROR_XML_DECL || error != XML_ERROR_TEXT_DECL)) xml_failure(ext_parser); } } XML_ParserFree(ext_parser); return XML_STATUS_OK; } int XMLCALL external_entity_not_standalone(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char *text1 = "\n" "\n" "%e1;\n"; const char *text2 = ""; XML_Parser ext_parser; UNUSED_P(base); UNUSED_P(publicId); if (systemId == NULL) return XML_STATUS_OK; ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); if (! xcstrcmp(systemId, XCS("foo"))) { XML_SetNotStandaloneHandler(ext_parser, reject_not_standalone_handler); if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE) != XML_STATUS_ERROR) fail("Expected not standalone rejection"); if (XML_GetErrorCode(ext_parser) != XML_ERROR_NOT_STANDALONE) xml_failure(ext_parser); XML_SetNotStandaloneHandler(ext_parser, NULL); XML_ParserFree(ext_parser); return XML_STATUS_ERROR; } else if (! xcstrcmp(systemId, XCS("bar"))) { if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE) == XML_STATUS_ERROR) xml_failure(ext_parser); } XML_ParserFree(ext_parser); return XML_STATUS_OK; } int XMLCALL external_entity_value_aborter(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char *text1 = "\n" "\n" "\n" "%e1;\n"; const char *text2 = ""; XML_Parser ext_parser; UNUSED_P(base); UNUSED_P(publicId); if (systemId == NULL) return XML_STATUS_OK; ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); if (! xcstrcmp(systemId, XCS("004-1.ent"))) { if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE) == XML_STATUS_ERROR) xml_failure(ext_parser); } if (! xcstrcmp(systemId, XCS("004-2.ent"))) { XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler); XML_SetUserData(ext_parser, ext_parser); if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE) != XML_STATUS_ERROR) fail("Aborted parse not faulted"); if (XML_GetErrorCode(ext_parser) != XML_ERROR_ABORTED) xml_failure(ext_parser); } XML_ParserFree(ext_parser); return XML_STATUS_OK; } int XMLCALL external_entity_public(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char *text1 = (const char *)XML_GetUserData(parser); const char *text2 = ""; const char *text = NULL; XML_Parser ext_parser; int parse_res; UNUSED_P(base); ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) return XML_STATUS_ERROR; if (systemId != NULL && ! xcstrcmp(systemId, XCS("http://example.org/"))) { text = text1; } else if (publicId != NULL && ! xcstrcmp(publicId, XCS("foo"))) { text = text2; } else fail("Unexpected parameters to external entity parser"); assert(text != NULL); parse_res = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE); XML_ParserFree(ext_parser); return parse_res; } int XMLCALL external_entity_devaluer(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char *text = "\n" "\n" "%e1;\n"; XML_Parser ext_parser; int clear_handler_flag = (XML_GetUserData(parser) != NULL); UNUSED_P(base); UNUSED_P(publicId); if (systemId == NULL || ! xcstrcmp(systemId, XCS("bar"))) return XML_STATUS_OK; if (xcstrcmp(systemId, XCS("foo"))) fail("Unexpected system ID"); ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could note create external entity parser"); if (clear_handler_flag) XML_SetExternalEntityRefHandler(ext_parser, NULL); if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE) == XML_STATUS_ERROR) xml_failure(ext_parser); XML_ParserFree(ext_parser); return XML_STATUS_OK; } int XMLCALL external_entity_oneshot_loader(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { ExtHdlrData *test_data = (ExtHdlrData *)XML_GetUserData(parser); XML_Parser ext_parser; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser."); /* Use the requested entity parser for further externals */ XML_SetExternalEntityRefHandler(ext_parser, test_data->handler); if (_XML_Parse_SINGLE_BYTES(ext_parser, test_data->parse_text, (int)strlen(test_data->parse_text), XML_TRUE) == XML_STATUS_ERROR) { xml_failure(ext_parser); } XML_ParserFree(ext_parser); return XML_STATUS_OK; } int XMLCALL external_entity_loader2(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { ExtTest2 *test_data = (ExtTest2 *)XML_GetUserData(parser); XML_Parser extparser; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); extparser = XML_ExternalEntityParserCreate(parser, context, NULL); if (extparser == NULL) fail("Coulr not create external entity parser"); if (test_data->encoding != NULL) { if (! XML_SetEncoding(extparser, test_data->encoding)) fail("XML_SetEncoding() ignored for external entity"); } if (_XML_Parse_SINGLE_BYTES(extparser, test_data->parse_text, test_data->parse_len, XML_TRUE) == XML_STATUS_ERROR) { xml_failure(extparser); } XML_ParserFree(extparser); return XML_STATUS_OK; } int XMLCALL external_entity_faulter2(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { ExtFaults2 *test_data = (ExtFaults2 *)XML_GetUserData(parser); XML_Parser extparser; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); extparser = XML_ExternalEntityParserCreate(parser, context, NULL); if (extparser == NULL) fail("Could not create external entity parser"); if (test_data->encoding != NULL) { if (! XML_SetEncoding(extparser, test_data->encoding)) fail("XML_SetEncoding() ignored for external entity"); } if (_XML_Parse_SINGLE_BYTES(extparser, test_data->parse_text, test_data->parse_len, XML_TRUE) != XML_STATUS_ERROR) fail(test_data->fail_text); if (XML_GetErrorCode(extparser) != test_data->error) xml_failure(extparser); XML_ParserFree(extparser); return XML_STATUS_ERROR; } int XMLCALL external_entity_unfinished_attlist(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char *text = "\n" "\n" "\n"; XML_Parser ext_parser; UNUSED_P(base); UNUSED_P(publicId); if (systemId == NULL) return XML_STATUS_OK; ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE) == XML_STATUS_ERROR) xml_failure(ext_parser); XML_ParserFree(ext_parser); return XML_STATUS_OK; } int XMLCALL external_entity_handler(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { void *user_data = XML_GetUserData(parser); const char *text; XML_Parser p2; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); if (user_data == NULL) text = ("\n" "\n" "\n"); else text = ("" ""); /* Set user data to any non-NULL value */ XML_SetUserData(parser, parser); p2 = XML_ExternalEntityParserCreate(parser, context, NULL); if (_XML_Parse_SINGLE_BYTES(p2, text, (int)strlen(text), XML_TRUE) == XML_STATUS_ERROR) { xml_failure(p2); return XML_STATUS_ERROR; } XML_ParserFree(p2); return XML_STATUS_OK; } int XMLCALL external_entity_duff_loader(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { XML_Parser new_parser; unsigned int i; const unsigned int max_alloc_count = 10; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); /* Try a few different allocation levels */ for (i = 0; i < max_alloc_count; i++) { g_allocation_count = i; new_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (new_parser != NULL) { XML_ParserFree(new_parser); break; } } if (i == 0) fail("External parser creation ignored failing allocator"); else if (i == max_alloc_count) fail("Extern parser not created with max allocation count"); /* Make sure other random allocation doesn't now fail */ g_allocation_count = ALLOC_ALWAYS_SUCCEED; /* Make sure the failure code path is executed too */ return XML_STATUS_ERROR; } int XMLCALL external_entity_dbl_handler(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { int *pcallno = (int *)XML_GetUserData(parser); int callno = *pcallno; const char *text; XML_Parser new_parser = NULL; int i; const int max_alloc_count = 20; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); if (callno == 0) { /* First time through, check how many calls to malloc occur */ text = ("\n" "\n" "\n"); g_allocation_count = 10000; new_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (new_parser == NULL) { fail("Unable to allocate first external parser"); return XML_STATUS_ERROR; } /* Stash the number of calls in the user data */ *pcallno = 10000 - g_allocation_count; } else { text = ("" ""); /* Try at varying levels to exercise more code paths */ for (i = 0; i < max_alloc_count; i++) { g_allocation_count = callno + i; new_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (new_parser != NULL) break; } if (i == 0) { fail("Second external parser unexpectedly created"); XML_ParserFree(new_parser); return XML_STATUS_ERROR; } else if (i == max_alloc_count) { fail("Second external parser not created"); return XML_STATUS_ERROR; } } g_allocation_count = ALLOC_ALWAYS_SUCCEED; if (_XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE) == XML_STATUS_ERROR) { xml_failure(new_parser); return XML_STATUS_ERROR; } XML_ParserFree(new_parser); return XML_STATUS_OK; } int XMLCALL external_entity_dbl_handler_2(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { int *pcallno = (int *)XML_GetUserData(parser); int callno = *pcallno; const char *text; XML_Parser new_parser; enum XML_Status rv; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); if (callno == 0) { /* Try different allocation levels for whole exercise */ text = ("\n" "\n" "\n"); *pcallno = 1; new_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (new_parser == NULL) return XML_STATUS_ERROR; rv = _XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE); } else { /* Just run through once */ text = ("" ""); new_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (new_parser == NULL) return XML_STATUS_ERROR; rv = _XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE); } XML_ParserFree(new_parser); if (rv == XML_STATUS_ERROR) return XML_STATUS_ERROR; return XML_STATUS_OK; } int XMLCALL external_entity_alloc_set_encoding(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { /* As for external_entity_loader() */ const char *text = "" "\xC3\xA9"; XML_Parser ext_parser; enum XML_Status status; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) return XML_STATUS_ERROR; if (! XML_SetEncoding(ext_parser, XCS("utf-8"))) { XML_ParserFree(ext_parser); return XML_STATUS_ERROR; } status = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE); XML_ParserFree(ext_parser); if (status == XML_STATUS_ERROR) return XML_STATUS_ERROR; return XML_STATUS_OK; } int XMLCALL external_entity_reallocator(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char *text = get_buffer_test_text; XML_Parser ext_parser; void *buffer; enum XML_Status status; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) fail("Could not create external entity parser"); g_reallocation_count = *(int *)XML_GetUserData(parser); buffer = XML_GetBuffer(ext_parser, 1536); if (buffer == NULL) fail("Buffer allocation failed"); assert(buffer != NULL); memcpy(buffer, text, strlen(text)); status = XML_ParseBuffer(ext_parser, (int)strlen(text), XML_FALSE); g_reallocation_count = -1; XML_ParserFree(ext_parser); return (status == XML_STATUS_OK) ? XML_STATUS_OK : XML_STATUS_ERROR; } int XMLCALL external_entity_alloc(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { const char *text = (const char *)XML_GetUserData(parser); XML_Parser ext_parser; int parse_res; UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL); if (ext_parser == NULL) return XML_STATUS_ERROR; parse_res = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE); XML_ParserFree(ext_parser); return parse_res; } int XMLCALL external_entity_parser_create_alloc_fail_handler(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); if (context != NULL) fail("Unexpected non-NULL context"); // The following number intends to fail the upcoming allocation in line // "parser->m_protocolEncodingName = copyString(encodingName, // &(parser->m_mem));" in function parserInit. g_allocation_count = 3; const XML_Char *const encodingName = XCS("UTF-8"); // needs something non-NULL const XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, context, encodingName); if (ext_parser != NULL) fail( "Call to XML_ExternalEntityParserCreate was expected to fail out-of-memory"); g_allocation_count = ALLOC_ALWAYS_SUCCEED; return XML_STATUS_ERROR; } #if XML_GE == 1 int accounting_external_entity_ref_handler(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { UNUSED_P(base); UNUSED_P(publicId); const struct AccountingTestCase *const testCase = (const struct AccountingTestCase *)XML_GetUserData(parser); const char *externalText = NULL; if (xcstrcmp(systemId, XCS("first.ent")) == 0) { externalText = testCase->firstExternalText; } else if (xcstrcmp(systemId, XCS("second.ent")) == 0) { externalText = testCase->secondExternalText; } else { assert(! "systemId is neither \"first.ent\" nor \"second.ent\""); } assert(externalText); XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0); assert(entParser); const enum XML_Status status = _XML_Parse_SINGLE_BYTES( entParser, externalText, (int)strlen(externalText), XML_TRUE); XML_ParserFree(entParser); return status; } #endif /* XML_GE == 1 */ /* NotStandalone handlers */ int XMLCALL reject_not_standalone_handler(void *userData) { UNUSED_P(userData); return XML_STATUS_ERROR; } int XMLCALL accept_not_standalone_handler(void *userData) { UNUSED_P(userData); return XML_STATUS_OK; } /* Attribute List handlers */ void XMLCALL verify_attlist_decl_handler(void *userData, const XML_Char *element_name, const XML_Char *attr_name, const XML_Char *attr_type, const XML_Char *default_value, int is_required) { AttTest *at = (AttTest *)userData; if (xcstrcmp(element_name, at->element_name)) fail("Unexpected element name in attribute declaration"); if (xcstrcmp(attr_name, at->attr_name)) fail("Unexpected attribute name in attribute declaration"); if (xcstrcmp(attr_type, at->attr_type)) fail("Unexpected attribute type in attribute declaration"); if ((default_value == NULL && at->default_value != NULL) || (default_value != NULL && at->default_value == NULL) || (default_value != NULL && xcstrcmp(default_value, at->default_value))) fail("Unexpected default value in attribute declaration"); if (is_required != at->is_required) fail("Requirement mismatch in attribute declaration"); } /* Character Data handlers */ void XMLCALL clearing_aborting_character_handler(void *userData, const XML_Char *s, int len) { UNUSED_P(userData); UNUSED_P(s); UNUSED_P(len); XML_StopParser(g_parser, g_resumable); XML_SetCharacterDataHandler(g_parser, NULL); } void XMLCALL parser_stop_character_handler(void *userData, const XML_Char *s, int len) { UNUSED_P(userData); UNUSED_P(s); UNUSED_P(len); XML_ParsingStatus status; XML_GetParsingStatus(g_parser, &status); if (status.parsing == XML_FINISHED) { return; // the parser was stopped by a previous call to this handler. } XML_StopParser(g_parser, g_resumable); XML_SetCharacterDataHandler(g_parser, NULL); if (! g_resumable) { /* Check that aborting an aborted parser is faulted */ if (XML_StopParser(g_parser, XML_FALSE) != XML_STATUS_ERROR) fail("Aborting aborted parser not faulted"); if (XML_GetErrorCode(g_parser) != XML_ERROR_FINISHED) xml_failure(g_parser); } else if (g_abortable) { /* Check that aborting a suspended parser works */ if (XML_StopParser(g_parser, XML_FALSE) == XML_STATUS_ERROR) xml_failure(g_parser); } else { /* Check that suspending a suspended parser works */ if (XML_StopParser(g_parser, XML_TRUE) != XML_STATUS_ERROR) fail("Suspending suspended parser not faulted"); if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED) xml_failure(g_parser); } } void XMLCALL cr_cdata_handler(void *userData, const XML_Char *s, int len) { int *pfound = (int *)userData; /* Internal processing turns the CR into a newline for the * character data handler, but not for the default handler */ if (len == 1 && (*s == XCS('\n') || *s == XCS('\r'))) *pfound = 1; } void XMLCALL rsqb_handler(void *userData, const XML_Char *s, int len) { int *pfound = (int *)userData; if (len == 1 && *s == XCS(']')) *pfound = 1; } void XMLCALL byte_character_handler(void *userData, const XML_Char *s, int len) { #if XML_CONTEXT_BYTES > 0 int offset, size; const char *buffer; ByteTestData *data = (ByteTestData *)userData; UNUSED_P(s); buffer = XML_GetInputContext(g_parser, &offset, &size); if (buffer == NULL) fail("Failed to get context buffer"); if (offset != data->start_element_len) fail("Context offset in unexpected position"); if (len != data->cdata_len) fail("CDATA length reported incorrectly"); if (size != data->total_string_len) fail("Context size is not full buffer"); if (XML_GetCurrentByteIndex(g_parser) != offset) fail("Character byte index incorrect"); if (XML_GetCurrentByteCount(g_parser) != len) fail("Character byte count incorrect"); #else UNUSED_P(s); UNUSED_P(userData); UNUSED_P(len); #endif } void XMLCALL ext2_accumulate_characters(void *userData, const XML_Char *s, int len) { ExtTest2 *test_data = (ExtTest2 *)userData; accumulate_characters(test_data->storage, s, len); } /* Handlers that record their function name and int arg. */ static void record_call(struct handler_record_list *const rec, const char *funcname, const int arg) { const int max_entries = sizeof(rec->entries) / sizeof(rec->entries[0]); assert_true(rec->count < max_entries); struct handler_record_entry *const e = &rec->entries[rec->count++]; e->name = funcname; e->arg = arg; } void XMLCALL record_default_handler(void *userData, const XML_Char *s, int len) { UNUSED_P(s); record_call((struct handler_record_list *)userData, __func__, len); } void XMLCALL record_cdata_handler(void *userData, const XML_Char *s, int len) { UNUSED_P(s); record_call((struct handler_record_list *)userData, __func__, len); XML_DefaultCurrent(g_parser); } void XMLCALL record_cdata_nodefault_handler(void *userData, const XML_Char *s, int len) { UNUSED_P(s); record_call((struct handler_record_list *)userData, __func__, len); } void XMLCALL record_skip_handler(void *userData, const XML_Char *entityName, int is_parameter_entity) { UNUSED_P(entityName); record_call((struct handler_record_list *)userData, __func__, is_parameter_entity); } void XMLCALL record_element_start_handler(void *userData, const XML_Char *name, const XML_Char **atts) { UNUSED_P(atts); CharData_AppendXMLChars((CharData *)userData, name, (int)xcstrlen(name)); } void XMLCALL record_element_end_handler(void *userData, const XML_Char *name) { CharData *storage = (CharData *)userData; CharData_AppendXMLChars(storage, XCS("/"), 1); CharData_AppendXMLChars(storage, name, -1); } const struct handler_record_entry * _handler_record_get(const struct handler_record_list *storage, int index, const char *file, int line) { if (storage->count <= index) { _fail(file, line, "too few handler calls"); } return &storage->entries[index]; } /* Entity Declaration Handlers */ static const XML_Char *entity_name_to_match = NULL; static const XML_Char *entity_value_to_match = NULL; static int entity_match_flag = ENTITY_MATCH_NOT_FOUND; void XMLCALL param_entity_match_handler(void *userData, const XML_Char *entityName, int is_parameter_entity, const XML_Char *value, int value_length, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId, const XML_Char *notationName) { UNUSED_P(userData); UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); UNUSED_P(notationName); if (! is_parameter_entity || entity_name_to_match == NULL || entity_value_to_match == NULL) { return; } if (! xcstrcmp(entityName, entity_name_to_match)) { /* The cast here is safe because we control the horizontal and * the vertical, and we therefore know our strings are never * going to overflow an int. */ if (value_length != (int)xcstrlen(entity_value_to_match) || xcstrncmp(value, entity_value_to_match, value_length)) { entity_match_flag = ENTITY_MATCH_FAIL; } else { entity_match_flag = ENTITY_MATCH_SUCCESS; } } /* Else leave the match flag alone */ } void param_entity_match_init(const XML_Char *name, const XML_Char *value) { entity_name_to_match = name; entity_value_to_match = value; entity_match_flag = ENTITY_MATCH_NOT_FOUND; } int get_param_entity_match_flag(void) { return entity_match_flag; } /* Misc handlers */ void XMLCALL xml_decl_handler(void *userData, const XML_Char *version, const XML_Char *encoding, int standalone) { UNUSED_P(version); UNUSED_P(encoding); if (userData != g_handler_data) fail("User data (xml decl) not correctly set"); if (standalone != -1) fail("Standalone not flagged as not present in XML decl"); g_xdecl_count++; } void XMLCALL param_check_skip_handler(void *userData, const XML_Char *entityName, int is_parameter_entity) { UNUSED_P(entityName); UNUSED_P(is_parameter_entity); if (userData != g_handler_data) fail("User data (skip) not correctly set"); g_skip_count++; } void XMLCALL data_check_comment_handler(void *userData, const XML_Char *data) { UNUSED_P(data); /* Check that the userData passed through is what we expect */ if (userData != g_handler_data) fail("User data (parser) not correctly set"); /* Check that the user data in the parser is appropriate */ if (XML_GetUserData(userData) != (void *)1) fail("User data in parser not correctly set"); g_comment_count++; } void XMLCALL selective_aborting_default_handler(void *userData, const XML_Char *s, int len) { const XML_Char trigger_char = *(const XML_Char *)userData; int found = 0; for (int i = 0; i < len; ++i) { if (s[i] == trigger_char) { found = 1; break; } } if (found) { XML_StopParser(g_parser, g_resumable); XML_SetDefaultHandler(g_parser, NULL); } } void XMLCALL suspending_comment_handler(void *userData, const XML_Char *data) { UNUSED_P(data); XML_Parser parser = (XML_Parser)userData; XML_StopParser(parser, XML_TRUE); } void XMLCALL element_decl_suspender(void *userData, const XML_Char *name, XML_Content *model) { UNUSED_P(userData); UNUSED_P(name); XML_StopParser(g_parser, XML_TRUE); XML_FreeContentModel(g_parser, model); } void XMLCALL accumulate_pi_characters(void *userData, const XML_Char *target, const XML_Char *data) { CharData *storage = (CharData *)userData; CharData_AppendXMLChars(storage, target, -1); CharData_AppendXMLChars(storage, XCS(": "), 2); CharData_AppendXMLChars(storage, data, -1); CharData_AppendXMLChars(storage, XCS("\n"), 1); } void XMLCALL accumulate_comment(void *userData, const XML_Char *data) { CharData *storage = (CharData *)userData; CharData_AppendXMLChars(storage, data, -1); } void XMLCALL accumulate_entity_decl(void *userData, const XML_Char *entityName, int is_parameter_entity, const XML_Char *value, int value_length, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId, const XML_Char *notationName) { CharData *storage = (CharData *)userData; UNUSED_P(is_parameter_entity); UNUSED_P(base); UNUSED_P(systemId); UNUSED_P(publicId); UNUSED_P(notationName); CharData_AppendXMLChars(storage, entityName, -1); CharData_AppendXMLChars(storage, XCS("="), 1); if (value == NULL) CharData_AppendXMLChars(storage, XCS("(null)"), -1); else CharData_AppendXMLChars(storage, value, value_length); CharData_AppendXMLChars(storage, XCS("\n"), 1); } void XMLCALL accumulate_start_element(void *userData, const XML_Char *name, const XML_Char **atts) { CharData *const storage = (CharData *)userData; CharData_AppendXMLChars(storage, XCS("("), 1); CharData_AppendXMLChars(storage, name, -1); if ((atts != NULL) && (atts[0] != NULL)) { CharData_AppendXMLChars(storage, XCS("("), 1); while (atts[0] != NULL) { CharData_AppendXMLChars(storage, atts[0], -1); CharData_AppendXMLChars(storage, XCS("="), 1); CharData_AppendXMLChars(storage, atts[1], -1); atts += 2; if (atts[0] != NULL) { CharData_AppendXMLChars(storage, XCS(","), 1); } } CharData_AppendXMLChars(storage, XCS(")"), 1); } CharData_AppendXMLChars(storage, XCS(")\n"), 2); } void XMLCALL accumulate_characters(void *userData, const XML_Char *s, int len) { CharData *const storage = (CharData *)userData; CharData_AppendXMLChars(storage, s, len); } void XMLCALL accumulate_attribute(void *userData, const XML_Char *name, const XML_Char **atts) { CharData *const storage = (CharData *)userData; UNUSED_P(name); /* Check there are attributes to deal with */ if (atts == NULL) return; while (storage->count < 0 && atts[0] != NULL) { /* "accumulate" the value of the first attribute we see */ CharData_AppendXMLChars(storage, atts[1], -1); atts += 2; } } void XMLCALL ext_accumulate_characters(void *userData, const XML_Char *s, int len) { ExtTest *const test_data = (ExtTest *)userData; accumulate_characters(test_data->storage, s, len); } void XMLCALL checking_default_handler(void *userData, const XML_Char *s, int len) { DefaultCheck *data = (DefaultCheck *)userData; int i; for (i = 0; data[i].expected != NULL; i++) { if (data[i].expectedLen == len && ! memcmp(data[i].expected, s, len * sizeof(XML_Char))) { data[i].seen = XML_TRUE; break; } } } void XMLCALL accumulate_and_suspend_comment_handler(void *userData, const XML_Char *data) { ParserPlusStorage *const parserPlusStorage = (ParserPlusStorage *)userData; accumulate_comment(parserPlusStorage->storage, data); XML_StopParser(parserPlusStorage->parser, XML_TRUE); }