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

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

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