00001 #include "XMLLoadSave.h"
00002 #include <iostream>
00003 #include <string>
00004 #include <libxml/xmlmemory.h>
00005 #include <libxml/parser.h>
00006 #include <libxml/parserInternals.h>
00007 #include <libxml/xmlsave.h>
00008 #include <libxml/xmlversion.h>
00009 #include <errno.h>
00010
00011 #if LIBXML_VERSION < 20617
00012
00013
00014
00015
00016
00017
00018 typedef enum {
00019 XML_SAVE_FORMAT = 1<<0
00020 } xmlSaveOption;
00021 #endif
00022
00023 using namespace std;
00024
00025 unsigned int XMLLoadSave::AutoInit::libxmlrefc=0;
00026
00027 XMLLoadSave::AutoInit::AutoInit() {
00028 if(libxmlrefc==0) {
00029
00030 xmlInitParser();
00031 xmlSubstituteEntitiesDefault(1);
00032 xmlKeepBlanksDefault(1);
00033 xmlLineNumbersDefault(1);
00034 xmlIndentTreeOutput = 1;
00035 }
00036 libxmlrefc++;
00037 }
00038
00039 XMLLoadSave::AutoInit::~AutoInit() {
00040 libxmlrefc--;
00041 if(libxmlrefc==0) {
00042 xmlCleanupParser();
00043
00044 }
00045 }
00046
00047
00048 #if LIBXML_VERSION >= 20623
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067 static int xmlEscapeMinimalEntities(unsigned char* out, int *outlen, const xmlChar* in, int *inlen) {
00068 unsigned char* outstart = out;
00069 const unsigned char* base = in;
00070 unsigned char* outend = out + *outlen;
00071 const unsigned char* inend;
00072 int val;
00073
00074 inend = in + (*inlen);
00075
00076 while ((in < inend) && (out < outend)) {
00077 if (*in == '<') {
00078 if (outend - out < 4) break;
00079 *out++ = '&';
00080 *out++ = 'l';
00081 *out++ = 't';
00082 *out++ = ';';
00083 in++;
00084 continue;
00085 } else if (*in == '>') {
00086 if (outend - out < 4) break;
00087 *out++ = '&';
00088 *out++ = 'g';
00089 *out++ = 't';
00090 *out++ = ';';
00091 in++;
00092 continue;
00093 } else if (*in == '&') {
00094 if (outend - out < 5) break;
00095 *out++ = '&';
00096 *out++ = 'a';
00097 *out++ = 'm';
00098 *out++ = 'p';
00099 *out++ = ';';
00100 in++;
00101 continue;
00102 } else if (((*in >= 0x20) && (*in < 0x80)) ||
00103 (*in == '\n') || (*in == '\t')) {
00104
00105
00106
00107 *out++ = *in++;
00108 continue;
00109 } else if (*in >= 0x80) {
00110
00111
00112
00113 if (outend - out < 10) break;
00114
00115 if (*in < 0xC0) {
00116 std::cerr << "XMLLoadSave::xmlEscapeMinimalEntities encountered non-UTF8 data: " << *in << std::endl;
00117 in++;
00118 goto error;
00119 } else if (*in < 0xE0) {
00120 if (inend - in < 2) break;
00121 val = (in[0]) & 0x1F;
00122 val <<= 6;
00123 val |= (in[1]) & 0x3F;
00124 *out++ = *in++;
00125 *out++ = *in++;
00126 } else if (*in < 0xF0) {
00127 if (inend - in < 3) break;
00128 val = (in[0]) & 0x0F;
00129 val <<= 6;
00130 val |= (in[1]) & 0x3F;
00131 val <<= 6;
00132 val |= (in[2]) & 0x3F;
00133 *out++ = *in++;
00134 *out++ = *in++;
00135 *out++ = *in++;
00136 } else if (*in < 0xF8) {
00137 if (inend - in < 4) break;
00138 val = (in[0]) & 0x07;
00139 val <<= 6;
00140 val |= (in[1]) & 0x3F;
00141 val <<= 6;
00142 val |= (in[2]) & 0x3F;
00143 val <<= 6;
00144 val |= (in[3]) & 0x3F;
00145 *out++ = *in++;
00146 *out++ = *in++;
00147 *out++ = *in++;
00148 *out++ = *in++;
00149 } else {
00150 std::cerr << "XMLLoadSave::xmlEscapeMinimalEntities encountered invalid UTF8 data " << *in << std::endl;
00151 in++;
00152 goto error;
00153 }
00154 if (!IS_CHAR(val)) {
00155 std::cerr << "XMLLoadSave::xmlEscapeMinimalEntities encountered unknown UTF8 data " << *in << std::endl;
00156 goto error;
00157 }
00158
00159 } else if (IS_BYTE_CHAR(*in)) {
00160 if (outend - out < 6) break;
00161 *out++ = *in++;
00162 } else {
00163 xmlGenericError(xmlGenericErrorContext,
00164 "xmlEscapeEntities : char out of range\n");
00165 in++;
00166 goto error;
00167 }
00168 }
00169 *outlen = out - outstart;
00170 *inlen = in - base;
00171 return(0);
00172 error:
00173 *outlen = out - outstart;
00174 *inlen = in - base;
00175 return(-1);
00176 }
00177 #endif
00178
00179 XMLLoadSave::XMLLoadSave()
00180 : xmldocument(NULL), compressionLevel(-1), autoFormat(true), libxmlInit()
00181 {}
00182
00183 XMLLoadSave::XMLLoadSave(const XMLLoadSave& xls)
00184 : LoadSave(xls), xmldocument(xls.xmldocument==NULL?NULL:xmlCopyDoc(xls.xmldocument,true)), compressionLevel(xls.compressionLevel), autoFormat(xls.autoFormat), libxmlInit()
00185 {}
00186
00187 XMLLoadSave& XMLLoadSave::operator=(const XMLLoadSave& xls) {
00188 LoadSave::operator=(xls);
00189 if(xls.xmldocument==NULL)
00190 clearParseTree();
00191 else
00192 setParseTree(xmlCopyDoc(xls.xmldocument,true));
00193 compressionLevel = xls.compressionLevel;
00194 autoFormat=xls.autoFormat;
00195 return *this;
00196 }
00197
00198 XMLLoadSave::~XMLLoadSave() {
00199 clearParseTree();
00200 }
00201
00202 void XMLLoadSave::reportError(const std::string& context, const bad_format& err) const {
00203 cerr << context << endl;
00204 cerr << " " << err.what() << endl;
00205 if(err.getNode()!=NULL) {
00206 xmlChar* path=xmlGetNodePath(err.getNode());
00207 xmlChar* uri = xmlNodeGetBase(err.getNode()->doc,err.getNode());
00208 std::string file;
00209 if(uri!=NULL && uri[0]!='\0')
00210 file = std::string(" of ") + (char*)uri + std::string(":");
00211 else
00212 file = " at line ";
00213 xmlFree(uri);
00214 cerr << " Error was flagged during processing" << file << xmlGetLineNo(err.getNode()) << ":\n"
00215 << " " << (char*)path << " '" << (char*)xmlNodeGetContent(err.getNode()) << '\'' << endl;
00216 xmlFree(path);
00217 }
00218 }
00219
00220 unsigned int XMLLoadSave::getBinSize() const {
00221 try {
00222 if(xmldocument==NULL)
00223 setParseTree(xmlNewDoc((const xmlChar*)"1.0"));
00224 if(compressionLevel>=0)
00225 xmlSetDocCompressMode(xmldocument,compressionLevel);
00226 xmlNode * cur = FindRootXMLElement(xmldocument);
00227 saveXML(cur);
00228 xmlChar* buf=NULL;
00229 int size=0;
00230
00231
00232 xmlDocDumpFormatMemory(xmldocument, &buf, &size, autoFormat);
00233 xmlFree(buf);
00234 return size;
00235 } catch(const bad_format& err) {
00236 reportError("During calculation of size:",err);
00237 return 0;
00238 }
00239 }
00240 unsigned int XMLLoadSave::loadBuffer(const char buf[], unsigned int len, const char* filename) {
00241 if(xmldocument!=NULL) {
00242 xmlFreeDoc(xmldocument);
00243 xmldocument=NULL;
00244 }
00245
00246
00247 xmlParserCtxt* ctxt=xmlCreateMemoryParserCtxt(buf,len);
00248 if(ctxt==NULL) {
00249 cerr << "Error: " << (filename ? filename : "") << " XMLLoadSave could not create memory parser context" << endl;
00250 return 0;
00251 }
00252 xmldocument = xmlParseDocument(ctxt)==0?ctxt->myDoc:NULL;
00253 if (xmldocument == NULL ) {
00254 cerr << "Error: XMLLoadSave buffer not parsed successfully. (xml syntax error)\n"
00255 << " Attempting to recover..." << endl;
00256 xmlFreeParserCtxt(ctxt);
00257 ctxt=xmlCreateMemoryParserCtxt(buf,len);
00258 if(ctxt==NULL) {
00259 cerr << "Error: XMLLoadSave could not create memory parser context" << endl;
00260 return 0;
00261 }
00262 ctxt->recovery=1;
00263 xmldocument = xmlParseDocument(ctxt)==0?ctxt->myDoc:NULL;
00264 if(xmldocument==NULL) {
00265 cerr << "Error: XMLLoadSave recovery failed." << endl;
00266 xmlFreeParserCtxt(ctxt);
00267 return 0;
00268 }
00269 }
00270 unsigned int size=ctxt->nbChars;
00271 xmlFreeParserCtxt(ctxt);
00272
00273 try {
00274 xmlNodePtr cur = FindRootXMLElement(xmldocument);
00275 loadXML(cur);
00276 return size;
00277 } catch(const bad_format& err) {
00278 reportError("During load of memory buffer:",err);
00279 xmlFreeDoc(xmldocument);
00280 xmldocument=NULL;
00281 return 0;
00282 }
00283 }
00284 unsigned int XMLLoadSave::saveBuffer(char buf[], unsigned int len) const {
00285 xmlBufferPtr xmlbuf = NULL;
00286 try {
00287 if(xmldocument==NULL)
00288 setParseTree(xmlNewDoc((const xmlChar*)"1.0"));
00289 if(compressionLevel>=0)
00290 xmlSetDocCompressMode(xmldocument,compressionLevel);
00291 xmlNode * cur = FindRootXMLElement(xmldocument);
00292 saveXML(cur);
00293 #if LIBXML_VERSION < 20623
00294
00295 (void)xmlbuf;
00296 xmlChar* xbuf=NULL;
00297 int size=0;
00298 xmlDocDumpFormatMemory(xmldocument, &xbuf, &size, autoFormat);
00299 if((unsigned int)size<=len)
00300 memcpy(buf,xbuf,size);
00301 else {
00302 cerr << "Error: XMLLoadSave::saveBuffer xmlDocDumpFormatMemory returned larger region than the target buffer" << endl;
00303 size=0;
00304 }
00305 xmlFree(xbuf);
00306 return size;
00307 #else
00308 xmlbuf = xmlBufferCreate();
00309 xmlSaveCtxtPtr ctxt = xmlSaveToBuffer(xmlbuf, NULL, (autoFormat ? XML_SAVE_FORMAT : 0));
00310 xmlSaveSetEscape(ctxt,xmlEscapeMinimalEntities);
00311 xmlSaveSetAttrEscape(ctxt,xmlEscapeMinimalEntities);
00312 size_t size = xmlSaveDoc(ctxt,xmldocument);
00313 xmlSaveClose(ctxt);
00314 ctxt=NULL;
00315 if(size==(size_t)-1) {
00316 cerr << "Error: XMLLoadSave::saveBuffer: xmlSaveDoc returned -1" << endl;
00317 return 0;
00318 }
00319 size=xmlBufferLength(xmlbuf);
00320 if(size<=len)
00321 memcpy(buf,xmlBufferContent(xmlbuf),size);
00322 else {
00323 cerr << "Error: XMLLoadSave::saveBuffer xmlSaveDoc returned larger region than the target buffer" << endl;
00324 size=0;
00325 }
00326 xmlBufferFree(xmlbuf);
00327 xmlbuf=NULL;
00328 return size;
00329 #endif
00330 } catch(const bad_format& err) {
00331 reportError("During save to memory buffer:",err);
00332 xmlBufferFree(xmlbuf);
00333 return 0;
00334 } catch(...) {
00335 xmlBufferFree(xmlbuf);
00336 throw;
00337 }
00338 }
00339
00340 unsigned int XMLLoadSave::loadFile(const char* filename) {
00341 if(xmldocument!=NULL) {
00342 xmlFreeDoc(xmldocument);
00343 xmldocument=NULL;
00344 }
00345
00346
00347 xmlParserCtxt* ctxt=xmlCreateFileParserCtxt(filename);
00348 if(ctxt==NULL) {
00349 cerr << "Error: XMLLoadSave could not create parser context for '"<< filename << "'" << endl;
00350 return 0;
00351 }
00352 xmldocument = xmlParseDocument(ctxt)==0?ctxt->myDoc:NULL;
00353 if (xmldocument == NULL ) {
00354 cerr << "Error: XMLLoadSave document '" << filename << "' not parsed successfully. (file not found or xml syntax error)\n"
00355 << " Attempting to recover..." << endl;
00356 xmlFreeParserCtxt(ctxt);
00357 ctxt=xmlCreateFileParserCtxt(filename);
00358 if(ctxt==NULL) {
00359 cerr << "Error: XMLLoadSave could not create parser context for '"<< filename << "'" << endl;
00360 return 0;
00361 }
00362 ctxt->recovery=1;
00363 xmldocument = xmlParseDocument(ctxt)==0?ctxt->myDoc:NULL;
00364 if(xmldocument==NULL) {
00365 cerr << "Error: XMLLoadSave document '" << filename << "' recovery failed." << endl;
00366 xmlFreeParserCtxt(ctxt);
00367 return 0;
00368 }
00369 }
00370 unsigned int size=ctxt->nbChars;
00371 xmlFreeParserCtxt(ctxt);
00372
00373 try {
00374 xmlNodePtr cur = FindRootXMLElement(xmldocument);
00375 loadXML(cur);
00376 return size;
00377 } catch(const bad_format& err) {
00378 string context("During load of '");
00379 context+=filename;
00380 context+="':";
00381 reportError(context,err);
00382 xmlFreeDoc(xmldocument);
00383 xmldocument=NULL;
00384 return 0;
00385 }
00386 }
00387 unsigned int XMLLoadSave::saveFile(const char* filename) const {
00388 xmlBufferPtr xmlbuf = NULL;
00389 try {
00390 if(xmldocument==NULL)
00391 setParseTree(xmlNewDoc((const xmlChar*)"1.0"));
00392 if(compressionLevel>=0)
00393 xmlSetDocCompressMode(xmldocument,compressionLevel);
00394 xmlNode * cur = FindRootXMLElement(xmldocument);
00395 saveXML(cur);
00396 #if LIBXML_VERSION < 20623
00397
00398
00399
00400 (void)xmlbuf;
00401 int size=xmlSaveFormatFile (filename, xmldocument, autoFormat);
00402 if(size==-1)
00403 cerr << "Error: XMLLoadSave::saveFile: xmlSaveFormatFile(\"" << filename << "\",...) returned -1" << endl;
00404 return size==-1?0:size;
00405 #else
00406 FILE* f = fopen(filename,"w");
00407 if(f==NULL) {
00408 std::cerr << "*** WARNING XMLLoadSave::saveFile: could not open file for saving \"" << filename << "\"" << std::endl;
00409 return 0;
00410 }
00411
00412 xmlbuf = xmlBufferCreate();
00413 xmlSaveCtxtPtr ctxt = xmlSaveToBuffer(xmlbuf, NULL, (autoFormat ? XML_SAVE_FORMAT : 0));
00414
00415 xmlSaveSetEscape(ctxt,xmlEscapeMinimalEntities);
00416 xmlSaveSetAttrEscape(ctxt,xmlEscapeMinimalEntities);
00417 size_t size = xmlSaveDoc(ctxt,xmldocument);
00418 xmlSaveClose(ctxt);
00419 ctxt=NULL;
00420 if(size==(size_t)-1) {
00421 cerr << "Error: XMLLoadSave::saveFile: xmlSaveDoc(\"" << filename << "\",...) returned -1" << endl;
00422 fclose(f);
00423 return 0;
00424 }
00425 size=xmlBufferLength(xmlbuf);
00426 size_t wrote=fwrite(xmlBufferContent(xmlbuf),1,xmlBufferLength(xmlbuf),f);
00427 if(wrote!=size)
00428 std::cerr << "*** WARNING XMLLoadSave::saveFile: short write (wrote " << wrote << ", expected " << size << ")" << std::endl;
00429 int err=fclose(f);
00430 if(err!=0) {
00431 std::cerr << "*** WARNING XMLLoadSave::saveFile: error '" << strerror(errno) << "' while closing " << filename << std::endl;
00432 return 0;
00433 }
00434 xmlBufferFree(xmlbuf);
00435 xmlbuf=NULL;
00436 return size;
00437 #endif
00438 } catch(const bad_format& err) {
00439 string context("During save to '");
00440 context+=filename;
00441 context+="':";
00442 reportError(context,err);
00443 xmlBufferFree(xmlbuf);
00444 return 0;
00445 } catch(...) {
00446 xmlBufferFree(xmlbuf);
00447 throw;
00448 }
00449 }
00450
00451 unsigned int XMLLoadSave::loadFileStream(FILE* f, const char* filename) {
00452 if(xmldocument!=NULL) {
00453 xmlFreeDoc(xmldocument);
00454 xmldocument=NULL;
00455 }
00456
00457
00458
00459 xmlParserCtxt* ctxt=xmlCreateIOParserCtxt(NULL,NULL,fileReadCallback,fileCloseCallback,f,XML_CHAR_ENCODING_UTF8);
00460 if(ctxt==NULL) {
00461 cerr << "Error: XMLLoadSave could not create file stream parser context" << endl;
00462 return 0;
00463 }
00464 ctxt->recovery=1;
00465 xmldocument = (xmlParseDocument(ctxt)==0) ? ctxt->myDoc : NULL;
00466 unsigned int size=ctxt->nbChars;
00467 bool wellFormed=ctxt->wellFormed;
00468 xmlFreeParserCtxt(ctxt);
00469 if (xmldocument==NULL) {
00470 cerr << "Error: XMLLoadSave file stream not parsed successfully. (xml syntax error)\n" << endl;
00471 return 0;
00472 }
00473 if(!wellFormed)
00474 cerr << "Warning: XMLLoadSave file stream was not well formed (but was recovered)." << endl;
00475
00476 try {
00477 xmlNodePtr cur = FindRootXMLElement(xmldocument);
00478 loadXML(cur);
00479 return size;
00480 } catch(const bad_format& err) {
00481 reportError("During load of file stream "+std::string(filename)+":",err);
00482 xmlFreeDoc(xmldocument);
00483 xmldocument=NULL;
00484 return 0;
00485 }
00486 }
00487 unsigned int XMLLoadSave::saveFileStream(FILE* f) const {
00488 xmlBufferPtr xmlbuf = NULL;
00489 try {
00490 if(xmldocument==NULL)
00491 setParseTree(xmlNewDoc((const xmlChar*)"1.0"));
00492 if(compressionLevel>=0)
00493 xmlSetDocCompressMode(xmldocument,compressionLevel);
00494 xmlNode * cur = FindRootXMLElement(xmldocument);
00495 saveXML(cur);
00496 #if LIBXML_VERSION < 20623
00497
00498
00499
00500 (void)xmlbuf;
00501 int size=xmlDocFormatDump(f, xmldocument, autoFormat);
00502 if(size==-1)
00503 cerr << "Error: XMLLoadSave::saveFileStream: xmlDocFormatDump(...) returned -1" << endl;
00504 return size==-1?0:size;
00505 #else
00506
00507 xmlbuf = xmlBufferCreate();
00508 xmlSaveCtxtPtr ctxt = xmlSaveToBuffer(xmlbuf, NULL, (autoFormat ? XML_SAVE_FORMAT : 0));
00509
00510 xmlSaveSetEscape(ctxt,xmlEscapeMinimalEntities);
00511 xmlSaveSetAttrEscape(ctxt,xmlEscapeMinimalEntities);
00512 size_t size = xmlSaveDoc(ctxt,xmldocument);
00513 xmlSaveClose(ctxt);
00514 ctxt=NULL;
00515 if(size==(size_t)-1) {
00516 cerr << "Error: XMLLoadSave::saveFileStream: xmlSaveDoc returned -1" << endl;
00517 return 0;
00518 }
00519 size=xmlBufferLength(xmlbuf);
00520 size_t wrote=fwrite(xmlBufferContent(xmlbuf),1,xmlBufferLength(xmlbuf),f);
00521 if(wrote!=size)
00522 std::cerr << "*** WARNING XMLLoadSave::saveFileStream: short write (wrote " << wrote << ", expected " << size << ")" << std::endl;
00523 xmlBufferFree(xmlbuf);
00524 xmlbuf=NULL;
00525 return size;
00526 #endif
00527 } catch(const bad_format& err) {
00528 reportError("During save to file stream:",err);
00529 xmlBufferFree(xmlbuf);
00530 return 0;
00531 } catch(...) {
00532 xmlBufferFree(xmlbuf);
00533 throw;
00534 }
00535 }
00536
00537
00538 struct StreamParser {
00539
00540
00541
00542 xmlParserCtxt _ctxt;
00543
00544
00545 StreamParser(std::istream& in, bool asFragment) : _ctxt(), handler(), ctxt(NULL), complete(false), is(&in), used(0) {
00546 if(!asFragment) {
00547 ctxt = xmlCreatePushParserCtxt(NULL,NULL,NULL,0,NULL);
00548 } else {
00549 xmlSAXVersion(&handler,1);
00550 handler.endElement = endElementCallback;
00551 ctxt = xmlCreatePushParserCtxt(&handler,NULL,NULL,0,NULL);
00552 }
00553 if(ctxt==NULL) {
00554 cerr << "Error: XMLLoadSave could not create file stream parser context" << endl;
00555 throw std::bad_alloc();
00556 }
00557 ctxt->recovery=1;
00558 ctxt->userData=this;
00559 _ctxt=(*ctxt);
00560 }
00561
00562 ~StreamParser() { xmlFreeParserCtxt(ctxt); ctxt=NULL; }
00563
00564 operator xmlParserCtxt*() { return &_ctxt; }
00565
00566
00567 xmlSAXHandler handler;
00568
00569 xmlParserCtxt* ctxt;
00570
00571
00572 bool complete;
00573
00574 std::istream* is;
00575
00576
00577 unsigned int used;
00578
00579
00580 static void endElementCallback(void * ctx, const xmlChar * name) { reinterpret_cast<StreamParser*>(ctx)->doEndElement(name); }
00581
00582
00583 void doEndElement(const xmlChar * curName) {
00584
00585 if(_ctxt.nameNr==1) {
00586 for(const xmlChar* x=_ctxt.input->end; x!=_ctxt.input->cur && *is; )
00587 is->putback(*--x);
00588
00589 used-=(_ctxt.input->end - _ctxt.input->cur);
00590 _ctxt.input->cur=_ctxt.input->end;
00591 complete=true;
00592 }
00593 xmlSAX2EndElement(this,curName);
00594 }
00595 private:
00596 StreamParser(const StreamParser&);
00597 StreamParser& operator=(const StreamParser&);
00598 };
00599
00600 unsigned int XMLLoadSave::loadStream(std::istream& is, bool asFragment ) {
00601 if(xmldocument!=NULL) {
00602 xmlFreeDoc(xmldocument);
00603 xmldocument=NULL;
00604 }
00605
00606 unsigned int totalUsed=0;
00607 {
00608 StreamParser parser(is,asFragment);
00609 const size_t BUFSIZE=4*1024;
00610 char buf[BUFSIZE];
00611 while(!parser.complete && is.read(buf,1)) {
00612 is.readsome(buf+1,BUFSIZE-1);
00613 parser.used = is.gcount()+1;
00614
00615 int err = xmlParseChunk(parser,buf,parser.used,false);
00616 if(err!=0) {
00617 std::cerr << "XMLLoadSave::loadStream encountered XML error " << err << std::endl;
00618 return 0;
00619 }
00620 totalUsed+=parser.used;
00621 }
00622 if(!is || !parser.complete)
00623 return 0;
00624 int err = xmlParseChunk(parser,NULL,0,true);
00625 if(err!=0) {
00626 std::cerr << "XMLLoadSave::loadStream encountered XML error " << err << std::endl;
00627 return 0;
00628 }
00629 if(!parser._ctxt.wellFormed)
00630 cerr << "Warning: XMLLoadSave file stream was not well formed (but was recovered)." << endl;
00631
00632 xmldocument = parser._ctxt.myDoc;
00633 if(xmldocument==NULL) {
00634 cerr << "ERROR: XMLLoadSave parsing completed but document is still NULL!" << endl;
00635 return 0;
00636 }
00637 }
00638
00639 try {
00640 xmlNodePtr cur = FindRootXMLElement(xmldocument);
00641 loadXML(cur);
00642 return totalUsed;
00643 } catch(const bad_format& err) {
00644 reportError("During load of file stream:",err);
00645 xmlFreeDoc(xmldocument);
00646 xmldocument=NULL;
00647 return 0;
00648 }
00649 }
00650 unsigned int XMLLoadSave::saveStream(std::ostream& os, bool asFragment) const {
00651 xmlBufferPtr xmlbuf = NULL;
00652 try {
00653 if(xmldocument==NULL)
00654 setParseTree(xmlNewDoc((const xmlChar*)"1.0"));
00655 if(compressionLevel>=0)
00656 xmlSetDocCompressMode(xmldocument,compressionLevel);
00657 xmlNode * cur = FindRootXMLElement(xmldocument);
00658 saveXML(cur);
00659 #if LIBXML_VERSION < 20623
00660
00661 (void)xmlbuf;
00662 xmlChar* xbuf=NULL;
00663 int size=0;
00664 xmlDocDumpFormatMemory(xmldocument, &xbuf, &size, autoFormat);
00665 os.write((const char*)xbuf,size);
00666 xmlFree(xbuf);
00667 return size;
00668 #else
00669 xmlbuf = xmlBufferCreate();
00670 xmlSaveCtxtPtr ctxt = xmlSaveToBuffer(xmlbuf, NULL, (autoFormat ? XML_SAVE_FORMAT : 0));
00671 xmlSaveSetEscape(ctxt,xmlEscapeMinimalEntities);
00672 xmlSaveSetAttrEscape(ctxt,xmlEscapeMinimalEntities);
00673 size_t size = asFragment ? xmlSaveTree(ctxt,xmlDocGetRootElement(xmldocument)) : xmlSaveDoc(ctxt,xmldocument);
00674 xmlSaveClose(ctxt);
00675 ctxt=NULL;
00676 if(size==(size_t)-1) {
00677 cerr << "Error: XMLLoadSave::saveBuffer: xmlSaveDoc/xmlSaveTree returned -1" << endl;
00678 return 0;
00679 }
00680 size=xmlBufferLength(xmlbuf);
00681 os.write((const char*)xmlBufferContent(xmlbuf),size);
00682 xmlBufferFree(xmlbuf);
00683 return size;
00684 #endif
00685 } catch(const bad_format& err) {
00686 reportError("During save to memory buffer:",err);
00687 xmlBufferFree(xmlbuf);
00688 return 0;
00689 } catch(...) {
00690 xmlBufferFree(xmlbuf);
00691 throw;
00692 }
00693 }
00694
00695 void XMLLoadSave::clearParseTree() {
00696 xmlFreeDoc(xmldocument);
00697 xmldocument=NULL;
00698 }
00699 void XMLLoadSave::setParseTree(xmlDoc* doc) const {
00700 if(doc==xmldocument)
00701 return;
00702 xmlFreeDoc(xmldocument);
00703 xmldocument=doc;
00704 }
00705 xmlDoc* XMLLoadSave::stealParseTree(xmlDoc* newdoc) const {
00706 xmlDoc * oldDoc = xmldocument;
00707 xmldocument=newdoc;
00708 return oldDoc;
00709 }
00710 void XMLLoadSave::readParseTree() {
00711 if(xmldocument==NULL)
00712 return;
00713 try {
00714 xmlNodePtr cur = FindRootXMLElement(xmldocument);
00715 loadXML(cur);
00716 } catch(const bad_format& err) {
00717 reportError("During XMLLoadSave::readParseTree:",err);
00718 xmlFreeDoc(xmldocument);
00719 xmldocument=NULL;
00720 }
00721 }
00722 void XMLLoadSave::writeParseTree() const {
00723 try {
00724 if(xmldocument==NULL)
00725 setParseTree(xmlNewDoc((const xmlChar*)"1.0"));
00726 if(compressionLevel>=0)
00727 xmlSetDocCompressMode(xmldocument,compressionLevel);
00728 xmlNode * cur = FindRootXMLElement(xmldocument);
00729 saveXML(cur);
00730 } catch(const bad_format& err) {
00731 reportError("During writeParseTree:",err);
00732 }
00733 }
00734
00735 void XMLLoadSave::setCompression(int level) {
00736 compressionLevel=level;
00737 if(xmldocument!=NULL)
00738 xmlSetDocCompressMode(xmldocument,compressionLevel);
00739 }
00740
00741 xmlNode* XMLLoadSave::FindRootXMLElement(xmlDoc* doc) const {
00742 if(doc==NULL)
00743 return NULL;
00744 xmlNode* cur=xmlDocGetRootElement(doc);
00745 if(cur==NULL) {
00746
00747 cur = xmlNewNode(NULL,(const xmlChar*)"");
00748 xmlFree(xmlDocSetRootElement(doc,cur));
00749 }
00750 return cur;
00751 }
00752
00753 int XMLLoadSave::fileReadCallback(void* f,char* buf, int len) {
00754 return ferror((FILE*)f) ? -1 : (int)fread(buf,sizeof(char),len,(FILE*)f);
00755 }
00756 int XMLLoadSave::fileCloseCallback(void* f) {
00757 return fclose((FILE*)f) ? -1 : 0;
00758 }
00759
00760 xmlNode* XMLLoadSave::skipToElement(xmlNode* cur) {
00761 while(cur!=NULL && cur->type!=XML_ELEMENT_NODE)
00762 cur=cur->next;
00763 return cur;
00764 }
00765
00766 xmlNode* XMLLoadSave::skipToElement(xmlNode* cur, std::string& comment) {
00767 comment.clear();
00768 while(cur!=NULL && cur->type!=XML_ELEMENT_NODE) {
00769 if(cur->type==XML_COMMENT_NODE) {
00770 xmlChar* cont=xmlNodeGetContent(cur);
00771 comment=(char*)cont;
00772 xmlFree(cont);
00773 }
00774 cur=cur->next;
00775 }
00776 return cur;
00777 }
00778
00779
00780
00781
00782