Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

plistPrimitives.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_plistPrimitives_h_
00003 #define INCLUDED_plistPrimitives_h_
00004 
00005 #include "plistBase.h"
00006 #include <map>
00007 
00008 extern "C" {
00009   //!@name libxml2 forward declarations
00010   //!forward declaration of the libxml2 struct of the same name
00011   xmlNode* xmlAddPrevSibling(xmlNode* node, xmlNode* sibling);
00012   xmlNode* xmlNewText(const xmlChar* s);
00013   xmlNode* xmlNewComment(const xmlChar* s);
00014   xmlNode* xmlAddChild(xmlNode * parent, xmlNode* child);
00015   xmlNode* xmlNewChild(xmlNode* parent, xmlNs* ns, const xmlChar * name, const xmlChar * content);
00016   int xmlStrEqual(const xmlChar* a, const xmlChar* b);
00017   xmlChar* xmlNodeGetContent(xmlNode* node);
00018   void xmlNodeSetContent(xmlNode* node, const xmlChar* content);
00019   xmlAttr* xmlHasProperty(xmlNode* node, const xmlChar* name);
00020   xmlChar* xmlGetProperty(xmlNode* node, const xmlChar* name);
00021   long xmlGetLineNo(xmlNode* node);
00022   extern void (*xmlFree)(void* ptr);
00023   void xmlNodeSetName(xmlNode* node, const xmlChar* name);
00024   void xmlFreeNode(xmlNode* node);
00025   void xmlUnlinkNode(xmlNode* node);
00026   //@}
00027 }
00028 
00029 namespace plist {
00030   //! returns a string indicating the plist entry type to use for the specified type
00031   /*! some primitives (bool, char) aren't handled because they require a specialization
00032    *  of Primitive and won't use this function.  If you want to use a plist Primitive of
00033    *  some custom type, you might be able to just define a new specialization of 
00034    *  this function and provide iostream <</>> operators for your type... */
00035   template<typename T> const char* getTypeName();
00036   /// @cond INTERNAL
00037   template<> inline const char* getTypeName<short>() { return "integer"; }
00038   template<> inline const char* getTypeName<unsigned short>() { return "integer"; }
00039   template<> inline const char* getTypeName<int>() { return "integer"; }
00040   template<> inline const char* getTypeName<unsigned int>() { return "integer"; }
00041   template<> inline const char* getTypeName<long>() { return "integer"; }
00042   template<> inline const char* getTypeName<unsigned long>() { return "integer"; }
00043   template<> inline const char* getTypeName<long long>() { return "integer"; }
00044   template<> inline const char* getTypeName<unsigned long long>() { return "integer"; }
00045   template<> inline const char* getTypeName<float>() { return "real"; }
00046   template<> inline const char* getTypeName<double>() { return "real"; }
00047   /// @endcond
00048   
00049   //! Implements type-specific functionality through template specialization, mainly involving value conversion and stringification formatting
00050   /*! Provides smart-pointer style functionality for transparent
00051    *  access to the value storage, as well as automatic casting
00052    *  to and from the value type so you can almost always treat
00053    *  the Primitive as if it was the value itself. */
00054   template<typename T>
00055   class Primitive : public PrimitiveBase {
00056   public:
00057     template<typename U, typename V> struct conversion_policy { typedef typename U::template ConversionTo<V> value_conversion; };
00058     
00059     //! constructor
00060     Primitive() : PrimitiveBase(), val(), prevVal() {}
00061     //! copy constructor, automatic conversion from value type
00062     Primitive(const T& v) : PrimitiveBase(), val(v), prevVal() {} 
00063     //! assignment from value type (template specializations add in-place modiciation (e.g. +=, *=))
00064     Primitive& operator=(const T& v) { if(&v==&prevVal) std::swap(val,prevVal); else { prevVal=val; val=v; } fireValueChanged(prevVal==val); return *this; }
00065     virtual Primitive& operator=(const PrimitiveBase& pb) { if(dynamic_cast<const Primitive*>(&pb)!=this) operator=(pb.to<T>()); return *this; }
00066     //! assignment from primitive of the same type (just assign value)
00067     Primitive& operator=(const Primitive& p) { operator=(p.val); return *this; }
00068 
00069     Primitive& operator+=(const T& v) { prevVal=val; val+=v; fireValueChanged(prevVal==val); return *this; } //!< add in-place
00070     Primitive& operator-=(const T& v) { prevVal=val; val-=v; fireValueChanged(prevVal==val); return *this; } //!< subtract in-place
00071     Primitive& operator*=(const T& v) { prevVal=val; val*=v; fireValueChanged(prevVal==val); return *this; } //!< multiply in-place
00072     Primitive& operator/=(const T& v) { prevVal=val; val/=v; fireValueChanged(prevVal==val); return *this; } //!< divide in-place
00073     
00074     //! smart pointer, dereference to access primitive storage
00075     const T& operator*() const { return val; }
00076     //! smart pointer, dereference to access primitive storage
00077     const T* operator->() const { return &val; }
00078     
00079     //! cast operator to automatically convert to value type
00080     operator T() const { return val; }
00081 
00082     //! interprets \a node as holding the specialization type
00083     void loadXML(xmlNode* node);
00084     //! saves #val into \a node
00085     void saveXML(xmlNode* node) const;
00086     void set(const std::string& str);
00087     using PrimitiveBase::set;
00088     std::string get() const {
00089       std::stringstream sstr;
00090       sstr <<std::setprecision(std::numeric_limits<T>::digits10)<< val;
00091       return sstr.str();
00092     }
00093     
00094     virtual long toLong() const { return static_cast<long>(val); }
00095     virtual double toDouble() const { return static_cast<double>(val); }
00096     
00097     //! clone definition for Primitive<T>
00098     PLIST_CLONE_DEF(Primitive<T>,new Primitive<T>(val));
00099     
00100     const T& getPreviousValue() const { return prevVal; } //!< returns the previously assigned value
00101 
00102   protected:
00103     T val; //!< storage of primitive value
00104     T prevVal; //!< following each assignment, this is the "old" value -- very handy for PrimitiveListeners
00105   };
00106   
00107   template<typename T>
00108   void Primitive<T>::loadXML(xmlNode* node) {
00109     if(node==NULL)
00110       return;
00111     prevVal=val;
00112     bool bt=xNodeHasName(node,"true");
00113     bool bf=xNodeHasName(node,"false");
00114     if(!bt && !bf && !xNodeHasName(node,"integer") && !xNodeHasName(node,"real") && !xNodeHasName(node,"string")) {
00115       std::stringstream errstr;
00116       errstr << "Error: plist::Primitive<" << typeid(T).name() << "> expects " << getTypeName<T>() << ", got unknown type " << (const char*)xNodeGetName(node);
00117       throw bad_format(node,errstr.str());
00118     }
00119     if(!xNodeHasName(node,getTypeName<T>()))
00120       std::cerr << "Warning: plist expected " << getTypeName<T>() << " got " << (const char*)xNodeGetName(node) << ", trying to convert. (line " << xmlGetLineNo(node) << ")" << std::endl;
00121     if(bt)
00122       val = true;
00123     else if(bf)
00124       val = false;
00125     else {
00126       xmlChar * cont=xmlNodeGetContent(node);
00127       std::stringstream str((const char*)cont);
00128       str >> val;
00129       xmlFree(cont);
00130     }
00131     fireValueChanged(prevVal==val);
00132   }
00133   template<typename T>
00134   void Primitive<T>::saveXML(xmlNode* node) const {
00135     if(node==NULL)
00136       return;
00137     xmlNodeSetName(node,(const xmlChar*)getTypeName<T>());
00138     std::stringstream str;
00139     str <<std::setprecision(std::numeric_limits<T>::digits10)<< val;
00140     xmlNodeSetContent(node,(const xmlChar*)str.str().c_str());
00141   }
00142   template<typename T>
00143   void Primitive<T>::set(const std::string& str) {
00144     prevVal=val;
00145     std::stringstream sstr(str);
00146     sstr >> val;
00147     while(sstr.good() && isspace(sstr.peek()))
00148       sstr.get();
00149     if(sstr.fail()) {
00150       if(matchTrue(str))
00151         val=true;
00152       else if(matchFalse(str))
00153         val=false;
00154       else {
00155         std::string err="Expected "; err+=getTypeName<T>(); err+=" value, got '"+str+"'";
00156         throw bad_format(NULL,err);
00157       }
00158       std::cerr << "Warning: expected " << getTypeName<T>() << " value, interpreting '" << str << "' as boolean (value of " << val << ")" << std::endl;
00159     }
00160     if(sstr.good()) {
00161       std::cerr << "Warning: expected " << getTypeName<T>() << " value, truncating remainder '";
00162       char c=sstr.get();
00163       while(sstr) { std::cerr << c; c=sstr.get(); }
00164       std::cerr << "'" << std::endl;
00165     }
00166     fireValueChanged(prevVal==val);
00167   }
00168   
00169   //! implements the clone function for Primitive<T>
00170   PLIST_CLONE_IMPT(T,Primitive,new Primitive<T>(val));
00171 
00172   
00173 /// @cond SHOW_PLIST_OBJECT_SPECIALIZATION
00174   
00175   //! provides a @c bool specialization of Primitive<T>
00176   /*! A @c bool can be treated as either a string or an integer\n
00177    *  When saving, "true" or "false" will be used, but users could
00178    *  also specify "yes"/"no" or "on"/"off".  If an integer is used,
00179    *  it will be interpreted as usual: 0==false, otherwise true. */
00180   template<>
00181   class Primitive<bool> : public PrimitiveBase {
00182   public:
00183     template<typename U, typename V> struct conversion_policy { typedef typename U::template ConversionTo<V> value_conversion; };
00184     Primitive() : PrimitiveBase(), val(), prevVal() {} //!< constructor
00185     Primitive(const bool& v) : PrimitiveBase(), val(v), prevVal() {} //!< casting constructor
00186     Primitive& operator=(const bool& v) { if(&v==&prevVal) std::swap(val,prevVal); else { prevVal=val; val=v; } fireValueChanged(prevVal==val); return *this; } //!< assignment constructor
00187     virtual Primitive& operator=(const PrimitiveBase& pb) { if(dynamic_cast<const Primitive*>(&pb)!=this) operator=(pb.to<bool>()); return *this; }
00188     Primitive& operator=(const Primitive& p) { operator=(p.val); return *this; }
00189     //bool& operator*() { return val; }
00190     const bool& operator*() const { return val; } //!< dereference will return data storage
00191     //bool* operator->() { return &val; }
00192     const bool* operator->() const { return &val; } //!< can use -> to access members of data storage
00193     operator bool() const { return val; } //!< casting operator
00194 
00195     void loadXML(xmlNode* node); //!< interprets @a node as a bool
00196     void saveXML(xmlNode* node) const;  //!< saves #val into @a node
00197     void set(const std::string& str);
00198     using PrimitiveBase::set;
00199     std::string get() const {
00200       return val?"true":"false";
00201     }
00202     virtual long toLong() const { return static_cast<long>(val); }
00203     virtual double toDouble() const { return static_cast<double>(val); }
00204     
00205     //! clone definition for Primitive<bool>
00206     PLIST_CLONE_DEF(Primitive<bool>,new Primitive<bool>(val));
00207     
00208     const bool& getPreviousValue() const { return prevVal; } //!< returns the previously assigned value
00209     
00210   protected:
00211     bool val; //!< the actual data storage
00212     bool prevVal; //!< following each assignment, this is the "old" value -- very handy for PrimitiveListeners
00213   };
00214   
00215 /// @endcond
00216 
00217   //! provides a @c char specialization of plist::Primitive<T>, adds a unique #numeric property to the usual template implementation
00218   /*! A @c char can be treated as either a string or an integer, you can use
00219    *  the setNumeric(bool) function to indicate which style to use when saving */
00220   template<>
00221   class Primitive<char> : public PrimitiveBase {
00222   public:
00223     template<typename U, typename V> struct conversion_policy { typedef typename U::template ConversionTo<V> value_conversion; };
00224     Primitive() : PrimitiveBase(), val(), prevVal(), numeric(false) {} //!< constructor
00225     Primitive(const char& v, bool isNum=false) : PrimitiveBase(), val(v), prevVal(), numeric(isNum) {} //!< casting constructor
00226     Primitive& operator=(char v) { if(&v==&prevVal) std::swap(val,prevVal); else { prevVal=val; val=v; } fireValueChanged(prevVal==val); return *this; } //!< assignment
00227     virtual Primitive& operator=(const PrimitiveBase& pb) { if(dynamic_cast<const Primitive*>(&pb)!=this) operator=(pb.to<char>()); return *this; }
00228     //! assignment from primitive of the same type (just assign value)
00229     Primitive& operator=(const Primitive& p) { operator=(p.val); return *this; }
00230     Primitive& operator+=(char v) { prevVal=val; val+=v; fireValueChanged(prevVal==val); return *this; } //!< add-assign
00231     Primitive& operator-=(char v) { prevVal=val; val-=v; fireValueChanged(prevVal==val); return *this; } //!< subtract-assign
00232     Primitive& operator*=(char v) { prevVal=val; val*=v; fireValueChanged(prevVal==val); return *this; } //!< multiply-assign
00233     Primitive& operator/=(char v) { prevVal=val; val/=v; fireValueChanged(prevVal==val); return *this; } //!< divide-assign
00234     //char& operator*() { return val; }
00235     const char& operator*() const { return val; } //!< dereference will return data storage
00236     //char* operator->() { return &val; }
00237     const char* operator->() const { return &val; } //!< can use -> to access members of data storage
00238     operator char() const { return val; } //!< casting operator
00239     
00240     void setNumeric(bool isNum) { numeric=isNum; } //!< sets #numeric
00241     bool getNumeric() const { return numeric; } //!< returns #numeric
00242     
00243     void loadXML(xmlNode* node); //!< interprets @a node as a char
00244     void saveXML(xmlNode* node) const; //! saves #val into @a node
00245     void set(const std::string& str);
00246     using PrimitiveBase::set;
00247     std::string get() const {
00248       if(numeric) {
00249         std::stringstream sstr;
00250         sstr << (int)val;
00251         return sstr.str();
00252       } else
00253         return std::string(1,val);
00254     }
00255     virtual long toLong() const { return static_cast<long>(val); }
00256     virtual double toDouble() const { return static_cast<double>(val); }
00257     
00258     //! clone definition for Primitive<char>
00259     PLIST_CLONE_DEF(Primitive<char>,new Primitive<char>(val));
00260     
00261     const char& getPreviousValue() const { return prevVal; } //!< returns the previously assigned value
00262     
00263   protected:
00264     char val; //!< data storage
00265     char prevVal; //!< following each assignment, this is the "old" value -- very handy for PrimitiveListeners
00266     bool numeric; //!< if true, requests that saves store the numeric value instead of corresponding character
00267   };
00268   
00269   //! provides an @c unsigned @c char specialization of plist::Primitive<T>, adds a unique #numeric property to the usual template implementation
00270   /*! A @c char can be treated as either a string or an integer, you can use
00271    *  the setNumeric(bool) function to indicate which style to use when saving */
00272   template<>
00273   class Primitive<unsigned char> : public PrimitiveBase {
00274   public:
00275     template<typename U, typename V> struct conversion_policy { typedef typename U::template ConversionTo<V> value_conversion; };
00276     Primitive() : PrimitiveBase(), val(), prevVal(), numeric(false) {} //!< constructor
00277     Primitive(const unsigned char& v, bool isNum=false) : PrimitiveBase(), val(v), prevVal(), numeric(isNum) {} //!< casting constructor
00278     Primitive& operator=(unsigned char v) { prevVal=val; val=v; fireValueChanged(prevVal==val); return *this; } //!< assignment
00279     virtual Primitive& operator=(const PrimitiveBase& pb) { if(dynamic_cast<const Primitive*>(&pb)!=this) operator=(pb.to<unsigned char>()); return *this; }
00280     //! assignment from primitive of the same type (just assign value)
00281     Primitive& operator=(const Primitive& p) { operator=(p.val); return *this; }
00282     Primitive& operator+=(unsigned char v) { prevVal=val; val+=v; fireValueChanged(prevVal==val); return *this; } //!< add-assign
00283     Primitive& operator-=(unsigned char v) { prevVal=val; val-=v; fireValueChanged(prevVal==val); return *this; } //!< subtract-assign
00284     Primitive& operator*=(unsigned char v) { prevVal=val; val*=v; fireValueChanged(prevVal==val); return *this; } //!< multiple-assign
00285     Primitive& operator/=(unsigned char v) { prevVal=val; val/=v; fireValueChanged(prevVal==val); return *this; } //!< divide-assign
00286     //unsigned char& operator*() { return val; }
00287     const unsigned char& operator*() const { return val; } //!< dereference will return data storage
00288     //unsigned char* operator->() { return &val; }
00289     const unsigned char* operator->() const { return &val; } //!< can use -> to access members of data storage
00290     operator unsigned char() const { return val; } //!< casting operator
00291     
00292     void setNumeric(bool isNum) { numeric=isNum; } //!< sets #numeric
00293     bool getNumeric() const { return numeric; } //!< returns #numeric
00294     
00295     void loadXML(xmlNode* node); //!< interprets @a node as a unsigned char
00296     void saveXML(xmlNode* node) const; //! saves #val into @a node
00297     void set(const std::string& str);
00298     using PrimitiveBase::set;
00299     std::string get() const {
00300       if(numeric) {
00301         std::stringstream sstr;
00302         sstr << (int)val;
00303         return sstr.str();
00304       } else
00305         return std::string(1,val);
00306     }
00307     virtual long toLong() const { return static_cast<long>(val); }
00308     virtual double toDouble() const { return static_cast<double>(val); }
00309     
00310     //! clone definition for Primitive<unsigned char>
00311     PLIST_CLONE_DEF(Primitive<unsigned char>,new Primitive<unsigned char>(val));
00312     
00313     const unsigned char& getPreviousValue() const { return prevVal; } //!< returns the previously assigned value
00314     
00315   protected:
00316     unsigned char val; //!< data storage
00317     unsigned char prevVal; //!< following each assignment, this is the "old" value -- very handy for PrimitiveListeners
00318     bool numeric; //!< if true, requests that saves store the numeric value instead of corresponding character
00319   };
00320   
00321   
00322   //! Provides a @c std::string specialization of Primitive<T>
00323   /*! Doesn't need to provide a operator cast because we subclass std::string itself! */
00324   template<>
00325   class Primitive<std::string> : public PrimitiveBase, public std::string {
00326   public:
00327     template<typename U, typename V> struct conversion_policy { typedef typename U::template ConversionTo<V> value_conversion; };
00328     Primitive() : PrimitiveBase(), std::string(), prevVal() {} //!< constructor
00329     Primitive(const std::string& v) : PrimitiveBase(), std::string(v), prevVal() {} //!< casting constructor
00330     Primitive(const std::string& v, size_type off, size_type count=npos) : PrimitiveBase(), std::string(v,off,count), prevVal() {} //!< casting constructor
00331     Primitive(const char* v, size_type count) : PrimitiveBase(), std::string(v,count), prevVal() {} //!< casting constructor
00332     Primitive(const char* v) : PrimitiveBase(), std::string(v), prevVal() {} //!< casting constructor
00333     Primitive(size_type count, char v) : PrimitiveBase(), std::string(count,v), prevVal() {} //!< casting constructor
00334     Primitive& operator=(const std::string& v) { if(&v==&prevVal) std::string::swap(prevVal); else { prevVal=*this; std::string::operator=(v); } fireValueChanged(prevVal==*this); return *this; } //!< assignment
00335     Primitive& operator=(const char* v) { prevVal=*this; std::string::operator=(v); fireValueChanged(prevVal==*this); return *this; } //!< assignment
00336     Primitive& operator=(char v) { prevVal=*this; std::string::operator=(v); fireValueChanged(prevVal==*this); return *this; } //!< assignment