pocjenkixx 0.30.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of pocjenkixx might be problematic. Click here for more details.
- package/LICENSE +19 -0
- package/Makefile +18 -0
- package/README.md +52 -0
- package/binding.gyp +81 -0
- package/index.d.ts +273 -0
- package/index.js +45 -0
- package/lib/bindings.js +1 -0
- package/lib/document.js +122 -0
- package/lib/element.js +82 -0
- package/lib/sax_parser.js +38 -0
- package/package.json +70 -0
- package/src/html_document.cc +7 -0
- package/src/html_document.h +18 -0
- package/src/libxmljs.cc +252 -0
- package/src/libxmljs.h +53 -0
- package/src/xml_attribute.cc +173 -0
- package/src/xml_attribute.h +40 -0
- package/src/xml_comment.cc +117 -0
- package/src/xml_comment.h +30 -0
- package/src/xml_document.cc +810 -0
- package/src/xml_document.h +67 -0
- package/src/xml_element.cc +565 -0
- package/src/xml_element.h +61 -0
- package/src/xml_namespace.cc +158 -0
- package/src/xml_namespace.h +39 -0
- package/src/xml_node.cc +761 -0
- package/src/xml_node.h +73 -0
- package/src/xml_pi.cc +161 -0
- package/src/xml_pi.h +34 -0
- package/src/xml_sax_parser.cc +424 -0
- package/src/xml_sax_parser.h +73 -0
- package/src/xml_syntax_error.cc +66 -0
- package/src/xml_syntax_error.h +25 -0
- package/src/xml_text.cc +320 -0
- package/src/xml_text.h +48 -0
- package/src/xml_textwriter.cc +315 -0
- package/src/xml_textwriter.h +62 -0
- package/src/xml_xpath_context.cc +70 -0
- package/src/xml_xpath_context.h +23 -0
- package/vendor/libxml/Copyright +23 -0
- package/vendor/libxml/DOCBparser.c +305 -0
- package/vendor/libxml/HTMLparser.c +7287 -0
- package/vendor/libxml/HTMLtree.c +1200 -0
- package/vendor/libxml/Makefile +2983 -0
- package/vendor/libxml/SAX.c +180 -0
- package/vendor/libxml/SAX2.c +3036 -0
- package/vendor/libxml/buf.c +1351 -0
- package/vendor/libxml/buf.h +72 -0
- package/vendor/libxml/c14n.c +2234 -0
- package/vendor/libxml/catalog.c +3828 -0
- package/vendor/libxml/chvalid.c +336 -0
- package/vendor/libxml/config.h +294 -0
- package/vendor/libxml/config.h.gch +0 -0
- package/vendor/libxml/debugXML.c +3423 -0
- package/vendor/libxml/dict.c +1298 -0
- package/vendor/libxml/elfgcchack.h +17818 -0
- package/vendor/libxml/enc.h +32 -0
- package/vendor/libxml/encoding.c +3975 -0
- package/vendor/libxml/entities.c +1163 -0
- package/vendor/libxml/error.c +998 -0
- package/vendor/libxml/globals.c +1126 -0
- package/vendor/libxml/hash.c +1146 -0
- package/vendor/libxml/include/libxml/DOCBparser.h +96 -0
- package/vendor/libxml/include/libxml/HTMLparser.h +306 -0
- package/vendor/libxml/include/libxml/HTMLtree.h +147 -0
- package/vendor/libxml/include/libxml/Makefile +725 -0
- package/vendor/libxml/include/libxml/Makefile.am +54 -0
- package/vendor/libxml/include/libxml/Makefile.in +725 -0
- package/vendor/libxml/include/libxml/SAX.h +173 -0
- package/vendor/libxml/include/libxml/SAX2.h +178 -0
- package/vendor/libxml/include/libxml/c14n.h +128 -0
- package/vendor/libxml/include/libxml/catalog.h +182 -0
- package/vendor/libxml/include/libxml/chvalid.h +230 -0
- package/vendor/libxml/include/libxml/debugXML.h +217 -0
- package/vendor/libxml/include/libxml/dict.h +79 -0
- package/vendor/libxml/include/libxml/encoding.h +245 -0
- package/vendor/libxml/include/libxml/entities.h +151 -0
- package/vendor/libxml/include/libxml/globals.h +508 -0
- package/vendor/libxml/include/libxml/hash.h +236 -0
- package/vendor/libxml/include/libxml/list.h +137 -0
- package/vendor/libxml/include/libxml/nanoftp.h +163 -0
- package/vendor/libxml/include/libxml/nanohttp.h +81 -0
- package/vendor/libxml/include/libxml/parser.h +1243 -0
- package/vendor/libxml/include/libxml/parserInternals.h +644 -0
- package/vendor/libxml/include/libxml/pattern.h +100 -0
- package/vendor/libxml/include/libxml/relaxng.h +217 -0
- package/vendor/libxml/include/libxml/schemasInternals.h +958 -0
- package/vendor/libxml/include/libxml/schematron.h +142 -0
- package/vendor/libxml/include/libxml/threads.h +89 -0
- package/vendor/libxml/include/libxml/tree.h +1311 -0
- package/vendor/libxml/include/libxml/uri.h +94 -0
- package/vendor/libxml/include/libxml/valid.h +458 -0
- package/vendor/libxml/include/libxml/xinclude.h +129 -0
- package/vendor/libxml/include/libxml/xlink.h +189 -0
- package/vendor/libxml/include/libxml/xmlIO.h +368 -0
- package/vendor/libxml/include/libxml/xmlautomata.h +146 -0
- package/vendor/libxml/include/libxml/xmlerror.h +945 -0
- package/vendor/libxml/include/libxml/xmlexports.h +77 -0
- package/vendor/libxml/include/libxml/xmlmemory.h +224 -0
- package/vendor/libxml/include/libxml/xmlmodule.h +57 -0
- package/vendor/libxml/include/libxml/xmlreader.h +428 -0
- package/vendor/libxml/include/libxml/xmlregexp.h +222 -0
- package/vendor/libxml/include/libxml/xmlsave.h +88 -0
- package/vendor/libxml/include/libxml/xmlschemas.h +246 -0
- package/vendor/libxml/include/libxml/xmlschemastypes.h +151 -0
- package/vendor/libxml/include/libxml/xmlstring.h +140 -0
- package/vendor/libxml/include/libxml/xmlunicode.h +202 -0
- package/vendor/libxml/include/libxml/xmlversion.h +484 -0
- package/vendor/libxml/include/libxml/xmlwin32version.h +239 -0
- package/vendor/libxml/include/libxml/xmlwriter.h +488 -0
- package/vendor/libxml/include/libxml/xpath.h +564 -0
- package/vendor/libxml/include/libxml/xpathInternals.h +632 -0
- package/vendor/libxml/include/libxml/xpointer.h +114 -0
- package/vendor/libxml/include/win32config.h +122 -0
- package/vendor/libxml/include/wsockcompat.h +54 -0
- package/vendor/libxml/legacy.c +1343 -0
- package/vendor/libxml/libxml.h +134 -0
- package/vendor/libxml/list.c +779 -0
- package/vendor/libxml/nanoftp.c +2118 -0
- package/vendor/libxml/nanohttp.c +1899 -0
- package/vendor/libxml/parser.c +15553 -0
- package/vendor/libxml/parserInternals.c +2164 -0
- package/vendor/libxml/pattern.c +2621 -0
- package/vendor/libxml/relaxng.c +11101 -0
- package/vendor/libxml/rngparser.c +1595 -0
- package/vendor/libxml/runsuite.c +1157 -0
- package/vendor/libxml/save.h +36 -0
- package/vendor/libxml/schematron.c +1787 -0
- package/vendor/libxml/threads.c +1049 -0
- package/vendor/libxml/timsort.h +601 -0
- package/vendor/libxml/tree.c +10183 -0
- package/vendor/libxml/trio.c +6895 -0
- package/vendor/libxml/trio.h +230 -0
- package/vendor/libxml/triodef.h +228 -0
- package/vendor/libxml/trionan.c +914 -0
- package/vendor/libxml/trionan.h +84 -0
- package/vendor/libxml/triop.h +150 -0
- package/vendor/libxml/triostr.c +2112 -0
- package/vendor/libxml/triostr.h +144 -0
- package/vendor/libxml/uri.c +2561 -0
- package/vendor/libxml/valid.c +7138 -0
- package/vendor/libxml/xinclude.c +2657 -0
- package/vendor/libxml/xlink.c +183 -0
- package/vendor/libxml/xmlIO.c +4135 -0
- package/vendor/libxml/xmlcatalog.c +624 -0
- package/vendor/libxml/xmllint.c +3796 -0
- package/vendor/libxml/xmlmemory.c +1163 -0
- package/vendor/libxml/xmlmodule.c +468 -0
- package/vendor/libxml/xmlreader.c +6033 -0
- package/vendor/libxml/xmlregexp.c +8271 -0
- package/vendor/libxml/xmlsave.c +2735 -0
- package/vendor/libxml/xmlschemas.c +29173 -0
- package/vendor/libxml/xmlschemastypes.c +6276 -0
- package/vendor/libxml/xmlstring.c +1050 -0
- package/vendor/libxml/xmlunicode.c +3179 -0
- package/vendor/libxml/xmlwriter.c +4738 -0
- package/vendor/libxml/xpath.c +14734 -0
- package/vendor/libxml/xpointer.c +2969 -0
- package/vendor/libxml/xzlib.c +815 -0
- package/vendor/libxml/xzlib.h +19 -0
@@ -0,0 +1,2735 @@
|
|
1
|
+
/*
|
2
|
+
* xmlsave.c: Implementation of the document serializer
|
3
|
+
*
|
4
|
+
* See Copyright for the status of this software.
|
5
|
+
*
|
6
|
+
* daniel@veillard.com
|
7
|
+
*/
|
8
|
+
|
9
|
+
#define IN_LIBXML
|
10
|
+
#include "libxml.h"
|
11
|
+
|
12
|
+
#include <string.h>
|
13
|
+
#include <libxml/xmlmemory.h>
|
14
|
+
#include <libxml/parserInternals.h>
|
15
|
+
#include <libxml/tree.h>
|
16
|
+
#include <libxml/xmlsave.h>
|
17
|
+
|
18
|
+
#define MAX_INDENT 60
|
19
|
+
|
20
|
+
#include <libxml/HTMLtree.h>
|
21
|
+
|
22
|
+
#include "buf.h"
|
23
|
+
#include "enc.h"
|
24
|
+
#include "save.h"
|
25
|
+
|
26
|
+
/************************************************************************
|
27
|
+
* *
|
28
|
+
* XHTML detection *
|
29
|
+
* *
|
30
|
+
************************************************************************/
|
31
|
+
#define XHTML_STRICT_PUBLIC_ID BAD_CAST \
|
32
|
+
"-//W3C//DTD XHTML 1.0 Strict//EN"
|
33
|
+
#define XHTML_STRICT_SYSTEM_ID BAD_CAST \
|
34
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
|
35
|
+
#define XHTML_FRAME_PUBLIC_ID BAD_CAST \
|
36
|
+
"-//W3C//DTD XHTML 1.0 Frameset//EN"
|
37
|
+
#define XHTML_FRAME_SYSTEM_ID BAD_CAST \
|
38
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
|
39
|
+
#define XHTML_TRANS_PUBLIC_ID BAD_CAST \
|
40
|
+
"-//W3C//DTD XHTML 1.0 Transitional//EN"
|
41
|
+
#define XHTML_TRANS_SYSTEM_ID BAD_CAST \
|
42
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
|
43
|
+
|
44
|
+
#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
|
45
|
+
/**
|
46
|
+
* xmlIsXHTML:
|
47
|
+
* @systemID: the system identifier
|
48
|
+
* @publicID: the public identifier
|
49
|
+
*
|
50
|
+
* Try to find if the document correspond to an XHTML DTD
|
51
|
+
*
|
52
|
+
* Returns 1 if true, 0 if not and -1 in case of error
|
53
|
+
*/
|
54
|
+
int
|
55
|
+
xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) {
|
56
|
+
if ((systemID == NULL) && (publicID == NULL))
|
57
|
+
return(-1);
|
58
|
+
if (publicID != NULL) {
|
59
|
+
if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1);
|
60
|
+
if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1);
|
61
|
+
if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1);
|
62
|
+
}
|
63
|
+
if (systemID != NULL) {
|
64
|
+
if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1);
|
65
|
+
if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1);
|
66
|
+
if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1);
|
67
|
+
}
|
68
|
+
return(0);
|
69
|
+
}
|
70
|
+
|
71
|
+
#ifdef LIBXML_OUTPUT_ENABLED
|
72
|
+
|
73
|
+
#define TODO \
|
74
|
+
xmlGenericError(xmlGenericErrorContext, \
|
75
|
+
"Unimplemented block at %s:%d\n", \
|
76
|
+
__FILE__, __LINE__);
|
77
|
+
|
78
|
+
struct _xmlSaveCtxt {
|
79
|
+
void *_private;
|
80
|
+
int type;
|
81
|
+
int fd;
|
82
|
+
const xmlChar *filename;
|
83
|
+
const xmlChar *encoding;
|
84
|
+
xmlCharEncodingHandlerPtr handler;
|
85
|
+
xmlOutputBufferPtr buf;
|
86
|
+
int options;
|
87
|
+
int level;
|
88
|
+
int format;
|
89
|
+
char indent[MAX_INDENT + 1]; /* array for indenting output */
|
90
|
+
int indent_nr;
|
91
|
+
int indent_size;
|
92
|
+
xmlCharEncodingOutputFunc escape; /* used for element content */
|
93
|
+
xmlCharEncodingOutputFunc escapeAttr;/* used for attribute content */
|
94
|
+
};
|
95
|
+
|
96
|
+
/************************************************************************
|
97
|
+
* *
|
98
|
+
* Output error handlers *
|
99
|
+
* *
|
100
|
+
************************************************************************/
|
101
|
+
/**
|
102
|
+
* xmlSaveErrMemory:
|
103
|
+
* @extra: extra information
|
104
|
+
*
|
105
|
+
* Handle an out of memory condition
|
106
|
+
*/
|
107
|
+
static void
|
108
|
+
xmlSaveErrMemory(const char *extra)
|
109
|
+
{
|
110
|
+
__xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra);
|
111
|
+
}
|
112
|
+
|
113
|
+
/**
|
114
|
+
* xmlSaveErr:
|
115
|
+
* @code: the error number
|
116
|
+
* @node: the location of the error.
|
117
|
+
* @extra: extra information
|
118
|
+
*
|
119
|
+
* Handle an out of memory condition
|
120
|
+
*/
|
121
|
+
static void
|
122
|
+
xmlSaveErr(int code, xmlNodePtr node, const char *extra)
|
123
|
+
{
|
124
|
+
const char *msg = NULL;
|
125
|
+
|
126
|
+
switch(code) {
|
127
|
+
case XML_SAVE_NOT_UTF8:
|
128
|
+
msg = "string is not in UTF-8\n";
|
129
|
+
break;
|
130
|
+
case XML_SAVE_CHAR_INVALID:
|
131
|
+
msg = "invalid character value\n";
|
132
|
+
break;
|
133
|
+
case XML_SAVE_UNKNOWN_ENCODING:
|
134
|
+
msg = "unknown encoding %s\n";
|
135
|
+
break;
|
136
|
+
case XML_SAVE_NO_DOCTYPE:
|
137
|
+
msg = "document has no DOCTYPE\n";
|
138
|
+
break;
|
139
|
+
default:
|
140
|
+
msg = "unexpected error number\n";
|
141
|
+
}
|
142
|
+
__xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra);
|
143
|
+
}
|
144
|
+
|
145
|
+
/************************************************************************
|
146
|
+
* *
|
147
|
+
* Special escaping routines *
|
148
|
+
* *
|
149
|
+
************************************************************************/
|
150
|
+
static unsigned char *
|
151
|
+
xmlSerializeHexCharRef(unsigned char *out, int val) {
|
152
|
+
unsigned char *ptr;
|
153
|
+
|
154
|
+
*out++ = '&';
|
155
|
+
*out++ = '#';
|
156
|
+
*out++ = 'x';
|
157
|
+
if (val < 0x10) ptr = out;
|
158
|
+
else if (val < 0x100) ptr = out + 1;
|
159
|
+
else if (val < 0x1000) ptr = out + 2;
|
160
|
+
else if (val < 0x10000) ptr = out + 3;
|
161
|
+
else if (val < 0x100000) ptr = out + 4;
|
162
|
+
else ptr = out + 5;
|
163
|
+
out = ptr + 1;
|
164
|
+
while (val > 0) {
|
165
|
+
switch (val & 0xF) {
|
166
|
+
case 0: *ptr-- = '0'; break;
|
167
|
+
case 1: *ptr-- = '1'; break;
|
168
|
+
case 2: *ptr-- = '2'; break;
|
169
|
+
case 3: *ptr-- = '3'; break;
|
170
|
+
case 4: *ptr-- = '4'; break;
|
171
|
+
case 5: *ptr-- = '5'; break;
|
172
|
+
case 6: *ptr-- = '6'; break;
|
173
|
+
case 7: *ptr-- = '7'; break;
|
174
|
+
case 8: *ptr-- = '8'; break;
|
175
|
+
case 9: *ptr-- = '9'; break;
|
176
|
+
case 0xA: *ptr-- = 'A'; break;
|
177
|
+
case 0xB: *ptr-- = 'B'; break;
|
178
|
+
case 0xC: *ptr-- = 'C'; break;
|
179
|
+
case 0xD: *ptr-- = 'D'; break;
|
180
|
+
case 0xE: *ptr-- = 'E'; break;
|
181
|
+
case 0xF: *ptr-- = 'F'; break;
|
182
|
+
default: *ptr-- = '0'; break;
|
183
|
+
}
|
184
|
+
val >>= 4;
|
185
|
+
}
|
186
|
+
*out++ = ';';
|
187
|
+
*out = 0;
|
188
|
+
return(out);
|
189
|
+
}
|
190
|
+
|
191
|
+
/**
|
192
|
+
* xmlEscapeEntities:
|
193
|
+
* @out: a pointer to an array of bytes to store the result
|
194
|
+
* @outlen: the length of @out
|
195
|
+
* @in: a pointer to an array of unescaped UTF-8 bytes
|
196
|
+
* @inlen: the length of @in
|
197
|
+
*
|
198
|
+
* Take a block of UTF-8 chars in and escape them. Used when there is no
|
199
|
+
* encoding specified.
|
200
|
+
*
|
201
|
+
* Returns 0 if success, or -1 otherwise
|
202
|
+
* The value of @inlen after return is the number of octets consumed
|
203
|
+
* if the return value is positive, else unpredictable.
|
204
|
+
* The value of @outlen after return is the number of octets consumed.
|
205
|
+
*/
|
206
|
+
static int
|
207
|
+
xmlEscapeEntities(unsigned char* out, int *outlen,
|
208
|
+
const xmlChar* in, int *inlen) {
|
209
|
+
unsigned char* outstart = out;
|
210
|
+
const unsigned char* base = in;
|
211
|
+
unsigned char* outend = out + *outlen;
|
212
|
+
const unsigned char* inend;
|
213
|
+
int val;
|
214
|
+
|
215
|
+
inend = in + (*inlen);
|
216
|
+
|
217
|
+
while ((in < inend) && (out < outend)) {
|
218
|
+
if (*in == '<') {
|
219
|
+
if (outend - out < 4) break;
|
220
|
+
*out++ = '&';
|
221
|
+
*out++ = 'l';
|
222
|
+
*out++ = 't';
|
223
|
+
*out++ = ';';
|
224
|
+
in++;
|
225
|
+
continue;
|
226
|
+
} else if (*in == '>') {
|
227
|
+
if (outend - out < 4) break;
|
228
|
+
*out++ = '&';
|
229
|
+
*out++ = 'g';
|
230
|
+
*out++ = 't';
|
231
|
+
*out++ = ';';
|
232
|
+
in++;
|
233
|
+
continue;
|
234
|
+
} else if (*in == '&') {
|
235
|
+
if (outend - out < 5) break;
|
236
|
+
*out++ = '&';
|
237
|
+
*out++ = 'a';
|
238
|
+
*out++ = 'm';
|
239
|
+
*out++ = 'p';
|
240
|
+
*out++ = ';';
|
241
|
+
in++;
|
242
|
+
continue;
|
243
|
+
} else if (((*in >= 0x20) && (*in < 0x80)) ||
|
244
|
+
(*in == '\n') || (*in == '\t')) {
|
245
|
+
/*
|
246
|
+
* default case, just copy !
|
247
|
+
*/
|
248
|
+
*out++ = *in++;
|
249
|
+
continue;
|
250
|
+
} else if (*in >= 0x80) {
|
251
|
+
/*
|
252
|
+
* We assume we have UTF-8 input.
|
253
|
+
*/
|
254
|
+
if (outend - out < 11) break;
|
255
|
+
|
256
|
+
if (*in < 0xC0) {
|
257
|
+
xmlSaveErr(XML_SAVE_NOT_UTF8, NULL, NULL);
|
258
|
+
in++;
|
259
|
+
goto error;
|
260
|
+
} else if (*in < 0xE0) {
|
261
|
+
if (inend - in < 2) break;
|
262
|
+
val = (in[0]) & 0x1F;
|
263
|
+
val <<= 6;
|
264
|
+
val |= (in[1]) & 0x3F;
|
265
|
+
in += 2;
|
266
|
+
} else if (*in < 0xF0) {
|
267
|
+
if (inend - in < 3) break;
|
268
|
+
val = (in[0]) & 0x0F;
|
269
|
+
val <<= 6;
|
270
|
+
val |= (in[1]) & 0x3F;
|
271
|
+
val <<= 6;
|
272
|
+
val |= (in[2]) & 0x3F;
|
273
|
+
in += 3;
|
274
|
+
} else if (*in < 0xF8) {
|
275
|
+
if (inend - in < 4) break;
|
276
|
+
val = (in[0]) & 0x07;
|
277
|
+
val <<= 6;
|
278
|
+
val |= (in[1]) & 0x3F;
|
279
|
+
val <<= 6;
|
280
|
+
val |= (in[2]) & 0x3F;
|
281
|
+
val <<= 6;
|
282
|
+
val |= (in[3]) & 0x3F;
|
283
|
+
in += 4;
|
284
|
+
} else {
|
285
|
+
xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL);
|
286
|
+
in++;
|
287
|
+
goto error;
|
288
|
+
}
|
289
|
+
if (!IS_CHAR(val)) {
|
290
|
+
xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL);
|
291
|
+
in++;
|
292
|
+
goto error;
|
293
|
+
}
|
294
|
+
|
295
|
+
/*
|
296
|
+
* We could do multiple things here. Just save as a char ref
|
297
|
+
*/
|
298
|
+
out = xmlSerializeHexCharRef(out, val);
|
299
|
+
} else if (IS_BYTE_CHAR(*in)) {
|
300
|
+
if (outend - out < 6) break;
|
301
|
+
out = xmlSerializeHexCharRef(out, *in++);
|
302
|
+
} else {
|
303
|
+
xmlGenericError(xmlGenericErrorContext,
|
304
|
+
"xmlEscapeEntities : char out of range\n");
|
305
|
+
in++;
|
306
|
+
goto error;
|
307
|
+
}
|
308
|
+
}
|
309
|
+
*outlen = out - outstart;
|
310
|
+
*inlen = in - base;
|
311
|
+
return(0);
|
312
|
+
error:
|
313
|
+
*outlen = out - outstart;
|
314
|
+
*inlen = in - base;
|
315
|
+
return(-1);
|
316
|
+
}
|
317
|
+
|
318
|
+
/************************************************************************
|
319
|
+
* *
|
320
|
+
* Allocation and deallocation *
|
321
|
+
* *
|
322
|
+
************************************************************************/
|
323
|
+
/**
|
324
|
+
* xmlSaveCtxtInit:
|
325
|
+
* @ctxt: the saving context
|
326
|
+
*
|
327
|
+
* Initialize a saving context
|
328
|
+
*/
|
329
|
+
static void
|
330
|
+
xmlSaveCtxtInit(xmlSaveCtxtPtr ctxt)
|
331
|
+
{
|
332
|
+
int i;
|
333
|
+
int len;
|
334
|
+
|
335
|
+
if (ctxt == NULL) return;
|
336
|
+
if ((ctxt->encoding == NULL) && (ctxt->escape == NULL))
|
337
|
+
ctxt->escape = xmlEscapeEntities;
|
338
|
+
len = xmlStrlen((xmlChar *)xmlTreeIndentString);
|
339
|
+
if ((xmlTreeIndentString == NULL) || (len == 0)) {
|
340
|
+
memset(&ctxt->indent[0], 0, MAX_INDENT + 1);
|
341
|
+
} else {
|
342
|
+
ctxt->indent_size = len;
|
343
|
+
ctxt->indent_nr = MAX_INDENT / ctxt->indent_size;
|
344
|
+
for (i = 0;i < ctxt->indent_nr;i++)
|
345
|
+
memcpy(&ctxt->indent[i * ctxt->indent_size], xmlTreeIndentString,
|
346
|
+
ctxt->indent_size);
|
347
|
+
ctxt->indent[ctxt->indent_nr * ctxt->indent_size] = 0;
|
348
|
+
}
|
349
|
+
|
350
|
+
if (xmlSaveNoEmptyTags) {
|
351
|
+
ctxt->options |= XML_SAVE_NO_EMPTY;
|
352
|
+
}
|
353
|
+
}
|
354
|
+
|
355
|
+
/**
|
356
|
+
* xmlFreeSaveCtxt:
|
357
|
+
*
|
358
|
+
* Free a saving context, destroying the output in any remaining buffer
|
359
|
+
*/
|
360
|
+
static void
|
361
|
+
xmlFreeSaveCtxt(xmlSaveCtxtPtr ctxt)
|
362
|
+
{
|
363
|
+
if (ctxt == NULL) return;
|
364
|
+
if (ctxt->encoding != NULL)
|
365
|
+
xmlFree((char *) ctxt->encoding);
|
366
|
+
if (ctxt->buf != NULL)
|
367
|
+
xmlOutputBufferClose(ctxt->buf);
|
368
|
+
xmlFree(ctxt);
|
369
|
+
}
|
370
|
+
|
371
|
+
/**
|
372
|
+
* xmlNewSaveCtxt:
|
373
|
+
*
|
374
|
+
* Create a new saving context
|
375
|
+
*
|
376
|
+
* Returns the new structure or NULL in case of error
|
377
|
+
*/
|
378
|
+
static xmlSaveCtxtPtr
|
379
|
+
xmlNewSaveCtxt(const char *encoding, int options)
|
380
|
+
{
|
381
|
+
xmlSaveCtxtPtr ret;
|
382
|
+
|
383
|
+
ret = (xmlSaveCtxtPtr) xmlMalloc(sizeof(xmlSaveCtxt));
|
384
|
+
if (ret == NULL) {
|
385
|
+
xmlSaveErrMemory("creating saving context");
|
386
|
+
return ( NULL );
|
387
|
+
}
|
388
|
+
memset(ret, 0, sizeof(xmlSaveCtxt));
|
389
|
+
|
390
|
+
if (encoding != NULL) {
|
391
|
+
ret->handler = xmlFindCharEncodingHandler(encoding);
|
392
|
+
if (ret->handler == NULL) {
|
393
|
+
xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding);
|
394
|
+
xmlFreeSaveCtxt(ret);
|
395
|
+
return(NULL);
|
396
|
+
}
|
397
|
+
ret->encoding = xmlStrdup((const xmlChar *)encoding);
|
398
|
+
ret->escape = NULL;
|
399
|
+
}
|
400
|
+
xmlSaveCtxtInit(ret);
|
401
|
+
|
402
|
+
/*
|
403
|
+
* Use the options
|
404
|
+
*/
|
405
|
+
|
406
|
+
/* Re-check this option as it may already have been set */
|
407
|
+
if ((ret->options & XML_SAVE_NO_EMPTY) && ! (options & XML_SAVE_NO_EMPTY)) {
|
408
|
+
options |= XML_SAVE_NO_EMPTY;
|
409
|
+
}
|
410
|
+
|
411
|
+
ret->options = options;
|
412
|
+
if (options & XML_SAVE_FORMAT)
|
413
|
+
ret->format = 1;
|
414
|
+
else if (options & XML_SAVE_WSNONSIG)
|
415
|
+
ret->format = 2;
|
416
|
+
|
417
|
+
return(ret);
|
418
|
+
}
|
419
|
+
|
420
|
+
/************************************************************************
|
421
|
+
* *
|
422
|
+
* Dumping XML tree content to a simple buffer *
|
423
|
+
* *
|
424
|
+
************************************************************************/
|
425
|
+
/**
|
426
|
+
* xmlAttrSerializeContent:
|
427
|
+
* @buf: the XML buffer output
|
428
|
+
* @doc: the document
|
429
|
+
* @attr: the attribute pointer
|
430
|
+
*
|
431
|
+
* Serialize the attribute in the buffer
|
432
|
+
*/
|
433
|
+
static void
|
434
|
+
xmlAttrSerializeContent(xmlOutputBufferPtr buf, xmlAttrPtr attr)
|
435
|
+
{
|
436
|
+
xmlNodePtr children;
|
437
|
+
|
438
|
+
children = attr->children;
|
439
|
+
while (children != NULL) {
|
440
|
+
switch (children->type) {
|
441
|
+
case XML_TEXT_NODE:
|
442
|
+
xmlBufAttrSerializeTxtContent(buf->buffer, attr->doc,
|
443
|
+
attr, children->content);
|
444
|
+
break;
|
445
|
+
case XML_ENTITY_REF_NODE:
|
446
|
+
xmlBufAdd(buf->buffer, BAD_CAST "&", 1);
|
447
|
+
xmlBufAdd(buf->buffer, children->name,
|
448
|
+
xmlStrlen(children->name));
|
449
|
+
xmlBufAdd(buf->buffer, BAD_CAST ";", 1);
|
450
|
+
break;
|
451
|
+
default:
|
452
|
+
/* should not happen unless we have a badly built tree */
|
453
|
+
break;
|
454
|
+
}
|
455
|
+
children = children->next;
|
456
|
+
}
|
457
|
+
}
|
458
|
+
|
459
|
+
/**
|
460
|
+
* xmlBufDumpNotationTable:
|
461
|
+
* @buf: an xmlBufPtr output
|
462
|
+
* @table: A notation table
|
463
|
+
*
|
464
|
+
* This will dump the content of the notation table as an XML DTD definition
|
465
|
+
*/
|
466
|
+
void
|
467
|
+
xmlBufDumpNotationTable(xmlBufPtr buf, xmlNotationTablePtr table) {
|
468
|
+
xmlBufferPtr buffer;
|
469
|
+
|
470
|
+
buffer = xmlBufferCreate();
|
471
|
+
if (buffer == NULL) {
|
472
|
+
/*
|
473
|
+
* TODO set the error in buf
|
474
|
+
*/
|
475
|
+
return;
|
476
|
+
}
|
477
|
+
xmlDumpNotationTable(buffer, table);
|
478
|
+
xmlBufMergeBuffer(buf, buffer);
|
479
|
+
}
|
480
|
+
|
481
|
+
/**
|
482
|
+
* xmlBufDumpElementDecl:
|
483
|
+
* @buf: an xmlBufPtr output
|
484
|
+
* @elem: An element table
|
485
|
+
*
|
486
|
+
* This will dump the content of the element declaration as an XML
|
487
|
+
* DTD definition
|
488
|
+
*/
|
489
|
+
void
|
490
|
+
xmlBufDumpElementDecl(xmlBufPtr buf, xmlElementPtr elem) {
|
491
|
+
xmlBufferPtr buffer;
|
492
|
+
|
493
|
+
buffer = xmlBufferCreate();
|
494
|
+
if (buffer == NULL) {
|
495
|
+
/*
|
496
|
+
* TODO set the error in buf
|
497
|
+
*/
|
498
|
+
return;
|
499
|
+
}
|
500
|
+
xmlDumpElementDecl(buffer, elem);
|
501
|
+
xmlBufMergeBuffer(buf, buffer);
|
502
|
+
}
|
503
|
+
|
504
|
+
/**
|
505
|
+
* xmlBufDumpAttributeDecl:
|
506
|
+
* @buf: an xmlBufPtr output
|
507
|
+
* @attr: An attribute declaration
|
508
|
+
*
|
509
|
+
* This will dump the content of the attribute declaration as an XML
|
510
|
+
* DTD definition
|
511
|
+
*/
|
512
|
+
void
|
513
|
+
xmlBufDumpAttributeDecl(xmlBufPtr buf, xmlAttributePtr attr) {
|
514
|
+
xmlBufferPtr buffer;
|
515
|
+
|
516
|
+
buffer = xmlBufferCreate();
|
517
|
+
if (buffer == NULL) {
|
518
|
+
/*
|
519
|
+
* TODO set the error in buf
|
520
|
+
*/
|
521
|
+
return;
|
522
|
+
}
|
523
|
+
xmlDumpAttributeDecl(buffer, attr);
|
524
|
+
xmlBufMergeBuffer(buf, buffer);
|
525
|
+
}
|
526
|
+
|
527
|
+
/**
|
528
|
+
* xmlBufDumpEntityDecl:
|
529
|
+
* @buf: an xmlBufPtr output
|
530
|
+
* @ent: An entity table
|
531
|
+
*
|
532
|
+
* This will dump the content of the entity table as an XML DTD definition
|
533
|
+
*/
|
534
|
+
void
|
535
|
+
xmlBufDumpEntityDecl(xmlBufPtr buf, xmlEntityPtr ent) {
|
536
|
+
xmlBufferPtr buffer;
|
537
|
+
|
538
|
+
buffer = xmlBufferCreate();
|
539
|
+
if (buffer == NULL) {
|
540
|
+
/*
|
541
|
+
* TODO set the error in buf
|
542
|
+
*/
|
543
|
+
return;
|
544
|
+
}
|
545
|
+
xmlDumpEntityDecl(buffer, ent);
|
546
|
+
xmlBufMergeBuffer(buf, buffer);
|
547
|
+
}
|
548
|
+
|
549
|
+
/************************************************************************
|
550
|
+
* *
|
551
|
+
* Dumping XML tree content to an I/O output buffer *
|
552
|
+
* *
|
553
|
+
************************************************************************/
|
554
|
+
|
555
|
+
static int xmlSaveSwitchEncoding(xmlSaveCtxtPtr ctxt, const char *encoding) {
|
556
|
+
xmlOutputBufferPtr buf = ctxt->buf;
|
557
|
+
|
558
|
+
if ((encoding != NULL) && (buf->encoder == NULL) && (buf->conv == NULL)) {
|
559
|
+
buf->encoder = xmlFindCharEncodingHandler((const char *)encoding);
|
560
|
+
if (buf->encoder == NULL) {
|
561
|
+
xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL,
|
562
|
+
(const char *)encoding);
|
563
|
+
return(-1);
|
564
|
+
}
|
565
|
+
buf->conv = xmlBufCreate();
|
566
|
+
if (buf->conv == NULL) {
|
567
|
+
xmlCharEncCloseFunc(buf->encoder);
|
568
|
+
xmlSaveErrMemory("creating encoding buffer");
|
569
|
+
return(-1);
|
570
|
+
}
|
571
|
+
/*
|
572
|
+
* initialize the state, e.g. if outputting a BOM
|
573
|
+
*/
|
574
|
+
xmlCharEncOutput(buf, 1);
|
575
|
+
}
|
576
|
+
return(0);
|
577
|
+
}
|
578
|
+
|
579
|
+
static int xmlSaveClearEncoding(xmlSaveCtxtPtr ctxt) {
|
580
|
+
xmlOutputBufferPtr buf = ctxt->buf;
|
581
|
+
xmlOutputBufferFlush(buf);
|
582
|
+
xmlCharEncCloseFunc(buf->encoder);
|
583
|
+
xmlBufFree(buf->conv);
|
584
|
+
buf->encoder = NULL;
|
585
|
+
buf->conv = NULL;
|
586
|
+
return(0);
|
587
|
+
}
|
588
|
+
|
589
|
+
#ifdef LIBXML_HTML_ENABLED
|
590
|
+
static void
|
591
|
+
xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
|
592
|
+
#endif
|
593
|
+
static void xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
|
594
|
+
void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
|
595
|
+
static int xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur);
|
596
|
+
|
597
|
+
/**
|
598
|
+
* xmlOutputBufferWriteWSNonSig:
|
599
|
+
* @ctxt: The save context
|
600
|
+
* @extra: Number of extra indents to apply to ctxt->level
|
601
|
+
*
|
602
|
+
* Write out formatting for non-significant whitespace output.
|
603
|
+
*/
|
604
|
+
static void
|
605
|
+
xmlOutputBufferWriteWSNonSig(xmlSaveCtxtPtr ctxt, int extra)
|
606
|
+
{
|
607
|
+
int i;
|
608
|
+
if ((ctxt == NULL) || (ctxt->buf == NULL))
|
609
|
+
return;
|
610
|
+
xmlOutputBufferWrite(ctxt->buf, 1, "\n");
|
611
|
+
for (i = 0; i < (ctxt->level + extra); i += ctxt->indent_nr) {
|
612
|
+
xmlOutputBufferWrite(ctxt->buf, ctxt->indent_size *
|
613
|
+
((ctxt->level + extra - i) > ctxt->indent_nr ?
|
614
|
+
ctxt->indent_nr : (ctxt->level + extra - i)),
|
615
|
+
ctxt->indent);
|
616
|
+
}
|
617
|
+
}
|
618
|
+
|
619
|
+
/**
|
620
|
+
* xmlNsDumpOutput:
|
621
|
+
* @buf: the XML buffer output
|
622
|
+
* @cur: a namespace
|
623
|
+
* @ctxt: the output save context. Optional.
|
624
|
+
*
|
625
|
+
* Dump a local Namespace definition.
|
626
|
+
* Should be called in the context of attributes dumps.
|
627
|
+
* If @ctxt is supplied, @buf should be its buffer.
|
628
|
+
*/
|
629
|
+
static void
|
630
|
+
xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur, xmlSaveCtxtPtr ctxt) {
|
631
|
+
if ((cur == NULL) || (buf == NULL)) return;
|
632
|
+
if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
|
633
|
+
if (xmlStrEqual(cur->prefix, BAD_CAST "xml"))
|
634
|
+
return;
|
635
|
+
|
636
|
+
if (ctxt != NULL && ctxt->format == 2)
|
637
|
+
xmlOutputBufferWriteWSNonSig(ctxt, 2);
|
638
|
+
else
|
639
|
+
xmlOutputBufferWrite(buf, 1, " ");
|
640
|
+
|
641
|
+
/* Within the context of an element attributes */
|
642
|
+
if (cur->prefix != NULL) {
|
643
|
+
xmlOutputBufferWrite(buf, 6, "xmlns:");
|
644
|
+
xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
|
645
|
+
} else
|
646
|
+
xmlOutputBufferWrite(buf, 5, "xmlns");
|
647
|
+
xmlOutputBufferWrite(buf, 1, "=");
|
648
|
+
xmlBufWriteQuotedString(buf->buffer, cur->href);
|
649
|
+
}
|
650
|
+
}
|
651
|
+
|
652
|
+
/**
|
653
|
+
* xmlNsDumpOutputCtxt
|
654
|
+
* @ctxt: the save context
|
655
|
+
* @cur: a namespace
|
656
|
+
*
|
657
|
+
* Dump a local Namespace definition to a save context.
|
658
|
+
* Should be called in the context of attribute dumps.
|
659
|
+
*/
|
660
|
+
static void
|
661
|
+
xmlNsDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlNsPtr cur) {
|
662
|
+
xmlNsDumpOutput(ctxt->buf, cur, ctxt);
|
663
|
+
}
|
664
|
+
|
665
|
+
/**
|
666
|
+
* xmlNsListDumpOutputCtxt
|
667
|
+
* @ctxt: the save context
|
668
|
+
* @cur: the first namespace
|
669
|
+
*
|
670
|
+
* Dump a list of local namespace definitions to a save context.
|
671
|
+
* Should be called in the context of attribute dumps.
|
672
|
+
*/
|
673
|
+
static void
|
674
|
+
xmlNsListDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlNsPtr cur) {
|
675
|
+
while (cur != NULL) {
|
676
|
+
xmlNsDumpOutput(ctxt->buf, cur, ctxt);
|
677
|
+
cur = cur->next;
|
678
|
+
}
|
679
|
+
}
|
680
|
+
|
681
|
+
/**
|
682
|
+
* xmlNsListDumpOutput:
|
683
|
+
* @buf: the XML buffer output
|
684
|
+
* @cur: the first namespace
|
685
|
+
*
|
686
|
+
* Dump a list of local Namespace definitions.
|
687
|
+
* Should be called in the context of attributes dumps.
|
688
|
+
*/
|
689
|
+
void
|
690
|
+
xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
|
691
|
+
while (cur != NULL) {
|
692
|
+
xmlNsDumpOutput(buf, cur, NULL);
|
693
|
+
cur = cur->next;
|
694
|
+
}
|
695
|
+
}
|
696
|
+
|
697
|
+
/**
|
698
|
+
* xmlDtdDumpOutput:
|
699
|
+
* @buf: the XML buffer output
|
700
|
+
* @dtd: the pointer to the DTD
|
701
|
+
*
|
702
|
+
* Dump the XML document DTD, if any.
|
703
|
+
*/
|
704
|
+
static void
|
705
|
+
xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) {
|
706
|
+
xmlOutputBufferPtr buf;
|
707
|
+
xmlNodePtr cur;
|
708
|
+
int format, level;
|
709
|
+
|
710
|
+
if (dtd == NULL) return;
|
711
|
+
if ((ctxt == NULL) || (ctxt->buf == NULL))
|
712
|
+
return;
|
713
|
+
buf = ctxt->buf;
|
714
|
+
xmlOutputBufferWrite(buf, 10, "<!DOCTYPE ");
|
715
|
+
xmlOutputBufferWriteString(buf, (const char *)dtd->name);
|
716
|
+
if (dtd->ExternalID != NULL) {
|
717
|
+
xmlOutputBufferWrite(buf, 8, " PUBLIC ");
|
718
|
+
xmlBufWriteQuotedString(buf->buffer, dtd->ExternalID);
|
719
|
+
xmlOutputBufferWrite(buf, 1, " ");
|
720
|
+
xmlBufWriteQuotedString(buf->buffer, dtd->SystemID);
|
721
|
+
} else if (dtd->SystemID != NULL) {
|
722
|
+
xmlOutputBufferWrite(buf, 8, " SYSTEM ");
|
723
|
+
xmlBufWriteQuotedString(buf->buffer, dtd->SystemID);
|
724
|
+
}
|
725
|
+
if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
|
726
|
+
(dtd->attributes == NULL) && (dtd->notations == NULL) &&
|
727
|
+
(dtd->pentities == NULL)) {
|
728
|
+
xmlOutputBufferWrite(buf, 1, ">");
|
729
|
+
return;
|
730
|
+
}
|
731
|
+
xmlOutputBufferWrite(buf, 3, " [\n");
|
732
|
+
/*
|
733
|
+
* Dump the notations first they are not in the DTD children list
|
734
|
+
* Do this only on a standalone DTD or on the internal subset though.
|
735
|
+
*/
|
736
|
+
if ((dtd->notations != NULL) && ((dtd->doc == NULL) ||
|
737
|
+
(dtd->doc->intSubset == dtd))) {
|
738
|
+
xmlBufDumpNotationTable(buf->buffer,
|
739
|
+
(xmlNotationTablePtr) dtd->notations);
|
740
|
+
}
|
741
|
+
format = ctxt->format;
|
742
|
+
level = ctxt->level;
|
743
|
+
ctxt->format = 0;
|
744
|
+
ctxt->level = -1;
|
745
|
+
for (cur = dtd->children; cur != NULL; cur = cur->next) {
|
746
|
+
xmlNodeDumpOutputInternal(ctxt, cur);
|
747
|
+
}
|
748
|
+
ctxt->format = format;
|
749
|
+
ctxt->level = level;
|
750
|
+
xmlOutputBufferWrite(buf, 2, "]>");
|
751
|
+
}
|
752
|
+
|
753
|
+
/**
|
754
|
+
* xmlAttrDumpOutput:
|
755
|
+
* @buf: the XML buffer output
|
756
|
+
* @cur: the attribute pointer
|
757
|
+
*
|
758
|
+
* Dump an XML attribute
|
759
|
+
*/
|
760
|
+
static void
|
761
|
+
xmlAttrDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
|
762
|
+
xmlOutputBufferPtr buf;
|
763
|
+
|
764
|
+
if (cur == NULL) return;
|
765
|
+
buf = ctxt->buf;
|
766
|
+
if (buf == NULL) return;
|
767
|
+
if (ctxt->format == 2)
|
768
|
+
xmlOutputBufferWriteWSNonSig(ctxt, 2);
|
769
|
+
else
|
770
|
+
xmlOutputBufferWrite(buf, 1, " ");
|
771
|
+
if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
|
772
|
+
xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
|
773
|
+
xmlOutputBufferWrite(buf, 1, ":");
|
774
|
+
}
|
775
|
+
xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
776
|
+
xmlOutputBufferWrite(buf, 2, "=\"");
|
777
|
+
xmlAttrSerializeContent(buf, cur);
|
778
|
+
xmlOutputBufferWrite(buf, 1, "\"");
|
779
|
+
}
|
780
|
+
|
781
|
+
#ifdef LIBXML_HTML_ENABLED
|
782
|
+
/**
|
783
|
+
* htmlNodeDumpOutputInternal:
|
784
|
+
* @cur: the current node
|
785
|
+
*
|
786
|
+
* Dump an HTML node, recursive behaviour, children are printed too.
|
787
|
+
*/
|
788
|
+
static int
|
789
|
+
htmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
|
790
|
+
const xmlChar *oldenc = NULL;
|
791
|
+
const xmlChar *oldctxtenc = ctxt->encoding;
|
792
|
+
const xmlChar *encoding = ctxt->encoding;
|
793
|
+
xmlOutputBufferPtr buf = ctxt->buf;
|
794
|
+
int switched_encoding = 0;
|
795
|
+
xmlDocPtr doc;
|
796
|
+
|
797
|
+
xmlInitParser();
|
798
|
+
|
799
|
+
doc = cur->doc;
|
800
|
+
if (doc != NULL) {
|
801
|
+
oldenc = doc->encoding;
|
802
|
+
if (ctxt->encoding != NULL) {
|
803
|
+
doc->encoding = BAD_CAST ctxt->encoding;
|
804
|
+
} else if (doc->encoding != NULL) {
|
805
|
+
encoding = doc->encoding;
|
806
|
+
}
|
807
|
+
}
|
808
|
+
|
809
|
+
if ((encoding != NULL) && (doc != NULL))
|
810
|
+
htmlSetMetaEncoding(doc, (const xmlChar *) encoding);
|
811
|
+
if ((encoding == NULL) && (doc != NULL))
|
812
|
+
encoding = htmlGetMetaEncoding(doc);
|
813
|
+
if (encoding == NULL)
|
814
|
+
encoding = BAD_CAST "HTML";
|
815
|
+
if ((encoding != NULL) && (oldctxtenc == NULL) &&
|
816
|
+
(buf->encoder == NULL) && (buf->conv == NULL)) {
|
817
|
+
if (xmlSaveSwitchEncoding(ctxt, (const char*) encoding) < 0) {
|
818
|
+
doc->encoding = oldenc;
|
819
|
+
return(-1);
|
820
|
+
}
|
821
|
+
switched_encoding = 1;
|
822
|
+
}
|
823
|
+
if (ctxt->options & XML_SAVE_FORMAT)
|
824
|
+
htmlNodeDumpFormatOutput(buf, doc, cur,
|
825
|
+
(const char *)encoding, 1);
|
826
|
+
else
|
827
|
+
htmlNodeDumpFormatOutput(buf, doc, cur,
|
828
|
+
(const char *)encoding, 0);
|
829
|
+
/*
|
830
|
+
* Restore the state of the saving context at the end of the document
|
831
|
+
*/
|
832
|
+
if ((switched_encoding) && (oldctxtenc == NULL)) {
|
833
|
+
xmlSaveClearEncoding(ctxt);
|
834
|
+
}
|
835
|
+
if (doc != NULL)
|
836
|
+
doc->encoding = oldenc;
|
837
|
+
return(0);
|
838
|
+
}
|
839
|
+
#endif
|
840
|
+
|
841
|
+
/**
|
842
|
+
* xmlNodeDumpOutputInternal:
|
843
|
+
* @cur: the current node
|
844
|
+
*
|
845
|
+
* Dump an XML node, recursive behaviour, children are printed too.
|
846
|
+
*/
|
847
|
+
static void
|
848
|
+
xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
|
849
|
+
int format = ctxt->format;
|
850
|
+
xmlNodePtr tmp, root, unformattedNode = NULL, parent;
|
851
|
+
xmlAttrPtr attr;
|
852
|
+
xmlChar *start, *end;
|
853
|
+
xmlOutputBufferPtr buf;
|
854
|
+
|
855
|
+
if (cur == NULL) return;
|
856
|
+
buf = ctxt->buf;
|
857
|
+
|
858
|
+
root = cur;
|
859
|
+
parent = cur->parent;
|
860
|
+
while (1) {
|
861
|
+
switch (cur->type) {
|
862
|
+
case XML_DOCUMENT_NODE:
|
863
|
+
case XML_HTML_DOCUMENT_NODE:
|
864
|
+
xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
|
865
|
+
break;
|
866
|
+
|
867
|
+
case XML_DTD_NODE:
|
868
|
+
xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
|
869
|
+
break;
|
870
|
+
|
871
|
+
case XML_DOCUMENT_FRAG_NODE:
|
872
|
+
/* Always validate cur->parent when descending. */
|
873
|
+
if ((cur->parent == parent) && (cur->children != NULL)) {
|
874
|
+
parent = cur;
|
875
|
+
cur = cur->children;
|
876
|
+
continue;
|
877
|
+
}
|
878
|
+
break;
|
879
|
+
|
880
|
+
case XML_ELEMENT_DECL:
|
881
|
+
xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
|
882
|
+
break;
|
883
|
+
|
884
|
+
case XML_ATTRIBUTE_DECL:
|
885
|
+
xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
|
886
|
+
break;
|
887
|
+
|
888
|
+
case XML_ENTITY_DECL:
|
889
|
+
xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
|
890
|
+
break;
|
891
|
+
|
892
|
+
case XML_ELEMENT_NODE:
|
893
|
+
if ((cur != root) && (ctxt->format == 1) &&
|
894
|
+
(xmlIndentTreeOutput))
|
895
|
+
xmlOutputBufferWrite(buf, ctxt->indent_size *
|
896
|
+
(ctxt->level > ctxt->indent_nr ?
|
897
|
+
ctxt->indent_nr : ctxt->level),
|
898
|
+
ctxt->indent);
|
899
|
+
|
900
|
+
/*
|
901
|
+
* Some users like lxml are known to pass nodes with a corrupted
|
902
|
+
* tree structure. Fall back to a recursive call to handle this
|
903
|
+
* case.
|
904
|
+
*/
|
905
|
+
if ((cur->parent != parent) && (cur->children != NULL)) {
|
906
|
+
xmlNodeDumpOutputInternal(ctxt, cur);
|
907
|
+
break;
|
908
|
+
}
|
909
|
+
|
910
|
+
xmlOutputBufferWrite(buf, 1, "<");
|
911
|
+
if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
|
912
|
+
xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
|
913
|
+
xmlOutputBufferWrite(buf, 1, ":");
|
914
|
+
}
|
915
|
+
xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
916
|
+
if (cur->nsDef)
|
917
|
+
xmlNsListDumpOutputCtxt(ctxt, cur->nsDef);
|
918
|
+
for (attr = cur->properties; attr != NULL; attr = attr->next)
|
919
|
+
xmlAttrDumpOutput(ctxt, attr);
|
920
|
+
|
921
|
+
if (cur->children == NULL) {
|
922
|
+
if ((ctxt->options & XML_SAVE_NO_EMPTY) == 0) {
|
923
|
+
if (ctxt->format == 2)
|
924
|
+
xmlOutputBufferWriteWSNonSig(ctxt, 0);
|
925
|
+
xmlOutputBufferWrite(buf, 2, "/>");
|
926
|
+
} else {
|
927
|
+
if (ctxt->format == 2)
|
928
|
+
xmlOutputBufferWriteWSNonSig(ctxt, 1);
|
929
|
+
xmlOutputBufferWrite(buf, 3, "></");
|
930
|
+
if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
|
931
|
+
xmlOutputBufferWriteString(buf,
|
932
|
+
(const char *)cur->ns->prefix);
|
933
|
+
xmlOutputBufferWrite(buf, 1, ":");
|
934
|
+
}
|
935
|
+
xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
936
|
+
if (ctxt->format == 2)
|
937
|
+
xmlOutputBufferWriteWSNonSig(ctxt, 0);
|
938
|
+
xmlOutputBufferWrite(buf, 1, ">");
|
939
|
+
}
|
940
|
+
} else {
|
941
|
+
if (ctxt->format == 1) {
|
942
|
+
tmp = cur->children;
|
943
|
+
while (tmp != NULL) {
|
944
|
+
if ((tmp->type == XML_TEXT_NODE) ||
|
945
|
+
(tmp->type == XML_CDATA_SECTION_NODE) ||
|
946
|
+
(tmp->type == XML_ENTITY_REF_NODE)) {
|
947
|
+
ctxt->format = 0;
|
948
|
+
unformattedNode = cur;
|
949
|
+
break;
|
950
|
+
}
|
951
|
+
tmp = tmp->next;
|
952
|
+
}
|
953
|
+
}
|
954
|
+
if (ctxt->format == 2)
|
955
|
+
xmlOutputBufferWriteWSNonSig(ctxt, 1);
|
956
|
+
xmlOutputBufferWrite(buf, 1, ">");
|
957
|
+
if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n");
|
958
|
+
if (ctxt->level >= 0) ctxt->level++;
|
959
|
+
parent = cur;
|
960
|
+
cur = cur->children;
|
961
|
+
continue;
|
962
|
+
}
|
963
|
+
|
964
|
+
break;
|
965
|
+
|
966
|
+
case XML_TEXT_NODE:
|
967
|
+
if (cur->content == NULL)
|
968
|
+
break;
|
969
|
+
if (cur->name != xmlStringTextNoenc) {
|
970
|
+
xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
|
971
|
+
} else {
|
972
|
+
/*
|
973
|
+
* Disable escaping, needed for XSLT
|
974
|
+
*/
|
975
|
+
xmlOutputBufferWriteString(buf, (const char *) cur->content);
|
976
|
+
}
|
977
|
+
break;
|
978
|
+
|
979
|
+
case XML_PI_NODE:
|
980
|
+
if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
|
981
|
+
xmlOutputBufferWrite(buf, ctxt->indent_size *
|
982
|
+
(ctxt->level > ctxt->indent_nr ?
|
983
|
+
ctxt->indent_nr : ctxt->level),
|
984
|
+
ctxt->indent);
|
985
|
+
|
986
|
+
if (cur->content != NULL) {
|
987
|
+
xmlOutputBufferWrite(buf, 2, "<?");
|
988
|
+
xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
989
|
+
if (cur->content != NULL) {
|
990
|
+
if (ctxt->format == 2)
|
991
|
+
xmlOutputBufferWriteWSNonSig(ctxt, 0);
|
992
|
+
else
|
993
|
+
xmlOutputBufferWrite(buf, 1, " ");
|
994
|
+
xmlOutputBufferWriteString(buf,
|
995
|
+
(const char *)cur->content);
|
996
|
+
}
|
997
|
+
xmlOutputBufferWrite(buf, 2, "?>");
|
998
|
+
} else {
|
999
|
+
xmlOutputBufferWrite(buf, 2, "<?");
|
1000
|
+
xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
1001
|
+
if (ctxt->format == 2)
|
1002
|
+
xmlOutputBufferWriteWSNonSig(ctxt, 0);
|
1003
|
+
xmlOutputBufferWrite(buf, 2, "?>");
|
1004
|
+
}
|
1005
|
+
break;
|
1006
|
+
|
1007
|
+
case XML_COMMENT_NODE:
|
1008
|
+
if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
|
1009
|
+
xmlOutputBufferWrite(buf, ctxt->indent_size *
|
1010
|
+
(ctxt->level > ctxt->indent_nr ?
|
1011
|
+
ctxt->indent_nr : ctxt->level),
|
1012
|
+
ctxt->indent);
|
1013
|
+
|
1014
|
+
if (cur->content != NULL) {
|
1015
|
+
xmlOutputBufferWrite(buf, 4, "<!--");
|
1016
|
+
xmlOutputBufferWriteString(buf, (const char *)cur->content);
|
1017
|
+
xmlOutputBufferWrite(buf, 3, "-->");
|
1018
|
+
}
|
1019
|
+
break;
|
1020
|
+
|
1021
|
+
case XML_ENTITY_REF_NODE:
|
1022
|
+
xmlOutputBufferWrite(buf, 1, "&");
|
1023
|
+
xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
1024
|
+
xmlOutputBufferWrite(buf, 1, ";");
|
1025
|
+
break;
|
1026
|
+
|
1027
|
+
case XML_CDATA_SECTION_NODE:
|
1028
|
+
if (cur->content == NULL || *cur->content == '\0') {
|
1029
|
+
xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
|
1030
|
+
} else {
|
1031
|
+
start = end = cur->content;
|
1032
|
+
while (*end != '\0') {
|
1033
|
+
if ((*end == ']') && (*(end + 1) == ']') &&
|
1034
|
+
(*(end + 2) == '>')) {
|
1035
|
+
end = end + 2;
|
1036
|
+
xmlOutputBufferWrite(buf, 9, "<![CDATA[");
|
1037
|
+
xmlOutputBufferWrite(buf, end - start,
|
1038
|
+
(const char *)start);
|
1039
|
+
xmlOutputBufferWrite(buf, 3, "]]>");
|
1040
|
+
start = end;
|
1041
|
+
}
|
1042
|
+
end++;
|
1043
|
+
}
|
1044
|
+
if (start != end) {
|
1045
|
+
xmlOutputBufferWrite(buf, 9, "<![CDATA[");
|
1046
|
+
xmlOutputBufferWriteString(buf, (const char *)start);
|
1047
|
+
xmlOutputBufferWrite(buf, 3, "]]>");
|
1048
|
+
}
|
1049
|
+
}
|
1050
|
+
break;
|
1051
|
+
|
1052
|
+
case XML_ATTRIBUTE_NODE:
|
1053
|
+
xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
|
1054
|
+
break;
|
1055
|
+
|
1056
|
+
case XML_NAMESPACE_DECL:
|
1057
|
+
xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur);
|
1058
|
+
break;
|
1059
|
+
|
1060
|
+
default:
|
1061
|
+
break;
|
1062
|
+
}
|
1063
|
+
|
1064
|
+
while (1) {
|
1065
|
+
if (cur == root)
|
1066
|
+
return;
|
1067
|
+
if ((ctxt->format == 1) &&
|
1068
|
+
(cur->type != XML_XINCLUDE_START) &&
|
1069
|
+
(cur->type != XML_XINCLUDE_END))
|
1070
|
+
xmlOutputBufferWrite(buf, 1, "\n");
|
1071
|
+
if (cur->next != NULL) {
|
1072
|
+
cur = cur->next;
|
1073
|
+
break;
|
1074
|
+
}
|
1075
|
+
|
1076
|
+
cur = parent;
|
1077
|
+
/* cur->parent was validated when descending. */
|
1078
|
+
parent = cur->parent;
|
1079
|
+
|
1080
|
+
if (cur->type == XML_ELEMENT_NODE) {
|
1081
|
+
if (ctxt->level > 0) ctxt->level--;
|
1082
|
+
if ((xmlIndentTreeOutput) && (ctxt->format == 1))
|
1083
|
+
xmlOutputBufferWrite(buf, ctxt->indent_size *
|
1084
|
+
(ctxt->level > ctxt->indent_nr ?
|
1085
|
+
ctxt->indent_nr : ctxt->level),
|
1086
|
+
ctxt->indent);
|
1087
|
+
|
1088
|
+
xmlOutputBufferWrite(buf, 2, "</");
|
1089
|
+
if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
|
1090
|
+
xmlOutputBufferWriteString(buf,
|
1091
|
+
(const char *)cur->ns->prefix);
|
1092
|
+
xmlOutputBufferWrite(buf, 1, ":");
|
1093
|
+
}
|
1094
|
+
|
1095
|
+
xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
1096
|
+
if (ctxt->format == 2)
|
1097
|
+
xmlOutputBufferWriteWSNonSig(ctxt, 0);
|
1098
|
+
xmlOutputBufferWrite(buf, 1, ">");
|
1099
|
+
|
1100
|
+
if (cur == unformattedNode) {
|
1101
|
+
ctxt->format = format;
|
1102
|
+
unformattedNode = NULL;
|
1103
|
+
}
|
1104
|
+
}
|
1105
|
+
}
|
1106
|
+
}
|
1107
|
+
}
|
1108
|
+
|
1109
|
+
/**
|
1110
|
+
* xmlDocContentDumpOutput:
|
1111
|
+
* @cur: the document
|
1112
|
+
*
|
1113
|
+
* Dump an XML document.
|
1114
|
+
*/
|
1115
|
+
static int
|
1116
|
+
xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur) {
|
1117
|
+
#ifdef LIBXML_HTML_ENABLED
|
1118
|
+
xmlDtdPtr dtd;
|
1119
|
+
int is_xhtml = 0;
|
1120
|
+
#endif
|
1121
|
+
const xmlChar *oldenc = cur->encoding;
|
1122
|
+
const xmlChar *oldctxtenc = ctxt->encoding;
|
1123
|
+
const xmlChar *encoding = ctxt->encoding;
|
1124
|
+
xmlCharEncodingOutputFunc oldescape = ctxt->escape;
|
1125
|
+
xmlCharEncodingOutputFunc oldescapeAttr = ctxt->escapeAttr;
|
1126
|
+
xmlOutputBufferPtr buf = ctxt->buf;
|
1127
|
+
xmlCharEncoding enc;
|
1128
|
+
int switched_encoding = 0;
|
1129
|
+
|
1130
|
+
xmlInitParser();
|
1131
|
+
|
1132
|
+
if ((cur->type != XML_HTML_DOCUMENT_NODE) &&
|
1133
|
+
(cur->type != XML_DOCUMENT_NODE))
|
1134
|
+
return(-1);
|
1135
|
+
|
1136
|
+
if (ctxt->encoding != NULL) {
|
1137
|
+
cur->encoding = BAD_CAST ctxt->encoding;
|
1138
|
+
} else if (cur->encoding != NULL) {
|
1139
|
+
encoding = cur->encoding;
|
1140
|
+
}
|
1141
|
+
|
1142
|
+
if (((cur->type == XML_HTML_DOCUMENT_NODE) &&
|
1143
|
+
((ctxt->options & XML_SAVE_AS_XML) == 0) &&
|
1144
|
+
((ctxt->options & XML_SAVE_XHTML) == 0)) ||
|
1145
|
+
(ctxt->options & XML_SAVE_AS_HTML)) {
|
1146
|
+
#ifdef LIBXML_HTML_ENABLED
|
1147
|
+
if (encoding != NULL)
|
1148
|
+
htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
|
1149
|
+
if (encoding == NULL)
|
1150
|
+
encoding = htmlGetMetaEncoding(cur);
|
1151
|
+
if (encoding == NULL)
|
1152
|
+
encoding = BAD_CAST "HTML";
|
1153
|
+
if ((encoding != NULL) && (oldctxtenc == NULL) &&
|
1154
|
+
(buf->encoder == NULL) && (buf->conv == NULL)) {
|
1155
|
+
if (xmlSaveSwitchEncoding(ctxt, (const char*) encoding) < 0) {
|
1156
|
+
cur->encoding = oldenc;
|
1157
|
+
return(-1);
|
1158
|
+
}
|
1159
|
+
}
|
1160
|
+
if (ctxt->options & XML_SAVE_FORMAT)
|
1161
|
+
htmlDocContentDumpFormatOutput(buf, cur,
|
1162
|
+
(const char *)encoding, 1);
|
1163
|
+
else
|
1164
|
+
htmlDocContentDumpFormatOutput(buf, cur,
|
1165
|
+
(const char *)encoding, 0);
|
1166
|
+
if (ctxt->encoding != NULL)
|
1167
|
+
cur->encoding = oldenc;
|
1168
|
+
return(0);
|
1169
|
+
#else
|
1170
|
+
return(-1);
|
1171
|
+
#endif
|
1172
|
+
} else if ((cur->type == XML_DOCUMENT_NODE) ||
|
1173
|
+
(ctxt->options & XML_SAVE_AS_XML) ||
|
1174
|
+
(ctxt->options & XML_SAVE_XHTML)) {
|
1175
|
+
enc = xmlParseCharEncoding((const char*) encoding);
|
1176
|
+
if ((encoding != NULL) && (oldctxtenc == NULL) &&
|
1177
|
+
(buf->encoder == NULL) && (buf->conv == NULL) &&
|
1178
|
+
((ctxt->options & XML_SAVE_NO_DECL) == 0)) {
|
1179
|
+
if ((enc != XML_CHAR_ENCODING_UTF8) &&
|
1180
|
+
(enc != XML_CHAR_ENCODING_NONE) &&
|
1181
|
+
(enc != XML_CHAR_ENCODING_ASCII)) {
|
1182
|
+
/*
|
1183
|
+
* we need to switch to this encoding but just for this
|
1184
|
+
* document since we output the XMLDecl the conversion
|
1185
|
+
* must be done to not generate not well formed documents.
|
1186
|
+
*/
|
1187
|
+
if (xmlSaveSwitchEncoding(ctxt, (const char*) encoding) < 0) {
|
1188
|
+
cur->encoding = oldenc;
|
1189
|
+
return(-1);
|
1190
|
+
}
|
1191
|
+
switched_encoding = 1;
|
1192
|
+
}
|
1193
|
+
if (ctxt->escape == xmlEscapeEntities)
|
1194
|
+
ctxt->escape = NULL;
|
1195
|
+
if (ctxt->escapeAttr == xmlEscapeEntities)
|
1196
|
+
ctxt->escapeAttr = NULL;
|
1197
|
+
}
|
1198
|
+
|
1199
|
+
|
1200
|
+
/*
|
1201
|
+
* Save the XML declaration
|
1202
|
+
*/
|
1203
|
+
if ((ctxt->options & XML_SAVE_NO_DECL) == 0) {
|
1204
|
+
xmlOutputBufferWrite(buf, 14, "<?xml version=");
|
1205
|
+
if (cur->version != NULL)
|
1206
|
+
xmlBufWriteQuotedString(buf->buffer, cur->version);
|
1207
|
+
else
|
1208
|
+
xmlOutputBufferWrite(buf, 5, "\"1.0\"");
|
1209
|
+
if (encoding != NULL) {
|
1210
|
+
xmlOutputBufferWrite(buf, 10, " encoding=");
|
1211
|
+
xmlBufWriteQuotedString(buf->buffer, (xmlChar *) encoding);
|
1212
|
+
}
|
1213
|
+
switch (cur->standalone) {
|
1214
|
+
case 0:
|
1215
|
+
xmlOutputBufferWrite(buf, 16, " standalone=\"no\"");
|
1216
|
+
break;
|
1217
|
+
case 1:
|
1218
|
+
xmlOutputBufferWrite(buf, 17, " standalone=\"yes\"");
|
1219
|
+
break;
|
1220
|
+
}
|
1221
|
+
xmlOutputBufferWrite(buf, 3, "?>\n");
|
1222
|
+
}
|
1223
|
+
|
1224
|
+
#ifdef LIBXML_HTML_ENABLED
|
1225
|
+
if (ctxt->options & XML_SAVE_XHTML)
|
1226
|
+
is_xhtml = 1;
|
1227
|
+
if ((ctxt->options & XML_SAVE_NO_XHTML) == 0) {
|
1228
|
+
dtd = xmlGetIntSubset(cur);
|
1229
|
+
if (dtd != NULL) {
|
1230
|
+
is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
|
1231
|
+
if (is_xhtml < 0) is_xhtml = 0;
|
1232
|
+
}
|
1233
|
+
}
|
1234
|
+
#endif
|
1235
|
+
if (cur->children != NULL) {
|
1236
|
+
xmlNodePtr child = cur->children;
|
1237
|
+
|
1238
|
+
while (child != NULL) {
|
1239
|
+
ctxt->level = 0;
|
1240
|
+
#ifdef LIBXML_HTML_ENABLED
|
1241
|
+
if (is_xhtml)
|
1242
|
+
xhtmlNodeDumpOutput(ctxt, child);
|
1243
|
+
else
|
1244
|
+
#endif
|
1245
|
+
xmlNodeDumpOutputInternal(ctxt, child);
|
1246
|
+
if ((child->type != XML_XINCLUDE_START) &&
|
1247
|
+
(child->type != XML_XINCLUDE_END))
|
1248
|
+
xmlOutputBufferWrite(buf, 1, "\n");
|
1249
|
+
child = child->next;
|
1250
|
+
}
|
1251
|
+
}
|
1252
|
+
}
|
1253
|
+
|
1254
|
+
/*
|
1255
|
+
* Restore the state of the saving context at the end of the document
|
1256
|
+
*/
|
1257
|
+
if ((switched_encoding) && (oldctxtenc == NULL)) {
|
1258
|
+
xmlSaveClearEncoding(ctxt);
|
1259
|
+
ctxt->escape = oldescape;
|
1260
|
+
ctxt->escapeAttr = oldescapeAttr;
|
1261
|
+
}
|
1262
|
+
cur->encoding = oldenc;
|
1263
|
+
return(0);
|
1264
|
+
}
|
1265
|
+
|
1266
|
+
#ifdef LIBXML_HTML_ENABLED
|
1267
|
+
/************************************************************************
|
1268
|
+
* *
|
1269
|
+
* Functions specific to XHTML serialization *
|
1270
|
+
* *
|
1271
|
+
************************************************************************/
|
1272
|
+
|
1273
|
+
/**
|
1274
|
+
* xhtmlIsEmpty:
|
1275
|
+
* @node: the node
|
1276
|
+
*
|
1277
|
+
* Check if a node is an empty xhtml node
|
1278
|
+
*
|
1279
|
+
* Returns 1 if the node is an empty node, 0 if not and -1 in case of error
|
1280
|
+
*/
|
1281
|
+
static int
|
1282
|
+
xhtmlIsEmpty(xmlNodePtr node) {
|
1283
|
+
if (node == NULL)
|
1284
|
+
return(-1);
|
1285
|
+
if (node->type != XML_ELEMENT_NODE)
|
1286
|
+
return(0);
|
1287
|
+
if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME)))
|
1288
|
+
return(0);
|
1289
|
+
if (node->children != NULL)
|
1290
|
+
return(0);
|
1291
|
+
switch (node->name[0]) {
|
1292
|
+
case 'a':
|
1293
|
+
if (xmlStrEqual(node->name, BAD_CAST "area"))
|
1294
|
+
return(1);
|
1295
|
+
return(0);
|
1296
|
+
case 'b':
|
1297
|
+
if (xmlStrEqual(node->name, BAD_CAST "br"))
|
1298
|
+
return(1);
|
1299
|
+
if (xmlStrEqual(node->name, BAD_CAST "base"))
|
1300
|
+
return(1);
|
1301
|
+
if (xmlStrEqual(node->name, BAD_CAST "basefont"))
|
1302
|
+
return(1);
|
1303
|
+
return(0);
|
1304
|
+
case 'c':
|
1305
|
+
if (xmlStrEqual(node->name, BAD_CAST "col"))
|
1306
|
+
return(1);
|
1307
|
+
return(0);
|
1308
|
+
case 'f':
|
1309
|
+
if (xmlStrEqual(node->name, BAD_CAST "frame"))
|
1310
|
+
return(1);
|
1311
|
+
return(0);
|
1312
|
+
case 'h':
|
1313
|
+
if (xmlStrEqual(node->name, BAD_CAST "hr"))
|
1314
|
+
return(1);
|
1315
|
+
return(0);
|
1316
|
+
case 'i':
|
1317
|
+
if (xmlStrEqual(node->name, BAD_CAST "img"))
|
1318
|
+
return(1);
|
1319
|
+
if (xmlStrEqual(node->name, BAD_CAST "input"))
|
1320
|
+
return(1);
|
1321
|
+
if (xmlStrEqual(node->name, BAD_CAST "isindex"))
|
1322
|
+
return(1);
|
1323
|
+
return(0);
|
1324
|
+
case 'l':
|
1325
|
+
if (xmlStrEqual(node->name, BAD_CAST "link"))
|
1326
|
+
return(1);
|
1327
|
+
return(0);
|
1328
|
+
case 'm':
|
1329
|
+
if (xmlStrEqual(node->name, BAD_CAST "meta"))
|
1330
|
+
return(1);
|
1331
|
+
return(0);
|
1332
|
+
case 'p':
|
1333
|
+
if (xmlStrEqual(node->name, BAD_CAST "param"))
|
1334
|
+
return(1);
|
1335
|
+
return(0);
|
1336
|
+
}
|
1337
|
+
return(0);
|
1338
|
+
}
|
1339
|
+
|
1340
|
+
/**
|
1341
|
+
* xhtmlAttrListDumpOutput:
|
1342
|
+
* @cur: the first attribute pointer
|
1343
|
+
*
|
1344
|
+
* Dump a list of XML attributes
|
1345
|
+
*/
|
1346
|
+
static void
|
1347
|
+
xhtmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
|
1348
|
+
xmlAttrPtr xml_lang = NULL;
|
1349
|
+
xmlAttrPtr lang = NULL;
|
1350
|
+
xmlAttrPtr name = NULL;
|
1351
|
+
xmlAttrPtr id = NULL;
|
1352
|
+
xmlNodePtr parent;
|
1353
|
+
xmlOutputBufferPtr buf;
|
1354
|
+
|
1355
|
+
if (cur == NULL) return;
|
1356
|
+
buf = ctxt->buf;
|
1357
|
+
parent = cur->parent;
|
1358
|
+
while (cur != NULL) {
|
1359
|
+
if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id")))
|
1360
|
+
id = cur;
|
1361
|
+
else
|
1362
|
+
if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name")))
|
1363
|
+
name = cur;
|
1364
|
+
else
|
1365
|
+
if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")))
|
1366
|
+
lang = cur;
|
1367
|
+
else
|
1368
|
+
if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) &&
|
1369
|
+
(xmlStrEqual(cur->ns->prefix, BAD_CAST "xml")))
|
1370
|
+
xml_lang = cur;
|
1371
|
+
else if ((cur->ns == NULL) &&
|
1372
|
+
((cur->children == NULL) ||
|
1373
|
+
(cur->children->content == NULL) ||
|
1374
|
+
(cur->children->content[0] == 0)) &&
|
1375
|
+
(htmlIsBooleanAttr(cur->name))) {
|
1376
|
+
if (cur->children != NULL)
|
1377
|
+
xmlFreeNode(cur->children);
|
1378
|
+
cur->children = xmlNewText(cur->name);
|
1379
|
+
if (cur->children != NULL)
|
1380
|
+
cur->children->parent = (xmlNodePtr) cur;
|
1381
|
+
}
|
1382
|
+
xmlAttrDumpOutput(ctxt, cur);
|
1383
|
+
cur = cur->next;
|
1384
|
+
}
|
1385
|
+
/*
|
1386
|
+
* C.8
|
1387
|
+
*/
|
1388
|
+
if ((name != NULL) && (id == NULL)) {
|
1389
|
+
if ((parent != NULL) && (parent->name != NULL) &&
|
1390
|
+
((xmlStrEqual(parent->name, BAD_CAST "a")) ||
|
1391
|
+
(xmlStrEqual(parent->name, BAD_CAST "p")) ||
|
1392
|
+
(xmlStrEqual(parent->name, BAD_CAST "div")) ||
|
1393
|
+
(xmlStrEqual(parent->name, BAD_CAST "img")) ||
|
1394
|
+
(xmlStrEqual(parent->name, BAD_CAST "map")) ||
|
1395
|
+
(xmlStrEqual(parent->name, BAD_CAST "applet")) ||
|
1396
|
+
(xmlStrEqual(parent->name, BAD_CAST "form")) ||
|
1397
|
+
(xmlStrEqual(parent->name, BAD_CAST "frame")) ||
|
1398
|
+
(xmlStrEqual(parent->name, BAD_CAST "iframe")))) {
|
1399
|
+
xmlOutputBufferWrite(buf, 5, " id=\"");
|
1400
|
+
xmlAttrSerializeContent(buf, name);
|
1401
|
+
xmlOutputBufferWrite(buf, 1, "\"");
|
1402
|
+
}
|
1403
|
+
}
|
1404
|
+
/*
|
1405
|
+
* C.7.
|
1406
|
+
*/
|
1407
|
+
if ((lang != NULL) && (xml_lang == NULL)) {
|
1408
|
+
xmlOutputBufferWrite(buf, 11, " xml:lang=\"");
|
1409
|
+
xmlAttrSerializeContent(buf, lang);
|
1410
|
+
xmlOutputBufferWrite(buf, 1, "\"");
|
1411
|
+
} else
|
1412
|
+
if ((xml_lang != NULL) && (lang == NULL)) {
|
1413
|
+
xmlOutputBufferWrite(buf, 7, " lang=\"");
|
1414
|
+
xmlAttrSerializeContent(buf, xml_lang);
|
1415
|
+
xmlOutputBufferWrite(buf, 1, "\"");
|
1416
|
+
}
|
1417
|
+
}
|
1418
|
+
|
1419
|
+
/**
|
1420
|
+
* xhtmlNodeDumpOutput:
|
1421
|
+
* @buf: the XML buffer output
|
1422
|
+
* @doc: the XHTML document
|
1423
|
+
* @cur: the current node
|
1424
|
+
* @level: the imbrication level for indenting
|
1425
|
+
* @format: is formatting allowed
|
1426
|
+
* @encoding: an optional encoding string
|
1427
|
+
*
|
1428
|
+
* Dump an XHTML node, recursive behaviour, children are printed too.
|
1429
|
+
*/
|
1430
|
+
static void
|
1431
|
+
xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
|
1432
|
+
int format = ctxt->format, addmeta;
|
1433
|
+
xmlNodePtr tmp, root, unformattedNode = NULL;
|
1434
|
+
xmlChar *start, *end;
|
1435
|
+
xmlOutputBufferPtr buf = ctxt->buf;
|
1436
|
+
|
1437
|
+
if (cur == NULL) return;
|
1438
|
+
|
1439
|
+
root = cur;
|
1440
|
+
while (1) {
|
1441
|
+
switch (cur->type) {
|
1442
|
+
case XML_DOCUMENT_NODE:
|
1443
|
+
case XML_HTML_DOCUMENT_NODE:
|
1444
|
+
xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
|
1445
|
+
break;
|
1446
|
+
|
1447
|
+
case XML_NAMESPACE_DECL:
|
1448
|
+
xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur);
|
1449
|
+
break;
|
1450
|
+
|
1451
|
+
case XML_DTD_NODE:
|
1452
|
+
xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
|
1453
|
+
break;
|
1454
|
+
|
1455
|
+
case XML_DOCUMENT_FRAG_NODE:
|
1456
|
+
if (cur->children) {
|
1457
|
+
cur = cur->children;
|
1458
|
+
continue;
|
1459
|
+
}
|
1460
|
+
break;
|
1461
|
+
|
1462
|
+
case XML_ELEMENT_DECL:
|
1463
|
+
xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
|
1464
|
+
break;
|
1465
|
+
|
1466
|
+
case XML_ATTRIBUTE_DECL:
|
1467
|
+
xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
|
1468
|
+
break;
|
1469
|
+
|
1470
|
+
case XML_ENTITY_DECL:
|
1471
|
+
xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
|
1472
|
+
break;
|
1473
|
+
|
1474
|
+
case XML_ELEMENT_NODE:
|
1475
|
+
addmeta = 0;
|
1476
|
+
|
1477
|
+
if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
|
1478
|
+
xmlOutputBufferWrite(buf, ctxt->indent_size *
|
1479
|
+
(ctxt->level > ctxt->indent_nr ?
|
1480
|
+
ctxt->indent_nr : ctxt->level),
|
1481
|
+
ctxt->indent);
|
1482
|
+
|
1483
|
+
xmlOutputBufferWrite(buf, 1, "<");
|
1484
|
+
if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
|
1485
|
+
xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
|
1486
|
+
xmlOutputBufferWrite(buf, 1, ":");
|
1487
|
+
}
|
1488
|
+
|
1489
|
+
xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
1490
|
+
if (cur->nsDef)
|
1491
|
+
xmlNsListDumpOutputCtxt(ctxt, cur->nsDef);
|
1492
|
+
if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
|
1493
|
+
(cur->ns == NULL) && (cur->nsDef == NULL))) {
|
1494
|
+
/*
|
1495
|
+
* 3.1.1. Strictly Conforming Documents A.3.1.1 3/
|
1496
|
+
*/
|
1497
|
+
xmlOutputBufferWriteString(buf,
|
1498
|
+
" xmlns=\"http://www.w3.org/1999/xhtml\"");
|
1499
|
+
}
|
1500
|
+
if (cur->properties != NULL)
|
1501
|
+
xhtmlAttrListDumpOutput(ctxt, cur->properties);
|
1502
|
+
|
1503
|
+
if ((cur->parent != NULL) &&
|
1504
|
+
(cur->parent->parent == (xmlNodePtr) cur->doc) &&
|
1505
|
+
xmlStrEqual(cur->name, BAD_CAST"head") &&
|
1506
|
+
xmlStrEqual(cur->parent->name, BAD_CAST"html")) {
|
1507
|
+
|
1508
|
+
tmp = cur->children;
|
1509
|
+
while (tmp != NULL) {
|
1510
|
+
if (xmlStrEqual(tmp->name, BAD_CAST"meta")) {
|
1511
|
+
xmlChar *httpequiv;
|
1512
|
+
|
1513
|
+
httpequiv = xmlGetProp(tmp, BAD_CAST"http-equiv");
|
1514
|
+
if (httpequiv != NULL) {
|
1515
|
+
if (xmlStrcasecmp(httpequiv,
|
1516
|
+
BAD_CAST"Content-Type") == 0) {
|
1517
|
+
xmlFree(httpequiv);
|
1518
|
+
break;
|
1519
|
+
}
|
1520
|
+
xmlFree(httpequiv);
|
1521
|
+
}
|
1522
|
+
}
|
1523
|
+
tmp = tmp->next;
|
1524
|
+
}
|
1525
|
+
if (tmp == NULL)
|
1526
|
+
addmeta = 1;
|
1527
|
+
}
|
1528
|
+
|
1529
|
+
if (cur->children == NULL) {
|
1530
|
+
if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
|
1531
|
+
((xhtmlIsEmpty(cur) == 1) && (addmeta == 0))) {
|
1532
|
+
/*
|
1533
|
+
* C.2. Empty Elements
|
1534
|
+
*/
|
1535
|
+
xmlOutputBufferWrite(buf, 3, " />");
|
1536
|
+
} else {
|
1537
|
+
if (addmeta == 1) {
|
1538
|
+
xmlOutputBufferWrite(buf, 1, ">");
|
1539
|
+
if (ctxt->format == 1) {
|
1540
|
+
xmlOutputBufferWrite(buf, 1, "\n");
|
1541
|
+
if (xmlIndentTreeOutput)
|
1542
|
+
xmlOutputBufferWrite(buf, ctxt->indent_size *
|
1543
|
+
(ctxt->level + 1 > ctxt->indent_nr ?
|
1544
|
+
ctxt->indent_nr : ctxt->level + 1),
|
1545
|
+
ctxt->indent);
|
1546
|
+
}
|
1547
|
+
xmlOutputBufferWriteString(buf,
|
1548
|
+
"<meta http-equiv=\"Content-Type\" "
|
1549
|
+
"content=\"text/html; charset=");
|
1550
|
+
if (ctxt->encoding) {
|
1551
|
+
xmlOutputBufferWriteString(buf,
|
1552
|
+
(const char *)ctxt->encoding);
|
1553
|
+
} else {
|
1554
|
+
xmlOutputBufferWrite(buf, 5, "UTF-8");
|
1555
|
+
}
|
1556
|
+
xmlOutputBufferWrite(buf, 4, "\" />");
|
1557
|
+
if (ctxt->format == 1)
|
1558
|
+
xmlOutputBufferWrite(buf, 1, "\n");
|
1559
|
+
} else {
|
1560
|
+
xmlOutputBufferWrite(buf, 1, ">");
|
1561
|
+
}
|
1562
|
+
/*
|
1563
|
+
* C.3. Element Minimization and Empty Element Content
|
1564
|
+
*/
|
1565
|
+
xmlOutputBufferWrite(buf, 2, "</");
|
1566
|
+
if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
|
1567
|
+
xmlOutputBufferWriteString(buf,
|
1568
|
+
(const char *)cur->ns->prefix);
|
1569
|
+
xmlOutputBufferWrite(buf, 1, ":");
|
1570
|
+
}
|
1571
|
+
xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
1572
|
+
xmlOutputBufferWrite(buf, 1, ">");
|
1573
|
+
}
|
1574
|
+
} else {
|
1575
|
+
xmlOutputBufferWrite(buf, 1, ">");
|
1576
|
+
if (addmeta == 1) {
|
1577
|
+
if (ctxt->format == 1) {
|
1578
|
+
xmlOutputBufferWrite(buf, 1, "\n");
|
1579
|
+
if (xmlIndentTreeOutput)
|
1580
|
+
xmlOutputBufferWrite(buf, ctxt->indent_size *
|
1581
|
+
(ctxt->level + 1 > ctxt->indent_nr ?
|
1582
|
+
ctxt->indent_nr : ctxt->level + 1),
|
1583
|
+
ctxt->indent);
|
1584
|
+
}
|
1585
|
+
xmlOutputBufferWriteString(buf,
|
1586
|
+
"<meta http-equiv=\"Content-Type\" "
|
1587
|
+
"content=\"text/html; charset=");
|
1588
|
+
if (ctxt->encoding) {
|
1589
|
+
xmlOutputBufferWriteString(buf,
|
1590
|
+
(const char *)ctxt->encoding);
|
1591
|
+
} else {
|
1592
|
+
xmlOutputBufferWrite(buf, 5, "UTF-8");
|
1593
|
+
}
|
1594
|
+
xmlOutputBufferWrite(buf, 4, "\" />");
|
1595
|
+
}
|
1596
|
+
|
1597
|
+
if (ctxt->format == 1) {
|
1598
|
+
tmp = cur->children;
|
1599
|
+
while (tmp != NULL) {
|
1600
|
+
if ((tmp->type == XML_TEXT_NODE) ||
|
1601
|
+
(tmp->type == XML_ENTITY_REF_NODE)) {
|
1602
|
+
unformattedNode = cur;
|
1603
|
+
ctxt->format = 0;
|
1604
|
+
break;
|
1605
|
+
}
|
1606
|
+
tmp = tmp->next;
|
1607
|
+
}
|
1608
|
+
}
|
1609
|
+
|
1610
|
+
if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n");
|
1611
|
+
if (ctxt->level >= 0) ctxt->level++;
|
1612
|
+
cur = cur->children;
|
1613
|
+
continue;
|
1614
|
+
}
|
1615
|
+
|
1616
|
+
break;
|
1617
|
+
|
1618
|
+
case XML_TEXT_NODE:
|
1619
|
+
if (cur->content == NULL)
|
1620
|
+
break;
|
1621
|
+
if ((cur->name == xmlStringText) ||
|
1622
|
+
(cur->name != xmlStringTextNoenc)) {
|
1623
|
+
xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
|
1624
|
+
} else {
|
1625
|
+
/*
|
1626
|
+
* Disable escaping, needed for XSLT
|
1627
|
+
*/
|
1628
|
+
xmlOutputBufferWriteString(buf, (const char *) cur->content);
|
1629
|
+
}
|
1630
|
+
break;
|
1631
|
+
|
1632
|
+
case XML_PI_NODE:
|
1633
|
+
if (cur->content != NULL) {
|
1634
|
+
xmlOutputBufferWrite(buf, 2, "<?");
|
1635
|
+
xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
1636
|
+
if (cur->content != NULL) {
|
1637
|
+
xmlOutputBufferWrite(buf, 1, " ");
|
1638
|
+
xmlOutputBufferWriteString(buf,
|
1639
|
+
(const char *)cur->content);
|
1640
|
+
}
|
1641
|
+
xmlOutputBufferWrite(buf, 2, "?>");
|
1642
|
+
} else {
|
1643
|
+
xmlOutputBufferWrite(buf, 2, "<?");
|
1644
|
+
xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
1645
|
+
xmlOutputBufferWrite(buf, 2, "?>");
|
1646
|
+
}
|
1647
|
+
break;
|
1648
|
+
|
1649
|
+
case XML_COMMENT_NODE:
|
1650
|
+
if (cur->content != NULL) {
|
1651
|
+
xmlOutputBufferWrite(buf, 4, "<!--");
|
1652
|
+
xmlOutputBufferWriteString(buf, (const char *)cur->content);
|
1653
|
+
xmlOutputBufferWrite(buf, 3, "-->");
|
1654
|
+
}
|
1655
|
+
break;
|
1656
|
+
|
1657
|
+
case XML_ENTITY_REF_NODE:
|
1658
|
+
xmlOutputBufferWrite(buf, 1, "&");
|
1659
|
+
xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
1660
|
+
xmlOutputBufferWrite(buf, 1, ";");
|
1661
|
+
break;
|
1662
|
+
|
1663
|
+
case XML_CDATA_SECTION_NODE:
|
1664
|
+
if (cur->content == NULL || *cur->content == '\0') {
|
1665
|
+
xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
|
1666
|
+
} else {
|
1667
|
+
start = end = cur->content;
|
1668
|
+
while (*end != '\0') {
|
1669
|
+
if (*end == ']' && *(end + 1) == ']' &&
|
1670
|
+
*(end + 2) == '>') {
|
1671
|
+
end = end + 2;
|
1672
|
+
xmlOutputBufferWrite(buf, 9, "<![CDATA[");
|
1673
|
+
xmlOutputBufferWrite(buf, end - start,
|
1674
|
+
(const char *)start);
|
1675
|
+
xmlOutputBufferWrite(buf, 3, "]]>");
|
1676
|
+
start = end;
|
1677
|
+
}
|
1678
|
+
end++;
|
1679
|
+
}
|
1680
|
+
if (start != end) {
|
1681
|
+
xmlOutputBufferWrite(buf, 9, "<![CDATA[");
|
1682
|
+
xmlOutputBufferWriteString(buf, (const char *)start);
|
1683
|
+
xmlOutputBufferWrite(buf, 3, "]]>");
|
1684
|
+
}
|
1685
|
+
}
|
1686
|
+
break;
|
1687
|
+
|
1688
|
+
case XML_ATTRIBUTE_NODE:
|
1689
|
+
xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
|
1690
|
+
break;
|
1691
|
+
|
1692
|
+
default:
|
1693
|
+
break;
|
1694
|
+
}
|
1695
|
+
|
1696
|
+
while (1) {
|
1697
|
+
if (cur == root)
|
1698
|
+
return;
|
1699
|
+
if (ctxt->format == 1)
|
1700
|
+
xmlOutputBufferWrite(buf, 1, "\n");
|
1701
|
+
if (cur->next != NULL) {
|
1702
|
+
cur = cur->next;
|
1703
|
+
break;
|
1704
|
+
}
|
1705
|
+
|
1706
|
+
/*
|
1707
|
+
* The parent should never be NULL here but we want to handle
|
1708
|
+
* corrupted documents gracefully.
|
1709
|
+
*/
|
1710
|
+
if (cur->parent == NULL)
|
1711
|
+
return;
|
1712
|
+
cur = cur->parent;
|
1713
|
+
|
1714
|
+
if (cur->type == XML_ELEMENT_NODE) {
|
1715
|
+
if (ctxt->level > 0) ctxt->level--;
|
1716
|
+
if ((xmlIndentTreeOutput) && (ctxt->format == 1))
|
1717
|
+
xmlOutputBufferWrite(buf, ctxt->indent_size *
|
1718
|
+
(ctxt->level > ctxt->indent_nr ?
|
1719
|
+
ctxt->indent_nr : ctxt->level),
|
1720
|
+
ctxt->indent);
|
1721
|
+
|
1722
|
+
xmlOutputBufferWrite(buf, 2, "</");
|
1723
|
+
if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
|
1724
|
+
xmlOutputBufferWriteString(buf,
|
1725
|
+
(const char *)cur->ns->prefix);
|
1726
|
+
xmlOutputBufferWrite(buf, 1, ":");
|
1727
|
+
}
|
1728
|
+
|
1729
|
+
xmlOutputBufferWriteString(buf, (const char *)cur->name);
|
1730
|
+
xmlOutputBufferWrite(buf, 1, ">");
|
1731
|
+
|
1732
|
+
if (cur == unformattedNode) {
|
1733
|
+
ctxt->format = format;
|
1734
|
+
unformattedNode = NULL;
|
1735
|
+
}
|
1736
|
+
}
|
1737
|
+
}
|
1738
|
+
}
|
1739
|
+
}
|
1740
|
+
#endif
|
1741
|
+
|
1742
|
+
/************************************************************************
|
1743
|
+
* *
|
1744
|
+
* Public entry points *
|
1745
|
+
* *
|
1746
|
+
************************************************************************/
|
1747
|
+
|
1748
|
+
/**
|
1749
|
+
* xmlSaveToFd:
|
1750
|
+
* @fd: a file descriptor number
|
1751
|
+
* @encoding: the encoding name to use or NULL
|
1752
|
+
* @options: a set of xmlSaveOptions
|
1753
|
+
*
|
1754
|
+
* Create a document saving context serializing to a file descriptor
|
1755
|
+
* with the encoding and the options given.
|
1756
|
+
*
|
1757
|
+
* Returns a new serialization context or NULL in case of error.
|
1758
|
+
*/
|
1759
|
+
xmlSaveCtxtPtr
|
1760
|
+
xmlSaveToFd(int fd, const char *encoding, int options)
|
1761
|
+
{
|
1762
|
+
xmlSaveCtxtPtr ret;
|
1763
|
+
|
1764
|
+
ret = xmlNewSaveCtxt(encoding, options);
|
1765
|
+
if (ret == NULL) return(NULL);
|
1766
|
+
ret->buf = xmlOutputBufferCreateFd(fd, ret->handler);
|
1767
|
+
if (ret->buf == NULL) {
|
1768
|
+
xmlCharEncCloseFunc(ret->handler);
|
1769
|
+
xmlFreeSaveCtxt(ret);
|
1770
|
+
return(NULL);
|
1771
|
+
}
|
1772
|
+
return(ret);
|
1773
|
+
}
|
1774
|
+
|
1775
|
+
/**
|
1776
|
+
* xmlSaveToFilename:
|
1777
|
+
* @filename: a file name or an URL
|
1778
|
+
* @encoding: the encoding name to use or NULL
|
1779
|
+
* @options: a set of xmlSaveOptions
|
1780
|
+
*
|
1781
|
+
* Create a document saving context serializing to a filename or possibly
|
1782
|
+
* to an URL (but this is less reliable) with the encoding and the options
|
1783
|
+
* given.
|
1784
|
+
*
|
1785
|
+
* Returns a new serialization context or NULL in case of error.
|
1786
|
+
*/
|
1787
|
+
xmlSaveCtxtPtr
|
1788
|
+
xmlSaveToFilename(const char *filename, const char *encoding, int options)
|
1789
|
+
{
|
1790
|
+
xmlSaveCtxtPtr ret;
|
1791
|
+
int compression = 0; /* TODO handle compression option */
|
1792
|
+
|
1793
|
+
ret = xmlNewSaveCtxt(encoding, options);
|
1794
|
+
if (ret == NULL) return(NULL);
|
1795
|
+
ret->buf = xmlOutputBufferCreateFilename(filename, ret->handler,
|
1796
|
+
compression);
|
1797
|
+
if (ret->buf == NULL) {
|
1798
|
+
xmlCharEncCloseFunc(ret->handler);
|
1799
|
+
xmlFreeSaveCtxt(ret);
|
1800
|
+
return(NULL);
|
1801
|
+
}
|
1802
|
+
return(ret);
|
1803
|
+
}
|
1804
|
+
|
1805
|
+
/**
|
1806
|
+
* xmlSaveToBuffer:
|
1807
|
+
* @buffer: a buffer
|
1808
|
+
* @encoding: the encoding name to use or NULL
|
1809
|
+
* @options: a set of xmlSaveOptions
|
1810
|
+
*
|
1811
|
+
* Create a document saving context serializing to a buffer
|
1812
|
+
* with the encoding and the options given
|
1813
|
+
*
|
1814
|
+
* Returns a new serialization context or NULL in case of error.
|
1815
|
+
*/
|
1816
|
+
|
1817
|
+
xmlSaveCtxtPtr
|
1818
|
+
xmlSaveToBuffer(xmlBufferPtr buffer, const char *encoding, int options)
|
1819
|
+
{
|
1820
|
+
xmlSaveCtxtPtr ret;
|
1821
|
+
|
1822
|
+
ret = xmlNewSaveCtxt(encoding, options);
|
1823
|
+
if (ret == NULL) return(NULL);
|
1824
|
+
ret->buf = xmlOutputBufferCreateBuffer(buffer, ret->handler);
|
1825
|
+
if (ret->buf == NULL) {
|
1826
|
+
xmlCharEncCloseFunc(ret->handler);
|
1827
|
+
xmlFreeSaveCtxt(ret);
|
1828
|
+
return(NULL);
|
1829
|
+
}
|
1830
|
+
return(ret);
|
1831
|
+
}
|
1832
|
+
|
1833
|
+
/**
|
1834
|
+
* xmlSaveToIO:
|
1835
|
+
* @iowrite: an I/O write function
|
1836
|
+
* @ioclose: an I/O close function
|
1837
|
+
* @ioctx: an I/O handler
|
1838
|
+
* @encoding: the encoding name to use or NULL
|
1839
|
+
* @options: a set of xmlSaveOptions
|
1840
|
+
*
|
1841
|
+
* Create a document saving context serializing to a file descriptor
|
1842
|
+
* with the encoding and the options given
|
1843
|
+
*
|
1844
|
+
* Returns a new serialization context or NULL in case of error.
|
1845
|
+
*/
|
1846
|
+
xmlSaveCtxtPtr
|
1847
|
+
xmlSaveToIO(xmlOutputWriteCallback iowrite,
|
1848
|
+
xmlOutputCloseCallback ioclose,
|
1849
|
+
void *ioctx, const char *encoding, int options)
|
1850
|
+
{
|
1851
|
+
xmlSaveCtxtPtr ret;
|
1852
|
+
|
1853
|
+
ret = xmlNewSaveCtxt(encoding, options);
|
1854
|
+
if (ret == NULL) return(NULL);
|
1855
|
+
ret->buf = xmlOutputBufferCreateIO(iowrite, ioclose, ioctx, ret->handler);
|
1856
|
+
if (ret->buf == NULL) {
|
1857
|
+
xmlCharEncCloseFunc(ret->handler);
|
1858
|
+
xmlFreeSaveCtxt(ret);
|
1859
|
+
return(NULL);
|
1860
|
+
}
|
1861
|
+
return(ret);
|
1862
|
+
}
|
1863
|
+
|
1864
|
+
/**
|
1865
|
+
* xmlSaveDoc:
|
1866
|
+
* @ctxt: a document saving context
|
1867
|
+
* @doc: a document
|
1868
|
+
*
|
1869
|
+
* Save a full document to a saving context
|
1870
|
+
* TODO: The function is not fully implemented yet as it does not return the
|
1871
|
+
* byte count but 0 instead
|
1872
|
+
*
|
1873
|
+
* Returns the number of byte written or -1 in case of error
|
1874
|
+
*/
|
1875
|
+
long
|
1876
|
+
xmlSaveDoc(xmlSaveCtxtPtr ctxt, xmlDocPtr doc)
|
1877
|
+
{
|
1878
|
+
long ret = 0;
|
1879
|
+
|
1880
|
+
if ((ctxt == NULL) || (doc == NULL)) return(-1);
|
1881
|
+
if (xmlDocContentDumpOutput(ctxt, doc) < 0)
|
1882
|
+
return(-1);
|
1883
|
+
return(ret);
|
1884
|
+
}
|
1885
|
+
|
1886
|
+
/**
|
1887
|
+
* xmlSaveTree:
|
1888
|
+
* @ctxt: a document saving context
|
1889
|
+
* @node: the top node of the subtree to save
|
1890
|
+
*
|
1891
|
+
* Save a subtree starting at the node parameter to a saving context
|
1892
|
+
* TODO: The function is not fully implemented yet as it does not return the
|
1893
|
+
* byte count but 0 instead
|
1894
|
+
*
|
1895
|
+
* Returns the number of byte written or -1 in case of error
|
1896
|
+
*/
|
1897
|
+
long
|
1898
|
+
xmlSaveTree(xmlSaveCtxtPtr ctxt, xmlNodePtr cur)
|
1899
|
+
{
|
1900
|
+
long ret = 0;
|
1901
|
+
|
1902
|
+
if ((ctxt == NULL) || (cur == NULL)) return(-1);
|
1903
|
+
#ifdef LIBXML_HTML_ENABLED
|
1904
|
+
if (ctxt->options & XML_SAVE_XHTML) {
|
1905
|
+
xhtmlNodeDumpOutput(ctxt, cur);
|
1906
|
+
return(ret);
|
1907
|
+
}
|
1908
|
+
if (((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL) &&
|
1909
|
+
(cur->doc->type == XML_HTML_DOCUMENT_NODE) &&
|
1910
|
+
((ctxt->options & XML_SAVE_AS_XML) == 0)) ||
|
1911
|
+
(ctxt->options & XML_SAVE_AS_HTML)) {
|
1912
|
+
htmlNodeDumpOutputInternal(ctxt, cur);
|
1913
|
+
return(ret);
|
1914
|
+
}
|
1915
|
+
#endif
|
1916
|
+
xmlNodeDumpOutputInternal(ctxt, cur);
|
1917
|
+
return(ret);
|
1918
|
+
}
|
1919
|
+
|
1920
|
+
/**
|
1921
|
+
* xmlSaveFlush:
|
1922
|
+
* @ctxt: a document saving context
|
1923
|
+
*
|
1924
|
+
* Flush a document saving context, i.e. make sure that all bytes have
|
1925
|
+
* been output.
|
1926
|
+
*
|
1927
|
+
* Returns the number of byte written or -1 in case of error.
|
1928
|
+
*/
|
1929
|
+
int
|
1930
|
+
xmlSaveFlush(xmlSaveCtxtPtr ctxt)
|
1931
|
+
{
|
1932
|
+
if (ctxt == NULL) return(-1);
|
1933
|
+
if (ctxt->buf == NULL) return(-1);
|
1934
|
+
return(xmlOutputBufferFlush(ctxt->buf));
|
1935
|
+
}
|
1936
|
+
|
1937
|
+
/**
|
1938
|
+
* xmlSaveClose:
|
1939
|
+
* @ctxt: a document saving context
|
1940
|
+
*
|
1941
|
+
* Close a document saving context, i.e. make sure that all bytes have
|
1942
|
+
* been output and free the associated data.
|
1943
|
+
*
|
1944
|
+
* Returns the number of byte written or -1 in case of error.
|
1945
|
+
*/
|
1946
|
+
int
|
1947
|
+
xmlSaveClose(xmlSaveCtxtPtr ctxt)
|
1948
|
+
{
|
1949
|
+
int ret;
|
1950
|
+
|
1951
|
+
if (ctxt == NULL) return(-1);
|
1952
|
+
ret = xmlSaveFlush(ctxt);
|
1953
|
+
xmlFreeSaveCtxt(ctxt);
|
1954
|
+
return(ret);
|
1955
|
+
}
|
1956
|
+
|
1957
|
+
/**
|
1958
|
+
* xmlSaveSetEscape:
|
1959
|
+
* @ctxt: a document saving context
|
1960
|
+
* @escape: the escaping function
|
1961
|
+
*
|
1962
|
+
* Set a custom escaping function to be used for text in element content
|
1963
|
+
*
|
1964
|
+
* Returns 0 if successful or -1 in case of error.
|
1965
|
+
*/
|
1966
|
+
int
|
1967
|
+
xmlSaveSetEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape)
|
1968
|
+
{
|
1969
|
+
if (ctxt == NULL) return(-1);
|
1970
|
+
ctxt->escape = escape;
|
1971
|
+
return(0);
|
1972
|
+
}
|
1973
|
+
|
1974
|
+
/**
|
1975
|
+
* xmlSaveSetAttrEscape:
|
1976
|
+
* @ctxt: a document saving context
|
1977
|
+
* @escape: the escaping function
|
1978
|
+
*
|
1979
|
+
* Set a custom escaping function to be used for text in attribute content
|
1980
|
+
*
|
1981
|
+
* Returns 0 if successful or -1 in case of error.
|
1982
|
+
*/
|
1983
|
+
int
|
1984
|
+
xmlSaveSetAttrEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape)
|
1985
|
+
{
|
1986
|
+
if (ctxt == NULL) return(-1);
|
1987
|
+
ctxt->escapeAttr = escape;
|
1988
|
+
return(0);
|
1989
|
+
}
|
1990
|
+
|
1991
|
+
/************************************************************************
|
1992
|
+
* *
|
1993
|
+
* Public entry points based on buffers *
|
1994
|
+
* *
|
1995
|
+
************************************************************************/
|
1996
|
+
|
1997
|
+
/**
|
1998
|
+
* xmlBufAttrSerializeTxtContent:
|
1999
|
+
* @buf: and xmlBufPtr output
|
2000
|
+
* @doc: the document
|
2001
|
+
* @attr: the attribute node
|
2002
|
+
* @string: the text content
|
2003
|
+
*
|
2004
|
+
* Serialize text attribute values to an xmlBufPtr
|
2005
|
+
*/
|
2006
|
+
void
|
2007
|
+
xmlBufAttrSerializeTxtContent(xmlBufPtr buf, xmlDocPtr doc,
|
2008
|
+
xmlAttrPtr attr, const xmlChar * string)
|
2009
|
+
{
|
2010
|
+
xmlChar *base, *cur;
|
2011
|
+
|
2012
|
+
if (string == NULL)
|
2013
|
+
return;
|
2014
|
+
base = cur = (xmlChar *) string;
|
2015
|
+
while (*cur != 0) {
|
2016
|
+
if (*cur == '\n') {
|
2017
|
+
if (base != cur)
|
2018
|
+
xmlBufAdd(buf, base, cur - base);
|
2019
|
+
xmlBufAdd(buf, BAD_CAST " ", 5);
|
2020
|
+
cur++;
|
2021
|
+
base = cur;
|
2022
|
+
} else if (*cur == '\r') {
|
2023
|
+
if (base != cur)
|
2024
|
+
xmlBufAdd(buf, base, cur - base);
|
2025
|
+
xmlBufAdd(buf, BAD_CAST " ", 5);
|
2026
|
+
cur++;
|
2027
|
+
base = cur;
|
2028
|
+
} else if (*cur == '\t') {
|
2029
|
+
if (base != cur)
|
2030
|
+
xmlBufAdd(buf, base, cur - base);
|
2031
|
+
xmlBufAdd(buf, BAD_CAST "	", 4);
|
2032
|
+
cur++;
|
2033
|
+
base = cur;
|
2034
|
+
} else if (*cur == '"') {
|
2035
|
+
if (base != cur)
|
2036
|
+
xmlBufAdd(buf, base, cur - base);
|
2037
|
+
xmlBufAdd(buf, BAD_CAST """, 6);
|
2038
|
+
cur++;
|
2039
|
+
base = cur;
|
2040
|
+
} else if (*cur == '<') {
|
2041
|
+
if (base != cur)
|
2042
|
+
xmlBufAdd(buf, base, cur - base);
|
2043
|
+
xmlBufAdd(buf, BAD_CAST "<", 4);
|
2044
|
+
cur++;
|
2045
|
+
base = cur;
|
2046
|
+
} else if (*cur == '>') {
|
2047
|
+
if (base != cur)
|
2048
|
+
xmlBufAdd(buf, base, cur - base);
|
2049
|
+
xmlBufAdd(buf, BAD_CAST ">", 4);
|
2050
|
+
cur++;
|
2051
|
+
base = cur;
|
2052
|
+
} else if (*cur == '&') {
|
2053
|
+
if (base != cur)
|
2054
|
+
xmlBufAdd(buf, base, cur - base);
|
2055
|
+
xmlBufAdd(buf, BAD_CAST "&", 5);
|
2056
|
+
cur++;
|
2057
|
+
base = cur;
|
2058
|
+
} else if ((*cur >= 0x80) && (cur[1] != 0) &&
|
2059
|
+
((doc == NULL) || (doc->encoding == NULL))) {
|
2060
|
+
/*
|
2061
|
+
* We assume we have UTF-8 content.
|
2062
|
+
*/
|
2063
|
+
unsigned char tmp[12];
|
2064
|
+
int val = 0, l = 1;
|
2065
|
+
|
2066
|
+
if (base != cur)
|
2067
|
+
xmlBufAdd(buf, base, cur - base);
|
2068
|
+
if (*cur < 0xC0) {
|
2069
|
+
xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr, NULL);
|
2070
|
+
xmlSerializeHexCharRef(tmp, *cur);
|
2071
|
+
xmlBufAdd(buf, (xmlChar *) tmp, -1);
|
2072
|
+
cur++;
|
2073
|
+
base = cur;
|
2074
|
+
continue;
|
2075
|
+
} else if (*cur < 0xE0) {
|
2076
|
+
val = (cur[0]) & 0x1F;
|
2077
|
+
val <<= 6;
|
2078
|
+
val |= (cur[1]) & 0x3F;
|
2079
|
+
l = 2;
|
2080
|
+
} else if ((*cur < 0xF0) && (cur [2] != 0)) {
|
2081
|
+
val = (cur[0]) & 0x0F;
|
2082
|
+
val <<= 6;
|
2083
|
+
val |= (cur[1]) & 0x3F;
|
2084
|
+
val <<= 6;
|
2085
|
+
val |= (cur[2]) & 0x3F;
|
2086
|
+
l = 3;
|
2087
|
+
} else if ((*cur < 0xF8) && (cur [2] != 0) && (cur[3] != 0)) {
|
2088
|
+
val = (cur[0]) & 0x07;
|
2089
|
+
val <<= 6;
|
2090
|
+
val |= (cur[1]) & 0x3F;
|
2091
|
+
val <<= 6;
|
2092
|
+
val |= (cur[2]) & 0x3F;
|
2093
|
+
val <<= 6;
|
2094
|
+
val |= (cur[3]) & 0x3F;
|
2095
|
+
l = 4;
|
2096
|
+
}
|
2097
|
+
if ((l == 1) || (!IS_CHAR(val))) {
|
2098
|
+
xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr, NULL);
|
2099
|
+
xmlSerializeHexCharRef(tmp, *cur);
|
2100
|
+
xmlBufAdd(buf, (xmlChar *) tmp, -1);
|
2101
|
+
cur++;
|
2102
|
+
base = cur;
|
2103
|
+
continue;
|
2104
|
+
}
|
2105
|
+
/*
|
2106
|
+
* We could do multiple things here. Just save
|
2107
|
+
* as a char ref
|
2108
|
+
*/
|
2109
|
+
xmlSerializeHexCharRef(tmp, val);
|
2110
|
+
xmlBufAdd(buf, (xmlChar *) tmp, -1);
|
2111
|
+
cur += l;
|
2112
|
+
base = cur;
|
2113
|
+
} else {
|
2114
|
+
cur++;
|
2115
|
+
}
|
2116
|
+
}
|
2117
|
+
if (base != cur)
|
2118
|
+
xmlBufAdd(buf, base, cur - base);
|
2119
|
+
}
|
2120
|
+
|
2121
|
+
/**
|
2122
|
+
* xmlAttrSerializeTxtContent:
|
2123
|
+
* @buf: the XML buffer output
|
2124
|
+
* @doc: the document
|
2125
|
+
* @attr: the attribute node
|
2126
|
+
* @string: the text content
|
2127
|
+
*
|
2128
|
+
* Serialize text attribute values to an xml simple buffer
|
2129
|
+
*/
|
2130
|
+
void
|
2131
|
+
xmlAttrSerializeTxtContent(xmlBufferPtr buf, xmlDocPtr doc,
|
2132
|
+
xmlAttrPtr attr, const xmlChar * string)
|
2133
|
+
{
|
2134
|
+
xmlBufPtr buffer;
|
2135
|
+
|
2136
|
+
if ((buf == NULL) || (string == NULL))
|
2137
|
+
return;
|
2138
|
+
buffer = xmlBufFromBuffer(buf);
|
2139
|
+
if (buffer == NULL)
|
2140
|
+
return;
|
2141
|
+
xmlBufAttrSerializeTxtContent(buffer, doc, attr, string);
|
2142
|
+
xmlBufBackToBuffer(buffer);
|
2143
|
+
}
|
2144
|
+
|
2145
|
+
/**
|
2146
|
+
* xmlNodeDump:
|
2147
|
+
* @buf: the XML buffer output
|
2148
|
+
* @doc: the document
|
2149
|
+
* @cur: the current node
|
2150
|
+
* @level: the imbrication level for indenting
|
2151
|
+
* @format: is formatting allowed
|
2152
|
+
*
|
2153
|
+
* Dump an XML node, recursive behaviour,children are printed too.
|
2154
|
+
* Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
|
2155
|
+
* or xmlKeepBlanksDefault(0) was called.
|
2156
|
+
* Since this is using xmlBuffer structures it is limited to 2GB and somehow
|
2157
|
+
* deprecated, use xmlNodeDumpOutput() instead.
|
2158
|
+
*
|
2159
|
+
* Returns the number of bytes written to the buffer or -1 in case of error
|
2160
|
+
*/
|
2161
|
+
int
|
2162
|
+
xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
|
2163
|
+
int format)
|
2164
|
+
{
|
2165
|
+
xmlBufPtr buffer;
|
2166
|
+
size_t ret;
|
2167
|
+
|
2168
|
+
if ((buf == NULL) || (cur == NULL))
|
2169
|
+
return(-1);
|
2170
|
+
buffer = xmlBufFromBuffer(buf);
|
2171
|
+
if (buffer == NULL)
|
2172
|
+
return(-1);
|
2173
|
+
ret = xmlBufNodeDump(buffer, doc, cur, level, format);
|
2174
|
+
xmlBufBackToBuffer(buffer);
|
2175
|
+
if (ret > INT_MAX)
|
2176
|
+
return(-1);
|
2177
|
+
return((int) ret);
|
2178
|
+
}
|
2179
|
+
|
2180
|
+
/**
|
2181
|
+
* xmlBufNodeDump:
|
2182
|
+
* @buf: the XML buffer output
|
2183
|
+
* @doc: the document
|
2184
|
+
* @cur: the current node
|
2185
|
+
* @level: the imbrication level for indenting
|
2186
|
+
* @format: is formatting allowed
|
2187
|
+
*
|
2188
|
+
* Dump an XML node, recursive behaviour,children are printed too.
|
2189
|
+
* Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
|
2190
|
+
* or xmlKeepBlanksDefault(0) was called
|
2191
|
+
*
|
2192
|
+
* Returns the number of bytes written to the buffer, in case of error 0
|
2193
|
+
* is returned or @buf stores the error
|
2194
|
+
*/
|
2195
|
+
|
2196
|
+
size_t
|
2197
|
+
xmlBufNodeDump(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
|
2198
|
+
int format)
|
2199
|
+
{
|
2200
|
+
size_t use;
|
2201
|
+
int ret;
|
2202
|
+
xmlOutputBufferPtr outbuf;
|
2203
|
+
int oldalloc;
|
2204
|
+
|
2205
|
+
xmlInitParser();
|
2206
|
+
|
2207
|
+
if (cur == NULL) {
|
2208
|
+
#ifdef DEBUG_TREE
|
2209
|
+
xmlGenericError(xmlGenericErrorContext,
|
2210
|
+
"xmlNodeDump : node == NULL\n");
|
2211
|
+
#endif
|
2212
|
+
return (-1);
|
2213
|
+
}
|
2214
|
+
if (buf == NULL) {
|
2215
|
+
#ifdef DEBUG_TREE
|
2216
|
+
xmlGenericError(xmlGenericErrorContext,
|
2217
|
+
"xmlNodeDump : buf == NULL\n");
|
2218
|
+
#endif
|
2219
|
+
return (-1);
|
2220
|
+
}
|
2221
|
+
outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
|
2222
|
+
if (outbuf == NULL) {
|
2223
|
+
xmlSaveErrMemory("creating buffer");
|
2224
|
+
return (-1);
|
2225
|
+
}
|
2226
|
+
memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
|
2227
|
+
outbuf->buffer = buf;
|
2228
|
+
outbuf->encoder = NULL;
|
2229
|
+
outbuf->writecallback = NULL;
|
2230
|
+
outbuf->closecallback = NULL;
|
2231
|
+
outbuf->context = NULL;
|
2232
|
+
outbuf->written = 0;
|
2233
|
+
|
2234
|
+
use = xmlBufUse(buf);
|
2235
|
+
oldalloc = xmlBufGetAllocationScheme(buf);
|
2236
|
+
xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
|
2237
|
+
xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
|
2238
|
+
xmlBufSetAllocationScheme(buf, oldalloc);
|
2239
|
+
xmlFree(outbuf);
|
2240
|
+
ret = xmlBufUse(buf) - use;
|
2241
|
+
return (ret);
|
2242
|
+
}
|
2243
|
+
|
2244
|
+
/**
|
2245
|
+
* xmlElemDump:
|
2246
|
+
* @f: the FILE * for the output
|
2247
|
+
* @doc: the document
|
2248
|
+
* @cur: the current node
|
2249
|
+
*
|
2250
|
+
* Dump an XML/HTML node, recursive behaviour, children are printed too.
|
2251
|
+
*/
|
2252
|
+
void
|
2253
|
+
xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur)
|
2254
|
+
{
|
2255
|
+
xmlOutputBufferPtr outbuf;
|
2256
|
+
|
2257
|
+
xmlInitParser();
|
2258
|
+
|
2259
|
+
if (cur == NULL) {
|
2260
|
+
#ifdef DEBUG_TREE
|
2261
|
+
xmlGenericError(xmlGenericErrorContext,
|
2262
|
+
"xmlElemDump : cur == NULL\n");
|
2263
|
+
#endif
|
2264
|
+
return;
|
2265
|
+
}
|
2266
|
+
#ifdef DEBUG_TREE
|
2267
|
+
if (doc == NULL) {
|
2268
|
+
xmlGenericError(xmlGenericErrorContext,
|
2269
|
+
"xmlElemDump : doc == NULL\n");
|
2270
|
+
}
|
2271
|
+
#endif
|
2272
|
+
|
2273
|
+
outbuf = xmlOutputBufferCreateFile(f, NULL);
|
2274
|
+
if (outbuf == NULL)
|
2275
|
+
return;
|
2276
|
+
if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
|
2277
|
+
#ifdef LIBXML_HTML_ENABLED
|
2278
|
+
htmlNodeDumpOutput(outbuf, doc, cur, NULL);
|
2279
|
+
#else
|
2280
|
+
xmlSaveErr(XML_ERR_INTERNAL_ERROR, cur, "HTML support not compiled in\n");
|
2281
|
+
#endif /* LIBXML_HTML_ENABLED */
|
2282
|
+
} else
|
2283
|
+
xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
|
2284
|
+
xmlOutputBufferClose(outbuf);
|
2285
|
+
}
|
2286
|
+
|
2287
|
+
/************************************************************************
|
2288
|
+
* *
|
2289
|
+
* Saving functions front-ends *
|
2290
|
+
* *
|
2291
|
+
************************************************************************/
|
2292
|
+
|
2293
|
+
/**
|
2294
|
+
* xmlNodeDumpOutput:
|
2295
|
+
* @buf: the XML buffer output
|
2296
|
+
* @doc: the document
|
2297
|
+
* @cur: the current node
|
2298
|
+
* @level: the imbrication level for indenting
|
2299
|
+
* @format: is formatting allowed
|
2300
|
+
* @encoding: an optional encoding string
|
2301
|
+
*
|
2302
|
+
* Dump an XML node, recursive behaviour, children are printed too.
|
2303
|
+
* Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
|
2304
|
+
* or xmlKeepBlanksDefault(0) was called
|
2305
|
+
*/
|
2306
|
+
void
|
2307
|
+
xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
|
2308
|
+
int level, int format, const char *encoding)
|
2309
|
+
{
|
2310
|
+
xmlSaveCtxt ctxt;
|
2311
|
+
#ifdef LIBXML_HTML_ENABLED
|
2312
|
+
xmlDtdPtr dtd;
|
2313
|
+
int is_xhtml = 0;
|
2314
|
+
#endif
|
2315
|
+
|
2316
|
+
xmlInitParser();
|
2317
|
+
|
2318
|
+
if ((buf == NULL) || (cur == NULL)) return;
|
2319
|
+
|
2320
|
+
if (encoding == NULL)
|
2321
|
+
encoding = "UTF-8";
|
2322
|
+
|
2323
|
+
memset(&ctxt, 0, sizeof(ctxt));
|
2324
|
+
ctxt.buf = buf;
|
2325
|
+
ctxt.level = level;
|
2326
|
+
ctxt.format = format ? 1 : 0;
|
2327
|
+
ctxt.encoding = (const xmlChar *) encoding;
|
2328
|
+
xmlSaveCtxtInit(&ctxt);
|
2329
|
+
ctxt.options |= XML_SAVE_AS_XML;
|
2330
|
+
|
2331
|
+
#ifdef LIBXML_HTML_ENABLED
|
2332
|
+
dtd = xmlGetIntSubset(doc);
|
2333
|
+
if (dtd != NULL) {
|
2334
|
+
is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID);
|
2335
|
+
if (is_xhtml < 0)
|
2336
|
+
is_xhtml = 0;
|
2337
|
+
}
|
2338
|
+
|
2339
|
+
if (is_xhtml)
|
2340
|
+
xhtmlNodeDumpOutput(&ctxt, cur);
|
2341
|
+
else
|
2342
|
+
#endif
|
2343
|
+
xmlNodeDumpOutputInternal(&ctxt, cur);
|
2344
|
+
}
|
2345
|
+
|
2346
|
+
/**
|
2347
|
+
* xmlDocDumpFormatMemoryEnc:
|
2348
|
+
* @out_doc: Document to generate XML text from
|
2349
|
+
* @doc_txt_ptr: Memory pointer for allocated XML text
|
2350
|
+
* @doc_txt_len: Length of the generated XML text
|
2351
|
+
* @txt_encoding: Character encoding to use when generating XML text
|
2352
|
+
* @format: should formatting spaces been added
|
2353
|
+
*
|
2354
|
+
* Dump the current DOM tree into memory using the character encoding specified
|
2355
|
+
* by the caller. Note it is up to the caller of this function to free the
|
2356
|
+
* allocated memory with xmlFree().
|
2357
|
+
* Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
|
2358
|
+
* or xmlKeepBlanksDefault(0) was called
|
2359
|
+
*/
|
2360
|
+
|
2361
|
+
void
|
2362
|
+
xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
|
2363
|
+
int * doc_txt_len, const char * txt_encoding,
|
2364
|
+
int format) {
|
2365
|
+
xmlSaveCtxt ctxt;
|
2366
|
+
int dummy = 0;
|
2367
|
+
xmlOutputBufferPtr out_buff = NULL;
|
2368
|
+
xmlCharEncodingHandlerPtr conv_hdlr = NULL;
|
2369
|
+
|
2370
|
+
if (doc_txt_len == NULL) {
|
2371
|
+
doc_txt_len = &dummy; /* Continue, caller just won't get length */
|
2372
|
+
}
|
2373
|
+
|
2374
|
+
if (doc_txt_ptr == NULL) {
|
2375
|
+
*doc_txt_len = 0;
|
2376
|
+
return;
|
2377
|
+
}
|
2378
|
+
|
2379
|
+
*doc_txt_ptr = NULL;
|
2380
|
+
*doc_txt_len = 0;
|
2381
|
+
|
2382
|
+
if (out_doc == NULL) {
|
2383
|
+
/* No document, no output */
|
2384
|
+
return;
|
2385
|
+
}
|
2386
|
+
|
2387
|
+
/*
|
2388
|
+
* Validate the encoding value, if provided.
|
2389
|
+
* This logic is copied from xmlSaveFileEnc.
|
2390
|
+
*/
|
2391
|
+
|
2392
|
+
if (txt_encoding == NULL)
|
2393
|
+
txt_encoding = (const char *) out_doc->encoding;
|
2394
|
+
if (txt_encoding != NULL) {
|
2395
|
+
conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
|
2396
|
+
if ( conv_hdlr == NULL ) {
|
2397
|
+
xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, (xmlNodePtr) out_doc,
|
2398
|
+
txt_encoding);
|
2399
|
+
return;
|
2400
|
+
}
|
2401
|
+
}
|
2402
|
+
|
2403
|
+
if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
|
2404
|
+
xmlSaveErrMemory("creating buffer");
|
2405
|
+
return;
|
2406
|
+
}
|
2407
|
+
|
2408
|
+
memset(&ctxt, 0, sizeof(ctxt));
|
2409
|
+
ctxt.buf = out_buff;
|
2410
|
+
ctxt.level = 0;
|
2411
|
+
ctxt.format = format ? 1 : 0;
|
2412
|
+
ctxt.encoding = (const xmlChar *) txt_encoding;
|
2413
|
+
xmlSaveCtxtInit(&ctxt);
|
2414
|
+
ctxt.options |= XML_SAVE_AS_XML;
|
2415
|
+
xmlDocContentDumpOutput(&ctxt, out_doc);
|
2416
|
+
xmlOutputBufferFlush(out_buff);
|
2417
|
+
if (out_buff->conv != NULL) {
|
2418
|
+
*doc_txt_len = xmlBufUse(out_buff->conv);
|
2419
|
+
*doc_txt_ptr = xmlStrndup(xmlBufContent(out_buff->conv), *doc_txt_len);
|
2420
|
+
} else {
|
2421
|
+
*doc_txt_len = xmlBufUse(out_buff->buffer);
|
2422
|
+
*doc_txt_ptr = xmlStrndup(xmlBufContent(out_buff->buffer),*doc_txt_len);
|
2423
|
+
}
|
2424
|
+
(void)xmlOutputBufferClose(out_buff);
|
2425
|
+
|
2426
|
+
if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
|
2427
|
+
*doc_txt_len = 0;
|
2428
|
+
xmlSaveErrMemory("creating output");
|
2429
|
+
}
|
2430
|
+
|
2431
|
+
return;
|
2432
|
+
}
|
2433
|
+
|
2434
|
+
/**
|
2435
|
+
* xmlDocDumpMemory:
|
2436
|
+
* @cur: the document
|
2437
|
+
* @mem: OUT: the memory pointer
|
2438
|
+
* @size: OUT: the memory length
|
2439
|
+
*
|
2440
|
+
* Dump an XML document in memory and return the #xmlChar * and it's size
|
2441
|
+
* in bytes. It's up to the caller to free the memory with xmlFree().
|
2442
|
+
* The resulting byte array is zero terminated, though the last 0 is not
|
2443
|
+
* included in the returned size.
|
2444
|
+
*/
|
2445
|
+
void
|
2446
|
+
xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
|
2447
|
+
xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
|
2448
|
+
}
|
2449
|
+
|
2450
|
+
/**
|
2451
|
+
* xmlDocDumpFormatMemory:
|
2452
|
+
* @cur: the document
|
2453
|
+
* @mem: OUT: the memory pointer
|
2454
|
+
* @size: OUT: the memory length
|
2455
|
+
* @format: should formatting spaces been added
|
2456
|
+
*
|
2457
|
+
*
|
2458
|
+
* Dump an XML document in memory and return the #xmlChar * and it's size.
|
2459
|
+
* It's up to the caller to free the memory with xmlFree().
|
2460
|
+
* Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
|
2461
|
+
* or xmlKeepBlanksDefault(0) was called
|
2462
|
+
*/
|
2463
|
+
void
|
2464
|
+
xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
|
2465
|
+
xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
|
2466
|
+
}
|
2467
|
+
|
2468
|
+
/**
|
2469
|
+
* xmlDocDumpMemoryEnc:
|
2470
|
+
* @out_doc: Document to generate XML text from
|
2471
|
+
* @doc_txt_ptr: Memory pointer for allocated XML text
|
2472
|
+
* @doc_txt_len: Length of the generated XML text
|
2473
|
+
* @txt_encoding: Character encoding to use when generating XML text
|
2474
|
+
*
|
2475
|
+
* Dump the current DOM tree into memory using the character encoding specified
|
2476
|
+
* by the caller. Note it is up to the caller of this function to free the
|
2477
|
+
* allocated memory with xmlFree().
|
2478
|
+
*/
|
2479
|
+
|
2480
|
+
void
|
2481
|
+
xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
|
2482
|
+
int * doc_txt_len, const char * txt_encoding) {
|
2483
|
+
xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
|
2484
|
+
txt_encoding, 0);
|
2485
|
+
}
|
2486
|
+
|
2487
|
+
/**
|
2488
|
+
* xmlDocFormatDump:
|
2489
|
+
* @f: the FILE*
|
2490
|
+
* @cur: the document
|
2491
|
+
* @format: should formatting spaces been added
|
2492
|
+
*
|
2493
|
+
* Dump an XML document to an open FILE.
|
2494
|
+
*
|
2495
|
+
* returns: the number of bytes written or -1 in case of failure.
|
2496
|
+
* Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
|
2497
|
+
* or xmlKeepBlanksDefault(0) was called
|
2498
|
+
*/
|
2499
|
+
int
|
2500
|
+
xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) {
|
2501
|
+
xmlSaveCtxt ctxt;
|
2502
|
+
xmlOutputBufferPtr buf;
|
2503
|
+
const char * encoding;
|
2504
|
+
xmlCharEncodingHandlerPtr handler = NULL;
|
2505
|
+
int ret;
|
2506
|
+
|
2507
|
+
if (cur == NULL) {
|
2508
|
+
#ifdef DEBUG_TREE
|
2509
|
+
xmlGenericError(xmlGenericErrorContext,
|
2510
|
+
"xmlDocDump : document == NULL\n");
|
2511
|
+
#endif
|
2512
|
+
return(-1);
|
2513
|
+
}
|
2514
|
+
encoding = (const char *) cur->encoding;
|
2515
|
+
|
2516
|
+
if (encoding != NULL) {
|
2517
|
+
handler = xmlFindCharEncodingHandler(encoding);
|
2518
|
+
if (handler == NULL) {
|
2519
|
+
xmlFree((char *) cur->encoding);
|
2520
|
+
cur->encoding = NULL;
|
2521
|
+
encoding = NULL;
|
2522
|
+
}
|
2523
|
+
}
|
2524
|
+
buf = xmlOutputBufferCreateFile(f, handler);
|
2525
|
+
if (buf == NULL) return(-1);
|
2526
|
+
memset(&ctxt, 0, sizeof(ctxt));
|
2527
|
+
ctxt.buf = buf;
|
2528
|
+
ctxt.level = 0;
|
2529
|
+
ctxt.format = format ? 1 : 0;
|
2530
|
+
ctxt.encoding = (const xmlChar *) encoding;
|
2531
|
+
xmlSaveCtxtInit(&ctxt);
|
2532
|
+
ctxt.options |= XML_SAVE_AS_XML;
|
2533
|
+
xmlDocContentDumpOutput(&ctxt, cur);
|
2534
|
+
|
2535
|
+
ret = xmlOutputBufferClose(buf);
|
2536
|
+
return(ret);
|
2537
|
+
}
|
2538
|
+
|
2539
|
+
/**
|
2540
|
+
* xmlDocDump:
|
2541
|
+
* @f: the FILE*
|
2542
|
+
* @cur: the document
|
2543
|
+
*
|
2544
|
+
* Dump an XML document to an open FILE.
|
2545
|
+
*
|
2546
|
+
* returns: the number of bytes written or -1 in case of failure.
|
2547
|
+
*/
|
2548
|
+
int
|
2549
|
+
xmlDocDump(FILE *f, xmlDocPtr cur) {
|
2550
|
+
return(xmlDocFormatDump (f, cur, 0));
|
2551
|
+
}
|
2552
|
+
|
2553
|
+
/**
|
2554
|
+
* xmlSaveFileTo:
|
2555
|
+
* @buf: an output I/O buffer
|
2556
|
+
* @cur: the document
|
2557
|
+
* @encoding: the encoding if any assuming the I/O layer handles the transcoding
|
2558
|
+
*
|
2559
|
+
* Dump an XML document to an I/O buffer.
|
2560
|
+
* Warning ! This call xmlOutputBufferClose() on buf which is not available
|
2561
|
+
* after this call.
|
2562
|
+
*
|
2563
|
+
* returns: the number of bytes written or -1 in case of failure.
|
2564
|
+
*/
|
2565
|
+
int
|
2566
|
+
xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
|
2567
|
+
xmlSaveCtxt ctxt;
|
2568
|
+
int ret;
|
2569
|
+
|
2570
|
+
if (buf == NULL) return(-1);
|
2571
|
+
if (cur == NULL) {
|
2572
|
+
xmlOutputBufferClose(buf);
|
2573
|
+
return(-1);
|
2574
|
+
}
|
2575
|
+
memset(&ctxt, 0, sizeof(ctxt));
|
2576
|
+
ctxt.buf = buf;
|
2577
|
+
ctxt.level = 0;
|
2578
|
+
ctxt.format = 0;
|
2579
|
+
ctxt.encoding = (const xmlChar *) encoding;
|
2580
|
+
xmlSaveCtxtInit(&ctxt);
|
2581
|
+
ctxt.options |= XML_SAVE_AS_XML;
|
2582
|
+
xmlDocContentDumpOutput(&ctxt, cur);
|
2583
|
+
ret = xmlOutputBufferClose(buf);
|
2584
|
+
return(ret);
|
2585
|
+
}
|
2586
|
+
|
2587
|
+
/**
|
2588
|
+
* xmlSaveFormatFileTo:
|
2589
|
+
* @buf: an output I/O buffer
|
2590
|
+
* @cur: the document
|
2591
|
+
* @encoding: the encoding if any assuming the I/O layer handles the transcoding
|
2592
|
+
* @format: should formatting spaces been added
|
2593
|
+
*
|
2594
|
+
* Dump an XML document to an I/O buffer.
|
2595
|
+
* Warning ! This call xmlOutputBufferClose() on buf which is not available
|
2596
|
+
* after this call.
|
2597
|
+
*
|
2598
|
+
* returns: the number of bytes written or -1 in case of failure.
|
2599
|
+
*/
|
2600
|
+
int
|
2601
|
+
xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur,
|
2602
|
+
const char *encoding, int format)
|
2603
|
+
{
|
2604
|
+
xmlSaveCtxt ctxt;
|
2605
|
+
int ret;
|
2606
|
+
|
2607
|
+
if (buf == NULL) return(-1);
|
2608
|
+
if ((cur == NULL) ||
|
2609
|
+
((cur->type != XML_DOCUMENT_NODE) &&
|
2610
|
+
(cur->type != XML_HTML_DOCUMENT_NODE))) {
|
2611
|
+
xmlOutputBufferClose(buf);
|
2612
|
+
return(-1);
|
2613
|
+
}
|
2614
|
+
memset(&ctxt, 0, sizeof(ctxt));
|
2615
|
+
ctxt.buf = buf;
|
2616
|
+
ctxt.level = 0;
|
2617
|
+
ctxt.format = format ? 1 : 0;
|
2618
|
+
ctxt.encoding = (const xmlChar *) encoding;
|
2619
|
+
xmlSaveCtxtInit(&ctxt);
|
2620
|
+
ctxt.options |= XML_SAVE_AS_XML;
|
2621
|
+
xmlDocContentDumpOutput(&ctxt, cur);
|
2622
|
+
ret = xmlOutputBufferClose(buf);
|
2623
|
+
return (ret);
|
2624
|
+
}
|
2625
|
+
|
2626
|
+
/**
|
2627
|
+
* xmlSaveFormatFileEnc:
|
2628
|
+
* @filename: the filename or URL to output
|
2629
|
+
* @cur: the document being saved
|
2630
|
+
* @encoding: the name of the encoding to use or NULL.
|
2631
|
+
* @format: should formatting spaces be added.
|
2632
|
+
*
|
2633
|
+
* Dump an XML document to a file or an URL.
|
2634
|
+
*
|
2635
|
+
* Returns the number of bytes written or -1 in case of error.
|
2636
|
+
* Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
|
2637
|
+
* or xmlKeepBlanksDefault(0) was called
|
2638
|
+
*/
|
2639
|
+
int
|
2640
|
+
xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur,
|
2641
|
+
const char * encoding, int format ) {
|
2642
|
+
xmlSaveCtxt ctxt;
|
2643
|
+
xmlOutputBufferPtr buf;
|
2644
|
+
xmlCharEncodingHandlerPtr handler = NULL;
|
2645
|
+
int ret;
|
2646
|
+
|
2647
|
+
if (cur == NULL)
|
2648
|
+
return(-1);
|
2649
|
+
|
2650
|
+
if (encoding == NULL)
|
2651
|
+
encoding = (const char *) cur->encoding;
|
2652
|
+
|
2653
|
+
if (encoding != NULL) {
|
2654
|
+
|
2655
|
+
handler = xmlFindCharEncodingHandler(encoding);
|
2656
|
+
if (handler == NULL)
|
2657
|
+
return(-1);
|
2658
|
+
}
|
2659
|
+
|
2660
|
+
#ifdef LIBXML_ZLIB_ENABLED
|
2661
|
+
if (cur->compression < 0) cur->compression = xmlGetCompressMode();
|
2662
|
+
#endif
|
2663
|
+
/*
|
2664
|
+
* save the content to a temp buffer.
|
2665
|
+
*/
|
2666
|
+
buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
|
2667
|
+
if (buf == NULL) return(-1);
|
2668
|
+
memset(&ctxt, 0, sizeof(ctxt));
|
2669
|
+
ctxt.buf = buf;
|
2670
|
+
ctxt.level = 0;
|
2671
|
+
ctxt.format = format ? 1 : 0;
|
2672
|
+
ctxt.encoding = (const xmlChar *) encoding;
|
2673
|
+
xmlSaveCtxtInit(&ctxt);
|
2674
|
+
ctxt.options |= XML_SAVE_AS_XML;
|
2675
|
+
|
2676
|
+
xmlDocContentDumpOutput(&ctxt, cur);
|
2677
|
+
|
2678
|
+
ret = xmlOutputBufferClose(buf);
|
2679
|
+
return(ret);
|
2680
|
+
}
|
2681
|
+
|
2682
|
+
|
2683
|
+
/**
|
2684
|
+
* xmlSaveFileEnc:
|
2685
|
+
* @filename: the filename (or URL)
|
2686
|
+
* @cur: the document
|
2687
|
+
* @encoding: the name of an encoding (or NULL)
|
2688
|
+
*
|
2689
|
+
* Dump an XML document, converting it to the given encoding
|
2690
|
+
*
|
2691
|
+
* returns: the number of bytes written or -1 in case of failure.
|
2692
|
+
*/
|
2693
|
+
int
|
2694
|
+
xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
|
2695
|
+
return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );
|
2696
|
+
}
|
2697
|
+
|
2698
|
+
/**
|
2699
|
+
* xmlSaveFormatFile:
|
2700
|
+
* @filename: the filename (or URL)
|
2701
|
+
* @cur: the document
|
2702
|
+
* @format: should formatting spaces been added
|
2703
|
+
*
|
2704
|
+
* Dump an XML document to a file. Will use compression if
|
2705
|
+
* compiled in and enabled. If @filename is "-" the stdout file is
|
2706
|
+
* used. If @format is set then the document will be indented on output.
|
2707
|
+
* Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
|
2708
|
+
* or xmlKeepBlanksDefault(0) was called
|
2709
|
+
*
|
2710
|
+
* returns: the number of bytes written or -1 in case of failure.
|
2711
|
+
*/
|
2712
|
+
int
|
2713
|
+
xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) {
|
2714
|
+
return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );
|
2715
|
+
}
|
2716
|
+
|
2717
|
+
/**
|
2718
|
+
* xmlSaveFile:
|
2719
|
+
* @filename: the filename (or URL)
|
2720
|
+
* @cur: the document
|
2721
|
+
*
|
2722
|
+
* Dump an XML document to a file. Will use compression if
|
2723
|
+
* compiled in and enabled. If @filename is "-" the stdout file is
|
2724
|
+
* used.
|
2725
|
+
* returns: the number of bytes written or -1 in case of failure.
|
2726
|
+
*/
|
2727
|
+
int
|
2728
|
+
xmlSaveFile(const char *filename, xmlDocPtr cur) {
|
2729
|
+
return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));
|
2730
|
+
}
|
2731
|
+
|
2732
|
+
#endif /* LIBXML_OUTPUT_ENABLED */
|
2733
|
+
|
2734
|
+
#define bottom_xmlsave
|
2735
|
+
#include "elfgcchack.h"
|