| 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 <list> 00013 00014 /* 00015 From: <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 00016 00017 <!ENTITY % plistObject "(array | data | date | dict | real | integer | string | true | false )" > 00018 <!ELEMENT plist %plistObject;> 00019 <!ATTLIST plist version CDATA "1.0" > 00020 00021 <!-- Collections --> 00022 <!ELEMENT array (%plistObject;)*> 00023 <!ELEMENT dict (key, %plistObject;)*> 00024 <!ELEMENT key (#PCDATA)> 00025 00026 <!--- Primitive types --> 00027 <!ELEMENT string (#PCDATA)> 00028 <!ELEMENT data (#PCDATA)> <!-- Contents interpreted as Base-64 encoded --> 00029 <!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) --> 00030 00031 <!-- Numerical primitives --> 00032 <!ELEMENT true EMPTY> <!-- Boolean constant true --> 00033 <!ELEMENT false EMPTY> <!-- Boolean constant false --> 00034 <!ELEMENT real (#PCDATA)> <!-- Contents should represent a floating point number matching ("+" | "-")? d+ ("."d*)? ("E" ("+" | "-") d+)? where d is a digit 0-9. --> 00035 <!ELEMENT integer (#PCDATA)> <!-- Contents should represent a (possibly signed) integer number in base 10 --> 00036 */ 00037 00038 extern "C" { 00039 struct _xmlNode; 00040 struct _xmlDoc; 00041 struct _xmlAttr; 00042 struct _xmlNs; 00043 typedef _xmlNode xmlNode; //!< forward declaration of xmlNode to avoid including actual header here 00044 typedef _xmlDoc xmlDoc; //!< forward declaration of xmlDoc to avoid including actual header here 00045 typedef _xmlAttr xmlAttr; //!< forward declaration of xmlAttr to avoid including actual header here 00046 typedef _xmlNs xmlNs; //!< forward declaration of xmlNs to avoid including actual header here 00047 typedef unsigned char xmlChar; //!< forward declaration of xmlChar to avoid including actual header here 00048 } 00049 00050 //! A collection of classes to implement the Propery List data storage format, a XML standard used by Apple and others 00051 namespace plist { 00052 00053 #ifdef PLIST_CLONE_ABS 00054 # error PLIST_CLONE_ABS already defined! 00055 #else 00056 # if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && (__GNUC_MINOR__ > 3)) 00057 //! defines abstract clone() (=0) using polymorphic return type @a TYPE if supported by current version of gcc, Cloneable otherwise 00058 # define PLIST_CLONE_ABS(TYPE) virtual TYPE* clone() const __attribute__ ((warn_unused_result)) =0; 00059 # else 00060 //! defines abstract clone() (=0) using polymorphic return type @a TYPE if supported by current version of gcc, Cloneable otherwise 00061 # define PLIST_CLONE_ABS(TYPE) virtual Cloneable* clone() const =0; 00062 # endif 00063 #endif 00064 00065 #ifdef PLIST_CLONE_DEF 00066 # error PLIST_CLONE_DEF already defined! 00067 #else 00068 # if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && (__GNUC_MINOR__ > 3)) 00069 //! declares clone() using polymorphic return type @a TYPE if supported by current version of gcc, Cloneable otherwise; returns @a RETVAL 00070 # define PLIST_CLONE_DEF(TYPE,RETVAL) virtual TYPE* clone() const __attribute__ ((warn_unused_result)); 00071 //! implements clone() using polymorphic return type @a TYPE if supported by current version of gcc, Cloneable otherwise; returns @a RETVAL 00072 # define PLIST_CLONE_IMP(TYPE,RETVAL) TYPE* TYPE::clone() const { return RETVAL; } 00073 //! implements clone() using templated polymorphic return type @a TYPE if supported by current version of gcc, Cloneable otherwise; returns @a RETVAL 00074 # define PLIST_CLONE_IMPT(TEMPL,TYPE,RETVAL) template<TEMPL> TYPE* TYPE::clone() const { return RETVAL; } 00075 # else 00076 //! declares clone() using polymorphic return type @a TYPE if supported by current version of gcc, Cloneable otherwise; returns @a RETVAL 00077 # define PLIST_CLONE_DEF(TYPE,RETVAL) virtual Cloneable* clone() const { return RETVAL; } 00078 //! implements clone() using polymorphic return type @a TYPE if supported by current version of gcc, Cloneable otherwise; returns @a RETVAL 00079 # define PLIST_CLONE_IMP(TYPE,RETVAL) 00080 //! implements clone() using templated polymorphic return type @a TYPE if supported by current version of gcc, Cloneable otherwise; returns @a RETVAL 00081 # define PLIST_CLONE_IMPT(TEMPL,TYPE,RETVAL) 00082 # endif 00083 #endif 00084 00085 //! Base class for the plist listener callbacks 00086 class Listener { 00087 public: 00088 //! destructor 00089 virtual ~Listener() {} 00090 }; 00091 00092 class PrimitiveBase; 00093 //! 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() 00094 class PrimitiveListener : public Listener { 00095 public: 00096 //! This will be called whenever a plist you have registered with is changed 00097 /*! @a pl is const to help you avoid infinite recursion from an 00098 * accidental modification of @a pl's value -- use a const cast 00099 * if you're sure you know what you're doing */ 00100 virtual void plistValueChanged(const PrimitiveBase& pl)=0; 00101 }; 00102 00103 class ObjectBase; 00104 class Collection; 00105 //! 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() 00106 class CollectionListener : public Listener { 00107 public: 00108 //! This will be called whenever an entry is added to the collection 00109 virtual void plistCollectionEntryAdded(Collection& /*col*/, ObjectBase& /*primitive*/) {} 00110 //! This will be called whenever an entry is added to the collection 00111 virtual void plistCollectionEntryRemoved(Collection& /*col*/, ObjectBase& /*primitive*/) {} 00112 //! This will be called whenever an entry is replaced, or multiple entries are added/removed at once, such as when an assignment occurs 00113 virtual void plistCollectionEntriesChanged(Collection& /*col*/) {} 00114 }; 00115 00116 //! This base class provides the root functionality for all plist entities -- Dictionary and the various templated subclasses of PrimitiveBase 00117 /*! The subclasses may throw std::bad_format if the 00118 * document is poorly structured or bad values are found. */ 00119 class ObjectBase : public XMLLoadSave, public Cloneable { 00120 friend ObjectBase* loadXML(xmlNode* node); 00121 public: 00122 ObjectBase(); //!< constructor 00123 virtual ~ObjectBase()=0; //!< destructor 00124 00125 //! return current value as a string 00126 virtual std::string toString() const=0; 00127 00128 //! subclasses are expected to provide a working implementation 00129 virtual void loadXML(xmlNode* node)=0; 00130 //! subclasses are expected to provide a working implementation 00131 virtual void saveXML(xmlNode* node) const=0; 00132 00133 //! allows a copy to be made of an event, supporting polymorphism 00134 PLIST_CLONE_ABS(ObjectBase); 00135 00136 protected: 00137 //!@name Inherited from XMLLoadSave 00138 virtual void setParseTree(xmlDoc * doc) const; 00139 virtual xmlNode* FindRootXMLElement(xmlDoc* doc) const; 00140 //@} 00141 00142 //!Provides accessor functions to struct fields without having to include libxml.h everywhere 00143 //!@name libxml Forwards 00144 static bool xNodeHasName(xmlNode* node, const char* name); //!< returns true if the name of @a node matches @a name 00145 static const xmlChar* xNodeGetName(xmlNode* node); //!< returns name of @a node (not a libxml function) 00146 static xmlNode* xNodeGetChildren(xmlNode* node); //!< returns children of @a node (not a libxml function) 00147 static xmlNode* xNodeGetNextNode(xmlNode* node); //!< returns next node (sibling) after @a node (not a libxml function) 00148 static xmlNode* xNodeGetParent(xmlNode* node); //!< returns parent node of @a node (not a libxml function) 00149 static xmlDoc* xNodeGetDoc(xmlNode* node); //!< returns document node of @a node (not a libxml function) 00150 //@} 00151 00152 //! returns true if @a str is some form of affirmative (e.g. "true" or "yes") 00153 static bool matchTrue(const std::string& str) { return str=="true" || str=="yes"; } 00154 //! returns true if @a str is some form of negative (e.g. "false" or "no") 00155 static bool matchFalse(const std::string& str) { return str=="false" || str=="no"; } 00156 }; 00157 //! output of an ObjectBase to a stream 00158 inline std::ostream& operator<<(std::ostream& os, const ObjectBase& pb) { 00159 return os << pb.toString(); 00160 } 00161 00162 00163 //! Provides common functionality to all primitive value classes (implemented in a templated subclass Primitive) 00164 /*! This class supports callbacks upon modification through the use of the 00165 * PrimitiveListener interface. Note that we only store a pointer to the 00166 * listener list, which is typically unallocated when no listeners are 00167 * active. This should ensure minimal memory usage per object, as well as 00168 * support safe storage of plist objects in inter-process shared memory 00169 * regions. 00170 * 00171 * If you are using these in a shared memory region, just be sure that only 00172 * the process with listeners does any and all modifications, and that it 00173 * unsubscribes before detaching from the region (or else destroys the region 00174 * itself) */ 00175 class PrimitiveBase : public ObjectBase { 00176 public: 00177 //! constructor 00178 PrimitiveBase() : ObjectBase(), primitiveListeners() {} 00179 //! copy constructor (don't copy listeners) 00180 PrimitiveBase(const PrimitiveBase& pb) : ObjectBase(pb), primitiveListeners() {} 00181 //! assignment (don't assign listeners) 00182 PrimitiveBase& operator=(const PrimitiveBase& pb) { ObjectBase::operator=(pb); fireValueChanged(); return *this; } 00183 //! destructor 00184 ~PrimitiveBase(); 00185 00186 //! assign a new value 00187 virtual void set(const std::string& str)=0; 00188 //! return current value as a string 00189 virtual std::string get() const=0; 00190 00191 virtual std::string toString() const { return get(); } 00192 00193 //! get notified of changes; be sure to call removeValueListener before destructing @a vl! 00194 virtual void addPrimitiveListener(PrimitiveListener* vl); 00195 //! no longer take notification of changes to this object's value 00196 virtual void removePrimitiveListener(PrimitiveListener* vl); 00197 //! test if @a l is currently registered as a listener 00198 virtual bool isPrimitiveListener(PrimitiveListener * vl); 00199 00200 protected: 00201 //! run through #primitiveListeners, calling PrimitiveListener::plistValueChanged(*this) 00202 virtual void fireValueChanged() const; 00203 //! stores a list of the current listeners 00204 std::list<PrimitiveListener*>* primitiveListeners; 00205 }; 00206 //! output stringified value (from PrimitiveBase::get()) to stream 00207 inline std::ostream& operator<<(std::ostream& os, const PrimitiveBase& pb) { 00208 return os << pb.get(); 00209 } 00210 //! input value from next word in @a is, via PrimitiveBase::set() 00211 inline std::istream& operator>>(std::istream& is, PrimitiveBase& pb) { 00212 std::string s; 00213 is >> s; 00214 pb.set(s); 00215 return is; 00216 } 00217 00218 } //namespace plist 00219 00220 00221 /*! @file 00222 * @brief 00223 * @author Ethan Tira-Thompson (ejt) (Creator) 00224 * 00225 * $Author: ejt $ 00226 * $Name: tekkotsu-3_0 $ 00227 * $Revision: 1.9 $ 00228 * $State: Exp $ 00229 * $Date: 2006/09/22 20:29:45 $ 00230 */ 00231 00232 #endif |
|
Tekkotsu v3.0 |
Generated Wed Oct 4 00:03:45 2006 by Doxygen 1.4.7 |