Coverage Report

Created: 2025-07-18 06:10

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