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