Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

base/Externalizer

Go to the documentation of this file.
00001 /* *-*-c++-*-****************************************************************
00002   Copyright (C)2002 David Jung <opensim@pobox.com>
00003 
00004   This program/file is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 of the License, or
00007   (at your option) any later version.
00008   
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details. (http://www.gnu.org)
00013   
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017   
00018   $Id: Externalizer 1067 2004-02-27 21:09:46Z jungd $
00019   $Revision: 1.5 $
00020   $Date: 2004-02-27 16:09:46 -0500 (Fri, 27 Feb 2004) $
00021   $Author: jungd $
00022  
00023 ****************************************************************************/
00024 
00025 #ifndef _BASE_EXTERNALIZER_
00026 #define _BASE_EXTERNALIZER_
00027 
00028 #include <base/base>
00029 #include <base/Externalizable>
00030 #include <base/Referenced>
00031 #include <base/PathName>
00032 #include <base/VFile>
00033 #include <base/Vector>
00034 #include <base/Vector3>
00035 #include <base/Matrix4>
00036 #include <base/Matrix>
00037 
00038 #include <base/DOM>
00039 
00040 #include <iostream>
00041 #include <list>
00042 #include <stack>
00043 
00044 
00045 
00046 
00047 
00048 
00049 
00050 namespace base {
00051 
00052 
00053   /// Helper class for transcoding between char* or String ASCII and XML Unicode strings
00054   ///  Use like XS("ascii") - has automatic conversion to XMLCh*
00055   ///        or XS(domElement->getTagName()) - has auto conversion to String
00056   class XS
00057   {
00058   public:
00059     XS(String str)
00060     { 
00061       const Int len = str.length();
00062       unicode = new XCh[len+8];
00063       dom::XMLString::transcode(str.c_str(), unicode, len+4);
00064     }
00065 
00066     XS(const char *cstr) 
00067     {
00068       const Int len = strlen(cstr);
00069       unicode = new XCh[len+8];
00070       dom::XMLString::transcode(cstr, unicode, len+4);
00071     }
00072 
00073     XS(const XCh* xstr)
00074     {
00075       unicode = new XCh[dom::XMLString::stringLen(xstr)+4];
00076       dom::XMLString::copyString(unicode, xstr);
00077     }
00078 
00079     ~XS() { delete[] unicode; }
00080 
00081     operator XCh*() const { return unicode; }
00082 
00083     operator String() const
00084     { 
00085       char* cstr = dom::XMLString::transcode(unicode);
00086       String str(cstr);
00087       delete[] cstr;
00088       return str;
00089     }
00090 
00091   private:
00092     XCh* unicode;
00093   };
00094 
00095 
00096 
00097 
00098 class Externalizer : public Object
00099 {
00100 public:
00101   Externalizer(Externalizable::ExternalizationType type, ref<VFile> archive); 
00102   Externalizer(Externalizable::ExternalizationType type, std::ios& stream);
00103   virtual ~Externalizer();
00104 
00105   virtual String className() const { return String("Externalizer"); }
00106 
00107   bool isOutput() const { return isoutput; }     ///< true is this is an output serialization stream
00108   bool isInput() const { return !isOutput(); } ///< true if this is an input serialization stream
00109   Externalizable::ExternalizationType ioType() { return isOutput()?Externalizable::Output:Externalizable::Input; }
00110 
00111   /// return the filesystem path of the stream to which this Externalizer is
00112   ///  attached; or the empty String (if unknown - i.e. instantiated from an iostream)
00113   PathName getArchivePath() const { return path; }
00114 
00115   void flush(); ///< flush output stream (no-op on input).  Should use this before closing an output file before Externalizer goes out-of-scope.
00116 
00117   bool moreInput() ///< still input remaining in current context?
00118     { Assert(isInput()); return bool(input()); } 
00119   String readLine();                      ///< read until end of line
00120   String readString(SInt maxLength=-1);   ///< read maxLength chars (or until end of context if -1)
00121   void   writeLine(const String& line);   ///< write 'line' followed by end-of-line char 
00122   void   writeString(const String& str);  ///< write String str (may contain end-of-line chars)
00123 
00124   void   writeComment(const String& comment); ///< output a comment ('# <text> <newline>' in raw mode, xml comment in XML mode)
00125 
00126   static String readLineFromStream(std::istream& istream)
00127   {
00128     char linebuf[1024];
00129     istream.getline(linebuf,1024);
00130     linebuf[1023]=char(0);
00131     return String(linebuf);
00132   }
00133 
00134 
00135   // XML IO methods
00136 
00137   dom::DOMDocument* doc() { if (!xmlMode) initXMLDoc(); return xmldoc; }
00138   dom::DOMNode* context() { if (!xmlMode) initXMLDoc(); return xmlcontext.top(); }
00139 
00140   // for writing
00141 
00142   /// if a DOCTYPE is to be set, always call setDocumentType() first on a new output Externalizer.  
00143   /// Subsequent calls will be ignored.  Only then can createElement() be called to create an element.
00144   ///  createElement() must be the first 'write' method called on a new output Externalizer - in which
00145   ///  case the element will be the root element of the document.
00146   void setDocumentType(const String& name, const String& publicid, const String& sysid);
00147   dom::DOMElement* createElement(const String& tagname, bool indenting=true);
00148   
00149   void pushContext(dom::DOMNode* context) { Assert(xmlMode); xmlcontext.push(context); }
00150   dom::DOMNode* popContext() { Assert(xmlMode); dom::DOMNode* top = xmlcontext.top(); xmlcontext.pop(); return top; }
00151 
00152   void appendElement(dom::DOMElement* e) { Assert(xmlMode); if (e != xmlcontext.top()) { xmlcontext.top()->appendChild(e); lastAppendedElem=e;} }
00153   void appendBreak() { Assert(xmlMode); appendText(xmlcontext.top(), newline); }
00154   dom::DOMElement* lastAppendedElement() { Assert(xmlMode); return lastAppendedElem; }
00155   String elementTagName(dom::DOMNode* n) { Assert(xmlMode); return !isElement(n)?String():String(XS(dynamic_cast<dom::DOMElement*>(n)->getTagName())); }
00156 
00157   void        appendElement(dom::DOMNode* n, const String& tagname, bool indenting=true);
00158   void        setElementAttribute(dom::DOMElement* e, const String& attrname, const String& value) { e->setAttribute(XS(attrname),XS(value)); }
00159   void        appendProcessingInstruction(dom::DOMNode* n, const String& target, const String& data);
00160   dom::DOMText*    createText(const String& text);
00161   void        appendText(dom::DOMNode* n, const String& text);
00162   dom::DOMComment* createComment(const String& comment);
00163   void        appendComment(dom::DOMNode* n, const String& comment);
00164   dom::DOMCDATASection* createCDATA(const String& text);
00165   void             appendCDATA(dom::DOMNode* n, const String& text);
00166   void        appendNode(dom::DOMNode* n, dom::DOMNode* n2) { Assert(xmlMode); n->appendChild(n2); }
00167   void        appendBreak(dom::DOMNode* n) { Assert(xmlMode); appendText(n, newline); }
00168 
00169   // for reading
00170   dom::DOMElement* getFirstElement(dom::DOMNode* n, const String& tagname, bool required=true);
00171   dom::DOMElement* getFirstChildElement(dom::DOMNode* n, const String& tagname, bool required=true);
00172   dom::DOMElement* getNextSiblingElement(dom::DOMNode* n, const String& tagname, bool required=true);
00173   void             removeElement(dom::DOMElement* e);
00174   String           getContainedText(dom::DOMNode* n, bool removeIndentation=false);
00175   String           getElementAttribute(dom::DOMElement* e, const String& attrname, bool required=true);
00176   String           getDefaultedElementAttribute(dom::DOMElement* e, const String& attrname, const String& defaultValue);
00177 
00178   // useful String processing
00179   static array<String> splitIntoLines(const String& text, bool removeBlankLines=true);
00180   static array<String> splitAtDelimiter(const String& line, char delimiter=',');
00181   static base::Vector  stringsToReals(const array<String>& strings, bool acceptUnits = true);
00182   static base::Matrix4 toMatrix4(const String& text);
00183   static String        toString(const base::Matrix4& m);
00184   static base::Vector3 toVector3(const String& text, bool acceptUnits = true);
00185   static base::Vector  toVector(const String& text, bool commasep=false, bool acceptUnits = true);
00186   static String        toString(const base::Vector3& v);
00187   static String        toString(const base::Vector& v, bool commasep=false);
00188   static String        toString(const base::Matrix& m);
00189   static String        toString(Real v, const String& units="m");
00190   static Real          toReal(const String& text, bool acceptUnits = true);
00191   static base::Matrix  toMatrix(const String& text);
00192   static String        removeChar(const String& text, char toRemove);
00193   static bool          isNumeric(const String& text);
00194   
00195 
00196 
00197 
00198   static const String newline;
00199   static const Int indentSpaces = 2;
00200 
00201 protected:  
00202   Externalizer(const Externalizer& e) 
00203     : xmlMode(e.xmlMode), parser(e.parser), 
00204       impl(e.impl), doctype(e.doctype),
00205       xmldoc(e.xmldoc), xmlcontext(e.xmlcontext),
00206       isoutput(e.isoutput), aborted(e.aborted)
00207   {}
00208 
00209   std::istream& input() { Assert(isInput()); return *istream; }
00210   std::ostream& output() { Assert(isOutput()); return *ostream; }
00211 
00212   bool xmlMode;
00213 
00214 
00215   static bool xmlInitialized;
00216   static void xmlInitialize();
00217 
00218   void initXMLDoc(const String& rootElementName = "");
00219 
00220   dom::DOMBuilder*  parser;
00221   dom::DOMImplementation *impl;
00222   dom::DOMDocumentType* doctype;
00223   dom::DOMDocument* xmldoc;
00224   std::stack<dom::DOMNode*> xmlcontext;
00225   dom::DOMElement* lastAppendedElem;
00226 
00227   dom::DOMDocument* xmlParseDocument();
00228   void         xmlWriteDocument(dom::DOMDocument* doc);
00229   void         xmlReleaseDocument();
00230   void         xmlFormat(dom::DOMNode* n, Int indent);
00231 
00232   bool         isNewline(dom::DOMNode* n);
00233   bool         equals(const XCh* str1, const String& str2);
00234   bool         isElement(dom::DOMNode* n) { return n->getNodeType() == dom::DOMNode::ELEMENT_NODE; }
00235   bool         isElement(dom::DOMNode* n, const String& tagname);
00236 
00237 
00238 
00239   const static String inputToConstErrorString;
00240   const static String inputDuringOutputErrorString;
00241 
00242   // helpers
00243   void abort(const String& exceptionString); // flags the externalization as aborted and throws an exception
00244 
00245 
00246   bool isoutput;
00247   bool aborted;
00248 
00249   std::istream* istream;
00250   std::ostream* ostream;
00251   PathName path;
00252   
00253 };
00254 
00255 
00256 } // base
00257 
00258 #endif

Generated on Thu Jul 29 15:56:05 2004 for OpenSim by doxygen 1.3.6