Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685/* * xmlsave.c: Implementation of the document serializer * * See Copyright for the status of this software. * * daniel@veillard.com */
#define IN_LIBXML#include "libxml.h"
#include <string.h>#include <libxml/xmlmemory.h>#include <libxml/parserInternals.h>#include <libxml/tree.h>#include <libxml/xmlsave.h>
#define MAX_INDENT 60
#include <libxml/HTMLtree.h>
#include "private/buf.h"#include "private/enc.h"#include "private/error.h"#include "private/save.h"
#ifdef LIBXML_OUTPUT_ENABLED
#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
#define TODO \ xmlGenericError(xmlGenericErrorContext, \ "Unimplemented block at %s:%d\n", \ __FILE__, __LINE__);
struct _xmlSaveCtxt { void *_private; int type; int fd; const xmlChar *filename; const xmlChar *encoding; xmlCharEncodingHandlerPtr handler; xmlOutputBufferPtr buf; int options; int level; int format; char indent[MAX_INDENT + 1]; /* array for indenting output */ int indent_nr; int indent_size; xmlCharEncodingOutputFunc escape; /* used for element content */ xmlCharEncodingOutputFunc escapeAttr;/* used for attribute content */};
/************************************************************************ * * * Output error handlers * * * ************************************************************************//** * xmlSaveErrMemory: * @extra: extra information * * Handle an out of memory condition */static voidxmlSaveErrMemory(const char *extra){ __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra);}
/** * xmlSaveErr: * @code: the error number * @node: the location of the error. * @extra: extra information * * Handle an out of memory condition */static voidxmlSaveErr(int code, xmlNodePtr node, const char *extra){ const char *msg = NULL;
switch(code) { case XML_SAVE_NOT_UTF8: msg = "string is not in UTF-8\n"; break; case XML_SAVE_CHAR_INVALID: msg = "invalid character value\n"; break; case XML_SAVE_UNKNOWN_ENCODING: msg = "unknown encoding %s\n"; break; case XML_SAVE_NO_DOCTYPE: msg = "document has no DOCTYPE\n"; break; default: msg = "unexpected error number\n"; } __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra);}
/************************************************************************ * * * Special escaping routines * * * ************************************************************************/static unsigned char *xmlSerializeHexCharRef(unsigned char *out, int val) { unsigned char *ptr;
*out++ = '&'; *out++ = '#'; *out++ = 'x'; if (val < 0x10) ptr = out; else if (val < 0x100) ptr = out + 1; else if (val < 0x1000) ptr = out + 2; else if (val < 0x10000) ptr = out + 3; else if (val < 0x100000) ptr = out + 4; else ptr = out + 5; out = ptr + 1; while (val > 0) { switch (val & 0xF) { case 0: *ptr-- = '0'; break; case 1: *ptr-- = '1'; break; case 2: *ptr-- = '2'; break; case 3: *ptr-- = '3'; break; case 4: *ptr-- = '4'; break; case 5: *ptr-- = '5'; break; case 6: *ptr-- = '6'; break; case 7: *ptr-- = '7'; break; case 8: *ptr-- = '8'; break; case 9: *ptr-- = '9'; break; case 0xA: *ptr-- = 'A'; break; case 0xB: *ptr-- = 'B'; break; case 0xC: *ptr-- = 'C'; break; case 0xD: *ptr-- = 'D'; break; case 0xE: *ptr-- = 'E'; break; case 0xF: *ptr-- = 'F'; break; default: *ptr-- = '0'; break; } val >>= 4; } *out++ = ';'; *out = 0; return(out);}
/** * xmlEscapeEntities: * @out: a pointer to an array of bytes to store the result * @outlen: the length of @out * @in: a pointer to an array of unescaped UTF-8 bytes * @inlen: the length of @in * * Take a block of UTF-8 chars in and escape them. Used when there is no * encoding specified. * * Returns 0 if success, or -1 otherwise * The value of @inlen after return is the number of octets consumed * if the return value is positive, else unpredictable. * The value of @outlen after return is the number of octets consumed. */static intxmlEscapeEntities(unsigned char* out, int *outlen, const xmlChar* in, int *inlen) { unsigned char* outstart = out; const unsigned char* base = in; unsigned char* outend = out + *outlen; const unsigned char* inend; int val;
inend = in + (*inlen);
while ((in < inend) && (out < outend)) { if (*in == '<') { if (outend - out < 4) break; *out++ = '&'; *out++ = 'l'; *out++ = 't'; *out++ = ';'; in++; continue; } else if (*in == '>') { if (outend - out < 4) break; *out++ = '&'; *out++ = 'g'; *out++ = 't'; *out++ = ';'; in++; continue; } else if (*in == '&') { if (outend - out < 5) break; *out++ = '&'; *out++ = 'a'; *out++ = 'm'; *out++ = 'p'; *out++ = ';'; in++; continue; } else if (((*in >= 0x20) && (*in < 0x80)) || (*in == '\n') || (*in == '\t')) { /* * default case, just copy ! */ *out++ = *in++; continue; } else if (*in >= 0x80) { /* * We assume we have UTF-8 input. */ if (outend - out < 11) break;
if (*in < 0xC0) { xmlSaveErr(XML_SAVE_NOT_UTF8, NULL, NULL); in++; goto error; } else if (*in < 0xE0) { if (inend - in < 2) break; val = (in[0]) & 0x1F; val <<= 6; val |= (in[1]) & 0x3F; in += 2; } else if (*in < 0xF0) { if (inend - in < 3) break; val = (in[0]) & 0x0F; val <<= 6; val |= (in[1]) & 0x3F; val <<= 6; val |= (in[2]) & 0x3F; in += 3; } else if (*in < 0xF8) { if (inend - in < 4) break; val = (in[0]) & 0x07; val <<= 6; val |= (in[1]) & 0x3F; val <<= 6; val |= (in[2]) & 0x3F; val <<= 6; val |= (in[3]) & 0x3F; in += 4; } else { xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL); in++; goto error; } if (!IS_CHAR(val)) { xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL); in++; goto error; }
/* * We could do multiple things here. Just save as a char ref */ out = xmlSerializeHexCharRef(out, val); } else if (IS_BYTE_CHAR(*in)) { if (outend - out < 6) break; out = xmlSerializeHexCharRef(out, *in++); } else { xmlGenericError(xmlGenericErrorContext, "xmlEscapeEntities : char out of range\n"); in++; goto error; } } *outlen = out - outstart; *inlen = in - base; return(0);error: *outlen = out - outstart; *inlen = in - base; return(-1);}
/************************************************************************ * * * Allocation and deallocation * * * ************************************************************************//** * xmlSaveCtxtInit: * @ctxt: the saving context * * Initialize a saving context */static voidxmlSaveCtxtInit(xmlSaveCtxtPtr ctxt){ int i; int len;
if (ctxt == NULL) return; if ((ctxt->encoding == NULL) && (ctxt->escape == NULL)) ctxt->escape = xmlEscapeEntities; len = xmlStrlen((xmlChar *)xmlTreeIndentString); if ((xmlTreeIndentString == NULL) || (len == 0)) { memset(&ctxt->indent[0], 0, MAX_INDENT + 1); } else { ctxt->indent_size = len; ctxt->indent_nr = MAX_INDENT / ctxt->indent_size; for (i = 0;i < ctxt->indent_nr;i++) memcpy(&ctxt->indent[i * ctxt->indent_size], xmlTreeIndentString, ctxt->indent_size); ctxt->indent[ctxt->indent_nr * ctxt->indent_size] = 0; }
if (xmlSaveNoEmptyTags) { ctxt->options |= XML_SAVE_NO_EMPTY; }}
/** * xmlFreeSaveCtxt: * * Free a saving context, destroying the output in any remaining buffer */static voidxmlFreeSaveCtxt(xmlSaveCtxtPtr ctxt){ if (ctxt == NULL) return; if (ctxt->encoding != NULL) xmlFree((char *) ctxt->encoding); if (ctxt->buf != NULL) xmlOutputBufferClose(ctxt->buf); xmlFree(ctxt);}
/** * xmlNewSaveCtxt: * * Create a new saving context * * Returns the new structure or NULL in case of error */static xmlSaveCtxtPtrxmlNewSaveCtxt(const char *encoding, int options){ xmlSaveCtxtPtr ret;
ret = (xmlSaveCtxtPtr) xmlMalloc(sizeof(xmlSaveCtxt)); if (ret == NULL) { xmlSaveErrMemory("creating saving context"); return ( NULL ); } memset(ret, 0, sizeof(xmlSaveCtxt));
if (encoding != NULL) { ret->handler = xmlFindCharEncodingHandler(encoding); if (ret->handler == NULL) { xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); xmlFreeSaveCtxt(ret); return(NULL); } ret->encoding = xmlStrdup((const xmlChar *)encoding); ret->escape = NULL; } xmlSaveCtxtInit(ret);
/* * Use the options */
/* Re-check this option as it may already have been set */ if ((ret->options & XML_SAVE_NO_EMPTY) && ! (options & XML_SAVE_NO_EMPTY)) { options |= XML_SAVE_NO_EMPTY; }
ret->options = options; if (options & XML_SAVE_FORMAT) ret->format = 1; else if (options & XML_SAVE_WSNONSIG) ret->format = 2;
return(ret);}
/************************************************************************ * * * Dumping XML tree content to a simple buffer * * * ************************************************************************//** * xmlAttrSerializeContent: * @buf: the XML buffer output * @doc: the document * @attr: the attribute pointer * * Serialize the attribute in the buffer */static voidxmlAttrSerializeContent(xmlOutputBufferPtr buf, xmlAttrPtr attr){ xmlNodePtr children;
children = attr->children; while (children != NULL) { switch (children->type) { case XML_TEXT_NODE: xmlBufAttrSerializeTxtContent(buf->buffer, attr->doc, attr, children->content); break; case XML_ENTITY_REF_NODE: xmlBufAdd(buf->buffer, BAD_CAST "&", 1); xmlBufAdd(buf->buffer, children->name, xmlStrlen(children->name)); xmlBufAdd(buf->buffer, BAD_CAST ";", 1); break; default: /* should not happen unless we have a badly built tree */ break; } children = children->next; }}
/** * xmlBufDumpNotationTable: * @buf: an xmlBufPtr output * @table: A notation table * * This will dump the content of the notation table as an XML DTD definition */static voidxmlBufDumpNotationTable(xmlBufPtr buf, xmlNotationTablePtr table) { xmlBufferPtr buffer;
buffer = xmlBufferCreate(); if (buffer == NULL) { /* * TODO set the error in buf */ return; } xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT); xmlDumpNotationTable(buffer, table); xmlBufMergeBuffer(buf, buffer);}
/** * xmlBufDumpElementDecl: * @buf: an xmlBufPtr output * @elem: An element table * * This will dump the content of the element declaration as an XML * DTD definition */static voidxmlBufDumpElementDecl(xmlBufPtr buf, xmlElementPtr elem) { xmlBufferPtr buffer;
buffer = xmlBufferCreate(); if (buffer == NULL) { /* * TODO set the error in buf */ return; } xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT); xmlDumpElementDecl(buffer, elem); xmlBufMergeBuffer(buf, buffer);}
/** * xmlBufDumpAttributeDecl: * @buf: an xmlBufPtr output * @attr: An attribute declaration * * This will dump the content of the attribute declaration as an XML * DTD definition */static voidxmlBufDumpAttributeDecl(xmlBufPtr buf, xmlAttributePtr attr) { xmlBufferPtr buffer;
buffer = xmlBufferCreate(); if (buffer == NULL) { /* * TODO set the error in buf */ return; } xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT); xmlDumpAttributeDecl(buffer, attr); xmlBufMergeBuffer(buf, buffer);}
/** * xmlBufDumpEntityDecl: * @buf: an xmlBufPtr output * @ent: An entity table * * This will dump the content of the entity table as an XML DTD definition */static voidxmlBufDumpEntityDecl(xmlBufPtr buf, xmlEntityPtr ent) { xmlBufferPtr buffer;
buffer = xmlBufferCreate(); if (buffer == NULL) { /* * TODO set the error in buf */ return; } xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT); xmlDumpEntityDecl(buffer, ent); xmlBufMergeBuffer(buf, buffer);}
/************************************************************************ * * * Dumping XML tree content to an I/O output buffer * * * ************************************************************************/
static int xmlSaveSwitchEncoding(xmlSaveCtxtPtr ctxt, const char *encoding) { xmlOutputBufferPtr buf = ctxt->buf;
if ((encoding != NULL) && (buf->encoder == NULL) && (buf->conv == NULL)) { buf->encoder = xmlFindCharEncodingHandler((const char *)encoding); if (buf->encoder == NULL) { xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, (const char *)encoding); return(-1); } buf->conv = xmlBufCreate(); if (buf->conv == NULL) { xmlCharEncCloseFunc(buf->encoder); xmlSaveErrMemory("creating encoding buffer"); return(-1); } /* * initialize the state, e.g. if outputting a BOM */ xmlCharEncOutput(buf, 1); } return(0);}
static int xmlSaveClearEncoding(xmlSaveCtxtPtr ctxt) { xmlOutputBufferPtr buf = ctxt->buf; xmlOutputBufferFlush(buf); xmlCharEncCloseFunc(buf->encoder); xmlBufFree(buf->conv); buf->encoder = NULL; buf->conv = NULL; return(0);}
#ifdef LIBXML_HTML_ENABLEDstatic voidxhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);#endifstatic void xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);static int xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur);
/** * xmlOutputBufferWriteWSNonSig: * @ctxt: The save context * @extra: Number of extra indents to apply to ctxt->level * * Write out formatting for non-significant whitespace output. */static voidxmlOutputBufferWriteWSNonSig(xmlSaveCtxtPtr ctxt, int extra){ int i; if ((ctxt == NULL) || (ctxt->buf == NULL)) return; xmlOutputBufferWrite(ctxt->buf, 1, "\n"); for (i = 0; i < (ctxt->level + extra); i += ctxt->indent_nr) { xmlOutputBufferWrite(ctxt->buf, ctxt->indent_size * ((ctxt->level + extra - i) > ctxt->indent_nr ? ctxt->indent_nr : (ctxt->level + extra - i)), ctxt->indent); }}
/** * xmlNsDumpOutput: * @buf: the XML buffer output * @cur: a namespace * @ctxt: the output save context. Optional. * * Dump a local Namespace definition. * Should be called in the context of attributes dumps. * If @ctxt is supplied, @buf should be its buffer. */static voidxmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur, xmlSaveCtxtPtr ctxt) { if ((cur == NULL) || (buf == NULL)) return; if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) { if (xmlStrEqual(cur->prefix, BAD_CAST "xml")) return;
if (ctxt != NULL && ctxt->format == 2) xmlOutputBufferWriteWSNonSig(ctxt, 2); else xmlOutputBufferWrite(buf, 1, " ");
/* Within the context of an element attributes */ if (cur->prefix != NULL) { xmlOutputBufferWrite(buf, 6, "xmlns:"); xmlOutputBufferWriteString(buf, (const char *)cur->prefix); } else xmlOutputBufferWrite(buf, 5, "xmlns"); xmlOutputBufferWrite(buf, 1, "="); xmlBufWriteQuotedString(buf->buffer, cur->href); }}
/** * xmlNsDumpOutputCtxt * @ctxt: the save context * @cur: a namespace * * Dump a local Namespace definition to a save context. * Should be called in the context of attribute dumps. */static voidxmlNsDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlNsPtr cur) { xmlNsDumpOutput(ctxt->buf, cur, ctxt);}
/** * xmlNsListDumpOutputCtxt * @ctxt: the save context * @cur: the first namespace * * Dump a list of local namespace definitions to a save context. * Should be called in the context of attribute dumps. */static voidxmlNsListDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlNsPtr cur) { while (cur != NULL) { xmlNsDumpOutput(ctxt->buf, cur, ctxt); cur = cur->next; }}
/** * xmlNsListDumpOutput: * @buf: the XML buffer output * @cur: the first namespace * * Dump a list of local Namespace definitions. * Should be called in the context of attributes dumps. */voidxmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) { while (cur != NULL) { xmlNsDumpOutput(buf, cur, NULL); cur = cur->next; }}
/** * xmlDtdDumpOutput: * @buf: the XML buffer output * @dtd: the pointer to the DTD * * Dump the XML document DTD, if any. */static voidxmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) { xmlOutputBufferPtr buf; xmlNodePtr cur; int format, level;
if (dtd == NULL) return; if ((ctxt == NULL) || (ctxt->buf == NULL)) return; buf = ctxt->buf; xmlOutputBufferWrite(buf, 10, "<!DOCTYPE "); xmlOutputBufferWriteString(buf, (const char *)dtd->name); if (dtd->ExternalID != NULL) { xmlOutputBufferWrite(buf, 8, " PUBLIC "); xmlBufWriteQuotedString(buf->buffer, dtd->ExternalID); xmlOutputBufferWrite(buf, 1, " "); xmlBufWriteQuotedString(buf->buffer, dtd->SystemID); } else if (dtd->SystemID != NULL) { xmlOutputBufferWrite(buf, 8, " SYSTEM "); xmlBufWriteQuotedString(buf->buffer, dtd->SystemID); } if ((dtd->entities == NULL) && (dtd->elements == NULL) && (dtd->attributes == NULL) && (dtd->notations == NULL) && (dtd->pentities == NULL)) { xmlOutputBufferWrite(buf, 1, ">"); return; } xmlOutputBufferWrite(buf, 3, " [\n"); /* * Dump the notations first they are not in the DTD children list * Do this only on a standalone DTD or on the internal subset though. */ if ((dtd->notations != NULL) && ((dtd->doc == NULL) || (dtd->doc->intSubset == dtd))) { xmlBufDumpNotationTable(buf->buffer, (xmlNotationTablePtr) dtd->notations); } format = ctxt->format; level = ctxt->level; ctxt->format = 0; ctxt->level = -1; for (cur = dtd->children; cur != NULL; cur = cur->next) { xmlNodeDumpOutputInternal(ctxt, cur); } ctxt->format = format; ctxt->level = level; xmlOutputBufferWrite(buf, 2, "]>");}
/** * xmlAttrDumpOutput: * @buf: the XML buffer output * @cur: the attribute pointer * * Dump an XML attribute */static voidxmlAttrDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) { xmlOutputBufferPtr buf;
if (cur == NULL) return; buf = ctxt->buf; if (buf == NULL) return; if (ctxt->format == 2) xmlOutputBufferWriteWSNonSig(ctxt, 2); else xmlOutputBufferWrite(buf, 1, " "); if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); xmlOutputBufferWrite(buf, 1, ":"); } xmlOutputBufferWriteString(buf, (const char *)cur->name); xmlOutputBufferWrite(buf, 2, "=\""); xmlAttrSerializeContent(buf, cur); xmlOutputBufferWrite(buf, 1, "\"");}
#ifdef LIBXML_HTML_ENABLED/** * htmlNodeDumpOutputInternal: * @cur: the current node * * Dump an HTML node, recursive behaviour, children are printed too. */static inthtmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { const xmlChar *oldenc = NULL; const xmlChar *oldctxtenc = ctxt->encoding; const xmlChar *encoding = ctxt->encoding; xmlOutputBufferPtr buf = ctxt->buf; int switched_encoding = 0; xmlDocPtr doc;
xmlInitParser();
doc = cur->doc; if (doc != NULL) { oldenc = doc->encoding; if (ctxt->encoding != NULL) { doc->encoding = BAD_CAST ctxt->encoding; } else if (doc->encoding != NULL) { encoding = doc->encoding; } }
if ((encoding != NULL) && (doc != NULL)) htmlSetMetaEncoding(doc, (const xmlChar *) encoding); if ((encoding == NULL) && (doc != NULL)) encoding = htmlGetMetaEncoding(doc); if (encoding == NULL) encoding = BAD_CAST "HTML"; if ((encoding != NULL) && (oldctxtenc == NULL) && (buf->encoder == NULL) && (buf->conv == NULL)) { if (xmlSaveSwitchEncoding(ctxt, (const char*) encoding) < 0) { doc->encoding = oldenc; return(-1); } switched_encoding = 1; } if (ctxt->options & XML_SAVE_FORMAT) htmlNodeDumpFormatOutput(buf, doc, cur, (const char *)encoding, 1); else htmlNodeDumpFormatOutput(buf, doc, cur, (const char *)encoding, 0); /* * Restore the state of the saving context at the end of the document */ if ((switched_encoding) && (oldctxtenc == NULL)) { xmlSaveClearEncoding(ctxt); } if (doc != NULL) doc->encoding = oldenc; return(0);}#endif
/** * xmlNodeDumpOutputInternal: * @cur: the current node * * Dump an XML node, recursive behaviour, children are printed too. */static voidxmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { int format = ctxt->format; xmlNodePtr tmp, root, unformattedNode = NULL, parent; xmlAttrPtr attr; xmlChar *start, *end; xmlOutputBufferPtr buf;
if (cur == NULL) return; buf = ctxt->buf;
root = cur; parent = cur->parent; while (1) { switch (cur->type) { case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur); break;
case XML_DTD_NODE: xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur); break;
case XML_DOCUMENT_FRAG_NODE: /* Always validate cur->parent when descending. */ if ((cur->parent == parent) && (cur->children != NULL)) { parent = cur; cur = cur->children; continue; } break;
case XML_ELEMENT_DECL: xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur); break;
case XML_ATTRIBUTE_DECL: xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur); break;
case XML_ENTITY_DECL: xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur); break;
case XML_ELEMENT_NODE: if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput)) xmlOutputBufferWrite(buf, ctxt->indent_size * (ctxt->level > ctxt->indent_nr ? ctxt->indent_nr : ctxt->level), ctxt->indent);
/* * Some users like lxml are known to pass nodes with a corrupted * tree structure. Fall back to a recursive call to handle this * case. */ if ((cur->parent != parent) && (cur->children != NULL)) { xmlNodeDumpOutputInternal(ctxt, cur); break; }
xmlOutputBufferWrite(buf, 1, "<"); if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); xmlOutputBufferWrite(buf, 1, ":"); } xmlOutputBufferWriteString(buf, (const char *)cur->name); if (cur->nsDef) xmlNsListDumpOutputCtxt(ctxt, cur->nsDef); for (attr = cur->properties; attr != NULL; attr = attr->next) xmlAttrDumpOutput(ctxt, attr);
if (cur->children == NULL) { if ((ctxt->options & XML_SAVE_NO_EMPTY) == 0) { if (ctxt->format == 2) xmlOutputBufferWriteWSNonSig(ctxt, 0); xmlOutputBufferWrite(buf, 2, "/>"); } else { if (ctxt->format == 2) xmlOutputBufferWriteWSNonSig(ctxt, 1); xmlOutputBufferWrite(buf, 3, "></"); if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); xmlOutputBufferWrite(buf, 1, ":"); } xmlOutputBufferWriteString(buf, (const char *)cur->name); if (ctxt->format == 2) xmlOutputBufferWriteWSNonSig(ctxt, 0); xmlOutputBufferWrite(buf, 1, ">"); } } else { if (ctxt->format == 1) { tmp = cur->children; while (tmp != NULL) { if ((tmp->type == XML_TEXT_NODE) || (tmp->type == XML_CDATA_SECTION_NODE) || (tmp->type == XML_ENTITY_REF_NODE)) { ctxt->format = 0; unformattedNode = cur; break; } tmp = tmp->next; } } if (ctxt->format == 2) xmlOutputBufferWriteWSNonSig(ctxt, 1); xmlOutputBufferWrite(buf, 1, ">"); if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n"); if (ctxt->level >= 0) ctxt->level++; parent = cur; cur = cur->children; continue; }
break;
case XML_TEXT_NODE: if (cur->content == NULL) break; if (cur->name != xmlStringTextNoenc) { xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape); } else { /* * Disable escaping, needed for XSLT */ xmlOutputBufferWriteString(buf, (const char *) cur->content); } break;
case XML_PI_NODE: if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput)) xmlOutputBufferWrite(buf, ctxt->indent_size * (ctxt->level > ctxt->indent_nr ? ctxt->indent_nr : ctxt->level), ctxt->indent);
if (cur->content != NULL) { xmlOutputBufferWrite(buf, 2, "<?"); xmlOutputBufferWriteString(buf, (const char *)cur->name); if (cur->content != NULL) { if (ctxt->format == 2) xmlOutputBufferWriteWSNonSig(ctxt, 0); else xmlOutputBufferWrite(buf, 1, " "); xmlOutputBufferWriteString(buf, (const char *)cur->content); } xmlOutputBufferWrite(buf, 2, "?>"); } else { xmlOutputBufferWrite(buf, 2, "<?"); xmlOutputBufferWriteString(buf, (const char *)cur->name); if (ctxt->format == 2) xmlOutputBufferWriteWSNonSig(ctxt, 0); xmlOutputBufferWrite(buf, 2, "?>"); } break;
case XML_COMMENT_NODE: if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput)) xmlOutputBufferWrite(buf, ctxt->indent_size * (ctxt->level > ctxt->indent_nr ? ctxt->indent_nr : ctxt->level), ctxt->indent);
if (cur->content != NULL) { xmlOutputBufferWrite(buf, 4, "<!--"); xmlOutputBufferWriteString(buf, (const char *)cur->content); xmlOutputBufferWrite(buf, 3, "-->"); } break;
case XML_ENTITY_REF_NODE: xmlOutputBufferWrite(buf, 1, "&"); xmlOutputBufferWriteString(buf, (const char *)cur->name); xmlOutputBufferWrite(buf, 1, ";"); break;
case XML_CDATA_SECTION_NODE: if (cur->content == NULL || *cur->content == '\0') { xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>"); } else { start = end = cur->content; while (*end != '\0') { if ((*end == ']') && (*(end + 1) == ']') && (*(end + 2) == '>')) { end = end + 2; xmlOutputBufferWrite(buf, 9, "<![CDATA["); xmlOutputBufferWrite(buf, end - start, (const char *)start); xmlOutputBufferWrite(buf, 3, "]]>"); start = end; } end++; } if (start != end) { xmlOutputBufferWrite(buf, 9, "<![CDATA["); xmlOutputBufferWriteString(buf, (const char *)start); xmlOutputBufferWrite(buf, 3, "]]>"); } } break;
case XML_ATTRIBUTE_NODE: xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur); break;
case XML_NAMESPACE_DECL: xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur); break;
default: break; }
while (1) { if (cur == root) return; if ((ctxt->format == 1) && (cur->type != XML_XINCLUDE_START) && (cur->type != XML_XINCLUDE_END)) xmlOutputBufferWrite(buf, 1, "\n"); if (cur->next != NULL) { cur = cur->next; break; }
cur = parent; /* cur->parent was validated when descending. */ parent = cur->parent;
if (cur->type == XML_ELEMENT_NODE) { if (ctxt->level > 0) ctxt->level--; if ((xmlIndentTreeOutput) && (ctxt->format == 1)) xmlOutputBufferWrite(buf, ctxt->indent_size * (ctxt->level > ctxt->indent_nr ? ctxt->indent_nr : ctxt->level), ctxt->indent);
xmlOutputBufferWrite(buf, 2, "</"); if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); xmlOutputBufferWrite(buf, 1, ":"); }
xmlOutputBufferWriteString(buf, (const char *)cur->name); if (ctxt->format == 2) xmlOutputBufferWriteWSNonSig(ctxt, 0); xmlOutputBufferWrite(buf, 1, ">");
if (cur == unformattedNode) { ctxt->format = format; unformattedNode = NULL; } } } }}
/** * xmlDocContentDumpOutput: * @cur: the document * * Dump an XML document. */static intxmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur) {#ifdef LIBXML_HTML_ENABLED xmlDtdPtr dtd; int is_xhtml = 0;#endif const xmlChar *oldenc = cur->encoding; const xmlChar *oldctxtenc = ctxt->encoding; const xmlChar *encoding = ctxt->encoding; xmlCharEncodingOutputFunc oldescape = ctxt->escape; xmlCharEncodingOutputFunc oldescapeAttr = ctxt->escapeAttr; xmlOutputBufferPtr buf = ctxt->buf; xmlCharEncoding enc; int switched_encoding = 0;
xmlInitParser();
if ((cur->type != XML_HTML_DOCUMENT_NODE) && (cur->type != XML_DOCUMENT_NODE)) return(-1);
if (ctxt->encoding != NULL) { cur->encoding = BAD_CAST ctxt->encoding; } else if (cur->encoding != NULL) { encoding = cur->encoding; }
if (((cur->type == XML_HTML_DOCUMENT_NODE) && ((ctxt->options & XML_SAVE_AS_XML) == 0) && ((ctxt->options & XML_SAVE_XHTML) == 0)) || (ctxt->options & XML_SAVE_AS_HTML)) {#ifdef LIBXML_HTML_ENABLED if (encoding != NULL) htmlSetMetaEncoding(cur, (const xmlChar *) encoding); if (encoding == NULL) encoding = htmlGetMetaEncoding(cur); if (encoding == NULL) encoding = BAD_CAST "HTML"; if ((encoding != NULL) && (oldctxtenc == NULL) && (buf->encoder == NULL) && (buf->conv == NULL)) { if (xmlSaveSwitchEncoding(ctxt, (const char*) encoding) < 0) { cur->encoding = oldenc; return(-1); } } if (ctxt->options & XML_SAVE_FORMAT) htmlDocContentDumpFormatOutput(buf, cur, (const char *)encoding, 1); else htmlDocContentDumpFormatOutput(buf, cur, (const char *)encoding, 0); if (ctxt->encoding != NULL) cur->encoding = oldenc; return(0);#else return(-1);#endif } else if ((cur->type == XML_DOCUMENT_NODE) || (ctxt->options & XML_SAVE_AS_XML) || (ctxt->options & XML_SAVE_XHTML)) { enc = xmlParseCharEncoding((const char*) encoding); if ((encoding != NULL) && (oldctxtenc == NULL) && (buf->encoder == NULL) && (buf->conv == NULL) && ((ctxt->options & XML_SAVE_NO_DECL) == 0)) { if ((enc != XML_CHAR_ENCODING_UTF8) && (enc != XML_CHAR_ENCODING_NONE) && (enc != XML_CHAR_ENCODING_ASCII)) { /* * we need to switch to this encoding but just for this * document since we output the XMLDecl the conversion * must be done to not generate not well formed documents. */ if (xmlSaveSwitchEncoding(ctxt, (const char*) encoding) < 0) { cur->encoding = oldenc; return(-1); } switched_encoding = 1; } if (ctxt->escape == xmlEscapeEntities) ctxt->escape = NULL; if (ctxt->escapeAttr == xmlEscapeEntities) ctxt->escapeAttr = NULL; }
/* * Save the XML declaration */ if ((ctxt->options & XML_SAVE_NO_DECL) == 0) { xmlOutputBufferWrite(buf, 14, "<?xml version="); if (cur->version != NULL) xmlBufWriteQuotedString(buf->buffer, cur->version); else xmlOutputBufferWrite(buf, 5, "\"1.0\""); if (encoding != NULL) { xmlOutputBufferWrite(buf, 10, " encoding="); xmlBufWriteQuotedString(buf->buffer, (xmlChar *) encoding); } switch (cur->standalone) { case 0: xmlOutputBufferWrite(buf, 16, " standalone=\"no\""); break; case 1: xmlOutputBufferWrite(buf, 17, " standalone=\"yes\""); break; } xmlOutputBufferWrite(buf, 3, "?>\n"); }
#ifdef LIBXML_HTML_ENABLED if (ctxt->options & XML_SAVE_XHTML) is_xhtml = 1; if ((ctxt->options & XML_SAVE_NO_XHTML) == 0) { dtd = xmlGetIntSubset(cur); if (dtd != NULL) { is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID); if (is_xhtml < 0) is_xhtml = 0; } }#endif if (cur->children != NULL) { xmlNodePtr child = cur->children;
while (child != NULL) { ctxt->level = 0;#ifdef LIBXML_HTML_ENABLED if (is_xhtml) xhtmlNodeDumpOutput(ctxt, child); else#endif xmlNodeDumpOutputInternal(ctxt, child); if ((child->type != XML_XINCLUDE_START) && (child->type != XML_XINCLUDE_END)) xmlOutputBufferWrite(buf, 1, "\n"); child = child->next; } } }
/* * Restore the state of the saving context at the end of the document */ if ((switched_encoding) && (oldctxtenc == NULL)) { xmlSaveClearEncoding(ctxt); ctxt->escape = oldescape; ctxt->escapeAttr = oldescapeAttr; } cur->encoding = oldenc; return(0);}
#ifdef LIBXML_HTML_ENABLED/************************************************************************ * * * Functions specific to XHTML serialization * * * ************************************************************************/
/** * xhtmlIsEmpty: * @node: the node * * Check if a node is an empty xhtml node * * Returns 1 if the node is an empty node, 0 if not and -1 in case of error */static intxhtmlIsEmpty(xmlNodePtr node) { if (node == NULL) return(-1); if (node->type != XML_ELEMENT_NODE) return(0); if ((node->ns != NULL) && (!xmlStrEqual(node->ns->href, XHTML_NS_NAME))) return(0); if (node->children != NULL) return(0); switch (node->name[0]) { case 'a': if (xmlStrEqual(node->name, BAD_CAST "area")) return(1); return(0); case 'b': if (xmlStrEqual(node->name, BAD_CAST "br")) return(1); if (xmlStrEqual(node->name, BAD_CAST "base")) return(1); if (xmlStrEqual(node->name, BAD_CAST "basefont")) return(1); return(0); case 'c': if (xmlStrEqual(node->name, BAD_CAST "col")) return(1); return(0); case 'f': if (xmlStrEqual(node->name, BAD_CAST "frame")) return(1); return(0); case 'h': if (xmlStrEqual(node->name, BAD_CAST "hr")) return(1); return(0); case 'i': if (xmlStrEqual(node->name, BAD_CAST "img")) return(1); if (xmlStrEqual(node->name, BAD_CAST "input")) return(1); if (xmlStrEqual(node->name, BAD_CAST "isindex")) return(1); return(0); case 'l': if (xmlStrEqual(node->name, BAD_CAST "link")) return(1); return(0); case 'm': if (xmlStrEqual(node->name, BAD_CAST "meta")) return(1); return(0); case 'p': if (xmlStrEqual(node->name, BAD_CAST "param")) return(1); return(0); } return(0);}
/** * xhtmlAttrListDumpOutput: * @cur: the first attribute pointer * * Dump a list of XML attributes */static voidxhtmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) { xmlAttrPtr xml_lang = NULL; xmlAttrPtr lang = NULL; xmlAttrPtr name = NULL; xmlAttrPtr id = NULL; xmlNodePtr parent; xmlOutputBufferPtr buf;
if (cur == NULL) return; buf = ctxt->buf; parent = cur->parent; while (cur != NULL) { if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "id"))) id = cur; else if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "name"))) name = cur; else if ((cur->ns == NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang"))) lang = cur; else if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) && (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml"))) xml_lang = cur; else if ((cur->ns == NULL) && ((cur->children == NULL) || (cur->children->content == NULL) || (cur->children->content[0] == 0)) && (htmlIsBooleanAttr(cur->name))) { if (cur->children != NULL) xmlFreeNode(cur->children); cur->children = xmlNewDocText(cur->doc, cur->name); if (cur->children != NULL) cur->children->parent = (xmlNodePtr) cur; } xmlAttrDumpOutput(ctxt, cur); cur = cur->next; } /* * C.8 */ if ((name != NULL) && (id == NULL)) { if ((parent != NULL) && (parent->name != NULL) && ((xmlStrEqual(parent->name, BAD_CAST "a")) || (xmlStrEqual(parent->name, BAD_CAST "p")) || (xmlStrEqual(parent->name, BAD_CAST "div")) || (xmlStrEqual(parent->name, BAD_CAST "img")) || (xmlStrEqual(parent->name, BAD_CAST "map")) || (xmlStrEqual(parent->name, BAD_CAST "applet")) || (xmlStrEqual(parent->name, BAD_CAST "form")) || (xmlStrEqual(parent->name, BAD_CAST "frame")) || (xmlStrEqual(parent->name, BAD_CAST "iframe")))) { xmlOutputBufferWrite(buf, 5, " id=\""); xmlAttrSerializeContent(buf, name); xmlOutputBufferWrite(buf, 1, "\""); } } /* * C.7. */ if ((lang != NULL) && (xml_lang == NULL)) { xmlOutputBufferWrite(buf, 11, " xml:lang=\""); xmlAttrSerializeContent(buf, lang); xmlOutputBufferWrite(buf, 1, "\""); } else if ((xml_lang != NULL) && (lang == NULL)) { xmlOutputBufferWrite(buf, 7, " lang=\""); xmlAttrSerializeContent(buf, xml_lang); xmlOutputBufferWrite(buf, 1, "\""); }}
/** * xhtmlNodeDumpOutput: * @buf: the XML buffer output * @doc: the XHTML document * @cur: the current node * @level: the imbrication level for indenting * @format: is formatting allowed * @encoding: an optional encoding string * * Dump an XHTML node, recursive behaviour, children are printed too. */static voidxhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { int format = ctxt->format, addmeta; xmlNodePtr tmp, root, unformattedNode = NULL, parent; xmlChar *start, *end; xmlOutputBufferPtr buf = ctxt->buf;
if (cur == NULL) return;
root = cur; parent = cur->parent; while (1) { switch (cur->type) { case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur); break;
case XML_NAMESPACE_DECL: xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur); break;
case XML_DTD_NODE: xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur); break;
case XML_DOCUMENT_FRAG_NODE: /* Always validate cur->parent when descending. */ if ((cur->parent == parent) && (cur->children != NULL)) { parent = cur; cur = cur->children; continue; } break;
case XML_ELEMENT_DECL: xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur); break;
case XML_ATTRIBUTE_DECL: xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur); break;
case XML_ENTITY_DECL: xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur); break;
case XML_ELEMENT_NODE: addmeta = 0;
if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput)) xmlOutputBufferWrite(buf, ctxt->indent_size * (ctxt->level > ctxt->indent_nr ? ctxt->indent_nr : ctxt->level), ctxt->indent);
/* * Some users like lxml are known to pass nodes with a corrupted * tree structure. Fall back to a recursive call to handle this * case. */ if ((cur->parent != parent) && (cur->children != NULL)) { xhtmlNodeDumpOutput(ctxt, cur); break; }
xmlOutputBufferWrite(buf, 1, "<"); if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); xmlOutputBufferWrite(buf, 1, ":"); }
xmlOutputBufferWriteString(buf, (const char *)cur->name); if (cur->nsDef) xmlNsListDumpOutputCtxt(ctxt, cur->nsDef); if ((xmlStrEqual(cur->name, BAD_CAST "html") && (cur->ns == NULL) && (cur->nsDef == NULL))) { /* * 3.1.1. Strictly Conforming Documents A.3.1.1 3/ */ xmlOutputBufferWriteString(buf, " xmlns=\"http://www.w3.org/1999/xhtml\""); } if (cur->properties != NULL) xhtmlAttrListDumpOutput(ctxt, cur->properties);
if ((parent != NULL) && (parent->parent == (xmlNodePtr) cur->doc) && xmlStrEqual(cur->name, BAD_CAST"head") && xmlStrEqual(parent->name, BAD_CAST"html")) {
tmp = cur->children; while (tmp != NULL) { if (xmlStrEqual(tmp->name, BAD_CAST"meta")) { xmlChar *httpequiv;
httpequiv = xmlGetProp(tmp, BAD_CAST"http-equiv"); if (httpequiv != NULL) { if (xmlStrcasecmp(httpequiv, BAD_CAST"Content-Type") == 0) { xmlFree(httpequiv); break; } xmlFree(httpequiv); } } tmp = tmp->next; } if (tmp == NULL) addmeta = 1; }
if (cur->children == NULL) { if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) && ((xhtmlIsEmpty(cur) == 1) && (addmeta == 0))) { /* * C.2. Empty Elements */ xmlOutputBufferWrite(buf, 3, " />"); } else { if (addmeta == 1) { xmlOutputBufferWrite(buf, 1, ">"); if (ctxt->format == 1) { xmlOutputBufferWrite(buf, 1, "\n"); if (xmlIndentTreeOutput) xmlOutputBufferWrite(buf, ctxt->indent_size * (ctxt->level + 1 > ctxt->indent_nr ? ctxt->indent_nr : ctxt->level + 1), ctxt->indent); } xmlOutputBufferWriteString(buf, "<meta http-equiv=\"Content-Type\" " "content=\"text/html; charset="); if (ctxt->encoding) { xmlOutputBufferWriteString(buf, (const char *)ctxt->encoding); } else { xmlOutputBufferWrite(buf, 5, "UTF-8"); } xmlOutputBufferWrite(buf, 4, "\" />"); if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n"); } else { xmlOutputBufferWrite(buf, 1, ">"); } /* * C.3. Element Minimization and Empty Element Content */ xmlOutputBufferWrite(buf, 2, "</"); if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); xmlOutputBufferWrite(buf, 1, ":"); } xmlOutputBufferWriteString(buf, (const char *)cur->name); xmlOutputBufferWrite(buf, 1, ">"); } } else { xmlOutputBufferWrite(buf, 1, ">"); if (addmeta == 1) { if (ctxt->format == 1) { xmlOutputBufferWrite(buf, 1, "\n"); if (xmlIndentTreeOutput) xmlOutputBufferWrite(buf, ctxt->indent_size * (ctxt->level + 1 > ctxt->indent_nr ? ctxt->indent_nr : ctxt->level + 1), ctxt->indent); } xmlOutputBufferWriteString(buf, "<meta http-equiv=\"Content-Type\" " "content=\"text/html; charset="); if (ctxt->encoding) { xmlOutputBufferWriteString(buf, (const char *)ctxt->encoding); } else { xmlOutputBufferWrite(buf, 5, "UTF-8"); } xmlOutputBufferWrite(buf, 4, "\" />"); }
if (ctxt->format == 1) { tmp = cur->children; while (tmp != NULL) { if ((tmp->type == XML_TEXT_NODE) || (tmp->type == XML_ENTITY_REF_NODE)) { unformattedNode = cur; ctxt->format = 0; break; } tmp = tmp->next; } }
if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n"); if (ctxt->level >= 0) ctxt->level++; parent = cur; cur = cur->children; continue; }
break;
case XML_TEXT_NODE: if (cur->content == NULL) break; if ((cur->name == xmlStringText) || (cur->name != xmlStringTextNoenc)) { xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape); } else { /* * Disable escaping, needed for XSLT */ xmlOutputBufferWriteString(buf, (const char *) cur->content); } break;
case XML_PI_NODE: if (cur->content != NULL) { xmlOutputBufferWrite(buf, 2, "<?"); xmlOutputBufferWriteString(buf, (const char *)cur->name); if (cur->content != NULL) { xmlOutputBufferWrite(buf, 1, " "); xmlOutputBufferWriteString(buf, (const char *)cur->content); } xmlOutputBufferWrite(buf, 2, "?>"); } else { xmlOutputBufferWrite(buf, 2, "<?"); xmlOutputBufferWriteString(buf, (const char *)cur->name); xmlOutputBufferWrite(buf, 2, "?>"); } break;
case XML_COMMENT_NODE: if (cur->content != NULL) { xmlOutputBufferWrite(buf, 4, "<!--"); xmlOutputBufferWriteString(buf, (const char *)cur->content); xmlOutputBufferWrite(buf, 3, "-->"); } break;
case XML_ENTITY_REF_NODE: xmlOutputBufferWrite(buf, 1, "&"); xmlOutputBufferWriteString(buf, (const char *)cur->name); xmlOutputBufferWrite(buf, 1, ";"); break;
case XML_CDATA_SECTION_NODE: if (cur->content == NULL || *cur->content == '\0') { xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>"); } else { start = end = cur->content; while (*end != '\0') { if (*end == ']' && *(end + 1) == ']' && *(end + 2) == '>') { end = end + 2; xmlOutputBufferWrite(buf, 9, "<![CDATA["); xmlOutputBufferWrite(buf, end - start, (const char *)start); xmlOutputBufferWrite(buf, 3, "]]>"); start = end; } end++; } if (start != end) { xmlOutputBufferWrite(buf, 9, "<![CDATA["); xmlOutputBufferWriteString(buf, (const char *)start); xmlOutputBufferWrite(buf, 3, "]]>"); } } break;
case XML_ATTRIBUTE_NODE: xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur); break;
default: break; }
while (1) { if (cur == root) return; if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n"); if (cur->next != NULL) { cur = cur->next; break; }
cur = parent; /* cur->parent was validated when descending. */ parent = cur->parent;
if (cur->type == XML_ELEMENT_NODE) { if (ctxt->level > 0) ctxt->level--; if ((xmlIndentTreeOutput) && (ctxt->format == 1)) xmlOutputBufferWrite(buf, ctxt->indent_size * (ctxt->level > ctxt->indent_nr ? ctxt->indent_nr : ctxt->level), ctxt->indent);
xmlOutputBufferWrite(buf, 2, "</"); if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); xmlOutputBufferWrite(buf, 1, ":"); }
xmlOutputBufferWriteString(buf, (const char *)cur->name); xmlOutputBufferWrite(buf, 1, ">");
if (cur == unformattedNode) { ctxt->format = format; unformattedNode = NULL; } } } }}#endif
/************************************************************************ * * * Public entry points * * * ************************************************************************/
/** * xmlSaveToFd: * @fd: a file descriptor number * @encoding: the encoding name to use or NULL * @options: a set of xmlSaveOptions * * Create a document saving context serializing to a file descriptor * with the encoding and the options given. * * Returns a new serialization context or NULL in case of error. */xmlSaveCtxtPtrxmlSaveToFd(int fd, const char *encoding, int options){ xmlSaveCtxtPtr ret;
ret = xmlNewSaveCtxt(encoding, options); if (ret == NULL) return(NULL); ret->buf = xmlOutputBufferCreateFd(fd, ret->handler); if (ret->buf == NULL) { xmlCharEncCloseFunc(ret->handler); xmlFreeSaveCtxt(ret); return(NULL); } return(ret);}
/** * xmlSaveToFilename: * @filename: a file name or an URL * @encoding: the encoding name to use or NULL * @options: a set of xmlSaveOptions * * Create a document saving context serializing to a filename or possibly * to an URL (but this is less reliable) with the encoding and the options * given. * * Returns a new serialization context or NULL in case of error. */xmlSaveCtxtPtrxmlSaveToFilename(const char *filename, const char *encoding, int options){ xmlSaveCtxtPtr ret; int compression = 0; /* TODO handle compression option */
ret = xmlNewSaveCtxt(encoding, options); if (ret == NULL) return(NULL); ret->buf = xmlOutputBufferCreateFilename(filename, ret->handler, compression); if (ret->buf == NULL) { xmlCharEncCloseFunc(ret->handler); xmlFreeSaveCtxt(ret); return(NULL); } return(ret);}
/** * xmlSaveToBuffer: * @buffer: a buffer * @encoding: the encoding name to use or NULL * @options: a set of xmlSaveOptions * * Create a document saving context serializing to a buffer * with the encoding and the options given * * Returns a new serialization context or NULL in case of error. */
xmlSaveCtxtPtrxmlSaveToBuffer(xmlBufferPtr buffer, const char *encoding, int options){ xmlSaveCtxtPtr ret;
ret = xmlNewSaveCtxt(encoding, options); if (ret == NULL) return(NULL); ret->buf = xmlOutputBufferCreateBuffer(buffer, ret->handler); if (ret->buf == NULL) { xmlCharEncCloseFunc(ret->handler); xmlFreeSaveCtxt(ret); return(NULL); } return(ret);}
/** * xmlSaveToIO: * @iowrite: an I/O write function * @ioclose: an I/O close function * @ioctx: an I/O handler * @encoding: the encoding name to use or NULL * @options: a set of xmlSaveOptions * * Create a document saving context serializing to a file descriptor * with the encoding and the options given * * Returns a new serialization context or NULL in case of error. */xmlSaveCtxtPtrxmlSaveToIO(xmlOutputWriteCallback iowrite, xmlOutputCloseCallback ioclose, void *ioctx, const char *encoding, int options){ xmlSaveCtxtPtr ret;
ret = xmlNewSaveCtxt(encoding, options); if (ret == NULL) return(NULL); ret->buf = xmlOutputBufferCreateIO(iowrite, ioclose, ioctx, ret->handler); if (ret->buf == NULL) { xmlCharEncCloseFunc(ret->handler); xmlFreeSaveCtxt(ret); return(NULL); } return(ret);}
/** * xmlSaveDoc: * @ctxt: a document saving context * @doc: a document * * Save a full document to a saving context * TODO: The function is not fully implemented yet as it does not return the * byte count but 0 instead * * Returns the number of byte written or -1 in case of error */longxmlSaveDoc(xmlSaveCtxtPtr ctxt, xmlDocPtr doc){ long ret = 0;
if ((ctxt == NULL) || (doc == NULL)) return(-1); if (xmlDocContentDumpOutput(ctxt, doc) < 0) return(-1); return(ret);}
/** * xmlSaveTree: * @ctxt: a document saving context * @cur: the top node of the subtree to save * * Save a subtree starting at the node parameter to a saving context * TODO: The function is not fully implemented yet as it does not return the * byte count but 0 instead * * Returns the number of byte written or -1 in case of error */longxmlSaveTree(xmlSaveCtxtPtr ctxt, xmlNodePtr cur){ long ret = 0;
if ((ctxt == NULL) || (cur == NULL)) return(-1);#ifdef LIBXML_HTML_ENABLED if (ctxt->options & XML_SAVE_XHTML) { xhtmlNodeDumpOutput(ctxt, cur); return(ret); } if (((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL) && (cur->doc->type == XML_HTML_DOCUMENT_NODE) && ((ctxt->options & XML_SAVE_AS_XML) == 0)) || (ctxt->options & XML_SAVE_AS_HTML)) { htmlNodeDumpOutputInternal(ctxt, cur); return(ret); }#endif xmlNodeDumpOutputInternal(ctxt, cur); return(ret);}
/** * xmlSaveFlush: * @ctxt: a document saving context * * Flush a document saving context, i.e. make sure that all bytes have * been output. * * Returns the number of byte written or -1 in case of error. */intxmlSaveFlush(xmlSaveCtxtPtr ctxt){ if (ctxt == NULL) return(-1); if (ctxt->buf == NULL) return(-1); return(xmlOutputBufferFlush(ctxt->buf));}
/** * xmlSaveClose: * @ctxt: a document saving context * * Close a document saving context, i.e. make sure that all bytes have * been output and free the associated data. * * Returns the number of byte written or -1 in case of error. */intxmlSaveClose(xmlSaveCtxtPtr ctxt){ int ret;
if (ctxt == NULL) return(-1); ret = xmlSaveFlush(ctxt); xmlFreeSaveCtxt(ctxt); return(ret);}
/** * xmlSaveSetEscape: * @ctxt: a document saving context * @escape: the escaping function * * Set a custom escaping function to be used for text in element content * * Returns 0 if successful or -1 in case of error. */intxmlSaveSetEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape){ if (ctxt == NULL) return(-1); ctxt->escape = escape; return(0);}
/** * xmlSaveSetAttrEscape: * @ctxt: a document saving context * @escape: the escaping function * * Set a custom escaping function to be used for text in attribute content * * Returns 0 if successful or -1 in case of error. */intxmlSaveSetAttrEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape){ if (ctxt == NULL) return(-1); ctxt->escapeAttr = escape; return(0);}
/************************************************************************ * * * Public entry points based on buffers * * * ************************************************************************/
/** * xmlBufAttrSerializeTxtContent: * @buf: and xmlBufPtr output * @doc: the document * @attr: the attribute node * @string: the text content * * Serialize text attribute values to an xmlBufPtr */voidxmlBufAttrSerializeTxtContent(xmlBufPtr buf, xmlDocPtr doc, xmlAttrPtr attr, const xmlChar * string){ xmlChar *base, *cur;
if (string == NULL) return; base = cur = (xmlChar *) string; while (*cur != 0) { if (*cur == '\n') { if (base != cur) xmlBufAdd(buf, base, cur - base); xmlBufAdd(buf, BAD_CAST " ", 5); cur++; base = cur; } else if (*cur == '\r') { if (base != cur) xmlBufAdd(buf, base, cur - base); xmlBufAdd(buf, BAD_CAST " ", 5); cur++; base = cur; } else if (*cur == '\t') { if (base != cur) xmlBufAdd(buf, base, cur - base); xmlBufAdd(buf, BAD_CAST "	", 4); cur++; base = cur; } else if (*cur == '"') { if (base != cur) xmlBufAdd(buf, base, cur - base); xmlBufAdd(buf, BAD_CAST """, 6); cur++; base = cur; } else if (*cur == '<') { if (base != cur) xmlBufAdd(buf, base, cur - base); xmlBufAdd(buf, BAD_CAST "<", 4); cur++; base = cur; } else if (*cur == '>') { if (base != cur) xmlBufAdd(buf, base, cur - base); xmlBufAdd(buf, BAD_CAST ">", 4); cur++; base = cur; } else if (*cur == '&') { if (base != cur) xmlBufAdd(buf, base, cur - base); xmlBufAdd(buf, BAD_CAST "&", 5); cur++; base = cur; } else if ((*cur >= 0x80) && (cur[1] != 0) && ((doc == NULL) || (doc->encoding == NULL))) { /* * We assume we have UTF-8 content. */ unsigned char tmp[12]; int val = 0, l = 1;
if (base != cur) xmlBufAdd(buf, base, cur - base); if (*cur < 0xC0) { xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr, NULL); xmlSerializeHexCharRef(tmp, *cur); xmlBufAdd(buf, (xmlChar *) tmp, -1); cur++; base = cur; continue; } else if (*cur < 0xE0) { val = (cur[0]) & 0x1F; val <<= 6; val |= (cur[1]) & 0x3F; l = 2; } else if ((*cur < 0xF0) && (cur [2] != 0)) { val = (cur[0]) & 0x0F; val <<= 6; val |= (cur[1]) & 0x3F; val <<= 6; val |= (cur[2]) & 0x3F; l = 3; } else if ((*cur < 0xF8) && (cur [2] != 0) && (cur[3] != 0)) { val = (cur[0]) & 0x07; val <<= 6; val |= (cur[1]) & 0x3F; val <<= 6; val |= (cur[2]) & 0x3F; val <<= 6; val |= (cur[3]) & 0x3F; l = 4; } if ((l == 1) || (!IS_CHAR(val))) { xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr, NULL); xmlSerializeHexCharRef(tmp, *cur); xmlBufAdd(buf, (xmlChar *) tmp, -1); cur++; base = cur; continue; } /* * We could do multiple things here. Just save * as a char ref */ xmlSerializeHexCharRef(tmp, val); xmlBufAdd(buf, (xmlChar *) tmp, -1); cur += l; base = cur; } else { cur++; } } if (base != cur) xmlBufAdd(buf, base, cur - base);}
/** * xmlAttrSerializeTxtContent: * @buf: the XML buffer output * @doc: the document * @attr: the attribute node * @string: the text content * * Serialize text attribute values to an xml simple buffer */voidxmlAttrSerializeTxtContent(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr attr, const xmlChar * string){ xmlBufPtr buffer;
if ((buf == NULL) || (string == NULL)) return; buffer = xmlBufFromBuffer(buf); if (buffer == NULL) return; xmlBufAttrSerializeTxtContent(buffer, doc, attr, string); xmlBufBackToBuffer(buffer);}
/** * xmlNodeDump: * @buf: the XML buffer output * @doc: the document * @cur: the current node * @level: the imbrication level for indenting * @format: is formatting allowed * * Dump an XML node, recursive behaviour,children are printed too. * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 * or xmlKeepBlanksDefault(0) was called. * Since this is using xmlBuffer structures it is limited to 2GB and somehow * deprecated, use xmlNodeDumpOutput() instead. * * Returns the number of bytes written to the buffer or -1 in case of error */intxmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, int format){ xmlBufPtr buffer; size_t ret;
if ((buf == NULL) || (cur == NULL)) return(-1); buffer = xmlBufFromBuffer(buf); if (buffer == NULL) return(-1); ret = xmlBufNodeDump(buffer, doc, cur, level, format); xmlBufBackToBuffer(buffer); if (ret > INT_MAX) return(-1); return(ret);}
/** * xmlBufNodeDump: * @buf: the XML buffer output * @doc: the document * @cur: the current node * @level: the imbrication level for indenting * @format: is formatting allowed * * Dump an XML node, recursive behaviour,children are printed too. * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 * or xmlKeepBlanksDefault(0) was called * * Returns the number of bytes written to the buffer, in case of error 0 * is returned or @buf stores the error */
size_txmlBufNodeDump(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, int format){ size_t use; int ret; xmlOutputBufferPtr outbuf; int oldalloc;
xmlInitParser();
if (cur == NULL) { return (-1); } if (buf == NULL) { return (-1); } outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); if (outbuf == NULL) { xmlSaveErrMemory("creating buffer"); return (-1); } memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer)); outbuf->buffer = buf; outbuf->encoder = NULL; outbuf->writecallback = NULL; outbuf->closecallback = NULL; outbuf->context = NULL; outbuf->written = 0;
use = xmlBufUse(buf); oldalloc = xmlBufGetAllocationScheme(buf); xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL); xmlBufSetAllocationScheme(buf, oldalloc); xmlFree(outbuf); ret = xmlBufUse(buf) - use; return (ret);}
/** * xmlElemDump: * @f: the FILE * for the output * @doc: the document * @cur: the current node * * Dump an XML/HTML node, recursive behaviour, children are printed too. */voidxmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur){ xmlOutputBufferPtr outbuf;
xmlInitParser();
if (cur == NULL) { return; }
outbuf = xmlOutputBufferCreateFile(f, NULL); if (outbuf == NULL) return; if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {#ifdef LIBXML_HTML_ENABLED htmlNodeDumpOutput(outbuf, doc, cur, NULL);#else xmlSaveErr(XML_ERR_INTERNAL_ERROR, cur, "HTML support not compiled in\n");#endif /* LIBXML_HTML_ENABLED */ } else xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL); xmlOutputBufferClose(outbuf);}
/************************************************************************ * * * Saving functions front-ends * * * ************************************************************************/
/** * xmlNodeDumpOutput: * @buf: the XML buffer output * @doc: the document * @cur: the current node * @level: the imbrication level for indenting * @format: is formatting allowed * @encoding: an optional encoding string * * Dump an XML node, recursive behaviour, children are printed too. * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 * or xmlKeepBlanksDefault(0) was called */voidxmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, int format, const char *encoding){ xmlSaveCtxt ctxt;#ifdef LIBXML_HTML_ENABLED xmlDtdPtr dtd; int is_xhtml = 0;#endif
(void) doc;
xmlInitParser();
if ((buf == NULL) || (cur == NULL)) return;
if (encoding == NULL) encoding = "UTF-8";
memset(&ctxt, 0, sizeof(ctxt)); ctxt.buf = buf; ctxt.level = level; ctxt.format = format ? 1 : 0; ctxt.encoding = (const xmlChar *) encoding; xmlSaveCtxtInit(&ctxt); ctxt.options |= XML_SAVE_AS_XML;
#ifdef LIBXML_HTML_ENABLED dtd = xmlGetIntSubset(doc); if (dtd != NULL) { is_xhtml = xmlIsXHTML(dtd->SystemID, dtd->ExternalID); if (is_xhtml < 0) is_xhtml = 0; }
if (is_xhtml) xhtmlNodeDumpOutput(&ctxt, cur); else#endif xmlNodeDumpOutputInternal(&ctxt, cur);}
/** * xmlDocDumpFormatMemoryEnc: * @out_doc: Document to generate XML text from * @doc_txt_ptr: Memory pointer for allocated XML text * @doc_txt_len: Length of the generated XML text * @txt_encoding: Character encoding to use when generating XML text * @format: should formatting spaces been added * * Dump the current DOM tree into memory using the character encoding specified * by the caller. Note it is up to the caller of this function to free the * allocated memory with xmlFree(). * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 * or xmlKeepBlanksDefault(0) was called */
voidxmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr, int * doc_txt_len, const char * txt_encoding, int format) { xmlSaveCtxt ctxt; int dummy = 0; xmlOutputBufferPtr out_buff = NULL; xmlCharEncodingHandlerPtr conv_hdlr = NULL;
if (doc_txt_len == NULL) { doc_txt_len = &dummy; /* Continue, caller just won't get length */ }
if (doc_txt_ptr == NULL) { *doc_txt_len = 0; return; }
*doc_txt_ptr = NULL; *doc_txt_len = 0;
if (out_doc == NULL) { /* No document, no output */ return; }
/* * Validate the encoding value, if provided. * This logic is copied from xmlSaveFileEnc. */
if (txt_encoding == NULL) txt_encoding = (const char *) out_doc->encoding; if (txt_encoding != NULL) { conv_hdlr = xmlFindCharEncodingHandler(txt_encoding); if ( conv_hdlr == NULL ) { xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, (xmlNodePtr) out_doc, txt_encoding); return; } }
if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) { xmlSaveErrMemory("creating buffer"); xmlCharEncCloseFunc(conv_hdlr); return; }
memset(&ctxt, 0, sizeof(ctxt)); ctxt.buf = out_buff; ctxt.level = 0; ctxt.format = format ? 1 : 0; ctxt.encoding = (const xmlChar *) txt_encoding; xmlSaveCtxtInit(&ctxt); ctxt.options |= XML_SAVE_AS_XML; xmlDocContentDumpOutput(&ctxt, out_doc); xmlOutputBufferFlush(out_buff); if (out_buff->conv != NULL) { *doc_txt_len = xmlBufUse(out_buff->conv); *doc_txt_ptr = xmlStrndup(xmlBufContent(out_buff->conv), *doc_txt_len); } else { *doc_txt_len = xmlBufUse(out_buff->buffer); *doc_txt_ptr = xmlStrndup(xmlBufContent(out_buff->buffer),*doc_txt_len); } (void)xmlOutputBufferClose(out_buff);
if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) { *doc_txt_len = 0; xmlSaveErrMemory("creating output"); }
return;}
/** * xmlDocDumpMemory: * @cur: the document * @mem: OUT: the memory pointer * @size: OUT: the memory length * * Dump an XML document in memory and return the #xmlChar * and it's size * in bytes. It's up to the caller to free the memory with xmlFree(). * The resulting byte array is zero terminated, though the last 0 is not * included in the returned size. */voidxmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) { xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);}
/** * xmlDocDumpFormatMemory: * @cur: the document * @mem: OUT: the memory pointer * @size: OUT: the memory length * @format: should formatting spaces been added * * * Dump an XML document in memory and return the #xmlChar * and it's size. * It's up to the caller to free the memory with xmlFree(). * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 * or xmlKeepBlanksDefault(0) was called */voidxmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) { xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);}
/** * xmlDocDumpMemoryEnc: * @out_doc: Document to generate XML text from * @doc_txt_ptr: Memory pointer for allocated XML text * @doc_txt_len: Length of the generated XML text * @txt_encoding: Character encoding to use when generating XML text * * Dump the current DOM tree into memory using the character encoding specified * by the caller. Note it is up to the caller of this function to free the * allocated memory with xmlFree(). */
voidxmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr, int * doc_txt_len, const char * txt_encoding) { xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len, txt_encoding, 0);}
/** * xmlDocFormatDump: * @f: the FILE* * @cur: the document * @format: should formatting spaces been added * * Dump an XML document to an open FILE. * * returns: the number of bytes written or -1 in case of failure. * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 * or xmlKeepBlanksDefault(0) was called */intxmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) { xmlSaveCtxt ctxt; xmlOutputBufferPtr buf; const char * encoding; xmlCharEncodingHandlerPtr handler = NULL; int ret;
if (cur == NULL) { return(-1); } encoding = (const char *) cur->encoding;
if (encoding != NULL) { handler = xmlFindCharEncodingHandler(encoding); if (handler == NULL) { xmlFree((char *) cur->encoding); cur->encoding = NULL; encoding = NULL; } } buf = xmlOutputBufferCreateFile(f, handler); if (buf == NULL) return(-1); memset(&ctxt, 0, sizeof(ctxt)); ctxt.buf = buf; ctxt.level = 0; ctxt.format = format ? 1 : 0; ctxt.encoding = (const xmlChar *) encoding; xmlSaveCtxtInit(&ctxt); ctxt.options |= XML_SAVE_AS_XML; xmlDocContentDumpOutput(&ctxt, cur);
ret = xmlOutputBufferClose(buf); return(ret);}
/** * xmlDocDump: * @f: the FILE* * @cur: the document * * Dump an XML document to an open FILE. * * returns: the number of bytes written or -1 in case of failure. */intxmlDocDump(FILE *f, xmlDocPtr cur) { return(xmlDocFormatDump (f, cur, 0));}
/** * xmlSaveFileTo: * @buf: an output I/O buffer * @cur: the document * @encoding: the encoding if any assuming the I/O layer handles the transcoding * * Dump an XML document to an I/O buffer. * Warning ! This call xmlOutputBufferClose() on buf which is not available * after this call. * * returns: the number of bytes written or -1 in case of failure. */intxmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) { xmlSaveCtxt ctxt; int ret;
if (buf == NULL) return(-1); if (cur == NULL) { xmlOutputBufferClose(buf); return(-1); } memset(&ctxt, 0, sizeof(ctxt)); ctxt.buf = buf; ctxt.level = 0; ctxt.format = 0; ctxt.encoding = (const xmlChar *) encoding; xmlSaveCtxtInit(&ctxt); ctxt.options |= XML_SAVE_AS_XML; xmlDocContentDumpOutput(&ctxt, cur); ret = xmlOutputBufferClose(buf); return(ret);}
/** * xmlSaveFormatFileTo: * @buf: an output I/O buffer * @cur: the document * @encoding: the encoding if any assuming the I/O layer handles the transcoding * @format: should formatting spaces been added * * Dump an XML document to an I/O buffer. * Warning ! This call xmlOutputBufferClose() on buf which is not available * after this call. * * returns: the number of bytes written or -1 in case of failure. */intxmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding, int format){ xmlSaveCtxt ctxt; int ret;
if (buf == NULL) return(-1); if ((cur == NULL) || ((cur->type != XML_DOCUMENT_NODE) && (cur->type != XML_HTML_DOCUMENT_NODE))) { xmlOutputBufferClose(buf); return(-1); } memset(&ctxt, 0, sizeof(ctxt)); ctxt.buf = buf; ctxt.level = 0; ctxt.format = format ? 1 : 0; ctxt.encoding = (const xmlChar *) encoding; xmlSaveCtxtInit(&ctxt); ctxt.options |= XML_SAVE_AS_XML; xmlDocContentDumpOutput(&ctxt, cur); ret = xmlOutputBufferClose(buf); return (ret);}
/** * xmlSaveFormatFileEnc: * @filename: the filename or URL to output * @cur: the document being saved * @encoding: the name of the encoding to use or NULL. * @format: should formatting spaces be added. * * Dump an XML document to a file or an URL. * * Returns the number of bytes written or -1 in case of error. * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 * or xmlKeepBlanksDefault(0) was called */intxmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur, const char * encoding, int format ) { xmlSaveCtxt ctxt; xmlOutputBufferPtr buf; xmlCharEncodingHandlerPtr handler = NULL; int ret;
if (cur == NULL) return(-1);
if (encoding == NULL) encoding = (const char *) cur->encoding;
if (encoding != NULL) {
handler = xmlFindCharEncodingHandler(encoding); if (handler == NULL) return(-1); }
#ifdef LIBXML_ZLIB_ENABLED if (cur->compression < 0) cur->compression = xmlGetCompressMode();#endif /* * save the content to a temp buffer. */ buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression); if (buf == NULL) return(-1); memset(&ctxt, 0, sizeof(ctxt)); ctxt.buf = buf; ctxt.level = 0; ctxt.format = format ? 1 : 0; ctxt.encoding = (const xmlChar *) encoding; xmlSaveCtxtInit(&ctxt); ctxt.options |= XML_SAVE_AS_XML;
xmlDocContentDumpOutput(&ctxt, cur);
ret = xmlOutputBufferClose(buf); return(ret);}
/** * xmlSaveFileEnc: * @filename: the filename (or URL) * @cur: the document * @encoding: the name of an encoding (or NULL) * * Dump an XML document, converting it to the given encoding * * returns: the number of bytes written or -1 in case of failure. */intxmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) { return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) );}
/** * xmlSaveFormatFile: * @filename: the filename (or URL) * @cur: the document * @format: should formatting spaces been added * * Dump an XML document to a file. Will use compression if * compiled in and enabled. If @filename is "-" the stdout file is * used. If @format is set then the document will be indented on output. * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 * or xmlKeepBlanksDefault(0) was called * * returns: the number of bytes written or -1 in case of failure. */intxmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) { return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) );}
/** * xmlSaveFile: * @filename: the filename (or URL) * @cur: the document * * Dump an XML document to a file. Will use compression if * compiled in and enabled. If @filename is "-" the stdout file is * used. * returns: the number of bytes written or -1 in case of failure. */intxmlSaveFile(const char *filename, xmlDocPtr cur) { return(xmlSaveFormatFileEnc(filename, cur, NULL, 0));}
#endif /* LIBXML_OUTPUT_ENABLED */