Tekkotsu Homepage | Demos | Overview | Downloads | Dev. Resources | Reference | Credits |
plistBase.hGo to the documentation of this file.00001 //-*-c++-*- 00002 #ifndef INCLUDED_plistBase_h_ 00003 #define INCLUDED_plistBase_h_ 00004 00005 #include "XMLLoadSave.h" 00006 #include "Cloneable.h" 00007 #include <exception> 00008 #include <string> 00009 #include <iostream> 00010 #include <iomanip> 00011 #include <sstream> 00012 #include <set> 00013 #include <cctype> 00014 00015 /* 00016 From: <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 00017 00018 <!ENTITY % plistObject "(array | data | date | dict | real | integer | string | true | false )" > 00019 <!ELEMENT plist %plistObject;> 00020 <!ATTLIST plist version CDATA "1.0" > 00021 00022 <!-- Collections --> 00023 <!ELEMENT array (%plistObject;)*> 00024 <!ELEMENT dict (key, %plistObject;)*> 00025 <!ELEMENT key (#PCDATA)> 00026 00027 <!--- Primitive types --> 00028 <!ELEMENT string (#PCDATA)> 00029 <!ELEMENT data (#PCDATA)> <!-- Contents interpreted as Base-64 encoded --> 00030 <!ELEMENT date (#PCDATA)> <!-- Contents should conform to a subset of ISO 8601 (in particular, YYYY '-' MM '-' DD 'T' HH ':' MM ':' SS 'Z'. Smaller units may be omitted with a loss of precision) --> 00031 00032 <!-- Numerical primitives --> 00033 <!ELEMENT true EMPTY> <!-- Boolean constant true --> 00034 <!ELEMENT false EMPTY> <!-- Boolean constant false --> 00035 <!ELEMENT real (#PCDATA)> <!-- Contents should represent a floating point number matching ("+" | "-")? d+ ("."d*)? ("E" ("+" | "-") d+)? where d is a digit 0-9. --> 00036 <!ELEMENT integer (#PCDATA)> <!-- Contents should represent a (possibly signed) integer number in base 10 --> 00037 */ 00038 00039 extern "C" { 00040 struct _xmlNode; 00041 struct _xmlDoc; 00042 struct _xmlAttr; 00043 struct _xmlNs; 00044 typedef _xmlNode xmlNode; //!< forward declaration of xmlNode to avoid including actual header here 00045 typedef _xmlDoc xmlDoc; //!< forward declaration of xmlDoc to avoid including actual header here 00046 typedef _xmlAttr xmlAttr; //!< forward declaration of xmlAttr to avoid including actual header here 00047 typedef _xmlNs xmlNs; //!< forward declaration of xmlNs to avoid including actual header here 00048 typedef unsigned char xmlChar; //!< forward declaration of xmlChar to avoid including actual header here 00049 } 00050 00051 //! A collection of classes to implement the Propery List data storage format, a XML standard used by Apple and others 00052 namespace plist { 00053 00054 #ifdef PLIST_CLONE_ABS 00055 # error PLIST_CLONE_ABS already defined! 00056 #else 00057 # if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && (__GNUC_MINOR__ > 3)) 00058 //! defines abstract clone() (=0) using polymorphic return type @a TYPE if supported by current version of gcc, Cloneable otherwise 00059 # define PLIST_CLONE_ABS(TYPE) virtual TYPE* clone() const __attribute__ ((warn_unused_result)) =0; 00060 # else 00061 //! defines abstract clone() (=0) using polymorphic return type @a TYPE if supported by current version of gcc, Cloneable otherwise 00062 # define PLIST_CLONE_ABS(TYPE) virtual Cloneable* clone() const =0; 00063 # endif 00064 #endif 00065 00066 #ifdef PLIST_CLONE_DEF 00067 # error PLIST_CLONE_DEF already defined! 00068 #else 00069 # if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && (__GNUC_MINOR__ > 3)) 00070 //! declares clone() using polymorphic return type @a TYPE if supported by current version of gcc, Cloneable otherwise; returns @a RETVAL 00071 # define PLIST_CLONE_DEF(TYPE,RETVAL) virtual TYPE* clone() const __attribute__ ((warn_unused_result)); 00072 //! implements clone() using polymorphic return type @a TYPE if supported by current version of gcc, Cloneable otherwise; returns @a RETVAL 00073 # define PLIST_CLONE_IMP(TYPE,RETVAL) TYPE* TYPE::clone() const { return RETVAL; } 00074 //! implements clone() using templated polymorphic return type @a TYPE if supported by current version of gcc, Cloneable otherwise; returns @a RETVAL 00075 # define PLIST_CLONE_IMPT(TEMPL,TYPE,RETVAL) template<typename TEMPL> TYPE<TEMPL>* TYPE<TEMPL>::clone() const { return RETVAL; } 00076 //! implements clone() using templated polymorphic return type @a TYPE if supported by current version of gcc, Cloneable otherwise; returns @a RETVAL 00077 # define PLIST_CLONE_IMPT2(TEMPL1,TEMPL2,TYPE,RETVAL) template<typename TEMPL1,typename TEMPL2> TYPE<TEMPL1,TEMPL2>* TYPE<TEMPL1,TEMPL2>::clone() const { return RETVAL; } 00078 # else 00079 //! declares clone() using polymorphic return type @a TYPE if supported by current version of gcc, Cloneable otherwise; returns @a RETVAL 00080 # define PLIST_CLONE_DEF(TYPE,RETVAL) virtual Cloneable* clone() const { return RETVAL; } 00081 //! implements clone() using polymorphic return type @a TYPE if supported by current version of gcc, Cloneable otherwise; returns @a RETVAL 00082 # define PLIST_CLONE_IMP(TYPE,RETVAL) 00083 //! implements clone() using templated polymorphic return type @a TYPE if supported by current version of gcc, Cloneable otherwise; returns @a RETVAL 00084 # define PLIST_CLONE_IMPT(TEMPL,TYPE,RETVAL) 00085 //! implements clone() using templated polymorphic return type @a TYPE if supported by current version of gcc, Cloneable otherwise; returns @a RETVAL 00086 # define PLIST_CLONE_IMPT2(TEMPL1,TEMPL2,TYPE,RETVAL) 00087 # endif 00088 #endif 00089 00090 //! Base class for the plist listener callbacks 00091 class Listener { 00092 public: 00093 //! destructor 00094 virtual ~Listener() {} 00095 }; 00096 00097 class PrimitiveBase; 00098 //! If you wish to be notified any time a particular plist primitive's value has been changed, inherit from this and implement the callback, then register it with the plist object through Primitive::addPrimitiveListener() 00099 class PrimitiveListener : public Listener { 00100 public: 00101 //! This will be called whenever a plist you have registered with is changed 00102 /*! @a pl is const to help you avoid infinite recursion from an 00103 * accidental modification of @a pl's value -- use a const cast 00104 * if you're sure you know what you're doing */ 00105 virtual void plistValueChanged(const PrimitiveBase& pl)=0; 00106 00107 //! This will be called whenever a plist you have registered with is reassigned is current value (usually something you'll want to ignore...) 00108 /*! Argument is const to help you avoid infinite recursion from an 00109 * accidental modification of its value -- use a const cast 00110 * if you're sure you know what you're doing */ 00111 virtual void plistValueTouched(const PrimitiveBase& /*pl*/) {} 00112 }; 00113 00114 class ObjectBase; 00115 class Collection; 00116 //! If you wish to be notified any time an entry is added, removed, or replaced from a Dictionary, Array, or Vector, inherit from this and implement one or both of the functions, then register it with the collection's addCollectionListener() 00117 class CollectionListener : public Listener { 00118 public: 00119 //! This will be called whenever an entry is added to the collection 00120 virtual void plistCollectionEntryAdded(Collection& /*col*/, ObjectBase& /*primitive*/) {} 00121 //! This will be called whenever an entry is added to the collection 00122 virtual void plistCollectionEntryRemoved(Collection& /*col*/, ObjectBase& /*primitive*/) {} 00123 //! This will be called whenever an entry is replaced, or multiple entries are added/removed at once, such as when an assignment occurs 00124 virtual void plistCollectionEntriesChanged(Collection& /*col*/) {} 00125 }; 00126 00127 //! This base class provides the root functionality for all plist entities -- Dictionary and the various templated subclasses of PrimitiveBase 00128 /*! The subclasses may throw std::bad_format if the document is poorly structured or bad values are found. */ 00129 class ObjectBase : public XMLLoadSave, public Cloneable { 00130 friend ObjectBase* loadXML(xmlNode* node); 00131 public: 00132 //! specifies that collections (e.g. plist::Array or plist::Dictionary) of these abstract base classes (ObjectBase, PrimitiveBase) can convert any primitive type to a plist::Primitive wrapper 00133 template<typename U, typename V> struct conversion_policy { typedef typename U::template WrapValueConversion<V> value_conversion; }; 00134 00135 ObjectBase(); //!< constructor 00136 virtual ~ObjectBase()=0; //!< destructor 00137 00138 //! polymorphic assignment (throws std::bad_cast if the assignment is between invalid types, i.e. a primitive and a collection, or different collection types) 00139 virtual void set(const ObjectBase&)=0; 00140 00141 //! casting operator: return current value as specified type (throws std::runtime_error exception if bad cast, e.g. dictionary or array to value type) 00142 /*! The implementation for this function is defined by a series of specializations. 00143 * This allows you to add casts for additional user-defined types, as well as get 00144 * compile time error if you attempt to cast to an unsupported type. 00145 * (I really wish we had virtual templated functions...) */ 00146 template<typename T> T to() const; 00147 00148 //! return current value as a string 00149 virtual std::string toString() const=0; 00150 //! return current value as an (long) integer (throws std::runtime_error exception if incompatable, e.g. dictionary or array to value type) 00151 virtual long toLong() const=0; 00152 //! return current value as a double (throws std::runtime_error exception if incompatable, e.g. dictionary or array to value type) 00153 virtual double toDouble() const=0; 00154 00155 //! subclasses are expected to provide a working implementation 00156 virtual void loadXML(xmlNode* node)=0; 00157 //! subclasses are expected to provide a working implementation 00158 virtual void saveXML(xmlNode* node) const=0; 00159 00160 //! allows a copy to be made of an event, supporting polymorphism 00161 PLIST_CLONE_ABS(ObjectBase); 00162 00163 protected: 00164 //! polymorphic assignment operator, see assign() 00165 /*! This is protected for two reasons: one, so you don't accidentally use it via simple '=' statement, 00166 * and two, to avoid 'operator= was hidden' warnings in every base class (because they keep 00167 * reintroducing their default operator=(), hiding/shadowing this one (if it were virtual, as it would 00168 * need to be to take on the role filled by assign(). */ 00169 ObjectBase& operator=(const ObjectBase&) { return *this; } 00170 00171 //!@name Inherited from XMLLoadSave 00172 virtual void setParseTree(xmlDoc * doc) const; 00173 virtual xmlNode* FindRootXMLElement(xmlDoc* doc) const; 00174 //@} 00175 00176 //!Provides accessor functions to struct fields without having to include libxml.h everywhere 00177 //!@name libxml Forwards 00178 static bool xNodeHasName(xmlNode* node, const char* name); //!< returns true if the name of @a node matches @a name 00179 static const xmlChar* xNodeGetName(xmlNode* node); //!< returns name of @a node (not a libxml function) 00180 static xmlNode* xNodeGetChildren(xmlNode* node); //!< returns children of @a node (not a libxml function) 00181 static xmlNode* xNodeGetLastChild(xmlNode* node); //!< returns last child of @a node (not a libxml function) 00182 static xmlNode* xNodeGetNextNode(xmlNode* node); //!< returns next node (sibling) after @a node (not a libxml function) 00183 static xmlNode* xNodeGetPrevNode(xmlNode* node); //!< returns previous node (sibling) before @a node (not a libxml function) 00184 static xmlNode* xNodeGetParent(xmlNode* node); //!< returns parent node of @a node (not a libxml function) 00185 static xmlDoc* xNodeGetDoc(xmlNode* node); //!< returns document node of @a node (not a libxml function) 00186 static bool xNodeIsText(xmlNode* node); //!< returns true if node is an XML_TEXT_NODE (not a libxml function) 00187 static bool xNodeIsElement(xmlNode* node); //!< returns true if node is an XML_ELEMENT_NODE (not a libxml function) 00188 static bool xNodeIsComment(xmlNode* node); //!< returns true if node is an XML_COMMENT_NODE (not a libxml function) 00189 //@} 00190 00191 //! returns true if @a str is some form of affirmative (e.g. "true" or "yes") 00192 static bool matchTrue(const std::string& str) { return str=="true" || str=="yes"; } 00193 //! returns true if @a str is some form of negative (e.g. "false" or "no") 00194 static bool matchFalse(const std::string& str) { return str=="false" || str=="no"; } 00195 }; 00196 //! output of an ObjectBase to a stream 00197 inline std::ostream& operator<<(std::ostream& os, const ObjectBase& pb) { 00198 return os << pb.toString(); 00199 } 00200 00201 // specializations to funnel cast requests through the appropriate conversion 00202 /// @cond INTERNAL 00203 template<> inline bool ObjectBase::to<bool>() const { return toLong(); } 00204 template<> inline char ObjectBase::to<char>() const { return toLong(); } 00205 template<> inline unsigned char ObjectBase::to<unsigned char>() const { return toLong(); } 00206 template<> inline short ObjectBase::to<short>() const { return toLong(); } 00207 template<> inline unsigned short ObjectBase::to<unsigned short>() const { return toLong(); } 00208 template<> inline int ObjectBase::to<int>() const { return toLong(); } 00209 template<> inline unsigned int ObjectBase::to<unsigned int>() const { return toLong(); } 00210 template<> inline long ObjectBase::to<long>() const { return toLong(); } 00211 template<> inline unsigned long ObjectBase::to<unsigned long>() const { return toLong(); } 00212 template<> inline long long ObjectBase::to<long long>() const { return toLong(); } 00213 template<> inline unsigned long long ObjectBase::to<unsigned long long>() const { return toLong(); } 00214 template<> inline float ObjectBase::to<float>() const { return toDouble(); } 00215 template<> inline double ObjectBase::to<double>() const { return toDouble(); } 00216 template<> inline const char* ObjectBase::to<const char*>() const { return toString().c_str(); } 00217 template<> inline std::string ObjectBase::to<std::string>() const { return toString(); } 00218 /// @endcond 00219 00220 template<typename T> class Primitive; // forward declaration so we can solve string/Primitive<string> ambiguity in operator= below 00221 00222 //! Provides common functionality to all primitive value classes (implemented in a templated subclass Primitive) 00223 /*! This class supports callbacks upon modification through the use of the 00224 * PrimitiveListener interface. Note that we only store a pointer to the 00225 * listener list, which is typically unallocated when no listeners are 00226 * active. This should ensure minimal memory usage per object, as well as 00227 * support safe storage of plist objects in inter-process shared memory 00228 * regions. 00229 * 00230 * If you are using these in a shared memory region, just be sure that only 00231 * the process with listeners does any and all modifications, and that it 00232 * unsubscribes before detaching from the region (or else destroys the region 00233 * itself) */ 00234 class PrimitiveBase : public ObjectBase { 00235 public: 00236 //! constructor 00237 PrimitiveBase() : ObjectBase(), primitiveListeners() {} 00238 //! copy constructor (don't copy listeners) 00239 PrimitiveBase(const PrimitiveBase& pb) : ObjectBase(pb), primitiveListeners() {} 00240 //! assignment (don't assign listeners); doesn't trigger fireValueChanged, subclass should do that from its own operator=() following assignment 00241 virtual PrimitiveBase& operator=(const PrimitiveBase& pb) { ObjectBase::operator=(pb); return *this; } 00242 //! assignment from Primitive<string>, solely to resolve ambiguity with this type between operator=(PrimitiveBase) and operator=(std::string) 00243 PrimitiveBase& operator=(const Primitive<std::string>& v); 00244 //! assignment from std::string, wraps it in a plist::Primitive and passes on to operator=(PrimitiveBase) 00245 PrimitiveBase& operator=(const std::string& v); 00246 //! assignment from long value, wraps it in a plist::Primitive and passes on to operator=(PrimitiveBase) 00247 PrimitiveBase& operator=(long v); 00248 //! assignment from unsigned long value, wraps it in a plist::Primitive and passes on to operator=(PrimitiveBase) 00249 PrimitiveBase& operator=(unsigned long v); 00250 //! assignment from double value, wraps it in a plist::Primitive and passes on to operator=(PrimitiveBase) 00251 PrimitiveBase& operator=(double v); 00252 //! destructor 00253 ~PrimitiveBase(); 00254 00255 //! assign a new value 00256 virtual void set(const std::string& str)=0; 00257 virtual void set(const ObjectBase& ob) { const PrimitiveBase& pb = dynamic_cast<const PrimitiveBase&>(ob); *this=pb; } 00258 //! return current value as a string 00259 virtual std::string get() const=0; 00260 00261 virtual std::string toString() const { return get(); } 00262 00263 //! get notified of changes; be sure to call removeValueListener before destructing @a vl! 00264 virtual void addPrimitiveListener(PrimitiveListener* vl); 00265 //! no longer take notification of changes to this object's value 00266 virtual void removePrimitiveListener(PrimitiveListener* vl); 00267 //! test if @a l is currently registered as a listener 00268 virtual bool isPrimitiveListener(PrimitiveListener * vl); 00269 00270 protected: 00271 //! run through #primitiveListeners, calling PrimitiveListener::plistValueChanged(*this) or PrimitiveListener::plistValueTouched(*this) 00272 virtual void fireValueChanged(bool touch) const; 00273 //! stores a list of the current listeners 00274 std::set<PrimitiveListener*>* primitiveListeners; 00275 }; 00276 //! output stringified value (from PrimitiveBase::get()) to stream 00277 inline std::ostream& operator<<(std::ostream& os, const PrimitiveBase& pb) { 00278 return os << pb.get(); 00279 } 00280 //! input value from next word in @a is, via PrimitiveBase::set() 00281 inline std::istream& operator>>(std::istream& is, PrimitiveBase& pb) { 00282 std::string s; 00283 is >> s; 00284 pb.set(s); 00285 return is; 00286 } 00287 00288 } //namespace plist 00289 00290 00291 /*! @file 00292 * @brief 00293 * @author Ethan Tira-Thompson (ejt) (Creator) 00294 * 00295 * $Author: ejt $ 00296 * $Name: tekkotsu-4_0 $ 00297 * $Revision: 1.18 $ 00298 * $State: Exp $ 00299 * $Date: 2007/11/15 02:44:06 $ 00300 */ 00301 00302 #endif |
Tekkotsu v4.0 |
Generated Thu Nov 22 00:54:54 2007 by Doxygen 1.5.4 |