Coverage Report

Created: 2024-02-25 06:11

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