xref: /aosp_15_r20/external/libxml2/HTMLtree.c (revision 7c5688314b92172186c154356a6374bf7684c3ca)
1*7c568831SAndroid Build Coastguard Worker /*
2*7c568831SAndroid Build Coastguard Worker  * HTMLtree.c : implementation of access function for an HTML tree.
3*7c568831SAndroid Build Coastguard Worker  *
4*7c568831SAndroid Build Coastguard Worker  * See Copyright for the status of this software.
5*7c568831SAndroid Build Coastguard Worker  *
6*7c568831SAndroid Build Coastguard Worker  * [email protected]
7*7c568831SAndroid Build Coastguard Worker  */
8*7c568831SAndroid Build Coastguard Worker 
9*7c568831SAndroid Build Coastguard Worker 
10*7c568831SAndroid Build Coastguard Worker #define IN_LIBXML
11*7c568831SAndroid Build Coastguard Worker #include "libxml.h"
12*7c568831SAndroid Build Coastguard Worker #ifdef LIBXML_HTML_ENABLED
13*7c568831SAndroid Build Coastguard Worker 
14*7c568831SAndroid Build Coastguard Worker #include <string.h> /* for memset() only ! */
15*7c568831SAndroid Build Coastguard Worker #include <ctype.h>
16*7c568831SAndroid Build Coastguard Worker #include <stdlib.h>
17*7c568831SAndroid Build Coastguard Worker 
18*7c568831SAndroid Build Coastguard Worker #include <libxml/xmlmemory.h>
19*7c568831SAndroid Build Coastguard Worker #include <libxml/HTMLparser.h>
20*7c568831SAndroid Build Coastguard Worker #include <libxml/HTMLtree.h>
21*7c568831SAndroid Build Coastguard Worker #include <libxml/entities.h>
22*7c568831SAndroid Build Coastguard Worker #include <libxml/xmlerror.h>
23*7c568831SAndroid Build Coastguard Worker #include <libxml/parserInternals.h>
24*7c568831SAndroid Build Coastguard Worker #include <libxml/uri.h>
25*7c568831SAndroid Build Coastguard Worker 
26*7c568831SAndroid Build Coastguard Worker #include "private/buf.h"
27*7c568831SAndroid Build Coastguard Worker #include "private/error.h"
28*7c568831SAndroid Build Coastguard Worker #include "private/io.h"
29*7c568831SAndroid Build Coastguard Worker #include "private/save.h"
30*7c568831SAndroid Build Coastguard Worker 
31*7c568831SAndroid Build Coastguard Worker /************************************************************************
32*7c568831SAndroid Build Coastguard Worker  *									*
33*7c568831SAndroid Build Coastguard Worker  *		Getting/Setting encoding meta tags			*
34*7c568831SAndroid Build Coastguard Worker  *									*
35*7c568831SAndroid Build Coastguard Worker  ************************************************************************/
36*7c568831SAndroid Build Coastguard Worker 
37*7c568831SAndroid Build Coastguard Worker /**
38*7c568831SAndroid Build Coastguard Worker  * htmlGetMetaEncoding:
39*7c568831SAndroid Build Coastguard Worker  * @doc:  the document
40*7c568831SAndroid Build Coastguard Worker  *
41*7c568831SAndroid Build Coastguard Worker  * Encoding definition lookup in the Meta tags
42*7c568831SAndroid Build Coastguard Worker  *
43*7c568831SAndroid Build Coastguard Worker  * Returns the current encoding as flagged in the HTML source
44*7c568831SAndroid Build Coastguard Worker  */
45*7c568831SAndroid Build Coastguard Worker const xmlChar *
htmlGetMetaEncoding(htmlDocPtr doc)46*7c568831SAndroid Build Coastguard Worker htmlGetMetaEncoding(htmlDocPtr doc) {
47*7c568831SAndroid Build Coastguard Worker     htmlNodePtr cur;
48*7c568831SAndroid Build Coastguard Worker     const xmlChar *content;
49*7c568831SAndroid Build Coastguard Worker     const xmlChar *encoding;
50*7c568831SAndroid Build Coastguard Worker 
51*7c568831SAndroid Build Coastguard Worker     if (doc == NULL)
52*7c568831SAndroid Build Coastguard Worker 	return(NULL);
53*7c568831SAndroid Build Coastguard Worker     cur = doc->children;
54*7c568831SAndroid Build Coastguard Worker 
55*7c568831SAndroid Build Coastguard Worker     /*
56*7c568831SAndroid Build Coastguard Worker      * Search the html
57*7c568831SAndroid Build Coastguard Worker      */
58*7c568831SAndroid Build Coastguard Worker     while (cur != NULL) {
59*7c568831SAndroid Build Coastguard Worker 	if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {
60*7c568831SAndroid Build Coastguard Worker 	    if (xmlStrEqual(cur->name, BAD_CAST"html"))
61*7c568831SAndroid Build Coastguard Worker 		break;
62*7c568831SAndroid Build Coastguard Worker 	    if (xmlStrEqual(cur->name, BAD_CAST"head"))
63*7c568831SAndroid Build Coastguard Worker 		goto found_head;
64*7c568831SAndroid Build Coastguard Worker 	    if (xmlStrEqual(cur->name, BAD_CAST"meta"))
65*7c568831SAndroid Build Coastguard Worker 		goto found_meta;
66*7c568831SAndroid Build Coastguard Worker 	}
67*7c568831SAndroid Build Coastguard Worker 	cur = cur->next;
68*7c568831SAndroid Build Coastguard Worker     }
69*7c568831SAndroid Build Coastguard Worker     if (cur == NULL)
70*7c568831SAndroid Build Coastguard Worker 	return(NULL);
71*7c568831SAndroid Build Coastguard Worker     cur = cur->children;
72*7c568831SAndroid Build Coastguard Worker 
73*7c568831SAndroid Build Coastguard Worker     /*
74*7c568831SAndroid Build Coastguard Worker      * Search the head
75*7c568831SAndroid Build Coastguard Worker      */
76*7c568831SAndroid Build Coastguard Worker     while (cur != NULL) {
77*7c568831SAndroid Build Coastguard Worker 	if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {
78*7c568831SAndroid Build Coastguard Worker 	    if (xmlStrEqual(cur->name, BAD_CAST"head"))
79*7c568831SAndroid Build Coastguard Worker 		break;
80*7c568831SAndroid Build Coastguard Worker 	    if (xmlStrEqual(cur->name, BAD_CAST"meta"))
81*7c568831SAndroid Build Coastguard Worker 		goto found_meta;
82*7c568831SAndroid Build Coastguard Worker 	}
83*7c568831SAndroid Build Coastguard Worker 	cur = cur->next;
84*7c568831SAndroid Build Coastguard Worker     }
85*7c568831SAndroid Build Coastguard Worker     if (cur == NULL)
86*7c568831SAndroid Build Coastguard Worker 	return(NULL);
87*7c568831SAndroid Build Coastguard Worker found_head:
88*7c568831SAndroid Build Coastguard Worker     cur = cur->children;
89*7c568831SAndroid Build Coastguard Worker 
90*7c568831SAndroid Build Coastguard Worker     /*
91*7c568831SAndroid Build Coastguard Worker      * Search the meta elements
92*7c568831SAndroid Build Coastguard Worker      */
93*7c568831SAndroid Build Coastguard Worker found_meta:
94*7c568831SAndroid Build Coastguard Worker     while (cur != NULL) {
95*7c568831SAndroid Build Coastguard Worker 	if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {
96*7c568831SAndroid Build Coastguard Worker 	    if (xmlStrEqual(cur->name, BAD_CAST"meta")) {
97*7c568831SAndroid Build Coastguard Worker 		xmlAttrPtr attr = cur->properties;
98*7c568831SAndroid Build Coastguard Worker 		int http;
99*7c568831SAndroid Build Coastguard Worker 		const xmlChar *value;
100*7c568831SAndroid Build Coastguard Worker 
101*7c568831SAndroid Build Coastguard Worker 		content = NULL;
102*7c568831SAndroid Build Coastguard Worker 		http = 0;
103*7c568831SAndroid Build Coastguard Worker 		while (attr != NULL) {
104*7c568831SAndroid Build Coastguard Worker 		    if ((attr->children != NULL) &&
105*7c568831SAndroid Build Coastguard Worker 		        (attr->children->type == XML_TEXT_NODE) &&
106*7c568831SAndroid Build Coastguard Worker 		        (attr->children->next == NULL)) {
107*7c568831SAndroid Build Coastguard Worker 			value = attr->children->content;
108*7c568831SAndroid Build Coastguard Worker 			if ((!xmlStrcasecmp(attr->name, BAD_CAST"http-equiv"))
109*7c568831SAndroid Build Coastguard Worker 			 && (!xmlStrcasecmp(value, BAD_CAST"Content-Type")))
110*7c568831SAndroid Build Coastguard Worker 			    http = 1;
111*7c568831SAndroid Build Coastguard Worker 			else if ((value != NULL)
112*7c568831SAndroid Build Coastguard Worker 			 && (!xmlStrcasecmp(attr->name, BAD_CAST"content")))
113*7c568831SAndroid Build Coastguard Worker 			    content = value;
114*7c568831SAndroid Build Coastguard Worker 			if ((http != 0) && (content != NULL))
115*7c568831SAndroid Build Coastguard Worker 			    goto found_content;
116*7c568831SAndroid Build Coastguard Worker 		    }
117*7c568831SAndroid Build Coastguard Worker 		    attr = attr->next;
118*7c568831SAndroid Build Coastguard Worker 		}
119*7c568831SAndroid Build Coastguard Worker 	    }
120*7c568831SAndroid Build Coastguard Worker 	}
121*7c568831SAndroid Build Coastguard Worker 	cur = cur->next;
122*7c568831SAndroid Build Coastguard Worker     }
123*7c568831SAndroid Build Coastguard Worker     return(NULL);
124*7c568831SAndroid Build Coastguard Worker 
125*7c568831SAndroid Build Coastguard Worker found_content:
126*7c568831SAndroid Build Coastguard Worker     encoding = xmlStrstr(content, BAD_CAST"charset=");
127*7c568831SAndroid Build Coastguard Worker     if (encoding == NULL)
128*7c568831SAndroid Build Coastguard Worker 	encoding = xmlStrstr(content, BAD_CAST"Charset=");
129*7c568831SAndroid Build Coastguard Worker     if (encoding == NULL)
130*7c568831SAndroid Build Coastguard Worker 	encoding = xmlStrstr(content, BAD_CAST"CHARSET=");
131*7c568831SAndroid Build Coastguard Worker     if (encoding != NULL) {
132*7c568831SAndroid Build Coastguard Worker 	encoding += 8;
133*7c568831SAndroid Build Coastguard Worker     } else {
134*7c568831SAndroid Build Coastguard Worker 	encoding = xmlStrstr(content, BAD_CAST"charset =");
135*7c568831SAndroid Build Coastguard Worker 	if (encoding == NULL)
136*7c568831SAndroid Build Coastguard Worker 	    encoding = xmlStrstr(content, BAD_CAST"Charset =");
137*7c568831SAndroid Build Coastguard Worker 	if (encoding == NULL)
138*7c568831SAndroid Build Coastguard Worker 	    encoding = xmlStrstr(content, BAD_CAST"CHARSET =");
139*7c568831SAndroid Build Coastguard Worker 	if (encoding != NULL)
140*7c568831SAndroid Build Coastguard Worker 	    encoding += 9;
141*7c568831SAndroid Build Coastguard Worker     }
142*7c568831SAndroid Build Coastguard Worker     if (encoding != NULL) {
143*7c568831SAndroid Build Coastguard Worker 	while ((*encoding == ' ') || (*encoding == '\t')) encoding++;
144*7c568831SAndroid Build Coastguard Worker     }
145*7c568831SAndroid Build Coastguard Worker     return(encoding);
146*7c568831SAndroid Build Coastguard Worker }
147*7c568831SAndroid Build Coastguard Worker 
148*7c568831SAndroid Build Coastguard Worker /**
149*7c568831SAndroid Build Coastguard Worker  * htmlSetMetaEncoding:
150*7c568831SAndroid Build Coastguard Worker  * @doc:  the document
151*7c568831SAndroid Build Coastguard Worker  * @encoding:  the encoding string
152*7c568831SAndroid Build Coastguard Worker  *
153*7c568831SAndroid Build Coastguard Worker  * Sets the current encoding in the Meta tags
154*7c568831SAndroid Build Coastguard Worker  * NOTE: this will not change the document content encoding, just
155*7c568831SAndroid Build Coastguard Worker  * the META flag associated.
156*7c568831SAndroid Build Coastguard Worker  *
157*7c568831SAndroid Build Coastguard Worker  * Returns 0 in case of success and -1 in case of error
158*7c568831SAndroid Build Coastguard Worker  */
159*7c568831SAndroid Build Coastguard Worker int
htmlSetMetaEncoding(htmlDocPtr doc,const xmlChar * encoding)160*7c568831SAndroid Build Coastguard Worker htmlSetMetaEncoding(htmlDocPtr doc, const xmlChar *encoding) {
161*7c568831SAndroid Build Coastguard Worker     htmlNodePtr cur, meta = NULL, head = NULL;
162*7c568831SAndroid Build Coastguard Worker     const xmlChar *content = NULL;
163*7c568831SAndroid Build Coastguard Worker     char newcontent[100];
164*7c568831SAndroid Build Coastguard Worker 
165*7c568831SAndroid Build Coastguard Worker     newcontent[0] = 0;
166*7c568831SAndroid Build Coastguard Worker 
167*7c568831SAndroid Build Coastguard Worker     if (doc == NULL)
168*7c568831SAndroid Build Coastguard Worker 	return(-1);
169*7c568831SAndroid Build Coastguard Worker 
170*7c568831SAndroid Build Coastguard Worker     /* html isn't a real encoding it's just libxml2 way to get entities */
171*7c568831SAndroid Build Coastguard Worker     if (!xmlStrcasecmp(encoding, BAD_CAST "html"))
172*7c568831SAndroid Build Coastguard Worker         return(-1);
173*7c568831SAndroid Build Coastguard Worker 
174*7c568831SAndroid Build Coastguard Worker     if (encoding != NULL) {
175*7c568831SAndroid Build Coastguard Worker 	snprintf(newcontent, sizeof(newcontent), "text/html; charset=%s",
176*7c568831SAndroid Build Coastguard Worker                 (char *)encoding);
177*7c568831SAndroid Build Coastguard Worker 	newcontent[sizeof(newcontent) - 1] = 0;
178*7c568831SAndroid Build Coastguard Worker     }
179*7c568831SAndroid Build Coastguard Worker 
180*7c568831SAndroid Build Coastguard Worker     cur = doc->children;
181*7c568831SAndroid Build Coastguard Worker 
182*7c568831SAndroid Build Coastguard Worker     /*
183*7c568831SAndroid Build Coastguard Worker      * Search the html
184*7c568831SAndroid Build Coastguard Worker      */
185*7c568831SAndroid Build Coastguard Worker     while (cur != NULL) {
186*7c568831SAndroid Build Coastguard Worker 	if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {
187*7c568831SAndroid Build Coastguard Worker 	    if (xmlStrcasecmp(cur->name, BAD_CAST"html") == 0)
188*7c568831SAndroid Build Coastguard Worker 		break;
189*7c568831SAndroid Build Coastguard Worker 	    if (xmlStrcasecmp(cur->name, BAD_CAST"head") == 0)
190*7c568831SAndroid Build Coastguard Worker 		goto found_head;
191*7c568831SAndroid Build Coastguard Worker 	    if (xmlStrcasecmp(cur->name, BAD_CAST"meta") == 0)
192*7c568831SAndroid Build Coastguard Worker 		goto found_meta;
193*7c568831SAndroid Build Coastguard Worker 	}
194*7c568831SAndroid Build Coastguard Worker 	cur = cur->next;
195*7c568831SAndroid Build Coastguard Worker     }
196*7c568831SAndroid Build Coastguard Worker     if (cur == NULL)
197*7c568831SAndroid Build Coastguard Worker 	return(-1);
198*7c568831SAndroid Build Coastguard Worker     cur = cur->children;
199*7c568831SAndroid Build Coastguard Worker 
200*7c568831SAndroid Build Coastguard Worker     /*
201*7c568831SAndroid Build Coastguard Worker      * Search the head
202*7c568831SAndroid Build Coastguard Worker      */
203*7c568831SAndroid Build Coastguard Worker     while (cur != NULL) {
204*7c568831SAndroid Build Coastguard Worker 	if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {
205*7c568831SAndroid Build Coastguard Worker 	    if (xmlStrcasecmp(cur->name, BAD_CAST"head") == 0)
206*7c568831SAndroid Build Coastguard Worker 		break;
207*7c568831SAndroid Build Coastguard Worker 	    if (xmlStrcasecmp(cur->name, BAD_CAST"meta") == 0) {
208*7c568831SAndroid Build Coastguard Worker                 head = cur->parent;
209*7c568831SAndroid Build Coastguard Worker 		goto found_meta;
210*7c568831SAndroid Build Coastguard Worker             }
211*7c568831SAndroid Build Coastguard Worker 	}
212*7c568831SAndroid Build Coastguard Worker 	cur = cur->next;
213*7c568831SAndroid Build Coastguard Worker     }
214*7c568831SAndroid Build Coastguard Worker     if (cur == NULL)
215*7c568831SAndroid Build Coastguard Worker 	return(-1);
216*7c568831SAndroid Build Coastguard Worker found_head:
217*7c568831SAndroid Build Coastguard Worker     head = cur;
218*7c568831SAndroid Build Coastguard Worker     if (cur->children == NULL)
219*7c568831SAndroid Build Coastguard Worker         goto create;
220*7c568831SAndroid Build Coastguard Worker     cur = cur->children;
221*7c568831SAndroid Build Coastguard Worker 
222*7c568831SAndroid Build Coastguard Worker found_meta:
223*7c568831SAndroid Build Coastguard Worker     /*
224*7c568831SAndroid Build Coastguard Worker      * Search and update all the remaining the meta elements carrying
225*7c568831SAndroid Build Coastguard Worker      * encoding information
226*7c568831SAndroid Build Coastguard Worker      */
227*7c568831SAndroid Build Coastguard Worker     while (cur != NULL) {
228*7c568831SAndroid Build Coastguard Worker 	if ((cur->type == XML_ELEMENT_NODE) && (cur->name != NULL)) {
229*7c568831SAndroid Build Coastguard Worker 	    if (xmlStrcasecmp(cur->name, BAD_CAST"meta") == 0) {
230*7c568831SAndroid Build Coastguard Worker 		xmlAttrPtr attr = cur->properties;
231*7c568831SAndroid Build Coastguard Worker 		int http;
232*7c568831SAndroid Build Coastguard Worker 		const xmlChar *value;
233*7c568831SAndroid Build Coastguard Worker 
234*7c568831SAndroid Build Coastguard Worker 		content = NULL;
235*7c568831SAndroid Build Coastguard Worker 		http = 0;
236*7c568831SAndroid Build Coastguard Worker 		while (attr != NULL) {
237*7c568831SAndroid Build Coastguard Worker 		    if ((attr->children != NULL) &&
238*7c568831SAndroid Build Coastguard Worker 		        (attr->children->type == XML_TEXT_NODE) &&
239*7c568831SAndroid Build Coastguard Worker 		        (attr->children->next == NULL)) {
240*7c568831SAndroid Build Coastguard Worker 			value = attr->children->content;
241*7c568831SAndroid Build Coastguard Worker 			if ((!xmlStrcasecmp(attr->name, BAD_CAST"http-equiv"))
242*7c568831SAndroid Build Coastguard Worker 			 && (!xmlStrcasecmp(value, BAD_CAST"Content-Type")))
243*7c568831SAndroid Build Coastguard Worker 			    http = 1;
244*7c568831SAndroid Build Coastguard Worker 			else
245*7c568831SAndroid Build Coastguard Worker                         {
246*7c568831SAndroid Build Coastguard Worker                            if ((value != NULL) &&
247*7c568831SAndroid Build Coastguard Worker                                (!xmlStrcasecmp(attr->name, BAD_CAST"content")))
248*7c568831SAndroid Build Coastguard Worker 			       content = value;
249*7c568831SAndroid Build Coastguard Worker                         }
250*7c568831SAndroid Build Coastguard Worker 		        if ((http != 0) && (content != NULL))
251*7c568831SAndroid Build Coastguard Worker 			    break;
252*7c568831SAndroid Build Coastguard Worker 		    }
253*7c568831SAndroid Build Coastguard Worker 		    attr = attr->next;
254*7c568831SAndroid Build Coastguard Worker 		}
255*7c568831SAndroid Build Coastguard Worker 		if ((http != 0) && (content != NULL)) {
256*7c568831SAndroid Build Coastguard Worker 		    meta = cur;
257*7c568831SAndroid Build Coastguard Worker 		    break;
258*7c568831SAndroid Build Coastguard Worker 		}
259*7c568831SAndroid Build Coastguard Worker 
260*7c568831SAndroid Build Coastguard Worker 	    }
261*7c568831SAndroid Build Coastguard Worker 	}
262*7c568831SAndroid Build Coastguard Worker 	cur = cur->next;
263*7c568831SAndroid Build Coastguard Worker     }
264*7c568831SAndroid Build Coastguard Worker create:
265*7c568831SAndroid Build Coastguard Worker     if (meta == NULL) {
266*7c568831SAndroid Build Coastguard Worker         if ((encoding != NULL) && (head != NULL)) {
267*7c568831SAndroid Build Coastguard Worker             /*
268*7c568831SAndroid Build Coastguard Worker              * Create a new Meta element with the right attributes
269*7c568831SAndroid Build Coastguard Worker              */
270*7c568831SAndroid Build Coastguard Worker 
271*7c568831SAndroid Build Coastguard Worker             meta = xmlNewDocNode(doc, NULL, BAD_CAST"meta", NULL);
272*7c568831SAndroid Build Coastguard Worker             if (head->children == NULL)
273*7c568831SAndroid Build Coastguard Worker                 xmlAddChild(head, meta);
274*7c568831SAndroid Build Coastguard Worker             else
275*7c568831SAndroid Build Coastguard Worker                 xmlAddPrevSibling(head->children, meta);
276*7c568831SAndroid Build Coastguard Worker             xmlNewProp(meta, BAD_CAST"http-equiv", BAD_CAST"Content-Type");
277*7c568831SAndroid Build Coastguard Worker             xmlNewProp(meta, BAD_CAST"content", BAD_CAST newcontent);
278*7c568831SAndroid Build Coastguard Worker         }
279*7c568831SAndroid Build Coastguard Worker     } else {
280*7c568831SAndroid Build Coastguard Worker         /* remove the meta tag if NULL is passed */
281*7c568831SAndroid Build Coastguard Worker         if (encoding == NULL) {
282*7c568831SAndroid Build Coastguard Worker             xmlUnlinkNode(meta);
283*7c568831SAndroid Build Coastguard Worker             xmlFreeNode(meta);
284*7c568831SAndroid Build Coastguard Worker         }
285*7c568831SAndroid Build Coastguard Worker         /* change the document only if there is a real encoding change */
286*7c568831SAndroid Build Coastguard Worker         else if (xmlStrcasestr(content, encoding) == NULL) {
287*7c568831SAndroid Build Coastguard Worker             xmlSetProp(meta, BAD_CAST"content", BAD_CAST newcontent);
288*7c568831SAndroid Build Coastguard Worker         }
289*7c568831SAndroid Build Coastguard Worker     }
290*7c568831SAndroid Build Coastguard Worker 
291*7c568831SAndroid Build Coastguard Worker 
292*7c568831SAndroid Build Coastguard Worker     return(0);
293*7c568831SAndroid Build Coastguard Worker }
294*7c568831SAndroid Build Coastguard Worker 
295*7c568831SAndroid Build Coastguard Worker /**
296*7c568831SAndroid Build Coastguard Worker  * booleanHTMLAttrs:
297*7c568831SAndroid Build Coastguard Worker  *
298*7c568831SAndroid Build Coastguard Worker  * These are the HTML attributes which will be output
299*7c568831SAndroid Build Coastguard Worker  * in minimized form, i.e. <option selected="selected"> will be
300*7c568831SAndroid Build Coastguard Worker  * output as <option selected>, as per XSLT 1.0 16.2 "HTML Output Method"
301*7c568831SAndroid Build Coastguard Worker  *
302*7c568831SAndroid Build Coastguard Worker  */
303*7c568831SAndroid Build Coastguard Worker static const char* const htmlBooleanAttrs[] = {
304*7c568831SAndroid Build Coastguard Worker   "checked", "compact", "declare", "defer", "disabled", "ismap",
305*7c568831SAndroid Build Coastguard Worker   "multiple", "nohref", "noresize", "noshade", "nowrap", "readonly",
306*7c568831SAndroid Build Coastguard Worker   "selected", NULL
307*7c568831SAndroid Build Coastguard Worker };
308*7c568831SAndroid Build Coastguard Worker 
309*7c568831SAndroid Build Coastguard Worker 
310*7c568831SAndroid Build Coastguard Worker /**
311*7c568831SAndroid Build Coastguard Worker  * htmlIsBooleanAttr:
312*7c568831SAndroid Build Coastguard Worker  * @name:  the name of the attribute to check
313*7c568831SAndroid Build Coastguard Worker  *
314*7c568831SAndroid Build Coastguard Worker  * DEPRECATED: Internal function, don't use.
315*7c568831SAndroid Build Coastguard Worker  *
316*7c568831SAndroid Build Coastguard Worker  * Determine if a given attribute is a boolean attribute.
317*7c568831SAndroid Build Coastguard Worker  *
318*7c568831SAndroid Build Coastguard Worker  * returns: false if the attribute is not boolean, true otherwise.
319*7c568831SAndroid Build Coastguard Worker  */
320*7c568831SAndroid Build Coastguard Worker int
htmlIsBooleanAttr(const xmlChar * name)321*7c568831SAndroid Build Coastguard Worker htmlIsBooleanAttr(const xmlChar *name)
322*7c568831SAndroid Build Coastguard Worker {
323*7c568831SAndroid Build Coastguard Worker     int i = 0;
324*7c568831SAndroid Build Coastguard Worker 
325*7c568831SAndroid Build Coastguard Worker     while (htmlBooleanAttrs[i] != NULL) {
326*7c568831SAndroid Build Coastguard Worker         if (xmlStrcasecmp((const xmlChar *)htmlBooleanAttrs[i], name) == 0)
327*7c568831SAndroid Build Coastguard Worker             return 1;
328*7c568831SAndroid Build Coastguard Worker         i++;
329*7c568831SAndroid Build Coastguard Worker     }
330*7c568831SAndroid Build Coastguard Worker     return 0;
331*7c568831SAndroid Build Coastguard Worker }
332*7c568831SAndroid Build Coastguard Worker 
333*7c568831SAndroid Build Coastguard Worker #ifdef LIBXML_OUTPUT_ENABLED
334*7c568831SAndroid Build Coastguard Worker /************************************************************************
335*7c568831SAndroid Build Coastguard Worker  *									*
336*7c568831SAndroid Build Coastguard Worker  *			Output error handlers				*
337*7c568831SAndroid Build Coastguard Worker  *									*
338*7c568831SAndroid Build Coastguard Worker  ************************************************************************/
339*7c568831SAndroid Build Coastguard Worker 
340*7c568831SAndroid Build Coastguard Worker /**
341*7c568831SAndroid Build Coastguard Worker  * htmlSaveErr:
342*7c568831SAndroid Build Coastguard Worker  * @code:  the error number
343*7c568831SAndroid Build Coastguard Worker  * @node:  the location of the error.
344*7c568831SAndroid Build Coastguard Worker  * @extra:  extra information
345*7c568831SAndroid Build Coastguard Worker  *
346*7c568831SAndroid Build Coastguard Worker  * Handle an out of memory condition
347*7c568831SAndroid Build Coastguard Worker  */
348*7c568831SAndroid Build Coastguard Worker static void
htmlSaveErr(int code,xmlNodePtr node,const char * extra)349*7c568831SAndroid Build Coastguard Worker htmlSaveErr(int code, xmlNodePtr node, const char *extra)
350*7c568831SAndroid Build Coastguard Worker {
351*7c568831SAndroid Build Coastguard Worker     const char *msg = NULL;
352*7c568831SAndroid Build Coastguard Worker     int res;
353*7c568831SAndroid Build Coastguard Worker 
354*7c568831SAndroid Build Coastguard Worker     switch(code) {
355*7c568831SAndroid Build Coastguard Worker         case XML_SAVE_NOT_UTF8:
356*7c568831SAndroid Build Coastguard Worker 	    msg = "string is not in UTF-8\n";
357*7c568831SAndroid Build Coastguard Worker 	    break;
358*7c568831SAndroid Build Coastguard Worker 	case XML_SAVE_CHAR_INVALID:
359*7c568831SAndroid Build Coastguard Worker 	    msg = "invalid character value\n";
360*7c568831SAndroid Build Coastguard Worker 	    break;
361*7c568831SAndroid Build Coastguard Worker 	case XML_SAVE_UNKNOWN_ENCODING:
362*7c568831SAndroid Build Coastguard Worker 	    msg = "unknown encoding %s\n";
363*7c568831SAndroid Build Coastguard Worker 	    break;
364*7c568831SAndroid Build Coastguard Worker 	case XML_SAVE_NO_DOCTYPE:
365*7c568831SAndroid Build Coastguard Worker 	    msg = "HTML has no DOCTYPE\n";
366*7c568831SAndroid Build Coastguard Worker 	    break;
367*7c568831SAndroid Build Coastguard Worker 	default:
368*7c568831SAndroid Build Coastguard Worker 	    msg = "unexpected error number\n";
369*7c568831SAndroid Build Coastguard Worker     }
370*7c568831SAndroid Build Coastguard Worker 
371*7c568831SAndroid Build Coastguard Worker     res = xmlRaiseError(NULL, NULL, NULL, NULL, node,
372*7c568831SAndroid Build Coastguard Worker                         XML_FROM_OUTPUT, code, XML_ERR_ERROR, NULL, 0,
373*7c568831SAndroid Build Coastguard Worker                         extra, NULL, NULL, 0, 0,
374*7c568831SAndroid Build Coastguard Worker                         msg, extra);
375*7c568831SAndroid Build Coastguard Worker     if (res < 0)
376*7c568831SAndroid Build Coastguard Worker         xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_OUTPUT, NULL);
377*7c568831SAndroid Build Coastguard Worker }
378*7c568831SAndroid Build Coastguard Worker 
379*7c568831SAndroid Build Coastguard Worker /************************************************************************
380*7c568831SAndroid Build Coastguard Worker  *									*
381*7c568831SAndroid Build Coastguard Worker  *		Dumping HTML tree content to a simple buffer		*
382*7c568831SAndroid Build Coastguard Worker  *									*
383*7c568831SAndroid Build Coastguard Worker  ************************************************************************/
384*7c568831SAndroid Build Coastguard Worker 
385*7c568831SAndroid Build Coastguard Worker static xmlCharEncodingHandler *
htmlFindOutputEncoder(const char * encoding)386*7c568831SAndroid Build Coastguard Worker htmlFindOutputEncoder(const char *encoding) {
387*7c568831SAndroid Build Coastguard Worker     xmlCharEncodingHandler *handler = NULL;
388*7c568831SAndroid Build Coastguard Worker 
389*7c568831SAndroid Build Coastguard Worker     if (encoding != NULL) {
390*7c568831SAndroid Build Coastguard Worker         int res;
391*7c568831SAndroid Build Coastguard Worker 
392*7c568831SAndroid Build Coastguard Worker         res = xmlOpenCharEncodingHandler(encoding, /* output */ 1,
393*7c568831SAndroid Build Coastguard Worker                                          &handler);
394*7c568831SAndroid Build Coastguard Worker         if (res != XML_ERR_OK)
395*7c568831SAndroid Build Coastguard Worker             htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding);
396*7c568831SAndroid Build Coastguard Worker     } else {
397*7c568831SAndroid Build Coastguard Worker         /*
398*7c568831SAndroid Build Coastguard Worker          * Fallback to HTML when the encoding is unspecified
399*7c568831SAndroid Build Coastguard Worker          */
400*7c568831SAndroid Build Coastguard Worker         xmlOpenCharEncodingHandler("HTML", /* output */ 1, &handler);
401*7c568831SAndroid Build Coastguard Worker     }
402*7c568831SAndroid Build Coastguard Worker 
403*7c568831SAndroid Build Coastguard Worker     return(handler);
404*7c568831SAndroid Build Coastguard Worker }
405*7c568831SAndroid Build Coastguard Worker 
406*7c568831SAndroid Build Coastguard Worker /**
407*7c568831SAndroid Build Coastguard Worker  * htmlBufNodeDumpFormat:
408*7c568831SAndroid Build Coastguard Worker  * @buf:  the xmlBufPtr output
409*7c568831SAndroid Build Coastguard Worker  * @doc:  the document
410*7c568831SAndroid Build Coastguard Worker  * @cur:  the current node
411*7c568831SAndroid Build Coastguard Worker  * @format:  should formatting spaces been added
412*7c568831SAndroid Build Coastguard Worker  *
413*7c568831SAndroid Build Coastguard Worker  * Dump an HTML node, recursive behaviour,children are printed too.
414*7c568831SAndroid Build Coastguard Worker  *
415*7c568831SAndroid Build Coastguard Worker  * Returns the number of byte written or -1 in case of error
416*7c568831SAndroid Build Coastguard Worker  */
417*7c568831SAndroid Build Coastguard Worker static size_t
htmlBufNodeDumpFormat(xmlBufPtr buf,xmlDocPtr doc,xmlNodePtr cur,int format)418*7c568831SAndroid Build Coastguard Worker htmlBufNodeDumpFormat(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur,
419*7c568831SAndroid Build Coastguard Worker 	           int format) {
420*7c568831SAndroid Build Coastguard Worker     size_t use;
421*7c568831SAndroid Build Coastguard Worker     size_t ret;
422*7c568831SAndroid Build Coastguard Worker     xmlOutputBufferPtr outbuf;
423*7c568831SAndroid Build Coastguard Worker 
424*7c568831SAndroid Build Coastguard Worker     if (cur == NULL) {
425*7c568831SAndroid Build Coastguard Worker 	return ((size_t) -1);
426*7c568831SAndroid Build Coastguard Worker     }
427*7c568831SAndroid Build Coastguard Worker     if (buf == NULL) {
428*7c568831SAndroid Build Coastguard Worker 	return ((size_t) -1);
429*7c568831SAndroid Build Coastguard Worker     }
430*7c568831SAndroid Build Coastguard Worker     outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
431*7c568831SAndroid Build Coastguard Worker     if (outbuf == NULL)
432*7c568831SAndroid Build Coastguard Worker 	return ((size_t) -1);
433*7c568831SAndroid Build Coastguard Worker     memset(outbuf, 0, sizeof(xmlOutputBuffer));
434*7c568831SAndroid Build Coastguard Worker     outbuf->buffer = buf;
435*7c568831SAndroid Build Coastguard Worker     outbuf->encoder = NULL;
436*7c568831SAndroid Build Coastguard Worker     outbuf->writecallback = NULL;
437*7c568831SAndroid Build Coastguard Worker     outbuf->closecallback = NULL;
438*7c568831SAndroid Build Coastguard Worker     outbuf->context = NULL;
439*7c568831SAndroid Build Coastguard Worker     outbuf->written = 0;
440*7c568831SAndroid Build Coastguard Worker 
441*7c568831SAndroid Build Coastguard Worker     use = xmlBufUse(buf);
442*7c568831SAndroid Build Coastguard Worker     htmlNodeDumpFormatOutput(outbuf, doc, cur, NULL, format);
443*7c568831SAndroid Build Coastguard Worker     if (outbuf->error)
444*7c568831SAndroid Build Coastguard Worker         ret = (size_t) -1;
445*7c568831SAndroid Build Coastguard Worker     else
446*7c568831SAndroid Build Coastguard Worker         ret = xmlBufUse(buf) - use;
447*7c568831SAndroid Build Coastguard Worker     xmlFree(outbuf);
448*7c568831SAndroid Build Coastguard Worker     return (ret);
449*7c568831SAndroid Build Coastguard Worker }
450*7c568831SAndroid Build Coastguard Worker 
451*7c568831SAndroid Build Coastguard Worker /**
452*7c568831SAndroid Build Coastguard Worker  * htmlNodeDump:
453*7c568831SAndroid Build Coastguard Worker  * @buf:  the HTML buffer output
454*7c568831SAndroid Build Coastguard Worker  * @doc:  the document
455*7c568831SAndroid Build Coastguard Worker  * @cur:  the current node
456*7c568831SAndroid Build Coastguard Worker  *
457*7c568831SAndroid Build Coastguard Worker  * Dump an HTML node, recursive behaviour,children are printed too,
458*7c568831SAndroid Build Coastguard Worker  * and formatting returns are added.
459*7c568831SAndroid Build Coastguard Worker  *
460*7c568831SAndroid Build Coastguard Worker  * Returns the number of byte written or -1 in case of error
461*7c568831SAndroid Build Coastguard Worker  */
462*7c568831SAndroid Build Coastguard Worker int
htmlNodeDump(xmlBufferPtr buf,xmlDocPtr doc,xmlNodePtr cur)463*7c568831SAndroid Build Coastguard Worker htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur) {
464*7c568831SAndroid Build Coastguard Worker     xmlBufPtr buffer;
465*7c568831SAndroid Build Coastguard Worker     size_t ret1;
466*7c568831SAndroid Build Coastguard Worker     int ret2;
467*7c568831SAndroid Build Coastguard Worker 
468*7c568831SAndroid Build Coastguard Worker     if ((buf == NULL) || (cur == NULL))
469*7c568831SAndroid Build Coastguard Worker         return(-1);
470*7c568831SAndroid Build Coastguard Worker 
471*7c568831SAndroid Build Coastguard Worker     xmlInitParser();
472*7c568831SAndroid Build Coastguard Worker     buffer = xmlBufFromBuffer(buf);
473*7c568831SAndroid Build Coastguard Worker     if (buffer == NULL)
474*7c568831SAndroid Build Coastguard Worker         return(-1);
475*7c568831SAndroid Build Coastguard Worker 
476*7c568831SAndroid Build Coastguard Worker     ret1 = htmlBufNodeDumpFormat(buffer, doc, cur, 1);
477*7c568831SAndroid Build Coastguard Worker 
478*7c568831SAndroid Build Coastguard Worker     ret2 = xmlBufBackToBuffer(buffer, buf);
479*7c568831SAndroid Build Coastguard Worker 
480*7c568831SAndroid Build Coastguard Worker     if ((ret1 == (size_t) -1) || (ret2 < 0))
481*7c568831SAndroid Build Coastguard Worker         return(-1);
482*7c568831SAndroid Build Coastguard Worker     return(ret1 > INT_MAX ? INT_MAX : ret1);
483*7c568831SAndroid Build Coastguard Worker }
484*7c568831SAndroid Build Coastguard Worker 
485*7c568831SAndroid Build Coastguard Worker /**
486*7c568831SAndroid Build Coastguard Worker  * htmlNodeDumpFileFormat:
487*7c568831SAndroid Build Coastguard Worker  * @out:  the FILE pointer
488*7c568831SAndroid Build Coastguard Worker  * @doc:  the document
489*7c568831SAndroid Build Coastguard Worker  * @cur:  the current node
490*7c568831SAndroid Build Coastguard Worker  * @encoding: the document encoding
491*7c568831SAndroid Build Coastguard Worker  * @format:  should formatting spaces been added
492*7c568831SAndroid Build Coastguard Worker  *
493*7c568831SAndroid Build Coastguard Worker  * Dump an HTML node, recursive behaviour,children are printed too.
494*7c568831SAndroid Build Coastguard Worker  *
495*7c568831SAndroid Build Coastguard Worker  * TODO: if encoding == NULL try to save in the doc encoding
496*7c568831SAndroid Build Coastguard Worker  *
497*7c568831SAndroid Build Coastguard Worker  * returns: the number of byte written or -1 in case of failure.
498*7c568831SAndroid Build Coastguard Worker  */
499*7c568831SAndroid Build Coastguard Worker int
htmlNodeDumpFileFormat(FILE * out,xmlDocPtr doc,xmlNodePtr cur,const char * encoding,int format)500*7c568831SAndroid Build Coastguard Worker htmlNodeDumpFileFormat(FILE *out, xmlDocPtr doc,
501*7c568831SAndroid Build Coastguard Worker 	               xmlNodePtr cur, const char *encoding, int format) {
502*7c568831SAndroid Build Coastguard Worker     xmlOutputBufferPtr buf;
503*7c568831SAndroid Build Coastguard Worker     xmlCharEncodingHandlerPtr handler;
504*7c568831SAndroid Build Coastguard Worker     int ret;
505*7c568831SAndroid Build Coastguard Worker 
506*7c568831SAndroid Build Coastguard Worker     xmlInitParser();
507*7c568831SAndroid Build Coastguard Worker 
508*7c568831SAndroid Build Coastguard Worker     /*
509*7c568831SAndroid Build Coastguard Worker      * save the content to a temp buffer.
510*7c568831SAndroid Build Coastguard Worker      */
511*7c568831SAndroid Build Coastguard Worker     handler = htmlFindOutputEncoder(encoding);
512*7c568831SAndroid Build Coastguard Worker     buf = xmlOutputBufferCreateFile(out, handler);
513*7c568831SAndroid Build Coastguard Worker     if (buf == NULL)
514*7c568831SAndroid Build Coastguard Worker         return(0);
515*7c568831SAndroid Build Coastguard Worker 
516*7c568831SAndroid Build Coastguard Worker     htmlNodeDumpFormatOutput(buf, doc, cur, NULL, format);
517*7c568831SAndroid Build Coastguard Worker 
518*7c568831SAndroid Build Coastguard Worker     ret = xmlOutputBufferClose(buf);
519*7c568831SAndroid Build Coastguard Worker     return(ret);
520*7c568831SAndroid Build Coastguard Worker }
521*7c568831SAndroid Build Coastguard Worker 
522*7c568831SAndroid Build Coastguard Worker /**
523*7c568831SAndroid Build Coastguard Worker  * htmlNodeDumpFile:
524*7c568831SAndroid Build Coastguard Worker  * @out:  the FILE pointer
525*7c568831SAndroid Build Coastguard Worker  * @doc:  the document
526*7c568831SAndroid Build Coastguard Worker  * @cur:  the current node
527*7c568831SAndroid Build Coastguard Worker  *
528*7c568831SAndroid Build Coastguard Worker  * Dump an HTML node, recursive behaviour,children are printed too,
529*7c568831SAndroid Build Coastguard Worker  * and formatting returns are added.
530*7c568831SAndroid Build Coastguard Worker  */
531*7c568831SAndroid Build Coastguard Worker void
htmlNodeDumpFile(FILE * out,xmlDocPtr doc,xmlNodePtr cur)532*7c568831SAndroid Build Coastguard Worker htmlNodeDumpFile(FILE *out, xmlDocPtr doc, xmlNodePtr cur) {
533*7c568831SAndroid Build Coastguard Worker     htmlNodeDumpFileFormat(out, doc, cur, NULL, 1);
534*7c568831SAndroid Build Coastguard Worker }
535*7c568831SAndroid Build Coastguard Worker 
536*7c568831SAndroid Build Coastguard Worker /**
537*7c568831SAndroid Build Coastguard Worker  * htmlDocDumpMemoryFormat:
538*7c568831SAndroid Build Coastguard Worker  * @cur:  the document
539*7c568831SAndroid Build Coastguard Worker  * @mem:  OUT: the memory pointer
540*7c568831SAndroid Build Coastguard Worker  * @size:  OUT: the memory length
541*7c568831SAndroid Build Coastguard Worker  * @format:  should formatting spaces been added
542*7c568831SAndroid Build Coastguard Worker  *
543*7c568831SAndroid Build Coastguard Worker  * Dump an HTML document in memory and return the xmlChar * and it's size.
544*7c568831SAndroid Build Coastguard Worker  * It's up to the caller to free the memory.
545*7c568831SAndroid Build Coastguard Worker  */
546*7c568831SAndroid Build Coastguard Worker void
htmlDocDumpMemoryFormat(xmlDocPtr cur,xmlChar ** mem,int * size,int format)547*7c568831SAndroid Build Coastguard Worker htmlDocDumpMemoryFormat(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
548*7c568831SAndroid Build Coastguard Worker     xmlOutputBufferPtr buf;
549*7c568831SAndroid Build Coastguard Worker     xmlCharEncodingHandlerPtr handler = NULL;
550*7c568831SAndroid Build Coastguard Worker     const char *encoding;
551*7c568831SAndroid Build Coastguard Worker 
552*7c568831SAndroid Build Coastguard Worker     xmlInitParser();
553*7c568831SAndroid Build Coastguard Worker 
554*7c568831SAndroid Build Coastguard Worker     if ((mem == NULL) || (size == NULL))
555*7c568831SAndroid Build Coastguard Worker         return;
556*7c568831SAndroid Build Coastguard Worker     *mem = NULL;
557*7c568831SAndroid Build Coastguard Worker     *size = 0;
558*7c568831SAndroid Build Coastguard Worker     if (cur == NULL)
559*7c568831SAndroid Build Coastguard Worker 	return;
560*7c568831SAndroid Build Coastguard Worker 
561*7c568831SAndroid Build Coastguard Worker     encoding = (const char *) htmlGetMetaEncoding(cur);
562*7c568831SAndroid Build Coastguard Worker     handler = htmlFindOutputEncoder(encoding);
563*7c568831SAndroid Build Coastguard Worker     buf = xmlAllocOutputBuffer(handler);
564*7c568831SAndroid Build Coastguard Worker     if (buf == NULL)
565*7c568831SAndroid Build Coastguard Worker 	return;
566*7c568831SAndroid Build Coastguard Worker 
567*7c568831SAndroid Build Coastguard Worker     htmlDocContentDumpFormatOutput(buf, cur, NULL, format);
568*7c568831SAndroid Build Coastguard Worker 
569*7c568831SAndroid Build Coastguard Worker     xmlOutputBufferFlush(buf);
570*7c568831SAndroid Build Coastguard Worker 
571*7c568831SAndroid Build Coastguard Worker     if (!buf->error) {
572*7c568831SAndroid Build Coastguard Worker         if (buf->conv != NULL) {
573*7c568831SAndroid Build Coastguard Worker             *size = xmlBufUse(buf->conv);
574*7c568831SAndroid Build Coastguard Worker             *mem = xmlStrndup(xmlBufContent(buf->conv), *size);
575*7c568831SAndroid Build Coastguard Worker         } else {
576*7c568831SAndroid Build Coastguard Worker             *size = xmlBufUse(buf->buffer);
577*7c568831SAndroid Build Coastguard Worker             *mem = xmlStrndup(xmlBufContent(buf->buffer), *size);
578*7c568831SAndroid Build Coastguard Worker         }
579*7c568831SAndroid Build Coastguard Worker     }
580*7c568831SAndroid Build Coastguard Worker 
581*7c568831SAndroid Build Coastguard Worker     xmlOutputBufferClose(buf);
582*7c568831SAndroid Build Coastguard Worker }
583*7c568831SAndroid Build Coastguard Worker 
584*7c568831SAndroid Build Coastguard Worker /**
585*7c568831SAndroid Build Coastguard Worker  * htmlDocDumpMemory:
586*7c568831SAndroid Build Coastguard Worker  * @cur:  the document
587*7c568831SAndroid Build Coastguard Worker  * @mem:  OUT: the memory pointer
588*7c568831SAndroid Build Coastguard Worker  * @size:  OUT: the memory length
589*7c568831SAndroid Build Coastguard Worker  *
590*7c568831SAndroid Build Coastguard Worker  * Dump an HTML document in memory and return the xmlChar * and it's size.
591*7c568831SAndroid Build Coastguard Worker  * It's up to the caller to free the memory.
592*7c568831SAndroid Build Coastguard Worker  */
593*7c568831SAndroid Build Coastguard Worker void
htmlDocDumpMemory(xmlDocPtr cur,xmlChar ** mem,int * size)594*7c568831SAndroid Build Coastguard Worker htmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
595*7c568831SAndroid Build Coastguard Worker 	htmlDocDumpMemoryFormat(cur, mem, size, 1);
596*7c568831SAndroid Build Coastguard Worker }
597*7c568831SAndroid Build Coastguard Worker 
598*7c568831SAndroid Build Coastguard Worker 
599*7c568831SAndroid Build Coastguard Worker /************************************************************************
600*7c568831SAndroid Build Coastguard Worker  *									*
601*7c568831SAndroid Build Coastguard Worker  *		Dumping HTML tree content to an I/O output buffer	*
602*7c568831SAndroid Build Coastguard Worker  *									*
603*7c568831SAndroid Build Coastguard Worker  ************************************************************************/
604*7c568831SAndroid Build Coastguard Worker 
605*7c568831SAndroid Build Coastguard Worker /**
606*7c568831SAndroid Build Coastguard Worker  * htmlDtdDumpOutput:
607*7c568831SAndroid Build Coastguard Worker  * @buf:  the HTML buffer output
608*7c568831SAndroid Build Coastguard Worker  * @doc:  the document
609*7c568831SAndroid Build Coastguard Worker  * @encoding:  the encoding string
610*7c568831SAndroid Build Coastguard Worker  *
611*7c568831SAndroid Build Coastguard Worker  * TODO: check whether encoding is needed
612*7c568831SAndroid Build Coastguard Worker  *
613*7c568831SAndroid Build Coastguard Worker  * Dump the HTML document DTD, if any.
614*7c568831SAndroid Build Coastguard Worker  */
615*7c568831SAndroid Build Coastguard Worker static void
htmlDtdDumpOutput(xmlOutputBufferPtr buf,xmlDocPtr doc,const char * encoding ATTRIBUTE_UNUSED)616*7c568831SAndroid Build Coastguard Worker htmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
617*7c568831SAndroid Build Coastguard Worker 	          const char *encoding ATTRIBUTE_UNUSED) {
618*7c568831SAndroid Build Coastguard Worker     xmlDtdPtr cur = doc->intSubset;
619*7c568831SAndroid Build Coastguard Worker 
620*7c568831SAndroid Build Coastguard Worker     if (cur == NULL) {
621*7c568831SAndroid Build Coastguard Worker 	htmlSaveErr(XML_SAVE_NO_DOCTYPE, (xmlNodePtr) doc, NULL);
622*7c568831SAndroid Build Coastguard Worker 	return;
623*7c568831SAndroid Build Coastguard Worker     }
624*7c568831SAndroid Build Coastguard Worker     xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
625*7c568831SAndroid Build Coastguard Worker     xmlOutputBufferWriteString(buf, (const char *)cur->name);
626*7c568831SAndroid Build Coastguard Worker     if (cur->ExternalID != NULL) {
627*7c568831SAndroid Build Coastguard Worker 	xmlOutputBufferWriteString(buf, " PUBLIC ");
628*7c568831SAndroid Build Coastguard Worker 	xmlOutputBufferWriteQuotedString(buf, cur->ExternalID);
629*7c568831SAndroid Build Coastguard Worker 	if (cur->SystemID != NULL) {
630*7c568831SAndroid Build Coastguard Worker 	    xmlOutputBufferWriteString(buf, " ");
631*7c568831SAndroid Build Coastguard Worker 	    xmlOutputBufferWriteQuotedString(buf, cur->SystemID);
632*7c568831SAndroid Build Coastguard Worker 	}
633*7c568831SAndroid Build Coastguard Worker     } else if (cur->SystemID != NULL &&
634*7c568831SAndroid Build Coastguard Worker 	       xmlStrcmp(cur->SystemID, BAD_CAST "about:legacy-compat")) {
635*7c568831SAndroid Build Coastguard Worker 	xmlOutputBufferWriteString(buf, " SYSTEM ");
636*7c568831SAndroid Build Coastguard Worker 	xmlOutputBufferWriteQuotedString(buf, cur->SystemID);
637*7c568831SAndroid Build Coastguard Worker     }
638*7c568831SAndroid Build Coastguard Worker     xmlOutputBufferWriteString(buf, ">\n");
639*7c568831SAndroid Build Coastguard Worker }
640*7c568831SAndroid Build Coastguard Worker 
641*7c568831SAndroid Build Coastguard Worker /**
642*7c568831SAndroid Build Coastguard Worker  * htmlAttrDumpOutput:
643*7c568831SAndroid Build Coastguard Worker  * @buf:  the HTML buffer output
644*7c568831SAndroid Build Coastguard Worker  * @doc:  the document
645*7c568831SAndroid Build Coastguard Worker  * @cur:  the attribute pointer
646*7c568831SAndroid Build Coastguard Worker  *
647*7c568831SAndroid Build Coastguard Worker  * Dump an HTML attribute
648*7c568831SAndroid Build Coastguard Worker  */
649*7c568831SAndroid Build Coastguard Worker static void
htmlAttrDumpOutput(xmlOutputBufferPtr buf,xmlDocPtr doc,xmlAttrPtr cur)650*7c568831SAndroid Build Coastguard Worker htmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
651*7c568831SAndroid Build Coastguard Worker     xmlChar *value;
652*7c568831SAndroid Build Coastguard Worker 
653*7c568831SAndroid Build Coastguard Worker     /*
654*7c568831SAndroid Build Coastguard Worker      * The html output method should not escape a & character
655*7c568831SAndroid Build Coastguard Worker      * occurring in an attribute value immediately followed by
656*7c568831SAndroid Build Coastguard Worker      * a { character (see Section B.7.1 of the HTML 4.0 Recommendation).
657*7c568831SAndroid Build Coastguard Worker      * This is implemented in xmlEncodeEntitiesReentrant
658*7c568831SAndroid Build Coastguard Worker      */
659*7c568831SAndroid Build Coastguard Worker 
660*7c568831SAndroid Build Coastguard Worker     if (cur == NULL) {
661*7c568831SAndroid Build Coastguard Worker 	return;
662*7c568831SAndroid Build Coastguard Worker     }
663*7c568831SAndroid Build Coastguard Worker     xmlOutputBufferWriteString(buf, " ");
664*7c568831SAndroid Build Coastguard Worker     if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
665*7c568831SAndroid Build Coastguard Worker         xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
666*7c568831SAndroid Build Coastguard Worker 	xmlOutputBufferWriteString(buf, ":");
667*7c568831SAndroid Build Coastguard Worker     }
668*7c568831SAndroid Build Coastguard Worker     xmlOutputBufferWriteString(buf, (const char *)cur->name);
669*7c568831SAndroid Build Coastguard Worker     if ((cur->children != NULL) && (!htmlIsBooleanAttr(cur->name))) {
670*7c568831SAndroid Build Coastguard Worker 	value = xmlNodeListGetString(doc, cur->children, 0);
671*7c568831SAndroid Build Coastguard Worker 	if (value) {
672*7c568831SAndroid Build Coastguard Worker 	    xmlOutputBufferWriteString(buf, "=");
673*7c568831SAndroid Build Coastguard Worker 	    if ((cur->ns == NULL) && (cur->parent != NULL) &&
674*7c568831SAndroid Build Coastguard Worker 		(cur->parent->ns == NULL) &&
675*7c568831SAndroid Build Coastguard Worker 		((!xmlStrcasecmp(cur->name, BAD_CAST "href")) ||
676*7c568831SAndroid Build Coastguard Worker 	         (!xmlStrcasecmp(cur->name, BAD_CAST "action")) ||
677*7c568831SAndroid Build Coastguard Worker 		 (!xmlStrcasecmp(cur->name, BAD_CAST "src")) ||
678*7c568831SAndroid Build Coastguard Worker 		 ((!xmlStrcasecmp(cur->name, BAD_CAST "name")) &&
679*7c568831SAndroid Build Coastguard Worker 		  (!xmlStrcasecmp(cur->parent->name, BAD_CAST "a"))))) {
680*7c568831SAndroid Build Coastguard Worker 		xmlChar *escaped;
681*7c568831SAndroid Build Coastguard Worker 		xmlChar *tmp = value;
682*7c568831SAndroid Build Coastguard Worker 
683*7c568831SAndroid Build Coastguard Worker 		while (IS_BLANK_CH(*tmp)) tmp++;
684*7c568831SAndroid Build Coastguard Worker 
685*7c568831SAndroid Build Coastguard Worker 		/*
686*7c568831SAndroid Build Coastguard Worker                  * Angle brackets are technically illegal in URIs, but they're
687*7c568831SAndroid Build Coastguard Worker                  * used in server side includes, for example. Curly brackets
688*7c568831SAndroid Build Coastguard Worker                  * are illegal as well and often used in templates.
689*7c568831SAndroid Build Coastguard Worker                  * Don't escape non-whitespace, printable ASCII chars for
690*7c568831SAndroid Build Coastguard Worker                  * improved interoperability. Only escape space, control
691*7c568831SAndroid Build Coastguard Worker                  * and non-ASCII chars.
692*7c568831SAndroid Build Coastguard Worker 		 */
693*7c568831SAndroid Build Coastguard Worker 		escaped = xmlURIEscapeStr(tmp,
694*7c568831SAndroid Build Coastguard Worker                         BAD_CAST "\"#$%&+,/:;<=>?@[\\]^`{|}");
695*7c568831SAndroid Build Coastguard Worker 		if (escaped != NULL) {
696*7c568831SAndroid Build Coastguard Worker 		    xmlOutputBufferWriteQuotedString(buf, escaped);
697*7c568831SAndroid Build Coastguard Worker 		    xmlFree(escaped);
698*7c568831SAndroid Build Coastguard Worker 		} else {
699*7c568831SAndroid Build Coastguard Worker                     buf->error = XML_ERR_NO_MEMORY;
700*7c568831SAndroid Build Coastguard Worker 		}
701*7c568831SAndroid Build Coastguard Worker 	    } else {
702*7c568831SAndroid Build Coastguard Worker 		xmlOutputBufferWriteQuotedString(buf, value);
703*7c568831SAndroid Build Coastguard Worker 	    }
704*7c568831SAndroid Build Coastguard Worker 	    xmlFree(value);
705*7c568831SAndroid Build Coastguard Worker 	} else  {
706*7c568831SAndroid Build Coastguard Worker             buf->error = XML_ERR_NO_MEMORY;
707*7c568831SAndroid Build Coastguard Worker 	}
708*7c568831SAndroid Build Coastguard Worker     }
709*7c568831SAndroid Build Coastguard Worker }
710*7c568831SAndroid Build Coastguard Worker 
711*7c568831SAndroid Build Coastguard Worker /**
712*7c568831SAndroid Build Coastguard Worker  * htmlNodeDumpFormatOutput:
713*7c568831SAndroid Build Coastguard Worker  * @buf:  the HTML buffer output
714*7c568831SAndroid Build Coastguard Worker  * @doc:  the document
715*7c568831SAndroid Build Coastguard Worker  * @cur:  the current node
716*7c568831SAndroid Build Coastguard Worker  * @encoding:  the encoding string (unused)
717*7c568831SAndroid Build Coastguard Worker  * @format:  should formatting spaces been added
718*7c568831SAndroid Build Coastguard Worker  *
719*7c568831SAndroid Build Coastguard Worker  * Dump an HTML node, recursive behaviour,children are printed too.
720*7c568831SAndroid Build Coastguard Worker  */
721*7c568831SAndroid Build Coastguard Worker void
htmlNodeDumpFormatOutput(xmlOutputBufferPtr buf,xmlDocPtr doc,xmlNodePtr cur,const char * encoding ATTRIBUTE_UNUSED,int format)722*7c568831SAndroid Build Coastguard Worker htmlNodeDumpFormatOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
723*7c568831SAndroid Build Coastguard Worker 	                 xmlNodePtr cur, const char *encoding ATTRIBUTE_UNUSED,
724*7c568831SAndroid Build Coastguard Worker                          int format) {
725*7c568831SAndroid Build Coastguard Worker     xmlNodePtr root, parent;
726*7c568831SAndroid Build Coastguard Worker     xmlAttrPtr attr;
727*7c568831SAndroid Build Coastguard Worker     const htmlElemDesc * info;
728*7c568831SAndroid Build Coastguard Worker 
729*7c568831SAndroid Build Coastguard Worker     xmlInitParser();
730*7c568831SAndroid Build Coastguard Worker 
731*7c568831SAndroid Build Coastguard Worker     if ((cur == NULL) || (buf == NULL)) {
732*7c568831SAndroid Build Coastguard Worker 	return;
733*7c568831SAndroid Build Coastguard Worker     }
734*7c568831SAndroid Build Coastguard Worker 
735*7c568831SAndroid Build Coastguard Worker     root = cur;
736*7c568831SAndroid Build Coastguard Worker     parent = cur->parent;
737*7c568831SAndroid Build Coastguard Worker     while (1) {
738*7c568831SAndroid Build Coastguard Worker         switch (cur->type) {
739*7c568831SAndroid Build Coastguard Worker         case XML_HTML_DOCUMENT_NODE:
740*7c568831SAndroid Build Coastguard Worker         case XML_DOCUMENT_NODE:
741*7c568831SAndroid Build Coastguard Worker             if (((xmlDocPtr) cur)->intSubset != NULL) {
742*7c568831SAndroid Build Coastguard Worker                 htmlDtdDumpOutput(buf, (xmlDocPtr) cur, NULL);
743*7c568831SAndroid Build Coastguard Worker             }
744*7c568831SAndroid Build Coastguard Worker             if (cur->children != NULL) {
745*7c568831SAndroid Build Coastguard Worker                 /* Always validate cur->parent when descending. */
746*7c568831SAndroid Build Coastguard Worker                 if (cur->parent == parent) {
747*7c568831SAndroid Build Coastguard Worker                     parent = cur;
748*7c568831SAndroid Build Coastguard Worker                     cur = cur->children;
749*7c568831SAndroid Build Coastguard Worker                     continue;
750*7c568831SAndroid Build Coastguard Worker                 }
751*7c568831SAndroid Build Coastguard Worker             } else {
752*7c568831SAndroid Build Coastguard Worker                 xmlOutputBufferWriteString(buf, "\n");
753*7c568831SAndroid Build Coastguard Worker             }
754*7c568831SAndroid Build Coastguard Worker             break;
755*7c568831SAndroid Build Coastguard Worker 
756*7c568831SAndroid Build Coastguard Worker         case XML_ELEMENT_NODE:
757*7c568831SAndroid Build Coastguard Worker             /*
758*7c568831SAndroid Build Coastguard Worker              * Some users like lxml are known to pass nodes with a corrupted
759*7c568831SAndroid Build Coastguard Worker              * tree structure. Fall back to a recursive call to handle this
760*7c568831SAndroid Build Coastguard Worker              * case.
761*7c568831SAndroid Build Coastguard Worker              */
762*7c568831SAndroid Build Coastguard Worker             if ((cur->parent != parent) && (cur->children != NULL)) {
763*7c568831SAndroid Build Coastguard Worker                 htmlNodeDumpFormatOutput(buf, doc, cur, encoding, format);
764*7c568831SAndroid Build Coastguard Worker                 break;
765*7c568831SAndroid Build Coastguard Worker             }
766*7c568831SAndroid Build Coastguard Worker 
767*7c568831SAndroid Build Coastguard Worker             /*
768*7c568831SAndroid Build Coastguard Worker              * Get specific HTML info for that node.
769*7c568831SAndroid Build Coastguard Worker              */
770*7c568831SAndroid Build Coastguard Worker             if (cur->ns == NULL)
771*7c568831SAndroid Build Coastguard Worker                 info = htmlTagLookup(cur->name);
772*7c568831SAndroid Build Coastguard Worker             else
773*7c568831SAndroid Build Coastguard Worker                 info = NULL;
774*7c568831SAndroid Build Coastguard Worker 
775*7c568831SAndroid Build Coastguard Worker             xmlOutputBufferWriteString(buf, "<");
776*7c568831SAndroid Build Coastguard Worker             if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
777*7c568831SAndroid Build Coastguard Worker                 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
778*7c568831SAndroid Build Coastguard Worker                 xmlOutputBufferWriteString(buf, ":");
779*7c568831SAndroid Build Coastguard Worker             }
780*7c568831SAndroid Build Coastguard Worker             xmlOutputBufferWriteString(buf, (const char *)cur->name);
781*7c568831SAndroid Build Coastguard Worker             if (cur->nsDef)
782*7c568831SAndroid Build Coastguard Worker                 xmlNsListDumpOutput(buf, cur->nsDef);
783*7c568831SAndroid Build Coastguard Worker             attr = cur->properties;
784*7c568831SAndroid Build Coastguard Worker             while (attr != NULL) {
785*7c568831SAndroid Build Coastguard Worker                 htmlAttrDumpOutput(buf, doc, attr);
786*7c568831SAndroid Build Coastguard Worker                 attr = attr->next;
787*7c568831SAndroid Build Coastguard Worker             }
788*7c568831SAndroid Build Coastguard Worker 
789*7c568831SAndroid Build Coastguard Worker             if ((info != NULL) && (info->empty)) {
790*7c568831SAndroid Build Coastguard Worker                 xmlOutputBufferWriteString(buf, ">");
791*7c568831SAndroid Build Coastguard Worker             } else if (cur->children == NULL) {
792*7c568831SAndroid Build Coastguard Worker                 if ((info != NULL) && (info->saveEndTag != 0) &&
793*7c568831SAndroid Build Coastguard Worker                     (xmlStrcmp(BAD_CAST info->name, BAD_CAST "html")) &&
794*7c568831SAndroid Build Coastguard Worker                     (xmlStrcmp(BAD_CAST info->name, BAD_CAST "body"))) {
795*7c568831SAndroid Build Coastguard Worker                     xmlOutputBufferWriteString(buf, ">");
796*7c568831SAndroid Build Coastguard Worker                 } else {
797*7c568831SAndroid Build Coastguard Worker                     xmlOutputBufferWriteString(buf, "></");
798*7c568831SAndroid Build Coastguard Worker                     if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
799*7c568831SAndroid Build Coastguard Worker                         xmlOutputBufferWriteString(buf,
800*7c568831SAndroid Build Coastguard Worker                                 (const char *)cur->ns->prefix);
801*7c568831SAndroid Build Coastguard Worker                         xmlOutputBufferWriteString(buf, ":");
802*7c568831SAndroid Build Coastguard Worker                     }
803*7c568831SAndroid Build Coastguard Worker                     xmlOutputBufferWriteString(buf, (const char *)cur->name);
804*7c568831SAndroid Build Coastguard Worker                     xmlOutputBufferWriteString(buf, ">");
805*7c568831SAndroid Build Coastguard Worker                 }
806*7c568831SAndroid Build Coastguard Worker             } else {
807*7c568831SAndroid Build Coastguard Worker                 xmlOutputBufferWriteString(buf, ">");
808*7c568831SAndroid Build Coastguard Worker                 if ((format) && (info != NULL) && (!info->isinline) &&
809*7c568831SAndroid Build Coastguard Worker                     (cur->children->type != HTML_TEXT_NODE) &&
810*7c568831SAndroid Build Coastguard Worker                     (cur->children->type != HTML_ENTITY_REF_NODE) &&
811*7c568831SAndroid Build Coastguard Worker                     (cur->children != cur->last) &&
812*7c568831SAndroid Build Coastguard Worker                     (cur->name != NULL) &&
813*7c568831SAndroid Build Coastguard Worker                     (cur->name[0] != 'p')) /* p, pre, param */
814*7c568831SAndroid Build Coastguard Worker                     xmlOutputBufferWriteString(buf, "\n");
815*7c568831SAndroid Build Coastguard Worker                 parent = cur;
816*7c568831SAndroid Build Coastguard Worker                 cur = cur->children;
817*7c568831SAndroid Build Coastguard Worker                 continue;
818*7c568831SAndroid Build Coastguard Worker             }
819*7c568831SAndroid Build Coastguard Worker 
820*7c568831SAndroid Build Coastguard Worker             if ((format) && (cur->next != NULL) &&
821*7c568831SAndroid Build Coastguard Worker                 (info != NULL) && (!info->isinline)) {
822*7c568831SAndroid Build Coastguard Worker                 if ((cur->next->type != HTML_TEXT_NODE) &&
823*7c568831SAndroid Build Coastguard Worker                     (cur->next->type != HTML_ENTITY_REF_NODE) &&
824*7c568831SAndroid Build Coastguard Worker                     (parent != NULL) &&
825*7c568831SAndroid Build Coastguard Worker                     (parent->name != NULL) &&
826*7c568831SAndroid Build Coastguard Worker                     (parent->name[0] != 'p')) /* p, pre, param */
827*7c568831SAndroid Build Coastguard Worker                     xmlOutputBufferWriteString(buf, "\n");
828*7c568831SAndroid Build Coastguard Worker             }
829*7c568831SAndroid Build Coastguard Worker 
830*7c568831SAndroid Build Coastguard Worker             break;
831*7c568831SAndroid Build Coastguard Worker 
832*7c568831SAndroid Build Coastguard Worker         case XML_ATTRIBUTE_NODE:
833*7c568831SAndroid Build Coastguard Worker             htmlAttrDumpOutput(buf, doc, (xmlAttrPtr) cur);
834*7c568831SAndroid Build Coastguard Worker             break;
835*7c568831SAndroid Build Coastguard Worker 
836*7c568831SAndroid Build Coastguard Worker         case HTML_TEXT_NODE:
837*7c568831SAndroid Build Coastguard Worker             if (cur->content == NULL)
838*7c568831SAndroid Build Coastguard Worker                 break;
839*7c568831SAndroid Build Coastguard Worker             if (((cur->name == (const xmlChar *)xmlStringText) ||
840*7c568831SAndroid Build Coastguard Worker                  (cur->name != (const xmlChar *)xmlStringTextNoenc)) &&
841*7c568831SAndroid Build Coastguard Worker                 ((parent == NULL) ||
842*7c568831SAndroid Build Coastguard Worker                  ((xmlStrcasecmp(parent->name, BAD_CAST "script")) &&
843*7c568831SAndroid Build Coastguard Worker                   (xmlStrcasecmp(parent->name, BAD_CAST "style"))))) {
844*7c568831SAndroid Build Coastguard Worker                 xmlChar *buffer;
845*7c568831SAndroid Build Coastguard Worker 
846*7c568831SAndroid Build Coastguard Worker                 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
847*7c568831SAndroid Build Coastguard Worker                 if (buffer == NULL) {
848*7c568831SAndroid Build Coastguard Worker                     buf->error = XML_ERR_NO_MEMORY;
849*7c568831SAndroid Build Coastguard Worker                     return;
850*7c568831SAndroid Build Coastguard Worker                 }
851*7c568831SAndroid Build Coastguard Worker                 xmlOutputBufferWriteString(buf, (const char *)buffer);
852*7c568831SAndroid Build Coastguard Worker                 xmlFree(buffer);
853*7c568831SAndroid Build Coastguard Worker             } else {
854*7c568831SAndroid Build Coastguard Worker                 xmlOutputBufferWriteString(buf, (const char *)cur->content);
855*7c568831SAndroid Build Coastguard Worker             }
856*7c568831SAndroid Build Coastguard Worker             break;
857*7c568831SAndroid Build Coastguard Worker 
858*7c568831SAndroid Build Coastguard Worker         case HTML_COMMENT_NODE:
859*7c568831SAndroid Build Coastguard Worker             if (cur->content != NULL) {
860*7c568831SAndroid Build Coastguard Worker                 xmlOutputBufferWriteString(buf, "<!--");
861*7c568831SAndroid Build Coastguard Worker                 xmlOutputBufferWriteString(buf, (const char *)cur->content);
862*7c568831SAndroid Build Coastguard Worker                 xmlOutputBufferWriteString(buf, "-->");
863*7c568831SAndroid Build Coastguard Worker             }
864*7c568831SAndroid Build Coastguard Worker             break;
865*7c568831SAndroid Build Coastguard Worker 
866*7c568831SAndroid Build Coastguard Worker         case HTML_PI_NODE:
867*7c568831SAndroid Build Coastguard Worker             if (cur->name != NULL) {
868*7c568831SAndroid Build Coastguard Worker                 xmlOutputBufferWriteString(buf, "<?");
869*7c568831SAndroid Build Coastguard Worker                 xmlOutputBufferWriteString(buf, (const char *)cur->name);
870*7c568831SAndroid Build Coastguard Worker                 if (cur->content != NULL) {
871*7c568831SAndroid Build Coastguard Worker                     xmlOutputBufferWriteString(buf, " ");
872*7c568831SAndroid Build Coastguard Worker                     xmlOutputBufferWriteString(buf,
873*7c568831SAndroid Build Coastguard Worker                             (const char *)cur->content);
874*7c568831SAndroid Build Coastguard Worker                 }
875*7c568831SAndroid Build Coastguard Worker                 xmlOutputBufferWriteString(buf, ">");
876*7c568831SAndroid Build Coastguard Worker             }
877*7c568831SAndroid Build Coastguard Worker             break;
878*7c568831SAndroid Build Coastguard Worker 
879*7c568831SAndroid Build Coastguard Worker         case HTML_ENTITY_REF_NODE:
880*7c568831SAndroid Build Coastguard Worker             xmlOutputBufferWriteString(buf, "&");
881*7c568831SAndroid Build Coastguard Worker             xmlOutputBufferWriteString(buf, (const char *)cur->name);
882*7c568831SAndroid Build Coastguard Worker             xmlOutputBufferWriteString(buf, ";");
883*7c568831SAndroid Build Coastguard Worker             break;
884*7c568831SAndroid Build Coastguard Worker 
885*7c568831SAndroid Build Coastguard Worker         case HTML_PRESERVE_NODE:
886*7c568831SAndroid Build Coastguard Worker             if (cur->content != NULL) {
887*7c568831SAndroid Build Coastguard Worker                 xmlOutputBufferWriteString(buf, (const char *)cur->content);
888*7c568831SAndroid Build Coastguard Worker             }
889*7c568831SAndroid Build Coastguard Worker             break;
890*7c568831SAndroid Build Coastguard Worker 
891*7c568831SAndroid Build Coastguard Worker         default:
892*7c568831SAndroid Build Coastguard Worker             break;
893*7c568831SAndroid Build Coastguard Worker         }
894*7c568831SAndroid Build Coastguard Worker 
895*7c568831SAndroid Build Coastguard Worker         while (1) {
896*7c568831SAndroid Build Coastguard Worker             if (cur == root)
897*7c568831SAndroid Build Coastguard Worker                 return;
898*7c568831SAndroid Build Coastguard Worker             if (cur->next != NULL) {
899*7c568831SAndroid Build Coastguard Worker                 cur = cur->next;
900*7c568831SAndroid Build Coastguard Worker                 break;
901*7c568831SAndroid Build Coastguard Worker             }
902*7c568831SAndroid Build Coastguard Worker 
903*7c568831SAndroid Build Coastguard Worker             cur = parent;
904*7c568831SAndroid Build Coastguard Worker             /* cur->parent was validated when descending. */
905*7c568831SAndroid Build Coastguard Worker             parent = cur->parent;
906*7c568831SAndroid Build Coastguard Worker 
907*7c568831SAndroid Build Coastguard Worker             if ((cur->type == XML_HTML_DOCUMENT_NODE) ||
908*7c568831SAndroid Build Coastguard Worker                 (cur->type == XML_DOCUMENT_NODE)) {
909*7c568831SAndroid Build Coastguard Worker                 xmlOutputBufferWriteString(buf, "\n");
910*7c568831SAndroid Build Coastguard Worker             } else {
911*7c568831SAndroid Build Coastguard Worker                 if ((format) && (cur->ns == NULL))
912*7c568831SAndroid Build Coastguard Worker                     info = htmlTagLookup(cur->name);
913*7c568831SAndroid Build Coastguard Worker                 else
914*7c568831SAndroid Build Coastguard Worker                     info = NULL;
915*7c568831SAndroid Build Coastguard Worker 
916*7c568831SAndroid Build Coastguard Worker                 if ((format) && (info != NULL) && (!info->isinline) &&
917*7c568831SAndroid Build Coastguard Worker                     (cur->last->type != HTML_TEXT_NODE) &&
918*7c568831SAndroid Build Coastguard Worker                     (cur->last->type != HTML_ENTITY_REF_NODE) &&
919*7c568831SAndroid Build Coastguard Worker                     (cur->children != cur->last) &&
920*7c568831SAndroid Build Coastguard Worker                     (cur->name != NULL) &&
921*7c568831SAndroid Build Coastguard Worker                     (cur->name[0] != 'p')) /* p, pre, param */
922*7c568831SAndroid Build Coastguard Worker                     xmlOutputBufferWriteString(buf, "\n");
923*7c568831SAndroid Build Coastguard Worker 
924*7c568831SAndroid Build Coastguard Worker                 xmlOutputBufferWriteString(buf, "</");
925*7c568831SAndroid Build Coastguard Worker                 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
926*7c568831SAndroid Build Coastguard Worker                     xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
927*7c568831SAndroid Build Coastguard Worker                     xmlOutputBufferWriteString(buf, ":");
928*7c568831SAndroid Build Coastguard Worker                 }
929*7c568831SAndroid Build Coastguard Worker                 xmlOutputBufferWriteString(buf, (const char *)cur->name);
930*7c568831SAndroid Build Coastguard Worker                 xmlOutputBufferWriteString(buf, ">");
931*7c568831SAndroid Build Coastguard Worker 
932*7c568831SAndroid Build Coastguard Worker                 if ((format) && (info != NULL) && (!info->isinline) &&
933*7c568831SAndroid Build Coastguard Worker                     (cur->next != NULL)) {
934*7c568831SAndroid Build Coastguard Worker                     if ((cur->next->type != HTML_TEXT_NODE) &&
935*7c568831SAndroid Build Coastguard Worker                         (cur->next->type != HTML_ENTITY_REF_NODE) &&
936*7c568831SAndroid Build Coastguard Worker                         (parent != NULL) &&
937*7c568831SAndroid Build Coastguard Worker                         (parent->name != NULL) &&
938*7c568831SAndroid Build Coastguard Worker                         (parent->name[0] != 'p')) /* p, pre, param */
939*7c568831SAndroid Build Coastguard Worker                         xmlOutputBufferWriteString(buf, "\n");
940*7c568831SAndroid Build Coastguard Worker                 }
941*7c568831SAndroid Build Coastguard Worker             }
942*7c568831SAndroid Build Coastguard Worker         }
943*7c568831SAndroid Build Coastguard Worker     }
944*7c568831SAndroid Build Coastguard Worker }
945*7c568831SAndroid Build Coastguard Worker 
946*7c568831SAndroid Build Coastguard Worker /**
947*7c568831SAndroid Build Coastguard Worker  * htmlNodeDumpOutput:
948*7c568831SAndroid Build Coastguard Worker  * @buf:  the HTML buffer output
949*7c568831SAndroid Build Coastguard Worker  * @doc:  the document
950*7c568831SAndroid Build Coastguard Worker  * @cur:  the current node
951*7c568831SAndroid Build Coastguard Worker  * @encoding:  the encoding string (unused)
952*7c568831SAndroid Build Coastguard Worker  *
953*7c568831SAndroid Build Coastguard Worker  * Dump an HTML node, recursive behaviour,children are printed too,
954*7c568831SAndroid Build Coastguard Worker  * and formatting returns/spaces are added.
955*7c568831SAndroid Build Coastguard Worker  */
956*7c568831SAndroid Build Coastguard Worker void
htmlNodeDumpOutput(xmlOutputBufferPtr buf,xmlDocPtr doc,xmlNodePtr cur,const char * encoding ATTRIBUTE_UNUSED)957*7c568831SAndroid Build Coastguard Worker htmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
958*7c568831SAndroid Build Coastguard Worker 	           xmlNodePtr cur, const char *encoding ATTRIBUTE_UNUSED) {
959*7c568831SAndroid Build Coastguard Worker     htmlNodeDumpFormatOutput(buf, doc, cur, NULL, 1);
960*7c568831SAndroid Build Coastguard Worker }
961*7c568831SAndroid Build Coastguard Worker 
962*7c568831SAndroid Build Coastguard Worker /**
963*7c568831SAndroid Build Coastguard Worker  * htmlDocContentDumpFormatOutput:
964*7c568831SAndroid Build Coastguard Worker  * @buf:  the HTML buffer output
965*7c568831SAndroid Build Coastguard Worker  * @cur:  the document
966*7c568831SAndroid Build Coastguard Worker  * @encoding:  the encoding string (unused)
967*7c568831SAndroid Build Coastguard Worker  * @format:  should formatting spaces been added
968*7c568831SAndroid Build Coastguard Worker  *
969*7c568831SAndroid Build Coastguard Worker  * Dump an HTML document.
970*7c568831SAndroid Build Coastguard Worker  */
971*7c568831SAndroid Build Coastguard Worker void
htmlDocContentDumpFormatOutput(xmlOutputBufferPtr buf,xmlDocPtr cur,const char * encoding ATTRIBUTE_UNUSED,int format)972*7c568831SAndroid Build Coastguard Worker htmlDocContentDumpFormatOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
973*7c568831SAndroid Build Coastguard Worker 	                       const char *encoding ATTRIBUTE_UNUSED,
974*7c568831SAndroid Build Coastguard Worker                                int format) {
975*7c568831SAndroid Build Coastguard Worker     int type = 0;
976*7c568831SAndroid Build Coastguard Worker     if (cur) {
977*7c568831SAndroid Build Coastguard Worker         type = cur->type;
978*7c568831SAndroid Build Coastguard Worker         cur->type = XML_HTML_DOCUMENT_NODE;
979*7c568831SAndroid Build Coastguard Worker     }
980*7c568831SAndroid Build Coastguard Worker     htmlNodeDumpFormatOutput(buf, cur, (xmlNodePtr) cur, NULL, format);
981*7c568831SAndroid Build Coastguard Worker     if (cur)
982*7c568831SAndroid Build Coastguard Worker         cur->type = (xmlElementType) type;
983*7c568831SAndroid Build Coastguard Worker }
984*7c568831SAndroid Build Coastguard Worker 
985*7c568831SAndroid Build Coastguard Worker /**
986*7c568831SAndroid Build Coastguard Worker  * htmlDocContentDumpOutput:
987*7c568831SAndroid Build Coastguard Worker  * @buf:  the HTML buffer output
988*7c568831SAndroid Build Coastguard Worker  * @cur:  the document
989*7c568831SAndroid Build Coastguard Worker  * @encoding:  the encoding string (unused)
990*7c568831SAndroid Build Coastguard Worker  *
991*7c568831SAndroid Build Coastguard Worker  * Dump an HTML document. Formatting return/spaces are added.
992*7c568831SAndroid Build Coastguard Worker  */
993*7c568831SAndroid Build Coastguard Worker void
htmlDocContentDumpOutput(xmlOutputBufferPtr buf,xmlDocPtr cur,const char * encoding ATTRIBUTE_UNUSED)994*7c568831SAndroid Build Coastguard Worker htmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
995*7c568831SAndroid Build Coastguard Worker 	                 const char *encoding ATTRIBUTE_UNUSED) {
996*7c568831SAndroid Build Coastguard Worker     htmlNodeDumpFormatOutput(buf, cur, (xmlNodePtr) cur, NULL, 1);
997*7c568831SAndroid Build Coastguard Worker }
998*7c568831SAndroid Build Coastguard Worker 
999*7c568831SAndroid Build Coastguard Worker /************************************************************************
1000*7c568831SAndroid Build Coastguard Worker  *									*
1001*7c568831SAndroid Build Coastguard Worker  *		Saving functions front-ends				*
1002*7c568831SAndroid Build Coastguard Worker  *									*
1003*7c568831SAndroid Build Coastguard Worker  ************************************************************************/
1004*7c568831SAndroid Build Coastguard Worker 
1005*7c568831SAndroid Build Coastguard Worker /**
1006*7c568831SAndroid Build Coastguard Worker  * htmlDocDump:
1007*7c568831SAndroid Build Coastguard Worker  * @f:  the FILE*
1008*7c568831SAndroid Build Coastguard Worker  * @cur:  the document
1009*7c568831SAndroid Build Coastguard Worker  *
1010*7c568831SAndroid Build Coastguard Worker  * Dump an HTML document to an open FILE.
1011*7c568831SAndroid Build Coastguard Worker  *
1012*7c568831SAndroid Build Coastguard Worker  * returns: the number of byte written or -1 in case of failure.
1013*7c568831SAndroid Build Coastguard Worker  */
1014*7c568831SAndroid Build Coastguard Worker int
htmlDocDump(FILE * f,xmlDocPtr cur)1015*7c568831SAndroid Build Coastguard Worker htmlDocDump(FILE *f, xmlDocPtr cur) {
1016*7c568831SAndroid Build Coastguard Worker     xmlOutputBufferPtr buf;
1017*7c568831SAndroid Build Coastguard Worker     xmlCharEncodingHandlerPtr handler = NULL;
1018*7c568831SAndroid Build Coastguard Worker     const char *encoding;
1019*7c568831SAndroid Build Coastguard Worker     int ret;
1020*7c568831SAndroid Build Coastguard Worker 
1021*7c568831SAndroid Build Coastguard Worker     xmlInitParser();
1022*7c568831SAndroid Build Coastguard Worker 
1023*7c568831SAndroid Build Coastguard Worker     if ((cur == NULL) || (f == NULL)) {
1024*7c568831SAndroid Build Coastguard Worker 	return(-1);
1025*7c568831SAndroid Build Coastguard Worker     }
1026*7c568831SAndroid Build Coastguard Worker 
1027*7c568831SAndroid Build Coastguard Worker     encoding = (const char *) htmlGetMetaEncoding(cur);
1028*7c568831SAndroid Build Coastguard Worker     handler = htmlFindOutputEncoder(encoding);
1029*7c568831SAndroid Build Coastguard Worker     buf = xmlOutputBufferCreateFile(f, handler);
1030*7c568831SAndroid Build Coastguard Worker     if (buf == NULL)
1031*7c568831SAndroid Build Coastguard Worker         return(-1);
1032*7c568831SAndroid Build Coastguard Worker     htmlDocContentDumpOutput(buf, cur, NULL);
1033*7c568831SAndroid Build Coastguard Worker 
1034*7c568831SAndroid Build Coastguard Worker     ret = xmlOutputBufferClose(buf);
1035*7c568831SAndroid Build Coastguard Worker     return(ret);
1036*7c568831SAndroid Build Coastguard Worker }
1037*7c568831SAndroid Build Coastguard Worker 
1038*7c568831SAndroid Build Coastguard Worker /**
1039*7c568831SAndroid Build Coastguard Worker  * htmlSaveFile:
1040*7c568831SAndroid Build Coastguard Worker  * @filename:  the filename (or URL)
1041*7c568831SAndroid Build Coastguard Worker  * @cur:  the document
1042*7c568831SAndroid Build Coastguard Worker  *
1043*7c568831SAndroid Build Coastguard Worker  * Dump an HTML document to a file. If @filename is "-" the stdout file is
1044*7c568831SAndroid Build Coastguard Worker  * used.
1045*7c568831SAndroid Build Coastguard Worker  * returns: the number of byte written or -1 in case of failure.
1046*7c568831SAndroid Build Coastguard Worker  */
1047*7c568831SAndroid Build Coastguard Worker int
htmlSaveFile(const char * filename,xmlDocPtr cur)1048*7c568831SAndroid Build Coastguard Worker htmlSaveFile(const char *filename, xmlDocPtr cur) {
1049*7c568831SAndroid Build Coastguard Worker     xmlOutputBufferPtr buf;
1050*7c568831SAndroid Build Coastguard Worker     xmlCharEncodingHandlerPtr handler = NULL;
1051*7c568831SAndroid Build Coastguard Worker     const char *encoding;
1052*7c568831SAndroid Build Coastguard Worker     int ret;
1053*7c568831SAndroid Build Coastguard Worker 
1054*7c568831SAndroid Build Coastguard Worker     if ((cur == NULL) || (filename == NULL))
1055*7c568831SAndroid Build Coastguard Worker         return(-1);
1056*7c568831SAndroid Build Coastguard Worker 
1057*7c568831SAndroid Build Coastguard Worker     xmlInitParser();
1058*7c568831SAndroid Build Coastguard Worker 
1059*7c568831SAndroid Build Coastguard Worker     encoding = (const char *) htmlGetMetaEncoding(cur);
1060*7c568831SAndroid Build Coastguard Worker     handler = htmlFindOutputEncoder(encoding);
1061*7c568831SAndroid Build Coastguard Worker     buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
1062*7c568831SAndroid Build Coastguard Worker     if (buf == NULL)
1063*7c568831SAndroid Build Coastguard Worker         return(0);
1064*7c568831SAndroid Build Coastguard Worker 
1065*7c568831SAndroid Build Coastguard Worker     htmlDocContentDumpOutput(buf, cur, NULL);
1066*7c568831SAndroid Build Coastguard Worker 
1067*7c568831SAndroid Build Coastguard Worker     ret = xmlOutputBufferClose(buf);
1068*7c568831SAndroid Build Coastguard Worker     return(ret);
1069*7c568831SAndroid Build Coastguard Worker }
1070*7c568831SAndroid Build Coastguard Worker 
1071*7c568831SAndroid Build Coastguard Worker /**
1072*7c568831SAndroid Build Coastguard Worker  * htmlSaveFileFormat:
1073*7c568831SAndroid Build Coastguard Worker  * @filename:  the filename
1074*7c568831SAndroid Build Coastguard Worker  * @cur:  the document
1075*7c568831SAndroid Build Coastguard Worker  * @format:  should formatting spaces been added
1076*7c568831SAndroid Build Coastguard Worker  * @encoding: the document encoding
1077*7c568831SAndroid Build Coastguard Worker  *
1078*7c568831SAndroid Build Coastguard Worker  * Dump an HTML document to a file using a given encoding.
1079*7c568831SAndroid Build Coastguard Worker  *
1080*7c568831SAndroid Build Coastguard Worker  * returns: the number of byte written or -1 in case of failure.
1081*7c568831SAndroid Build Coastguard Worker  */
1082*7c568831SAndroid Build Coastguard Worker int
htmlSaveFileFormat(const char * filename,xmlDocPtr cur,const char * encoding,int format)1083*7c568831SAndroid Build Coastguard Worker htmlSaveFileFormat(const char *filename, xmlDocPtr cur,
1084*7c568831SAndroid Build Coastguard Worker 	           const char *encoding, int format) {
1085*7c568831SAndroid Build Coastguard Worker     xmlOutputBufferPtr buf;
1086*7c568831SAndroid Build Coastguard Worker     xmlCharEncodingHandlerPtr handler = NULL;
1087*7c568831SAndroid Build Coastguard Worker     int ret;
1088*7c568831SAndroid Build Coastguard Worker 
1089*7c568831SAndroid Build Coastguard Worker     if ((cur == NULL) || (filename == NULL))
1090*7c568831SAndroid Build Coastguard Worker         return(-1);
1091*7c568831SAndroid Build Coastguard Worker 
1092*7c568831SAndroid Build Coastguard Worker     xmlInitParser();
1093*7c568831SAndroid Build Coastguard Worker 
1094*7c568831SAndroid Build Coastguard Worker     handler = htmlFindOutputEncoder(encoding);
1095*7c568831SAndroid Build Coastguard Worker     if (handler != NULL)
1096*7c568831SAndroid Build Coastguard Worker         htmlSetMetaEncoding(cur, (const xmlChar *) handler->name);
1097*7c568831SAndroid Build Coastguard Worker     else
1098*7c568831SAndroid Build Coastguard Worker 	htmlSetMetaEncoding(cur, (const xmlChar *) "UTF-8");
1099*7c568831SAndroid Build Coastguard Worker 
1100*7c568831SAndroid Build Coastguard Worker     /*
1101*7c568831SAndroid Build Coastguard Worker      * save the content to a temp buffer.
1102*7c568831SAndroid Build Coastguard Worker      */
1103*7c568831SAndroid Build Coastguard Worker     buf = xmlOutputBufferCreateFilename(filename, handler, 0);
1104*7c568831SAndroid Build Coastguard Worker     if (buf == NULL)
1105*7c568831SAndroid Build Coastguard Worker         return(0);
1106*7c568831SAndroid Build Coastguard Worker 
1107*7c568831SAndroid Build Coastguard Worker     htmlDocContentDumpFormatOutput(buf, cur, encoding, format);
1108*7c568831SAndroid Build Coastguard Worker 
1109*7c568831SAndroid Build Coastguard Worker     ret = xmlOutputBufferClose(buf);
1110*7c568831SAndroid Build Coastguard Worker     return(ret);
1111*7c568831SAndroid Build Coastguard Worker }
1112*7c568831SAndroid Build Coastguard Worker 
1113*7c568831SAndroid Build Coastguard Worker /**
1114*7c568831SAndroid Build Coastguard Worker  * htmlSaveFileEnc:
1115*7c568831SAndroid Build Coastguard Worker  * @filename:  the filename
1116*7c568831SAndroid Build Coastguard Worker  * @cur:  the document
1117*7c568831SAndroid Build Coastguard Worker  * @encoding: the document encoding
1118*7c568831SAndroid Build Coastguard Worker  *
1119*7c568831SAndroid Build Coastguard Worker  * Dump an HTML document to a file using a given encoding
1120*7c568831SAndroid Build Coastguard Worker  * and formatting returns/spaces are added.
1121*7c568831SAndroid Build Coastguard Worker  *
1122*7c568831SAndroid Build Coastguard Worker  * returns: the number of byte written or -1 in case of failure.
1123*7c568831SAndroid Build Coastguard Worker  */
1124*7c568831SAndroid Build Coastguard Worker int
htmlSaveFileEnc(const char * filename,xmlDocPtr cur,const char * encoding)1125*7c568831SAndroid Build Coastguard Worker htmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
1126*7c568831SAndroid Build Coastguard Worker     return(htmlSaveFileFormat(filename, cur, encoding, 1));
1127*7c568831SAndroid Build Coastguard Worker }
1128*7c568831SAndroid Build Coastguard Worker 
1129*7c568831SAndroid Build Coastguard Worker #endif /* LIBXML_OUTPUT_ENABLED */
1130*7c568831SAndroid Build Coastguard Worker 
1131*7c568831SAndroid Build Coastguard Worker #endif /* LIBXML_HTML_ENABLED */
1132