| /* |
| * testparser.c: Additional parser tests |
| * |
| * See Copyright for the status of this software. |
| */ |
| |
| #define XML_DEPRECATED |
| |
| #include "libxml.h" |
| #include <libxml/parser.h> |
| #include <libxml/parserInternals.h> |
| #include <libxml/uri.h> |
| #include <libxml/xmlreader.h> |
| #include <libxml/xmlsave.h> |
| #include <libxml/xmlwriter.h> |
| #include <libxml/HTMLparser.h> |
| |
| #include <string.h> |
| |
| static int |
| testNewDocNode(void) { |
| xmlNodePtr node; |
| int err = 0; |
| |
| node = xmlNewDocNode(NULL, NULL, BAD_CAST "c", BAD_CAST ""); |
| if (node->children != NULL) { |
| fprintf(stderr, "empty node has children\n"); |
| err = 1; |
| } |
| xmlFreeNode(node); |
| |
| return err; |
| } |
| |
| static int |
| testStandaloneWithEncoding(void) { |
| xmlDocPtr doc; |
| const char *str = |
| "<?xml version=\"1.0\" standalone=\"yes\"?>\n" |
| "<doc></doc>\n"; |
| int err = 0; |
| |
| xmlResetLastError(); |
| |
| doc = xmlReadDoc(BAD_CAST str, NULL, "UTF-8", 0); |
| if (doc == NULL) { |
| fprintf(stderr, "xmlReadDoc failed\n"); |
| err = 1; |
| } |
| xmlFreeDoc(doc); |
| |
| return err; |
| } |
| |
| static int |
| testUnsupportedEncoding(void) { |
| xmlDocPtr doc; |
| const xmlError *error; |
| int err = 0; |
| |
| xmlResetLastError(); |
| |
| doc = xmlReadDoc(BAD_CAST "<doc/>", NULL, "#unsupported", |
| XML_PARSE_NOWARNING); |
| if (doc == NULL) { |
| fprintf(stderr, "xmlReadDoc failed with unsupported encoding\n"); |
| err = 1; |
| } |
| xmlFreeDoc(doc); |
| |
| error = xmlGetLastError(); |
| if (error == NULL || |
| error->code != XML_ERR_UNSUPPORTED_ENCODING || |
| error->level != XML_ERR_WARNING || |
| strcmp(error->message, "Unsupported encoding: #unsupported\n") != 0) |
| { |
| fprintf(stderr, "xmlReadDoc failed to raise correct error\n"); |
| err = 1; |
| } |
| |
| return err; |
| } |
| |
| static int |
| testNodeGetContent(void) { |
| xmlDocPtr doc; |
| xmlChar *content; |
| int err = 0; |
| |
| doc = xmlReadDoc(BAD_CAST "<doc/>", NULL, NULL, 0); |
| xmlAddChild(doc->children, xmlNewReference(doc, BAD_CAST "lt")); |
| content = xmlNodeGetContent((xmlNodePtr) doc); |
| if (strcmp((char *) content, "<") != 0) { |
| fprintf(stderr, "xmlNodeGetContent failed\n"); |
| err = 1; |
| } |
| xmlFree(content); |
| xmlFreeDoc(doc); |
| |
| return err; |
| } |
| |
| static int |
| testCFileIO(void) { |
| xmlDocPtr doc; |
| int err = 0; |
| |
| /* Deprecated FILE-based API */ |
| xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen, xmlFileRead, |
| xmlFileClose); |
| doc = xmlReadFile("test/ent1", NULL, 0); |
| |
| if (doc == NULL) { |
| err = 1; |
| } else { |
| xmlNodePtr root = xmlDocGetRootElement(doc); |
| |
| if (root == NULL || !xmlStrEqual(root->name, BAD_CAST "EXAMPLE")) |
| err = 1; |
| } |
| |
| xmlFreeDoc(doc); |
| xmlPopInputCallbacks(); |
| |
| if (err) |
| fprintf(stderr, "xmlReadFile failed with FILE input callbacks\n"); |
| |
| return err; |
| } |
| |
| #ifdef LIBXML_VALID_ENABLED |
| static void |
| testSwitchDtdExtSubset(void *vctxt, const xmlChar *name ATTRIBUTE_UNUSED, |
| const xmlChar *externalId ATTRIBUTE_UNUSED, |
| const xmlChar *systemId ATTRIBUTE_UNUSED) { |
| xmlParserCtxtPtr ctxt = vctxt; |
| |
| ctxt->myDoc->extSubset = ctxt->_private; |
| } |
| |
| static int |
| testSwitchDtd(void) { |
| const char dtdContent[] = |
| "<!ENTITY test '<elem1/><elem2/>'>\n"; |
| const char docContent[] = |
| "<!DOCTYPE doc SYSTEM 'entities.dtd'>\n" |
| "<doc>&test;</doc>\n"; |
| xmlParserInputBufferPtr input; |
| xmlParserCtxtPtr ctxt; |
| xmlDtdPtr dtd; |
| xmlDocPtr doc; |
| xmlEntityPtr ent; |
| int err = 0; |
| |
| input = xmlParserInputBufferCreateStatic(dtdContent, |
| sizeof(dtdContent) - 1, |
| XML_CHAR_ENCODING_NONE); |
| dtd = xmlIOParseDTD(NULL, input, XML_CHAR_ENCODING_NONE); |
| |
| ctxt = xmlNewParserCtxt(); |
| ctxt->_private = dtd; |
| ctxt->sax->externalSubset = testSwitchDtdExtSubset; |
| doc = xmlCtxtReadMemory(ctxt, docContent, sizeof(docContent) - 1, NULL, |
| NULL, XML_PARSE_NOENT | XML_PARSE_DTDLOAD); |
| xmlFreeParserCtxt(ctxt); |
| |
| ent = xmlGetDocEntity(doc, BAD_CAST "test"); |
| if (ent->children->doc != NULL) { |
| fprintf(stderr, "Entity content should have NULL doc\n"); |
| err = 1; |
| } |
| |
| /* Free doc before DTD */ |
| doc->extSubset = NULL; |
| xmlFreeDoc(doc); |
| xmlFreeDtd(dtd); |
| |
| return err; |
| } |
| #endif /* LIBXML_VALID_ENABLED */ |
| |
| #ifdef LIBXML_OUTPUT_ENABLED |
| static xmlChar * |
| dumpNodeList(xmlNodePtr list) { |
| xmlBufferPtr buffer; |
| xmlSaveCtxtPtr save; |
| xmlNodePtr cur; |
| xmlChar *ret; |
| |
| buffer = xmlBufferCreate(); |
| save = xmlSaveToBuffer(buffer, "UTF-8", 0); |
| for (cur = list; cur != NULL; cur = cur->next) |
| xmlSaveTree(save, cur); |
| xmlSaveClose(save); |
| |
| ret = xmlBufferDetach(buffer); |
| xmlBufferFree(buffer); |
| return ret; |
| } |
| |
| static int |
| testCtxtParseContent(void) { |
| xmlParserCtxtPtr ctxt; |
| xmlParserInputPtr input; |
| xmlDocPtr doc; |
| xmlNodePtr node, list; |
| const char *content; |
| xmlChar *output; |
| int i, j; |
| int err = 0; |
| |
| static const char *const tests[] = { |
| "<!-- c -->\xF0\x9F\x98\x84<a/><b/>end", |
| "text<a:foo><b:foo/></a:foo>text<!-- c -->" |
| }; |
| |
| doc = xmlReadDoc(BAD_CAST "<doc xmlns:a='a'><elem xmlns:b='b'/></doc>", |
| NULL, NULL, 0); |
| node = doc->children->children; |
| |
| ctxt = xmlNewParserCtxt(); |
| |
| for (i = 0; (size_t) i < sizeof(tests) / sizeof(tests[0]); i++) { |
| content = tests[i]; |
| |
| for (j = 0; j < 2; j++) { |
| if (j == 0) { |
| input = xmlNewInputFromString(NULL, content, |
| XML_INPUT_BUF_STATIC); |
| list = xmlCtxtParseContent(ctxt, input, node, 0); |
| } else { |
| xmlParseInNodeContext(node, content, strlen(content), 0, |
| &list); |
| } |
| |
| output = dumpNodeList(list); |
| |
| if ((j == 0 && ctxt->nsWellFormed == 0) || |
| strcmp((char *) output, content) != 0) { |
| fprintf(stderr, "%s failed test %d, got:\n%s\n", |
| j == 0 ? |
| "xmlCtxtParseContent" : |
| "xmlParseInNodeContext", |
| i, output); |
| err = 1; |
| } |
| |
| xmlFree(output); |
| xmlFreeNodeList(list); |
| } |
| } |
| |
| xmlFreeParserCtxt(ctxt); |
| xmlFreeDoc(doc); |
| |
| return err; |
| } |
| |
| static int |
| testNoBlanks(void) { |
| const xmlChar xml[] = |
| "<refentry>\n" |
| " <refsect1>\n" |
| " <para>\n" |
| " Run <command>tester --help</command> for more options.\n" |
| " </para>\n" |
| " </refsect1>\n" |
| "</refentry>\n"; |
| const xmlChar expect[] = |
| "<?xml version=\"1.0\"?>\n" |
| "<refentry><refsect1><para>\n" |
| " Run <command>tester --help</command> for more options.\n" |
| " </para></refsect1></refentry>\n"; |
| xmlDocPtr doc; |
| xmlChar *out; |
| int size; |
| int err = 0; |
| |
| doc = xmlReadDoc(xml, NULL, NULL, XML_PARSE_NOBLANKS); |
| xmlDocDumpMemory(doc, &out, &size); |
| xmlFreeDoc(doc); |
| |
| if (!xmlStrEqual(out, expect)) { |
| fprintf(stderr, "parsing with XML_PARSE_NOBLANKS failed\n"); |
| err = 1; |
| } |
| xmlFree(out); |
| |
| return err; |
| } |
| #endif /* LIBXML_OUTPUT_ENABLED */ |
| |
| #ifdef LIBXML_SAX1_ENABLED |
| static int |
| testBalancedChunk(void) { |
| xmlNodePtr list; |
| xmlNodePtr elem; |
| int ret; |
| int err = 0; |
| |
| ret = xmlParseBalancedChunkMemory(NULL, NULL, NULL, 0, |
| BAD_CAST "start <node xml:lang='en'>abc</node> end", &list); |
| |
| if ((ret != XML_ERR_OK) || |
| (list == NULL) || |
| ((elem = list->next) == NULL) || |
| (elem->type != XML_ELEMENT_NODE) || |
| (elem->nsDef == NULL) || |
| (!xmlStrEqual(elem->nsDef->href, XML_XML_NAMESPACE))) { |
| fprintf(stderr, "xmlParseBalancedChunkMemory failed\n"); |
| err = 1; |
| } |
| |
| xmlFreeNodeList(list); |
| |
| return(err); |
| } |
| #endif |
| |
| static int |
| testStandaloneWithEncoding(void) { |
| xmlDocPtr doc; |
| const char *str = |
| "<?xml version=\"1.0\" standalone=\"yes\"?>\n" |
| "<doc></doc>\n"; |
| int err = 0; |
| |
| xmlResetLastError(); |
| |
| doc = xmlReadDoc(BAD_CAST str, NULL, "UTF-8", 0); |
| if (doc == NULL) { |
| fprintf(stderr, "xmlReadDoc failed\n"); |
| err = 1; |
| } |
| xmlFreeDoc(doc); |
| |
| return err; |
| } |
| |
| #ifdef LIBXML_PUSH_ENABLED |
| static int |
| testHugePush(void) { |
| xmlParserCtxtPtr ctxt; |
| int err, i; |
| |
| ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL); |
| |
| /* |
| * Push parse a document larger than XML_MAX_LOOKUP_LIMIT |
| * (10,000,000 bytes). This mainly tests whether shrinking the |
| * buffer works when push parsing. |
| */ |
| xmlParseChunk(ctxt, "<doc>", 5, 0); |
| for (i = 0; i < 1000000; i++) |
| xmlParseChunk(ctxt, "<elem>text</elem>", 17, 0); |
| xmlParseChunk(ctxt, "</doc>", 6, 1); |
| |
| err = ctxt->wellFormed ? 0 : 1; |
| xmlFreeDoc(ctxt->myDoc); |
| xmlFreeParserCtxt(ctxt); |
| |
| return err; |
| } |
| |
| static int |
| testHugeEncodedChunk(void) { |
| xmlBufferPtr buf; |
| xmlChar *chunk; |
| xmlParserCtxtPtr ctxt; |
| int err = 0, i; |
| |
| /* |
| * Test the push parser with a built-in encoding handler like ISO-8859-1 |
| * and a chunk larger than the initial decoded buffer (currently 4 KB). |
| */ |
| buf = xmlBufferCreate(); |
| xmlBufferCat(buf, |
| BAD_CAST "<?xml version='1.0' encoding='ISO-8859-1'?>\n"); |
| xmlBufferCat(buf, BAD_CAST "<doc><!-- "); |
| for (i = 0; i < 2000; i++) |
| xmlBufferCat(buf, BAD_CAST "0123456789"); |
| xmlBufferCat(buf, BAD_CAST " --></doc>"); |
| chunk = xmlBufferDetach(buf); |
| xmlBufferFree(buf); |
| |
| ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL); |
| |
| xmlParseChunk(ctxt, (char *) chunk, xmlStrlen(chunk), 0); |
| xmlParseChunk(ctxt, NULL, 0, 1); |
| |
| if (!ctxt->wellFormed) |
| err = 1; |
| xmlFreeDoc(ctxt->myDoc); |
| xmlFreeParserCtxt(ctxt); |
| xmlFree(chunk); |
| |
| /* |
| * Test the push parser with |
| * |
| * - a single call to xmlParseChunk, |
| * - a non-UTF8 encoding, |
| * - a chunk larger then MINLEN (4000 bytes). |
| * |
| * This verifies that the whole buffer is processed in the initial |
| * charset conversion. |
| */ |
| buf = xmlBufferCreate(); |
| xmlBufferCat(buf, |
| BAD_CAST "<?xml version='1.0' encoding='ISO-8859-1'?>\n"); |
| xmlBufferCat(buf, BAD_CAST "<doc>"); |
| /* 20,000 characters */ |
| for (i = 0; i < 2000; i++) |
| xmlBufferCat(buf, BAD_CAST "0123456789"); |
| xmlBufferCat(buf, BAD_CAST "</doc>"); |
| chunk = xmlBufferDetach(buf); |
| xmlBufferFree(buf); |
| |
| ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL); |
| |
| xmlParseChunk(ctxt, (char *) chunk, xmlStrlen(chunk), 1); |
| |
| if (!ctxt->wellFormed) |
| err = 1; |
| xmlFreeDoc(ctxt->myDoc); |
| xmlFreeParserCtxt(ctxt); |
| xmlFree(chunk); |
| |
| return err; |
| } |
| |
| static int |
| testPushCDataEnd(void) { |
| int err = 0; |
| int k; |
| |
| for (k = 0; k < 2; k++) { |
| xmlBufferPtr buf; |
| xmlChar *chunk; |
| xmlParserCtxtPtr ctxt; |
| int i; |
| |
| ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL); |
| xmlCtxtSetOptions(ctxt, XML_PARSE_NOERROR); |
| |
| /* |
| * Push parse text data with ']]>' split across chunks. |
| */ |
| buf = xmlBufferCreate(); |
| xmlBufferCCat(buf, "<doc>"); |
| |
| /* |
| * Also test xmlParseCharDataCopmlex |
| */ |
| if (k == 0) |
| xmlBufferCCat(buf, "x"); |
| else |
| xmlBufferCCat(buf, "\xC3\xA4"); |
| |
| /* |
| * Create enough data to trigger a "characters" SAX callback. |
| * (XML_PARSER_BIG_BUFFER_SIZE = 300) |
| */ |
| for (i = 0; i < 2000; i++) |
| xmlBufferCCat(buf, "x"); |
| |
| xmlBufferCCat(buf, "]"); |
| chunk = xmlBufferDetach(buf); |
| xmlBufferFree(buf); |
| |
| xmlParseChunk(ctxt, (char *) chunk, xmlStrlen(chunk), 0); |
| xmlParseChunk(ctxt, "]>xxx</doc>", 11, 1); |
| |
| if (ctxt->errNo != XML_ERR_MISPLACED_CDATA_END) { |
| fprintf(stderr, "xmlParseChunk failed to detect CData end: %d\n", |
| ctxt->errNo); |
| err = 1; |
| } |
| |
| xmlFree(chunk); |
| xmlFreeDoc(ctxt->myDoc); |
| xmlFreeParserCtxt(ctxt); |
| } |
| |
| return err; |
| } |
| #endif /* PUSH */ |
| |
| #ifdef LIBXML_HTML_ENABLED |
| static int |
| testHtmlIds(void) { |
| const char *htmlContent = |
| "<html><body><div id='myId'>Hello, World!</div></body></html>"; |
| htmlDocPtr doc; |
| xmlAttrPtr node; |
| |
| doc = htmlReadDoc(BAD_CAST htmlContent, NULL, NULL, 0); |
| if (doc == NULL) { |
| fprintf(stderr, "could not parse HTML content\n"); |
| return 1; |
| } |
| |
| node = xmlGetID(doc, BAD_CAST "myId"); |
| if (node == NULL) { |
| fprintf(stderr, "xmlGetID doesn't work on HTML\n"); |
| return 1; |
| } |
| |
| xmlFreeDoc(doc); |
| return 0; |
| } |
| |
| #ifdef LIBXML_PUSH_ENABLED |
| static int |
| testHtmlPushWithEncoding(void) { |
| htmlParserCtxtPtr ctxt; |
| htmlDocPtr doc; |
| htmlNodePtr node; |
| int err = 0; |
| |
| ctxt = htmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL, |
| XML_CHAR_ENCODING_UTF8); |
| htmlParseChunk(ctxt, "-\xC3\xA4-", 4, 1); |
| |
| doc = ctxt->myDoc; |
| if (!xmlStrEqual(doc->encoding, BAD_CAST "UTF-8")) { |
| fprintf(stderr, "testHtmlPushWithEncoding failed\n"); |
| err = 1; |
| } |
| |
| node = xmlDocGetRootElement(doc)->children->children; |
| if (!xmlStrEqual(node->content, BAD_CAST "-\xC3\xA4-")) { |
| fprintf(stderr, "testHtmlPushWithEncoding failed\n"); |
| err = 1; |
| } |
| |
| xmlFreeDoc(doc); |
| htmlFreeParserCtxt(ctxt); |
| return err; |
| } |
| #endif |
| #endif |
| |
| #ifdef LIBXML_READER_ENABLED |
| static int |
| testReaderEncoding(void) { |
| xmlBuffer *buf; |
| xmlTextReader *reader; |
| xmlChar *xml; |
| const xmlChar *encoding; |
| int err = 0; |
| int i; |
| |
| buf = xmlBufferCreate(); |
| xmlBufferCCat(buf, "<?xml version='1.0' encoding='ISO-8859-1'?>\n"); |
| xmlBufferCCat(buf, "<doc>"); |
| for (i = 0; i < 8192; i++) |
| xmlBufferCCat(buf, "x"); |
| xmlBufferCCat(buf, "</doc>"); |
| xml = xmlBufferDetach(buf); |
| xmlBufferFree(buf); |
| |
| reader = xmlReaderForDoc(BAD_CAST xml, NULL, NULL, 0); |
| xmlTextReaderRead(reader); |
| encoding = xmlTextReaderConstEncoding(reader); |
| |
| if (!xmlStrEqual(encoding, BAD_CAST "ISO-8859-1")) { |
| fprintf(stderr, "testReaderEncoding failed\n"); |
| err = 1; |
| } |
| |
| xmlFreeTextReader(reader); |
| xmlFree(xml); |
| return err; |
| } |
| |
| static int |
| testReaderContent(void) { |
| xmlTextReader *reader; |
| const xmlChar *xml = BAD_CAST "<d>x<e>y</e><f>z</f></d>"; |
| xmlChar *string; |
| int err = 0; |
| |
| reader = xmlReaderForDoc(xml, NULL, NULL, 0); |
| xmlTextReaderRead(reader); |
| |
| string = xmlTextReaderReadOuterXml(reader); |
| if (!xmlStrEqual(string, xml)) { |
| fprintf(stderr, "xmlTextReaderReadOuterXml failed\n"); |
| err = 1; |
| } |
| xmlFree(string); |
| |
| string = xmlTextReaderReadInnerXml(reader); |
| if (!xmlStrEqual(string, BAD_CAST "x<e>y</e><f>z</f>")) { |
| fprintf(stderr, "xmlTextReaderReadInnerXml failed\n"); |
| err = 1; |
| } |
| xmlFree(string); |
| |
| string = xmlTextReaderReadString(reader); |
| if (!xmlStrEqual(string, BAD_CAST "xyz")) { |
| fprintf(stderr, "xmlTextReaderReadString failed\n"); |
| err = 1; |
| } |
| xmlFree(string); |
| |
| xmlFreeTextReader(reader); |
| return err; |
| } |
| |
| static int |
| testReaderNode(xmlTextReader *reader) { |
| xmlChar *string; |
| int type; |
| int err = 0; |
| |
| type = xmlTextReaderNodeType(reader); |
| string = xmlTextReaderReadString(reader); |
| |
| if (type == XML_READER_TYPE_ELEMENT) { |
| xmlNodePtr node = xmlTextReaderCurrentNode(reader); |
| |
| if ((node->children == NULL) != (string == NULL)) |
| err = 1; |
| } else if (type == XML_READER_TYPE_TEXT || |
| type == XML_READER_TYPE_CDATA || |
| type == XML_READER_TYPE_WHITESPACE || |
| type == XML_READER_TYPE_SIGNIFICANT_WHITESPACE) { |
| if (string == NULL) |
| err = 1; |
| } else { |
| if (string != NULL) |
| err = 1; |
| } |
| |
| if (err) |
| fprintf(stderr, "xmlTextReaderReadString failed for %d\n", type); |
| |
| xmlFree(string); |
| |
| return err; |
| } |
| |
| static int |
| testReader(void) { |
| xmlTextReader *reader; |
| const xmlChar *xml = BAD_CAST |
| "<d>\n" |
| " x<e a='v'>y</e><f>z</f>\n" |
| " <![CDATA[cdata]]>\n" |
| " <!-- comment -->\n" |
| " <?pi content?>\n" |
| " <empty/>\n" |
| "</d>"; |
| int err = 0; |
| |
| reader = xmlReaderForDoc(xml, NULL, NULL, 0); |
| |
| while (xmlTextReaderRead(reader) > 0) { |
| if (testReaderNode(reader) > 0) { |
| err = 1; |
| break; |
| } |
| |
| if (xmlTextReaderMoveToFirstAttribute(reader) > 0) { |
| do { |
| if (testReaderNode(reader) > 0) { |
| err = 1; |
| break; |
| } |
| } while (xmlTextReaderMoveToNextAttribute(reader) > 0); |
| |
| xmlTextReaderMoveToElement(reader); |
| } |
| } |
| |
| xmlFreeTextReader(reader); |
| return err; |
| } |
| |
| #ifdef LIBXML_XINCLUDE_ENABLED |
| typedef struct { |
| char *message; |
| int code; |
| } testReaderErrorCtxt; |
| |
| static void |
| testReaderError(void *arg, const char *msg, |
| xmlParserSeverities severity ATTRIBUTE_UNUSED, |
| xmlTextReaderLocatorPtr locator ATTRIBUTE_UNUSED) { |
| testReaderErrorCtxt *ctxt = arg; |
| |
| if (ctxt->message != NULL) |
| xmlFree(ctxt->message); |
| ctxt->message = xmlMemStrdup(msg); |
| } |
| |
| static void |
| testStructuredReaderError(void *arg, const xmlError *error) { |
| testReaderErrorCtxt *ctxt = arg; |
| |
| if (ctxt->message != NULL) |
| xmlFree(ctxt->message); |
| ctxt->message = xmlMemStrdup(error->message); |
| ctxt->code = error->code; |
| } |
| |
| static int |
| testReaderXIncludeError(void) { |
| /* |
| * Test whether XInclude errors are reported to the custom error |
| * handler of a reader. |
| */ |
| const char *doc = |
| "<doc xmlns:xi='http://www.w3.org/2001/XInclude'>\n" |
| " <xi:include/>\n" |
| "</doc>\n"; |
| xmlTextReader *reader; |
| testReaderErrorCtxt errorCtxt; |
| int err = 0; |
| |
| reader = xmlReaderForDoc(BAD_CAST doc, NULL, NULL, XML_PARSE_XINCLUDE); |
| xmlTextReaderSetErrorHandler(reader, testReaderError, &errorCtxt); |
| errorCtxt.message = NULL; |
| errorCtxt.code = 0; |
| while (xmlTextReaderRead(reader) > 0) |
| ; |
| |
| if (errorCtxt.message == NULL || |
| strstr(errorCtxt.message, "href or xpointer") == NULL) { |
| fprintf(stderr, "xmlTextReaderSetErrorHandler failed\n"); |
| err = 1; |
| } |
| |
| xmlFree(errorCtxt.message); |
| xmlFreeTextReader(reader); |
| |
| reader = xmlReaderForDoc(BAD_CAST doc, NULL, NULL, XML_PARSE_XINCLUDE); |
| xmlTextReaderSetStructuredErrorHandler(reader, testStructuredReaderError, |
| &errorCtxt); |
| errorCtxt.message = NULL; |
| errorCtxt.code = 0; |
| while (xmlTextReaderRead(reader) > 0) |
| ; |
| |
| if (errorCtxt.code != XML_XINCLUDE_NO_HREF || |
| errorCtxt.message == NULL || |
| strstr(errorCtxt.message, "href or xpointer") == NULL) { |
| fprintf(stderr, "xmlTextReaderSetStructuredErrorHandler failed\n"); |
| err = 1; |
| } |
| |
| xmlFree(errorCtxt.message); |
| xmlFreeTextReader(reader); |
| |
| return err; |
| } |
| #endif |
| #endif |
| |
| #ifdef LIBXML_WRITER_ENABLED |
| static int |
| testWriterIOWrite(void *ctxt, const char *data, int len) { |
| (void) ctxt; |
| (void) data; |
| |
| return len; |
| } |
| |
| static int |
| testWriterIOClose(void *ctxt) { |
| (void) ctxt; |
| |
| return XML_IO_ENAMETOOLONG; |
| } |
| |
| static int |
| testWriterClose(void){ |
| xmlOutputBufferPtr out; |
| xmlTextWriterPtr writer; |
| int err = 0; |
| int result; |
| |
| out = xmlOutputBufferCreateIO(testWriterIOWrite, testWriterIOClose, |
| NULL, NULL); |
| writer = xmlNewTextWriter(out); |
| xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL); |
| xmlTextWriterStartElement(writer, BAD_CAST "elem"); |
| xmlTextWriterEndElement(writer); |
| xmlTextWriterEndDocument(writer); |
| result = xmlTextWriterClose(writer); |
| |
| if (result != XML_IO_ENAMETOOLONG) { |
| fprintf(stderr, "xmlTextWriterClose reported wrong error %d\n", |
| result); |
| err = 1; |
| } |
| |
| xmlFreeTextWriter(writer); |
| return err; |
| } |
| #endif |
| |
| typedef struct { |
| const char *uri; |
| const char *base; |
| const char *result; |
| } xmlRelativeUriTest; |
| |
| static int |
| testBuildRelativeUri(void) { |
| xmlChar *res; |
| int err = 0; |
| int i; |
| |
| static const xmlRelativeUriTest tests[] = { |
| { |
| "/a/b1/c1", |
| "/a/b2/c2", |
| "../b1/c1" |
| }, { |
| "a/b1/c1", |
| "a/b2/c2", |
| "../b1/c1" |
| }, { |
| "a/././b1/x/y/../z/../.././c1", |
| "./a/./b2/././b2", |
| "../b1/c1" |
| }, { |
| "file:///a/b1/c1", |
| "/a/b2/c2", |
| NULL |
| }, { |
| "/a/b1/c1", |
| "file:///a/b2/c2", |
| NULL |
| }, { |
| "a/b1/c1", |
| "/a/b2/c2", |
| NULL |
| }, { |
| "/a/b1/c1", |
| "a/b2/c2", |
| NULL |
| }, { |
| "http://example.org/a/b1/c1", |
| "http://example.org/a/b2/c2", |
| "../b1/c1" |
| }, { |
| "http://example.org/a/b1/c1", |
| "https://example.org/a/b2/c2", |
| NULL |
| }, { |
| "http://example.org/a/b1/c1", |
| "http://localhost/a/b2/c2", |
| NULL |
| }, { |
| "with space/x x/y y", |
| "with space/b2/c2", |
| "../x%20x/y%20y" |
| }, { |
| "with space/x x/y y", |
| "/b2/c2", |
| "with%20space/x%20x/y%20y" |
| } |
| #if defined(_WIN32) || defined(__CYGWIN__) |
| , { |
| "\\a\\b1\\c1", |
| "\\a\\b2\\c2", |
| "../b1/c1" |
| }, { |
| "\\a\\b1\\c1", |
| "/a/b2/c2", |
| "../b1/c1" |
| }, { |
| "a\\b1\\c1", |
| "a/b2/c2", |
| "../b1/c1" |
| }, { |
| "file://server/a/b1/c1", |
| "\\\\?\\UNC\\server\\a\\b2\\c2", |
| "../b1/c1" |
| }, { |
| "file://server/a/b1/c1", |
| "\\\\server\\a\\b2\\c2", |
| "../b1/c1" |
| }, { |
| "file:///x:/a/b1/c1", |
| "x:\\a\\b2\\c2", |
| "../b1/c1" |
| }, { |
| "file:///x:/a/b1/c1", |
| "\\\\?\\x:\\a\\b2\\c2", |
| "../b1/c1" |
| }, { |
| "file:///x:/a/b1/c1", |
| "file:///y:/a/b2/c2", |
| NULL |
| }, { |
| "x:/a/b1/c1", |
| "y:/a/b2/c2", |
| "file:///x:/a/b1/c1" |
| }, { |
| "/a/b1/c1", |
| "y:/a/b2/c2", |
| NULL |
| }, { |
| "\\\\server\\a\\b1\\c1", |
| "a/b2/c2", |
| "file://server/a/b1/c1" |
| } |
| #endif |
| }; |
| |
| for (i = 0; (size_t) i < sizeof(tests) / sizeof(tests[0]); i++) { |
| const xmlRelativeUriTest *test = tests + i; |
| const char *expect; |
| |
| res = xmlBuildRelativeURI(BAD_CAST test->uri, BAD_CAST test->base); |
| expect = test->result ? test->result : test->uri; |
| if (!xmlStrEqual(res, BAD_CAST expect)) { |
| fprintf(stderr, "xmlBuildRelativeURI failed uri=%s base=%s " |
| "result=%s expected=%s\n", test->uri, test->base, |
| res, expect); |
| err = 1; |
| } |
| xmlFree(res); |
| } |
| |
| return err; |
| } |
| |
| #if defined(_WIN32) || defined(__CYGWIN__) |
| static int |
| testWindowsUri(void) { |
| const char *url = "c:/a%20b/file.txt"; |
| xmlURIPtr uri; |
| xmlChar *res; |
| int err = 0; |
| int i; |
| |
| static const xmlRelativeUriTest tests[] = { |
| { |
| "c:/a%20b/file.txt", |
| "base.xml", |
| "c:/a b/file.txt" |
| }, { |
| "file:///c:/a%20b/file.txt", |
| "base.xml", |
| "file:///c:/a%20b/file.txt" |
| }, { |
| "Z:/a%20b/file.txt", |
| "http://example.com/", |
| "Z:/a b/file.txt" |
| }, { |
| "a%20b/b1/c1", |
| "C:/a/b2/c2", |
| "C:/a/b2/a b/b1/c1" |
| }, { |
| "a%20b/b1/c1", |
| "\\a\\b2\\c2", |
| "/a/b2/a b/b1/c1" |
| }, { |
| "a%20b/b1/c1", |
| "\\\\?\\a\\b2\\c2", |
| "//?/a/b2/a b/b1/c1" |
| }, { |
| "a%20b/b1/c1", |
| "\\\\\\\\server\\b2\\c2", |
| "//server/b2/a b/b1/c1" |
| } |
| }; |
| |
| uri = xmlParseURI(url); |
| if (uri == NULL) { |
| fprintf(stderr, "xmlParseURI failed\n"); |
| err = 1; |
| } else { |
| if (uri->scheme != NULL) { |
| fprintf(stderr, "invalid scheme: %s\n", uri->scheme); |
| err = 1; |
| } |
| if (uri->path == NULL || strcmp(uri->path, "c:/a b/file.txt") != 0) { |
| fprintf(stderr, "invalid path: %s\n", uri->path); |
| err = 1; |
| } |
| |
| xmlFreeURI(uri); |
| } |
| |
| for (i = 0; (size_t) i < sizeof(tests) / sizeof(tests[0]); i++) { |
| const xmlRelativeUriTest *test = tests + i; |
| |
| res = xmlBuildURI(BAD_CAST test->uri, BAD_CAST test->base); |
| if (res == NULL || !xmlStrEqual(res, BAD_CAST test->result)) { |
| fprintf(stderr, "xmlBuildURI failed uri=%s base=%s " |
| "result=%s expected=%s\n", test->uri, test->base, |
| res, test->result); |
| err = 1; |
| } |
| xmlFree(res); |
| } |
| |
| return err; |
| } |
| #endif /* WIN32 */ |
| |
| #if defined(LIBXML_ICONV_ENABLED) || defined(LIBXML_ICU_ENABLED) |
| static int |
| testTruncatedMultiByte(void) { |
| const char xml[] = |
| "<?xml version=\"1.0\" encoding=\"EUC-JP\"?>\n" |
| "<doc/>\xC3"; |
| #ifdef LIBXML_HTML_ENABLED |
| const char html[] = |
| "<meta charset=\"EUC-JP\">\n" |
| "<div/>\xC3"; |
| #endif |
| xmlDocPtr doc; |
| const xmlError *error; |
| int err = 0; |
| |
| xmlResetLastError(); |
| doc = xmlReadDoc(BAD_CAST xml, NULL, NULL, XML_PARSE_NOERROR); |
| error = xmlGetLastError(); |
| if (error == NULL || error->code != XML_ERR_INVALID_ENCODING) { |
| fprintf(stderr, "xml, pull: expected XML_ERR_INVALID_ENCODING\n"); |
| err = 1; |
| } |
| xmlFreeDoc(doc); |
| |
| #ifdef LIBXML_HTML_ENABLED |
| xmlResetLastError(); |
| doc = htmlReadDoc(BAD_CAST html, NULL, NULL, XML_PARSE_NOERROR); |
| error = xmlGetLastError(); |
| if (error == NULL || error->code != XML_ERR_INVALID_ENCODING) { |
| fprintf(stderr, "html, pull: expected XML_ERR_INVALID_ENCODING\n"); |
| err = 1; |
| } |
| xmlFreeDoc(doc); |
| #endif /* LIBXML_HTML_ENABLED */ |
| |
| #ifdef LIBXML_PUSH_ENABLED |
| { |
| xmlParserCtxtPtr ctxt; |
| |
| ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL); |
| xmlCtxtSetOptions(ctxt, XML_PARSE_NOERROR); |
| |
| xmlParseChunk(ctxt, xml, sizeof(xml) - 1, 0); |
| xmlParseChunk(ctxt, "", 0, 1); |
| |
| if (ctxt->errNo != XML_ERR_INVALID_ENCODING) { |
| fprintf(stderr, "xml, push: expected XML_ERR_INVALID_ENCODING\n"); |
| err = 1; |
| } |
| |
| xmlFreeDoc(ctxt->myDoc); |
| xmlFreeParserCtxt(ctxt); |
| |
| #ifdef LIBXML_HTML_ENABLED |
| ctxt = htmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL, |
| XML_CHAR_ENCODING_NONE); |
| xmlCtxtSetOptions(ctxt, XML_PARSE_NOERROR); |
| |
| htmlParseChunk(ctxt, html, sizeof(html) - 1, 0); |
| htmlParseChunk(ctxt, "", 0, 1); |
| |
| if (ctxt->errNo != XML_ERR_INVALID_ENCODING) { |
| fprintf(stderr, "html, push: expected XML_ERR_INVALID_ENCODING\n"); |
| err = 1; |
| } |
| |
| xmlFreeDoc(ctxt->myDoc); |
| htmlFreeParserCtxt(ctxt); |
| #endif /* LIBXML_HTML_ENABLED */ |
| } |
| #endif /* LIBXML_PUSH_ENABLED */ |
| |
| return err; |
| } |
| #endif /* iconv || icu */ |
| |
| static int charEncConvImplError; |
| |
| static xmlCharEncError |
| rot13Convert(void *vctxt, unsigned char *out, int *outlen, |
| const unsigned char *in, int *inlen, |
| int flush ATTRIBUTE_UNUSED) { |
| int *ctxt = vctxt; |
| int inSize = *inlen; |
| int outSize = *outlen; |
| int rot, i; |
| |
| rot = *ctxt; |
| |
| for (i = 0; i < inSize && i < outSize; i++) { |
| int c = in[i]; |
| |
| if (c >= 'A' && c <= 'Z') |
| c = 'A' + (c - 'A' + rot) % 26; |
| else if (c >= 'a' && c <= 'z') |
| c = 'a' + (c - 'a' + rot) % 26; |
| |
| out[i] = c; |
| } |
| |
| *inlen = i; |
| *outlen = i; |
| |
| return XML_ENC_ERR_SUCCESS; |
| } |
| |
| static void |
| rot13ConvCtxtDtor(void *vctxt) { |
| xmlFree(vctxt); |
| } |
| |
| static xmlParserErrors |
| rot13ConvImpl(void *vctxt ATTRIBUTE_UNUSED, const char *name, |
| xmlCharEncFlags flags, xmlCharEncodingHandler **out) { |
| int *inputCtxt; |
| |
| if (strcmp(name, "rot13") != 0) |
| return xmlCreateCharEncodingHandler(name, flags, NULL, NULL, out); |
| |
| if (flags & XML_ENC_OUTPUT) |
| return XML_ERR_UNSUPPORTED_ENCODING; |
| |
| inputCtxt = xmlMalloc(sizeof(*inputCtxt)); |
| *inputCtxt = 13; |
| |
| return xmlCharEncNewCustomHandler(name, rot13Convert, NULL, |
| rot13ConvCtxtDtor, inputCtxt, NULL, |
| out); |
| } |
| |
| static int |
| testCharEncConvImpl(void) { |
| xmlParserCtxtPtr ctxt; |
| xmlDocPtr doc; |
| xmlNodePtr root; |
| int err = 0; |
| |
| ctxt = xmlNewParserCtxt(); |
| xmlCtxtSetCharEncConvImpl(ctxt, rot13ConvImpl, NULL); |
| charEncConvImplError = 0; |
| doc = xmlCtxtReadDoc(ctxt, BAD_CAST "<?kzy irefvba='1.0'?><qbp/>", NULL, |
| "rot13", 0); |
| if (charEncConvImplError) |
| err = 1; |
| xmlFreeParserCtxt(ctxt); |
| |
| root = xmlDocGetRootElement(doc); |
| if (root == NULL || strcmp((char *) root->name, "doc") != 0) { |
| fprintf(stderr, "testCharEncConvImpl failed\n"); |
| err = 1; |
| } |
| |
| xmlFreeDoc(doc); |
| |
| return err; |
| } |
| |
| int |
| main(void) { |
| int err = 0; |
| |
| err |= testNewDocNode(); |
| err |= testStandaloneWithEncoding(); |
| err |= testUnsupportedEncoding(); |
| err |= testNodeGetContent(); |
| err |= testCFileIO(); |
| #ifdef LIBXML_VALID_ENABLED |
| err |= testSwitchDtd(); |
| #endif |
| #ifdef LIBXML_OUTPUT_ENABLED |
| err |= testCtxtParseContent(); |
| err |= testNoBlanks(); |
| #endif |
| #ifdef LIBXML_SAX1_ENABLED |
| err |= testBalancedChunk(); |
| #endif |
| #ifdef LIBXML_PUSH_ENABLED |
| err |= testHugePush(); |
| err |= testHugeEncodedChunk(); |
| err |= testPushCDataEnd(); |
| #endif |
| #ifdef LIBXML_HTML_ENABLED |
| err |= testHtmlIds(); |
| #ifdef LIBXML_PUSH_ENABLED |
| err |= testHtmlPushWithEncoding(); |
| #endif |
| #endif |
| #ifdef LIBXML_READER_ENABLED |
| err |= testReaderEncoding(); |
| err |= testReaderContent(); |
| err |= testReader(); |
| #ifdef LIBXML_XINCLUDE_ENABLED |
| err |= testReaderXIncludeError(); |
| #endif |
| #endif |
| #ifdef LIBXML_WRITER_ENABLED |
| err |= testWriterClose(); |
| #endif |
| err |= testBuildRelativeUri(); |
| #if defined(_WIN32) || defined(__CYGWIN__) |
| err |= testWindowsUri(); |
| #endif |
| #if defined(LIBXML_ICONV_ENABLED) || defined(LIBXML_ICU_ENABLED) |
| err |= testTruncatedMultiByte(); |
| #endif |
| err |= testCharEncConvImpl(); |
| |
| return err; |
| } |
| |