1253 lines · 32.4 KB · C
RawDownload
/* * HTMLtree.c : implementation of access function for an HTML tree. * * See Copyright for the status of this software. * * daniel@veillard.com */  #define IN_LIBXML#include "libxml.h"#ifdef LIBXML_HTML_ENABLED #include <string.h> /* for memset() only ! */ #ifdef HAVE_CTYPE_H#include <ctype.h>#endif#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif #include <libxml/xmlmemory.h>#include <libxml/HTMLparser.h>#include <libxml/HTMLtree.h>#include <libxml/entities.h>#include <libxml/valid.h>#include <libxml/xmlerror.h>#include <libxml/parserInternals.h>#include <libxml/globals.h>#include <libxml/uri.h> #include "buf.h" /************************************************************************ *									* *		Getting/Setting encoding meta tags			* *									* ************************************************************************/ /** * htmlGetMetaEncoding: * @doc:  the document * * Encoding definition lookup in the Meta tags * * Returns the current encoding as flagged in the HTML source */const xmlChar *htmlGetMetaEncoding(htmlDocPtr doc) {    htmlNodePtr cur;    const xmlChar *content;    const xmlChar *encoding;     if (doc == NULL)	return(NULL);    cur = doc->children;     /*     * Search the html     */    while (cur != NULL) {	if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {	    if (xmlStrEqual(cur->name, BAD_CAST"html"))		break;	    if (xmlStrEqual(cur->name, BAD_CAST"head"))		goto found_head;	    if (xmlStrEqual(cur->name, BAD_CAST"meta"))		goto found_meta;	}	cur = cur->next;    }    if (cur == NULL)	return(NULL);    cur = cur->children;     /*     * Search the head     */    while (cur != NULL) {	if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {	    if (xmlStrEqual(cur->name, BAD_CAST"head"))		break;	    if (xmlStrEqual(cur->name, BAD_CAST"meta"))		goto found_meta;	}	cur = cur->next;    }    if (cur == NULL)	return(NULL);found_head:    cur = cur->children;     /*     * Search the meta elements     */found_meta:    while (cur != NULL) {	if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {	    if (xmlStrEqual(cur->name, BAD_CAST"meta")) {		xmlAttrPtr attr = cur->properties;		int http;		const xmlChar *value; 		content = NULL;		http = 0;		while (attr != NULL) {		    if ((attr->children != NULL) &&		        (attr->children->type == XML_TEXT_NODE) &&		        (attr->children->next == NULL)) {			value = attr->children->content;			if ((!xmlStrcasecmp(attr->name, BAD_CAST"http-equiv"))			 && (!xmlStrcasecmp(value, BAD_CAST"Content-Type")))			    http = 1;			else if ((value != NULL)			 && (!xmlStrcasecmp(attr->name, BAD_CAST"content")))			    content = value;			if ((http != 0) && (content != NULL))			    goto found_content;		    }		    attr = attr->next;		}	    }	}	cur = cur->next;    }    return(NULL); found_content:    encoding = xmlStrstr(content, BAD_CAST"charset=");    if (encoding == NULL)	encoding = xmlStrstr(content, BAD_CAST"Charset=");    if (encoding == NULL)	encoding = xmlStrstr(content, BAD_CAST"CHARSET=");    if (encoding != NULL) {	encoding += 8;    } else {	encoding = xmlStrstr(content, BAD_CAST"charset =");	if (encoding == NULL)	    encoding = xmlStrstr(content, BAD_CAST"Charset =");	if (encoding == NULL)	    encoding = xmlStrstr(content, BAD_CAST"CHARSET =");	if (encoding != NULL)	    encoding += 9;    }    if (encoding != NULL) {	while ((*encoding == ' ') || (*encoding == '\t')) encoding++;    }    return(encoding);} /** * htmlSetMetaEncoding: * @doc:  the document * @encoding:  the encoding string * * Sets the current encoding in the Meta tags * NOTE: this will not change the document content encoding, just * the META flag associated. * * Returns 0 in case of success and -1 in case of error */inthtmlSetMetaEncoding(htmlDocPtr doc, const xmlChar *encoding) {    htmlNodePtr cur, meta = NULL, head = NULL;    const xmlChar *content = NULL;    char newcontent[100];     newcontent[0] = 0;     if (doc == NULL)	return(-1);     /* html isn't a real encoding it's just libxml2 way to get entities */    if (!xmlStrcasecmp(encoding, BAD_CAST "html"))        return(-1);     if (encoding != NULL) {	snprintf(newcontent, sizeof(newcontent), "text/html; charset=%s",                (char *)encoding);	newcontent[sizeof(newcontent) - 1] = 0;    }     cur = doc->children;     /*     * Search the html     */    while (cur != NULL) {	if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {	    if (xmlStrcasecmp(cur->name, BAD_CAST"html") == 0)		break;	    if (xmlStrcasecmp(cur->name, BAD_CAST"head") == 0)		goto found_head;	    if (xmlStrcasecmp(cur->name, BAD_CAST"meta") == 0)		goto found_meta;	}	cur = cur->next;    }    if (cur == NULL)	return(-1);    cur = cur->children;     /*     * Search the head     */    while (cur != NULL) {	if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {	    if (xmlStrcasecmp(cur->name, BAD_CAST"head") == 0)		break;	    if (xmlStrcasecmp(cur->name, BAD_CAST"meta") == 0) {                head = cur->parent;		goto found_meta;            }	}	cur = cur->next;    }    if (cur == NULL)	return(-1);found_head:    head = cur;    if (cur->children == NULL)        goto create;    cur = cur->children; found_meta:    /*     * Search and update all the remaining the meta elements carrying     * encoding informations     */    while (cur != NULL) {	if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {	    if (xmlStrcasecmp(cur->name, BAD_CAST"meta") == 0) {		xmlAttrPtr attr = cur->properties;		int http;		const xmlChar *value; 		content = NULL;		http = 0;		while (attr != NULL) {		    if ((attr->children != NULL) &&		        (attr->children->type == XML_TEXT_NODE) &&		        (attr->children->next == NULL)) {			value = attr->children->content;			if ((!xmlStrcasecmp(attr->name, BAD_CAST"http-equiv"))			 && (!xmlStrcasecmp(value, BAD_CAST"Content-Type")))			    http = 1;			else                        {                           if ((value != NULL) &&                               (!xmlStrcasecmp(attr->name, BAD_CAST"content")))			       content = value;                        }		        if ((http != 0) && (content != NULL))			    break;		    }		    attr = attr->next;		}		if ((http != 0) && (content != NULL)) {		    meta = cur;		    break;		} 	    }	}	cur = cur->next;    }create:    if (meta == NULL) {        if ((encoding != NULL) && (head != NULL)) {            /*             * Create a new Meta element with the right attributes             */             meta = xmlNewDocNode(doc, NULL, BAD_CAST"meta", NULL);            if (head->children == NULL)                xmlAddChild(head, meta);            else                xmlAddPrevSibling(head->children, meta);            xmlNewProp(meta, BAD_CAST"http-equiv", BAD_CAST"Content-Type");            xmlNewProp(meta, BAD_CAST"content", BAD_CAST newcontent);        }    } else {        /* remove the meta tag if NULL is passed */        if (encoding == NULL) {            xmlUnlinkNode(meta);            xmlFreeNode(meta);        }        /* change the document only if there is a real encoding change */        else if (xmlStrcasestr(content, encoding) == NULL) {            xmlSetProp(meta, BAD_CAST"content", BAD_CAST newcontent);        }    }      return(0);} /** * booleanHTMLAttrs: * * These are the HTML attributes which will be output * in minimized form, i.e. <option selected="selected"> will be * output as <option selected>, as per XSLT 1.0 16.2 "HTML Output Method" * */static const char* htmlBooleanAttrs[] = {  "checked", "compact", "declare", "defer", "disabled", "ismap",  "multiple", "nohref", "noresize", "noshade", "nowrap", "readonly",  "selected", NULL};  /** * htmlIsBooleanAttr: * @name:  the name of the attribute to check * * Determine if a given attribute is a boolean attribute. * * returns: false if the attribute is not boolean, true otherwise. */inthtmlIsBooleanAttr(const xmlChar *name){    int i = 0;     while (htmlBooleanAttrs[i] != NULL) {        if (xmlStrcasecmp((const xmlChar *)htmlBooleanAttrs[i], name) == 0)            return 1;        i++;    }    return 0;} #ifdef LIBXML_OUTPUT_ENABLED/* * private routine exported from xmlIO.c */xmlOutputBufferPtrxmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder);/************************************************************************ *									* *			Output error handlers				* *									* ************************************************************************//** * htmlSaveErrMemory: * @extra:  extra informations * * Handle an out of memory condition */static voidhtmlSaveErrMemory(const char *extra){    __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra);} /** * htmlSaveErr: * @code:  the error number * @node:  the location of the error. * @extra:  extra informations * * Handle an out of memory condition */static voidhtmlSaveErr(int code, xmlNodePtr node, const char *extra){    const char *msg = NULL;     switch(code) {        case XML_SAVE_NOT_UTF8:	    msg = "string is not in UTF-8\n";	    break;	case XML_SAVE_CHAR_INVALID:	    msg = "invalid character value\n";	    break;	case XML_SAVE_UNKNOWN_ENCODING:	    msg = "unknown encoding %s\n";	    break;	case XML_SAVE_NO_DOCTYPE:	    msg = "HTML has no DOCTYPE\n";	    break;	default:	    msg = "unexpected error number\n";    }    __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra);} /************************************************************************ *									* *		Dumping HTML tree content to a simple buffer		* *									* ************************************************************************/ /** * htmlBufNodeDumpFormat: * @buf:  the xmlBufPtr output * @doc:  the document * @cur:  the current node * @format:  should formatting spaces been added * * Dump an HTML node, recursive behaviour,children are printed too. * * Returns the number of byte written or -1 in case of error */static size_thtmlBufNodeDumpFormat(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur,	           int format) {    size_t use;    int ret;    xmlOutputBufferPtr outbuf;     if (cur == NULL) {	return (-1);    }    if (buf == NULL) {	return (-1);    }    outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));    if (outbuf == NULL) {        htmlSaveErrMemory("allocating HTML output buffer");	return (-1);    }    memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));    outbuf->buffer = buf;    outbuf->encoder = NULL;    outbuf->writecallback = NULL;    outbuf->closecallback = NULL;    outbuf->context = NULL;    outbuf->written = 0;     use = xmlBufUse(buf);    htmlNodeDumpFormatOutput(outbuf, doc, cur, NULL, format);    xmlFree(outbuf);    ret = xmlBufUse(buf) - use;    return (ret);} /** * htmlNodeDump: * @buf:  the HTML buffer output * @doc:  the document * @cur:  the current node * * Dump an HTML node, recursive behaviour,children are printed too, * and formatting returns are added. * * Returns the number of byte written or -1 in case of error */inthtmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur) {    xmlBufPtr buffer;    size_t ret;     if ((buf == NULL) || (cur == NULL))        return(-1);     xmlInitParser();    buffer = xmlBufFromBuffer(buf);    if (buffer == NULL)        return(-1);     ret = htmlBufNodeDumpFormat(buffer, doc, cur, 1);     xmlBufBackToBuffer(buffer);     if (ret > INT_MAX)        return(-1);    return((int) ret);} /** * htmlNodeDumpFileFormat: * @out:  the FILE pointer * @doc:  the document * @cur:  the current node * @encoding: the document encoding * @format:  should formatting spaces been added * * Dump an HTML node, recursive behaviour,children are printed too. * * TODO: if encoding == NULL try to save in the doc encoding * * returns: the number of byte written or -1 in case of failure. */inthtmlNodeDumpFileFormat(FILE *out, xmlDocPtr doc,	               xmlNodePtr cur, const char *encoding, int format) {    xmlOutputBufferPtr buf;    xmlCharEncodingHandlerPtr handler = NULL;    int ret;     xmlInitParser();     if (encoding != NULL) {	xmlCharEncoding enc; 	enc = xmlParseCharEncoding(encoding);	if (enc != XML_CHAR_ENCODING_UTF8) {

Lines 1–500 of 1253.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t