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 
00007 //!@name libxml2 forward declarations
00008 //!forward declaration of the libxml2 struct of the same name
00009 extern "C" {
00010   xmlNode* xmlAddPrevSibling(xmlNode* node, xmlNode* sibling);
00011   xmlNode* xmlNewText(const xmlChar* s);
00012   xmlNode* xmlNewComment(const xmlChar* s);
00013   xmlNode* xmlAddChild(xmlNode * parent, xmlNode* child);
00014   xmlNode* xmlNewChild(xmlNode* parent, xmlNs* ns, const xmlChar * name, const xmlChar * content);
00015   int xmlStrEqual(const xmlChar* a, const xmlChar* b);
00016   xmlChar* xmlNodeGetContent(xmlNode* node);
00017   void xmlNodeSetContent(xmlNode* node, const xmlChar* content);
00018   xmlAttr* xmlHasProperty(xmlNode* node, const xmlChar* name);
00019   xmlChar* xmlGetProperty(xmlNode* node, const xmlChar* name);
00020   long xmlGetLineNo(xmlNode* node);
00021   extern void (*xmlFree)(void* ptr);
00022   void xmlNodeSetName(xmlNode* node, const xmlChar* name);
00023   void xmlFreeNode(xmlNode* node);
00024   void xmlUnlinkNode(xmlNode* node);
00025 }
00026 
00027 namespace plist {
00028 
00029   //! Implements type-specific functionality through template specialization, mainly involving value conversion and stringification formatting
00030   /*! Provides smart-pointer style functionality for transparent
00031    *  access to the value storage, as well as automatic casting
00032    *  to and from the value type so you can almost always treat
00033    *  the Primitive as if it was the value itself. */
00034   template<typename T>
00035   class Primitive : public PrimitiveBase {
00036   public:
00037     //! constructor
00038     Primitive() : ObjectBase(), val() {}
00039     //! constructor, provides automatic casting from the value type
00040     Primitive(const T& v) : ObjectBase(), val(v) {} 
00041     //! assignment from value type (template specializations add in-place modiciation (e.g. +=, *=))
00042     Primitive& operator=(const T& v) { val=v; fireValueChanged(); return *this; }
00043 
00044     Primitive& operator+=(const T& v) { val+=v; fireValueChanged(); return *this; } //!< add in-place
00045     Primitive& operator-=(const T& v) { val-=v; fireValueChanged(); return *this; } //!< subtract in-place
00046     Primitive& operator*=(const T& v) { val*=v; fireValueChanged(); return *this; } //!< multiply in-place
00047     Primitive& operator/=(const T& v) { val/=v; fireValueChanged(); return *this; } //!< divide in-place
00048     
00049     //! smart pointer access to value
00050     const T& operator*() const { return val; }
00051     //! smart pointer access to value
00052     const T* operator->() const { return &val; }
00053     
00054     //! automatic casting to the value type
00055     operator T() const { return val; }
00056 
00057     // **** Template specializations should provide their own implementations of loadXML and saveXML ****
00058     /*void loadXML(xmlNode* node) {
00059       if(node==NULL)
00060         return;
00061       //decode base64 from xml node
00062       //val->loadBuffer(buf,bufsize);
00063       fireValueChanged(); 
00064     }
00065     void saveXML(xmlNode* node) const {
00066       if(node==NULL)
00067         return;
00068       unsigned int bufsize=val->getBinSize();
00069       char * buf = new char[bufsize];
00070       val->saveBuffer(buf,bufsize);
00071       //base64 encode into xml node
00072       delete [] buf;
00073     }*/
00074     
00075     //! clone definition for Primitive<T>
00076     PLIST_CLONE_DEF(Primitive<T>,new Primitive<T>(val));
00077 
00078   protected:
00079     T val; //!< value storage
00080   };
00081   //! implements the clone function for Primitive<T>
00082   PLIST_CLONE_IMPT(class T,Primitive<T>,new Primitive<T>(val));
00083 
00084   
00085 /*! @cond SHOW_PLIST_OBJECT_SPECIALIZATION */
00086   
00087   //! provides a @c bool specialization of Primitive<T>
00088   /*! A @c bool can be treated as either a string or an integer\n
00089    *  When saving, "true" or "false" will be used, but users could
00090    *  also specify "yes"/"no" or "on"/"off".  If an integer is used,
00091    *  it will be interpreted as usual: 0==false, otherwise true. */
00092   template<>
00093   class Primitive<bool> : public PrimitiveBase {
00094   public:
00095     Primitive() : PrimitiveBase(), val() {} //!< constructor
00096     Primitive(const bool& v) : PrimitiveBase(), val(v) {} //!< casting constructor
00097     Primitive& operator=(const bool& v) { val=v; fireValueChanged(); return *this; } //!< assignment constructor
00098     //bool& operator*() { return val; }
00099     const bool& operator*() const { return val; } //!< dereference will return data storage
00100     //bool* operator->() { return &val; }
00101     const bool* operator->() const { return &val; } //!< can use -> to access members of data storage
00102     operator bool() const { return val; } //!< casting operator
00103     
00104     void loadXML(xmlNode* node); //!< interprets @a node as a bool
00105     void saveXML(xmlNode* node) const;  //!< saves #val into @a node
00106     void set(const std::string& str);
00107     std::string get() const {
00108       return val?"true":"false";
00109     }
00110     //! clone definition for Primitive<bool>
00111     PLIST_CLONE_DEF(Primitive<bool>,new Primitive<bool>(val));
00112     
00113   protected:
00114     bool val; //!< the actual data storage
00115   };
00116   
00117 /*! @endcond */
00118 
00119   //! provides a @c char specialization of plist::Primitive<T>, adds a unique #numeric property to the usual template implementation
00120   /*! A @c char can be treated as either a string or an integer, you can use
00121    *  the setNumeric(bool) function to indicate which style to use when saving */
00122   template<>
00123   class Primitive<char> : public PrimitiveBase {
00124   public:
00125     Primitive() : PrimitiveBase(), val(), numeric(false) {} //!< constructor
00126     Primitive(const char& v, bool isNum=false) : PrimitiveBase(), val(v), numeric(isNum) {} //!< casting constructor
00127     Primitive& operator=(const char& v) { val=v; fireValueChanged(); return *this; } //!< assignment
00128     Primitive& operator+=(const char& v) { val+=v; fireValueChanged(); return *this; } //!< add-assign
00129     Primitive& operator-=(const char& v) { val-=v; fireValueChanged(); return *this; } //!< subtract-assign
00130     Primitive& operator*=(const char& v) { val*=v; fireValueChanged(); return *this; } //!< multiply-assign
00131     Primitive& operator/=(const char& v) { val/=v; fireValueChanged(); return *this; } //!< divide-assign
00132     //char& operator*() { return val; }
00133     const char& operator*() const { return val; } //!< dereference will return data storage
00134     //char* operator->() { return &val; }
00135     const char* operator->() const { return &val; } //!< can use -> to access members of data storage
00136     operator char() const { return val; } //!< casting operator
00137     
00138     void setNumeric(bool isNum) { numeric=isNum; } //!< sets #numeric
00139     bool getNumeric() const { return numeric; } //!< returns #numeric
00140     
00141     void loadXML(xmlNode* node); //!< interprets @a node as a char
00142     void saveXML(xmlNode* node) const; //! saves #val into @a node
00143     void set(const std::string& str);
00144     std::string get() const {
00145       if(numeric) {
00146         std::stringstream sstr;
00147         sstr << (int)val;
00148         return sstr.str();
00149       } else
00150         return std::string(1,val);
00151     }
00152     //! clone definition for Primitive<char>
00153     PLIST_CLONE_DEF(Primitive<char>,new Primitive<char>(val));
00154     
00155   protected:
00156     char val; //!< data storage
00157     bool numeric; //!< if true, requests that saves store the numeric value instead of corresponding character
00158   };
00159   
00160   //! provides an @c unsigned @c char specialization of plist::Primitive<T>, adds a unique #numeric property to the usual template implementation
00161   /*! A @c char can be treated as either a string or an integer, you can use
00162    *  the setNumeric(bool) function to indicate which style to use when saving */
00163   template<>
00164   class Primitive<unsigned char> : public PrimitiveBase {
00165   public:
00166     Primitive() : PrimitiveBase(), val(), numeric(false) {} //!< constructor
00167     Primitive(const unsigned char& v, bool isNum=false) : PrimitiveBase(), val(v), numeric(isNum) {} //!< casting constructor
00168     Primitive& operator=(const unsigned char& v) { val=v; fireValueChanged(); return *this; } //!< assignment
00169     Primitive& operator+=(const unsigned char& v) { val+=v; fireValueChanged(); return *this; } //!< add-assign
00170     Primitive& operator-=(const unsigned char& v) { val-=v; fireValueChanged(); return *this; } //!< subtract-assign
00171     Primitive& operator*=(const unsigned char& v) { val*=v; fireValueChanged(); return *this; } //!< multiple-assign
00172     Primitive& operator/=(const unsigned char& v) { val/=v; fireValueChanged(); return *this; } //!< divide-assign
00173     //unsigned char& operator*() { return val; }
00174     const unsigned char& operator*() const { return val; } //!< dereference will return data storage
00175     //unsigned char* operator->() { return &val; }
00176     const unsigned char* operator->() const { return &val; } //!< can use -> to access members of data storage
00177     operator unsigned char() const { return val; } //!< casting operator
00178     
00179     void setNumeric(bool isNum) { numeric=isNum; } //!< sets #numeric
00180     bool getNumeric() const { return numeric; } //!< returns #numeric
00181     
00182     void loadXML(xmlNode* node); //!< interprets @a node as a unsigned char
00183     void saveXML(xmlNode* node) const; //! saves #val into @a node
00184     void set(const std::string& str);
00185     std::string get() const {
00186       if(numeric) {
00187         std::stringstream sstr;
00188         sstr << (int)val;
00189         return sstr.str();
00190       } else
00191         return std::string(1,val);
00192     }
00193     //! clone definition for Primitive<unsigned char>
00194     PLIST_CLONE_DEF(Primitive<unsigned char>,new Primitive<unsigned char>(val));
00195     
00196   protected:
00197     unsigned char val; //!< data storage
00198     bool numeric; //!< if true, requests that saves store the numeric value instead of corresponding character
00199   };
00200   
00201 /*! @cond SHOW_PLIST_OBJECT_SPECIALIZATION */
00202 
00203 //! a macro to provide template specializations for the numeric primitives, which only need to vary their string name
00204 #define PLIST_OBJECT_SPECIALIZATION(T,PRIM) \
00205   template<> \
00206   class Primitive<T> : public PrimitiveBase { \
00207   public: \
00208     /*! \brief constructor */ \
00209     Primitive() : PrimitiveBase(), val() {} \
00210     /*! \brief copy constructor, automatic conversion from value type */ \
00211     Primitive(const T& v) : PrimitiveBase(), val(v) {} \
00212     /*! \brief assignment from value type */ \
00213     Primitive& operator=(const T& v) { val=v; fireValueChanged(); return *this; } \
00214     Primitive& operator+=(const T& v) { val+=v; fireValueChanged(); return *this; } /*!< \brief in-place modification supported */ \
00215     Primitive& operator-=(const T& v) { val-=v; fireValueChanged(); return *this; } /*!< \brief in-place modification supported */ \
00216     Primitive& operator*=(const T& v) { val*=v; fireValueChanged(); return *this; } /*!< \brief in-place modification supported */ \
00217     Primitive& operator/=(const T& v) { val/=v; fireValueChanged(); return *this; } /*!< \brief in-place modification supported */ \
00218     /*! \brief dereference to access primitive storage */ \
00219     const T& operator*() const { return val; } \
00220     /*! \brief dereference to access primitive storage */ \
00221     const T* operator->() const { return &val; } \
00222     /*! \brief cast operator to automatically convert to value type */ \
00223     operator T() const { return val; } \
00224     /*! \brief interprets \a node as holding the specialization type */ \
00225     void loadXML(xmlNode* node); \
00226     /*! \brief saves #val into \a node */ \
00227     void saveXML(xmlNode* node) const; \
00228     void set(const std::string& str); \
00229     std::string get() const { \
00230       std::stringstream sstr; \
00231       sstr <<std::setprecision(64)<< val; \
00232       return sstr.str(); \
00233     } \
00234     PLIST_CLONE_DEF(Primitive<T>,new Primitive<T>(val)); \
00235   protected: \
00236     /*! \brief storage of primitve value */ \
00237     T val; \
00238   }
00239   
00240   PLIST_OBJECT_SPECIALIZATION(short,"integer");
00241   PLIST_OBJECT_SPECIALIZATION(unsigned short,"integer");
00242   PLIST_OBJECT_SPECIALIZATION(int,"integer");
00243   PLIST_OBJECT_SPECIALIZATION(unsigned int,"integer");
00244   PLIST_OBJECT_SPECIALIZATION(long,"integer");
00245   PLIST_OBJECT_SPECIALIZATION(unsigned long,"integer");
00246   PLIST_OBJECT_SPECIALIZATION(long long,"integer");
00247   PLIST_OBJECT_SPECIALIZATION(unsigned long long,"integer");
00248   PLIST_OBJECT_SPECIALIZATION(float,"real");
00249   PLIST_OBJECT_SPECIALIZATION(double,"real");
00250   
00251 #undef PLIST_OBJECT_SPECIALIZATION
00252 /*! @endcond */
00253 
00254   //! Provides a @c std::string specialization of Primitive<T>
00255   /*! Doesn't need to provide a operator cast because we subclass std::string itself! */
00256   template<>
00257   class Primitive<std::string> : public PrimitiveBase, public std::string {
00258   public:
00259     Primitive() : PrimitiveBase(), std::string() {} //!< constructor
00260     Primitive(const std::string& v) : PrimitiveBase(), std::string(v) {} //!< casting constructor
00261     Primitive(const std::string& v, size_type off, size_type count=npos) : PrimitiveBase(), std::string(v,off,count) {} //!< casting constructor
00262     Primitive(const char* v, size_type count) : PrimitiveBase(), std::string(v,count) {} //!< casting constructor
00263     Primitive(const char* v) : PrimitiveBase(), std::string(v) {} //!< casting constructor
00264     Primitive(size_type count, char v) : PrimitiveBase(), std::string(count,v) {} //!< casting constructor
00265     Primitive& operator=(const std::string& v) { std::string::operator=(v); fireValueChanged(); return *this; } //!< assignment
00266     Primitive& operator=(const char* v) { std::string::operator=(v); fireValueChanged(); return *this; } //!< assignment
00267     Primitive& operator=(char v) { std::string::operator=(v); fireValueChanged(); return *this; } //!< assignment
00268     //std::string& operator*() { return *this; }
00269     const std::string& operator*() const { return *this; } //!< dereference will return data storage as a string (for uniformity with the other Primitives, although unnecessary with this instantiation)
00270     //std::string* operator->() { return this; }
00271     const std::string* operator->() const { return this; } //!< returns a pointer to this (for uniformity with the other Primitives, although unnecessary with this instantiation)
00272     //no casting operator because we subclass string
00273     
00274     void loadXML(xmlNode* node); //!< interprets @a node as a string
00275     void saveXML(xmlNode* node) const; //!< saves the content of the string into @a node
00276     void set(const std::string& str) { operator=(str); } // operator= will fireValueChanged
00277     std::string get() const { return *this; }
00278     //! clone definition for Primitive<std::string>
00279     PLIST_CLONE_DEF(Primitive<std::string>,new Primitive<std::string>(get()));
00280   };
00281   
00282   //! Provides an interface for the use of enumerations in a plist -- you can specify values by either the string name or the corresponding integer value
00283   /*! Where an array of names is required, you must order the array such that
00284    *  the enumeration value can be used as an index into the array.
00285    *  The 'maxval' parameters should be one above the maximum enumeration -- 
00286    *  if your enumeration runs sequentially from 0 to n, #max should be the
00287    *  number of enumerations: n+1 */
00288   template<typename T> 
00289   class NamedEnumeration : public PrimitiveBase {
00290   public:
00291     NamedEnumeration() : PrimitiveBase(), val(), names(NULL), max(0) {} //!< constructor
00292     NamedEnumeration(const NamedEnumeration& ne) : PrimitiveBase(ne), val(ne.val), names(ne.names), max(ne.max) {} //!< copy constructor
00293     NamedEnumeration(const T& v, const char * const* enumnames, unsigned int maxval) : PrimitiveBase(), val(v), names(enumnames), max(maxval) {} //!< constructor, pass initial value, array of strings (the names), and the one-plus-maximum enum value (i.e. the number of enumeration values if they run sequentially from 0)
00294     NamedEnumeration(const T& v) : PrimitiveBase(), val(v), names(NULL), max(0) {} //!< automatic casting from the enumeration
00295     NamedEnumeration& operator=(const T& v) { val=v; fireValueChanged(); return *this; } //!< assignment from enumeration value (numeric)
00296     NamedEnumeration& operator=(const std::string& v) { set(v); return *this; } //!< assignment from string
00297     NamedEnumeration& operator=(const NamedEnumeration<T>& ne) { val=ne.val; names=ne.names; max=ne.max; return PrimitiveBase::operator=(ne); } //!< assignment
00298     //T& operator*() { return val; }
00299     const T& operator*() const { return val; } //!< value access
00300     operator T() const { return val; } //!< automatic casting to the enumeration value
00301     void setNames(const char *  const* enumnames, unsigned int maxval) { names=enumnames; max=maxval; } //!< (re)set the array of names and one-plus-maximum enum value (i.e. the number of enumeration values if they run sequentially from 0)
00302     const char*  const* getNames() const { return names; } //!< returns the array of names previously provided from constructor or setNames()
00303     const char* getName(unsigned int i) const { return names[i]; } //!< returns the name for a particular index
00304     unsigned int getMax() const { return max; } //!< returns the one-past-maximum of enumeration values previously provided to constructor or setNames()
00305 
00306     //! interprets @a node as either a string holding the name, or a number corresponding to its index (name is preferred)
00307     void loadXML(xmlNode* node) {
00308       if(node==NULL)
00309         return;
00310       if(xNodeHasName(node,"true") || xNodeHasName(node,"false")) {
00311         std::string name=(const char*)xNodeGetName(node);
00312         unsigned int i=findName(name.c_str());
00313         if(i==-1U)
00314           throw bad_format(node,("Error: plist NamedEnumeration cannot be '"+name+"'").c_str());
00315         val=static_cast<T>(i);
00316         std::cerr << "Warning: plist NamedEnumeration should use <string>" << name << "</string>, not <" << name << "/>" << std::endl;
00317       } else if(xNodeHasName(node,"integer") || xNodeHasName(node,"real") || xNodeHasName(node,"string")) {
00318         xmlChar * cont=xmlNodeGetContent(node);
00319         try {
00320           set((char*)cont);
00321         } catch(const bad_format& err) {
00322           xmlFree(cont);
00323           throw bad_format(node,err.what());
00324         } catch(...) {
00325           xmlFree(cont);
00326           throw;
00327         }
00328         xmlFree(cont);
00329       } else
00330         throw bad_format(node,"Error: plist NamedEnumeration must be numeric or valid string");
00331     }
00332     //! saves name of current value (if available, index used otherwise) into @a node
00333     void saveXML(xmlNode* node) const {
00334       if(node==NULL)
00335         return;
00336       if(names!=NULL && names[val]!=NULL && val>0 && (unsigned int)val<max) {
00337         xmlNodeSetName(node,(const xmlChar*)"string");
00338       } else {
00339         xmlNodeSetName(node,(const xmlChar*)"integer");
00340       }
00341       xmlNodeSetContent(node,(const xmlChar*)get().c_str());
00342     }
00343     void set(const std::string& str) {
00344       unsigned int i=findName(str.c_str());
00345       if(i==-1U) {
00346         if(sscanf(str.c_str(),"%d",&i)==0)
00347           throw bad_format(NULL,"Error: plist NamedEnumeration must be numeric or valid string");
00348       }
00349       val=static_cast<T>(i);
00350       fireValueChanged(); 
00351     }
00352     std::string get() const {
00353       if(names!=NULL && names[val]!=NULL && val>=0 && (unsigned int)val<max)
00354         return names[val];
00355       std::stringstream str;
00356       str << val;
00357       return str.str();
00358     }
00359     //! implements the clone function for NamedEnumeration<T>
00360     PLIST_CLONE_DEF(NamedEnumeration<T>,new NamedEnumeration<T>(*this));
00361 
00362   protected:
00363     //! returns the enum corresponding to @a name
00364     unsigned int findName(const char* name) {
00365       if(name==NULL || names==NULL)
00366         return -1U;
00367       //prefer case sensitive match
00368       for(unsigned int i=0; i<max; i++)
00369         if(names[i] && strcmp(name,names[i])==0)
00370           return i;
00371       //but allow case insensitive if exact match not found
00372       for(unsigned int i=0; i<max; i++)
00373         if(names[i] && strcasecmp(name,names[i])==0)
00374           return i;
00375       return -1U;
00376     }
00377     T val; //!< storage of enum value
00378     const char *  const* names; //!< pointer to array of names -- enum value must be able to serve as index for lookup
00379     unsigned int max; //!< one-plus-maximum enum value, i.e. the number of enum entries if they are ordered sequentially from 0
00380   };
00381   //! implements the clone function for NamedEnumeration<T>
00382   PLIST_CLONE_IMPT(class T,NamedEnumeration<T>,new NamedEnumeration<T>(*this));
00383 
00384 } //namespace plist
00385 
00386 
00387 /*! @file
00388  * @brief 
00389  * @author Ethan Tira-Thompson (ejt) (Creator)
00390  *
00391  * $Author: ejt $
00392  * $Name: tekkotsu-3_0 $
00393  * $Revision: 1.17 $
00394  * $State: Exp $
00395  * $Date: 2006/09/27 20:11:38 $
00396  */
00397 
00398 #endif

Tekkotsu v3.0
Generated Wed Oct 4 00:03:45 2006 by Doxygen 1.4.7