Annotation of embedaddon/libxml2/xmlsave.c, revision 1.1.1.2

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>