Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

XMLLoadSave.cc

Go to the documentation of this file.
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 
00008 using namespace std;
00009 
00010 unsigned int XMLLoadSave::AutoInit::libxmlrefc=0;
00011 
00012 XMLLoadSave::AutoInit::AutoInit() {
00013   if(libxmlrefc==0) {
00014     //cout << "libxmlinit" << endl;
00015     xmlInitParser();
00016     xmlKeepBlanksDefault(1);
00017     xmlLineNumbersDefault(1);
00018     xmlIndentTreeOutput = 1;
00019   }
00020   libxmlrefc++;
00021 }
00022 
00023 XMLLoadSave::AutoInit::~AutoInit() {
00024   libxmlrefc--;
00025   if(libxmlrefc==0) {
00026     xmlCleanupParser();
00027     //cout << "libxmldest" << endl;
00028   }
00029 }
00030 
00031 XMLLoadSave::XMLLoadSave()
00032   : xmldocument(NULL), compressionLevel(-1), autoFormat(true), libxmlInit()
00033 {}
00034 
00035 XMLLoadSave::XMLLoadSave(const XMLLoadSave& xls)
00036   : LoadSave(xls), xmldocument(xls.xmldocument==NULL?NULL:xmlCopyDoc(xls.xmldocument,true)), compressionLevel(xls.compressionLevel), autoFormat(xls.autoFormat), libxmlInit()
00037 {}
00038 
00039 XMLLoadSave& XMLLoadSave::operator=(const XMLLoadSave& xls) {
00040   LoadSave::operator=(xls);
00041   if(xls.xmldocument==NULL)
00042     clearParseTree();
00043   else
00044     setParseTree(xmlCopyDoc(xls.xmldocument,true));
00045   compressionLevel = xls.compressionLevel;
00046   autoFormat=xls.autoFormat;
00047   return *this;
00048 }
00049 
00050 XMLLoadSave::~XMLLoadSave() {
00051   clearParseTree();
00052 }
00053 
00054 void XMLLoadSave::reportError(const std::string& context, const bad_format& err) const {
00055   cerr << context << endl;
00056   cerr << "  " << err.what() << endl;
00057   if(err.getNode()!=NULL) {
00058     xmlChar* path=xmlGetNodePath(err.getNode());
00059     cerr << "  Error was flagged during processing of node at line " << xmlGetLineNo(err.getNode()) << ": " << path << " '" << xmlNodeGetContent(err.getNode()) << '\'' << endl;
00060     xmlFree(path);
00061   }
00062 }
00063 
00064 unsigned int XMLLoadSave::getBinSize() const {
00065   try {
00066     if(xmldocument==NULL)
00067       setParseTree(xmlNewDoc((const xmlChar*)"1.0"));
00068     if(compressionLevel>=0)
00069       xmlSetDocCompressMode(xmldocument,compressionLevel);
00070     xmlNode * cur = FindRootXMLElement(xmldocument);
00071     SaveXML(cur);
00072     xmlChar* buf=NULL;
00073     int size=0;
00074     xmlDocDumpFormatMemory(xmldocument, &buf, &size, autoFormat);
00075     xmlFree(buf);
00076     return size;
00077   } catch(const bad_format& err) {
00078     reportError("During calculation of size:",err);
00079     return 0;
00080   }
00081 }
00082 unsigned int XMLLoadSave::LoadBuffer(const char buf[], unsigned int len) {
00083   if(xmldocument!=NULL)
00084     xmlFreeDoc(xmldocument);
00085   
00086   //does actual low-level XML parsing
00087   xmlParserCtxt* ctxt=xmlCreateMemoryParserCtxt(buf,len);
00088   if(ctxt==NULL) {
00089     cerr << "Error: XMLLoadSave could not create memory parser context" << endl;
00090     return 0;
00091   }
00092   xmldocument = xmlParseDocument(ctxt)==0?ctxt->myDoc:NULL;
00093   if (xmldocument == NULL ) {
00094     cerr << "Error: XMLLoadSave buffer not parsed successfully. (xml syntax error)\n"
00095          << "       Attempting to recover..." << endl;
00096     xmlFreeParserCtxt(ctxt);
00097     ctxt=xmlCreateMemoryParserCtxt(buf,len);
00098     if(ctxt==NULL) {
00099       cerr << "Error: XMLLoadSave could not create memory parser context" << endl;
00100       return 0;
00101     }
00102     ctxt->recovery=1;
00103     xmldocument = xmlParseDocument(ctxt)==0?ctxt->myDoc:NULL;
00104     if(xmldocument==NULL) {
00105       cerr << "Error: XMLLoadSave recovery failed." << endl;
00106       xmlFreeParserCtxt(ctxt);
00107       return 0;
00108     }
00109   }
00110   unsigned int size=ctxt->nbChars;
00111   xmlFreeParserCtxt(ctxt);
00112   
00113   try {
00114     xmlNodePtr cur = FindRootXMLElement(xmldocument);
00115     LoadXML(cur);
00116     return size;
00117   } catch(const bad_format& err) {
00118     reportError("During load of memory buffer:",err);
00119     xmlFreeDoc(xmldocument);
00120     xmldocument=NULL;
00121     return 0;
00122   }
00123 }
00124 unsigned int XMLLoadSave::SaveBuffer(char buf[], unsigned int len) const {
00125   try {
00126     if(xmldocument==NULL)
00127       setParseTree(xmlNewDoc((const xmlChar*)"1.0"));
00128     if(compressionLevel>=0)
00129       xmlSetDocCompressMode(xmldocument,compressionLevel);
00130     xmlNode * cur = FindRootXMLElement(xmldocument);
00131     SaveXML(cur);
00132     xmlChar* xbuf=NULL;
00133     int size=0;
00134     xmlDocDumpFormatMemory(xmldocument, &xbuf, &size, autoFormat);
00135     if((unsigned int)size<=len)
00136       memcpy(buf,xbuf,size);
00137     else {
00138       cerr << "Error: XMLLoadSave::SaveBuffer xmlDocDumpFormatMemory returned larger region than the target buffer" << endl;
00139       size=0;
00140     }
00141     return size;
00142   } catch(const bad_format& err) {
00143     reportError("During save to memory buffer:",err);
00144     return 0;
00145   }
00146 }
00147 
00148 unsigned int XMLLoadSave::LoadFile(const char* filename) {
00149   if(xmldocument!=NULL)
00150     xmlFreeDoc(xmldocument);
00151   
00152   //does actual low-level XML parsing
00153   xmlParserCtxt* ctxt=xmlCreateFileParserCtxt(filename);
00154   if(ctxt==NULL) {
00155     cerr << "Error: XMLLoadSave could not create parser context for '"<< filename << "'" << endl;
00156     return 0;
00157   }
00158   xmldocument = xmlParseDocument(ctxt)==0?ctxt->myDoc:NULL;
00159   if (xmldocument == NULL ) {
00160     cerr << "Error: XMLLoadSave document '" << filename << "' not parsed successfully. (file not found or xml syntax error)\n"
00161     << "       Attempting to recover..." << endl;
00162     xmlFreeParserCtxt(ctxt);
00163     ctxt=xmlCreateFileParserCtxt(filename);
00164     if(ctxt==NULL) {
00165       cerr << "Error: XMLLoadSave could not create parser context for '"<< filename << "'" << endl;
00166       return 0;
00167     }
00168     ctxt->recovery=1;
00169     xmldocument = xmlParseDocument(ctxt)==0?ctxt->myDoc:NULL;
00170     if(xmldocument==NULL) {
00171       cerr << "Error: XMLLoadSave document '" << filename << "' recovery failed." << endl;
00172       xmlFreeParserCtxt(ctxt);
00173       return 0;
00174     }
00175   }
00176   unsigned int size=ctxt->nbChars;
00177   xmlFreeParserCtxt(ctxt);
00178   
00179   try {
00180     xmlNodePtr cur = FindRootXMLElement(xmldocument);
00181     LoadXML(cur);
00182     return size;
00183   } catch(const bad_format& err) {
00184     string context("During load of '");
00185     context+=filename;
00186     context+="':";
00187     reportError(context,err);
00188     xmlFreeDoc(xmldocument);
00189     xmldocument=NULL;
00190     return 0;
00191   }
00192 }
00193 unsigned int XMLLoadSave::SaveFile(const char* filename) const {
00194   try {
00195     if(xmldocument==NULL)
00196       setParseTree(xmlNewDoc((const xmlChar*)"1.0"));
00197     if(compressionLevel>=0)
00198       xmlSetDocCompressMode(xmldocument,compressionLevel);
00199     xmlNode * cur = FindRootXMLElement(xmldocument);
00200     SaveXML(cur);
00201     int size=xmlSaveFormatFile (filename, xmldocument, autoFormat);
00202     if(size==-1)
00203       cerr << "Error: XMLLoadSave::SaveFile: xmlSaveFormatFile(\"" << filename << "\",...) returned -1" << endl;
00204     return size==-1?0:size;
00205   } catch(const bad_format& err) {
00206     string context("During save to '");
00207     context+=filename;
00208     context+="':";
00209     reportError(context,err);
00210     return 0;
00211   }
00212 }
00213 
00214 unsigned int XMLLoadSave::LoadFileStream(FILE* f) {
00215   if(xmldocument!=NULL)
00216     xmlFreeDoc(xmldocument);
00217   
00218   //does actual low-level XML parsing
00219   //This is a little sketchy trying to shoehorn a SAX style call, but it seems to work
00220   xmlParserCtxt* ctxt=xmlCreateIOParserCtxt(NULL,NULL,fileReadCallback,fileCloseCallback,f,XML_CHAR_ENCODING_UTF8);
00221   if(ctxt==NULL) {
00222     cerr << "Error: XMLLoadSave could not create file stream parser context" << endl;
00223     return 0;
00224   }
00225   ctxt->recovery=1;
00226   xmldocument = xmlParseDocument(ctxt)==0?ctxt->myDoc:NULL;
00227   unsigned int size=ctxt->nbChars;
00228   bool wellFormed=ctxt->wellFormed;
00229   xmlFreeParserCtxt(ctxt);
00230   if (xmldocument == NULL ) {
00231     cerr << "Error: XMLLoadSave file stream not parsed successfully. (xml syntax error)\n" << endl;
00232     return 0;
00233   }
00234   if(!wellFormed)
00235     cerr << "Warning: XMLLoadSave file stream was not well formed (but was recovered)." << endl;
00236   
00237   try {
00238     xmlNodePtr cur = FindRootXMLElement(xmldocument);
00239     LoadXML(cur);
00240     return size;
00241   } catch(const bad_format& err) {
00242     reportError("During load of file stream:",err);
00243     xmlFreeDoc(xmldocument);
00244     xmldocument=NULL;
00245     return 0;
00246   }
00247 }
00248 unsigned int XMLLoadSave::SaveFileStream(FILE* f) const {
00249   try {
00250     if(xmldocument==NULL)
00251       setParseTree(xmlNewDoc((const xmlChar*)"1.0"));
00252     if(compressionLevel>=0)
00253       xmlSetDocCompressMode(xmldocument,compressionLevel);
00254     xmlNode * cur = FindRootXMLElement(xmldocument);
00255     SaveXML(cur);
00256     int size=xmlDocFormatDump(f, xmldocument, autoFormat);
00257     if(size==-1)
00258       cerr << "Error: XMLLoadSave::SaveFileStream: xmlDocFormatDump(...) returned -1" << endl;
00259     return size==-1?0:size;
00260   } catch(const bad_format& err) {
00261     reportError("During save to file stream:",err);
00262     return 0;
00263   }
00264 }
00265 
00266 void XMLLoadSave::clearParseTree() {
00267   xmlFreeDoc(xmldocument);
00268   xmldocument=NULL;
00269 }
00270 void XMLLoadSave::setParseTree(xmlDoc* doc) const {
00271   if(doc==xmldocument)
00272     return;
00273   xmlFreeDoc(xmldocument);
00274   xmldocument=doc;
00275 }
00276 void XMLLoadSave::readParseTree() {
00277   if(xmldocument==NULL)
00278     return;
00279   try {
00280     xmlNodePtr cur = FindRootXMLElement(xmldocument);
00281     LoadXML(cur);
00282   } catch(const bad_format& err) {
00283     reportError("During readParseTree:",err);
00284     xmlFreeDoc(xmldocument);
00285     xmldocument=NULL;
00286   }
00287 }
00288 void XMLLoadSave::writeParseTree() {
00289   try {
00290     if(xmldocument==NULL)
00291       setParseTree(xmlNewDoc((const xmlChar*)"1.0"));
00292     if(compressionLevel>=0)
00293       xmlSetDocCompressMode(xmldocument,compressionLevel);
00294     xmlNode * cur = FindRootXMLElement(xmldocument);
00295     SaveXML(cur);
00296   } catch(const bad_format& err) {
00297     reportError("During writeParseTree:",err);
00298   }
00299 }
00300 
00301 void XMLLoadSave::setCompression(int level) {
00302   compressionLevel=level;
00303   if(xmldocument!=NULL)
00304     xmlSetDocCompressMode(xmldocument,compressionLevel);
00305 }
00306 
00307 xmlNode* XMLLoadSave::FindRootXMLElement(xmlDoc* doc) const {
00308   if(doc==NULL)
00309     return NULL;
00310   xmlNode* cur=xmlDocGetRootElement(doc);
00311   if(cur==NULL) {
00312     //empty file
00313     cur = xmlNewNode(NULL,(const xmlChar*)"");
00314     xmlDocSetRootElement(doc,cur);
00315   } 
00316   return cur;
00317 }
00318 
00319 int XMLLoadSave::fileReadCallback(void* f,char* buf, int len) {
00320   return ferror((FILE*)f)?-1:(int)fread(buf,sizeof(char),len,(FILE*)f);
00321 }
00322 int XMLLoadSave::fileCloseCallback(void* f) {
00323   return fclose((FILE*)f)==0?0:-1;
00324 }
00325 
00326 xmlNode* XMLLoadSave::skipToElement(xmlNode* cur) {
00327   while(cur!=NULL && cur->type!=XML_ELEMENT_NODE)
00328     cur=cur->next;
00329   return cur;
00330 }
00331 
00332 xmlNode* XMLLoadSave::skipToElement(xmlNode* cur, std::string& comment) {
00333   comment.clear();
00334   while(cur!=NULL && cur->type!=XML_ELEMENT_NODE) {
00335     if(cur->type==XML_COMMENT_NODE) {
00336       xmlChar* cont=xmlNodeGetContent(cur);
00337       comment+=(char*)cont;
00338       xmlFree(cont);
00339     }
00340     cur=cur->next;
00341   }
00342   return cur;
00343 }
00344 
00345 /*! @file
00346  * @brief 
00347  * @author Ethan Tira-Thompson (ejt) (Creator)
00348  *
00349  * $Author: ejt $
00350  * $Name: tekkotsu-2_4_1 $
00351  * $Revision: 1.4 $
00352  * $State: Exp $
00353  * $Date: 2005/07/27 05:58:24 $
00354  */

Tekkotsu v2.4.1
Generated Tue Aug 16 16:32:50 2005 by Doxygen 1.4.4