Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

plistBase.h

Go 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