00001
00002 #ifndef INCLUDED_plistPrimitives_h_
00003 #define INCLUDED_plistPrimitives_h_
00004
00005 #include "plistBase.h"
00006 #include "string_util.h"
00007 #include <limits>
00008 #include <typeinfo>
00009 #include <algorithm>
00010 #include <map>
00011 #include <libxml/xmlmemory.h>
00012
00013 extern "C" {
00014
00015
00016 xmlNode* xmlAddPrevSibling(xmlNode* node, xmlNode* sibling);
00017 xmlNode* xmlNewText(const xmlChar* s);
00018 xmlNode* xmlNewComment(const xmlChar* s);
00019 xmlNode* xmlAddChild(xmlNode * parent, xmlNode* child);
00020 xmlNode* xmlNewChild(xmlNode* parent, xmlNs* ns, const xmlChar * name, const xmlChar * content);
00021 int xmlStrEqual(const xmlChar* a, const xmlChar* b);
00022 xmlChar* xmlNodeGetContent(xmlNode* node);
00023 void xmlNodeSetContent(xmlNode* node, const xmlChar* content);
00024 xmlAttr* xmlHasProperty(xmlNode* node, const xmlChar* name);
00025 xmlChar* xmlGetProperty(xmlNode* node, const xmlChar* name);
00026 long xmlGetLineNo(xmlNode* node);
00027 xmlChar* xmlGetNodePath(xmlNode* node);
00028 void xmlNodeSetName(xmlNode* node, const xmlChar* name);
00029 void xmlFreeNode(xmlNode* node);
00030 void xmlUnlinkNode(xmlNode* node);
00031
00032 }
00033
00034 namespace plist {
00035
00036
00037
00038
00039
00040 template<typename T> const char* getTypeName();
00041
00042 template<> inline const char* getTypeName<short>() { return "integer"; }
00043 template<> inline const char* getTypeName<unsigned short>() { return "integer"; }
00044 template<> inline const char* getTypeName<int>() { return "integer"; }
00045 template<> inline const char* getTypeName<unsigned int>() { return "integer"; }
00046 template<> inline const char* getTypeName<long>() { return "integer"; }
00047 template<> inline const char* getTypeName<unsigned long>() { return "integer"; }
00048 template<> inline const char* getTypeName<long long>() { return "integer"; }
00049 template<> inline const char* getTypeName<unsigned long long>() { return "integer"; }
00050 template<> inline const char* getTypeName<float>() { return "real"; }
00051 template<> inline const char* getTypeName<double>() { return "real"; }
00052
00053
00054
00055
00056
00057
00058
00059 template<typename T>
00060 class Primitive : public PrimitiveBase {
00061 public:
00062 template<typename U, typename V> struct conversion_policy { typedef typename U::template ConversionTo<V> value_conversion; };
00063
00064
00065 Primitive() : PrimitiveBase(), val(), prevVal() {}
00066
00067 Primitive(const T& v) : PrimitiveBase(), val(v), prevVal() {}
00068
00069 Primitive& operator=(const T& v) { if(&v==&prevVal) std::swap(val,prevVal); else { prevVal=val; val=v; } fireValueChanged(prevVal==val); return *this; }
00070 virtual Primitive& operator=(const PrimitiveBase& pb) { if(dynamic_cast<const Primitive*>(&pb)!=this) operator=(pb.castTo<T>()); return *this; }
00071
00072 Primitive& operator=(const Primitive& p) { operator=(p.val); return *this; }
00073
00074 Primitive& operator+=(const T& v) { prevVal=val; val+=v; fireValueChanged(prevVal==val); return *this; }
00075 Primitive& operator-=(const T& v) { prevVal=val; val-=v; fireValueChanged(prevVal==val); return *this; }
00076 Primitive& operator*=(const T& v) { prevVal=val; val*=v; fireValueChanged(prevVal==val); return *this; }
00077 Primitive& operator/=(const T& v) { prevVal=val; val/=v; fireValueChanged(prevVal==val); return *this; }
00078
00079
00080 const T& operator*() const { return val; }
00081
00082 const T* operator->() const { return &val; }
00083
00084
00085 operator T() const { return val; }
00086
00087
00088 void loadXML(xmlNode* node);
00089
00090 void saveXML(xmlNode* node) const;
00091 void set(const std::string& str);
00092 using PrimitiveBase::set;
00093 std::string get() const {
00094 std::stringstream sstr;
00095 sstr <<std::setprecision(std::numeric_limits<T>::digits10)<< val;
00096 return sstr.str();
00097 }
00098
00099
00100
00101 virtual bool operator==(const PrimitiveBase& other) {
00102 if(const Primitive* p = dynamic_cast<const Primitive*>(&other))
00103 return p->val == val;
00104 else
00105 return p->get() == get();
00106 }
00107
00108 virtual long toLong() const { return static_cast<long>(val); }
00109 virtual double toDouble() const { return static_cast<double>(val); }
00110
00111
00112 PLIST_CLONE_DEF(Primitive<T>,new Primitive<T>(val));
00113
00114 const T& getPreviousValue() const { return prevVal; }
00115
00116 protected:
00117 T val;
00118 T prevVal;
00119 };
00120
00121 template<typename T>
00122 void Primitive<T>::loadXML(xmlNode* node) {
00123 if(node==NULL)
00124 return;
00125 bool bt=xNodeHasName(node,"true");
00126 bool bf=xNodeHasName(node,"false");
00127 if(!bt && !bf && !xNodeHasName(node,"integer") && !xNodeHasName(node,"real") && !xNodeHasName(node,"string")) {
00128 std::stringstream errstr;
00129 errstr << "Error: plist::Primitive<" << typeid(T).name() << "> expects " << getTypeName<T>() << ", got unknown type " << (const char*)xNodeGetName(node);
00130 throw bad_format(node,errstr.str());
00131 }
00132 if(!xNodeHasName(node,getTypeName<T>()))
00133 std::cerr << "Warning: plist expected " << getTypeName<T>() << " got " << (const char*)xNodeGetName(node) << ", trying to convert. (line " << xmlGetLineNo(node) << ")" << std::endl;
00134 if(bt) {
00135 prevVal=val;
00136 val = true;
00137 fireValueChanged(prevVal==val);
00138 } else if(bf) {
00139 prevVal=val;
00140 val = false;
00141 fireValueChanged(prevVal==val);
00142 } else {
00143 xmlChar * cont=xmlNodeGetContent(node);
00144 const std::string str((const char*)cont);
00145 xmlFree(cont);
00146 set(str);
00147 }
00148 }
00149 template<typename T>
00150 void Primitive<T>::saveXML(xmlNode* node) const {
00151 if(node==NULL)
00152 return;
00153 xmlNodeSetName(node,(const xmlChar*)getTypeName<T>());
00154 std::stringstream str;
00155 str <<std::setprecision(std::numeric_limits<T>::digits10)<< val;
00156 xmlNodeSetContent(node,(const xmlChar*)str.str().c_str());
00157 }
00158 template<typename T>
00159 void Primitive<T>::set(const std::string& str) {
00160 std::string trimmed = string_util::trim(str);
00161 if(trimmed.size()==0) {
00162 std::cerr << "Warning: plist expected " << getTypeName<T>() << ", got empty string" << std::endl;
00163 return;
00164 }
00165 bool neg=false;
00166 if(trimmed[0]=='-') {
00167 neg=true;
00168 trimmed=trimmed.substr(1);
00169 }
00170 prevVal=val;
00171 if((trimmed=="∞" || string_util::makeLower(trimmed)=="inf") && std::numeric_limits<T>::has_infinity) {
00172 val = neg ? -std::numeric_limits<T>::infinity() : std::numeric_limits<T>::infinity();
00173 } else {
00174 std::stringstream sstr(str);
00175 if(!(sstr >> val)) {
00176 std::string err="Expected "; err+=getTypeName<T>(); err+=" value, got '"+str+"'";
00177 throw bad_format(NULL,err);
00178 }
00179 while(sstr.good() && isspace(sstr.peek()))
00180 sstr.get();
00181 if(!sstr.eof()) {
00182 std::string err="Expected "; err+=getTypeName<T>(); err+=" value, got '"+sstr.str()+"'";
00183 throw bad_format(NULL,err);
00184 }
00185 }
00186 fireValueChanged(prevVal==val);
00187 }
00188
00189
00190 PLIST_CLONE_IMPT(T,Primitive,new Primitive<T>(val));
00191
00192
00193
00194 struct AutoPrimitiveListener : public plist::PrimitiveListener {
00195
00196 AutoPrimitiveListener(const plist::PrimitiveBase& source) : plist::PrimitiveListener(), src(source) { src.addPrimitiveListener(this); }
00197
00198 AutoPrimitiveListener& operator=(const AutoPrimitiveListener&) { return *this; }
00199
00200 ~AutoPrimitiveListener() { src.removePrimitiveListener(this); }
00201 const plist::PrimitiveBase& src;
00202 };
00203
00204 template<typename O>
00205 struct PrimitiveCallbackMember : public plist::AutoPrimitiveListener {
00206
00207 PrimitiveCallbackMember(const plist::PrimitiveBase& source, O& component, void(O::*func)(), bool callNow=true)
00208 : plist::AutoPrimitiveListener(source), comp(component), callback(func) { if(callNow) (comp.*callback)(); }
00209
00210 PrimitiveCallbackMember& operator=(const PrimitiveCallbackMember&) { return *this; }
00211 virtual void plistValueChanged(const plist::PrimitiveBase& ) { (comp.*callback)(); }
00212 O& comp;
00213 void(O::*callback)();
00214 };
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225 template<>
00226 class Primitive<bool> : public PrimitiveBase {
00227 public:
00228 template<typename U, typename V> struct conversion_policy { typedef typename U::template ConversionTo<V> value_conversion; };
00229 Primitive() : PrimitiveBase(), val(), prevVal() {}
00230 Primitive(const bool& v) : PrimitiveBase(), val(v), prevVal() {}
00231 Primitive& operator=(const bool& v) { if(&v==&prevVal) std::swap(val,prevVal); else { prevVal=val; val=v; } fireValueChanged(prevVal==val); return *this; }
00232 virtual Primitive& operator=(const PrimitiveBase& pb) { if(dynamic_cast<const Primitive*>(&pb)!=this) operator=(pb.castTo<bool>()); return *this; }
00233 Primitive& operator=(const Primitive& p) { operator=(p.val); return *this; }
00234
00235 const bool& operator*() const { return val; }
00236
00237 const bool* operator->() const { return &val; }
00238 operator bool() const { return val; }
00239
00240 void loadXML(xmlNode* node);
00241 void saveXML(xmlNode* node) const;
00242 void set(const std::string& str);
00243 using PrimitiveBase::set;
00244 std::string get() const {
00245 return val?"true":"false";
00246 }
00247
00248
00249
00250 virtual bool operator==(const PrimitiveBase& other) {
00251 if(const Primitive* p = dynamic_cast<const Primitive*>(&other))
00252 return p->val == val;
00253 else
00254 return p->get() == get();
00255 }
00256
00257 virtual long toLong() const { return static_cast<long>(val); }
00258 virtual double toDouble() const { return static_cast<double>(val); }
00259
00260
00261 PLIST_CLONE_DEF(Primitive<bool>,new Primitive<bool>(val));
00262
00263 const bool& getPreviousValue() const { return prevVal; }
00264
00265 protected:
00266 bool val;
00267 bool prevVal;
00268 };
00269
00270
00271
00272
00273 template<>
00274 class Primitive<char> : public PrimitiveBase {
00275 public:
00276 template<typename U, typename V> struct conversion_policy { typedef typename U::template ConversionTo<V> value_conversion; };
00277 Primitive() : PrimitiveBase(), val(), prevVal(), numeric(false) {}
00278 Primitive(const char& v, bool isNum=false) : PrimitiveBase(), val(v), prevVal(), numeric(isNum) {}
00279 Primitive& operator=(char v) { if(&v==&prevVal) std::swap(val,prevVal); else { prevVal=val; val=v; } fireValueChanged(prevVal==val); return *this; }
00280 virtual Primitive& operator=(const PrimitiveBase& pb) { if(dynamic_cast<const Primitive*>(&pb)!=this) operator=(pb.castTo<char>()); return *this; }
00281
00282 Primitive& operator=(const Primitive& p) { operator=(p.val); return *this; }
00283 Primitive& operator+=(char v) { prevVal=val; val+=v; fireValueChanged(prevVal==val); return *this; }
00284 Primitive& operator-=(char v) { prevVal=val; val-=v; fireValueChanged(prevVal==val); return *this; }
00285 Primitive& operator*=(char v) { prevVal=val; val*=v; fireValueChanged(prevVal==val); return *this; }
00286 Primitive& operator/=(char v) { prevVal=val; val/=v; fireValueChanged(prevVal==val); return *this; }
00287
00288 const char& operator*() const { return val; }
00289
00290 const char* operator->() const { return &val; }
00291 operator char() const { return val; }
00292
00293 void setNumeric(bool isNum) { numeric=isNum; }
00294 bool getNumeric() const { return numeric; }
00295
00296 void loadXML(xmlNode* node);
00297 void saveXML(xmlNode* node) const;
00298 void set(const std::string& str);
00299 using PrimitiveBase::set;
00300 std::string get() const {
00301 if(numeric) {
00302 std::stringstream sstr;
00303 sstr << (int)val;
00304 return sstr.str();
00305 } else
00306 return std::string(1,val);
00307 }
00308
00309
00310
00311 virtual bool operator==(const PrimitiveBase& other) {
00312 if(const Primitive* p = dynamic_cast<const Primitive*>(&other))
00313 return p->val == val;
00314 else
00315 return p->get() == get();
00316 }
00317
00318 virtual long toLong() const { return static_cast<long>(val); }
00319 virtual double toDouble() const { return static_cast<double>(val); }
00320
00321
00322 PLIST_CLONE_DEF(Primitive<char>,new Primitive<char>(val));
00323
00324 const char& getPreviousValue() const { return prevVal; }
00325
00326 protected:
00327 char val;
00328 char prevVal;
00329 bool numeric;
00330 };
00331
00332
00333
00334
00335 template<>
00336 class Primitive<unsigned char> : public PrimitiveBase {
00337 public:
00338 template<typename U, typename V> struct conversion_policy { typedef typename U::template ConversionTo<V> value_conversion; };
00339 Primitive() : PrimitiveBase(), val(), prevVal(), numeric(false) {}
00340 Primitive(const unsigned char& v, bool isNum=false) : PrimitiveBase(), val(v), prevVal(), numeric(isNum) {}
00341 Primitive& operator=(unsigned char v) { prevVal=val; val=v; fireValueChanged(prevVal==val); return *this; }
00342 virtual Primitive& operator=(const PrimitiveBase& pb) { if(dynamic_cast<const Primitive*>(&pb)!=this) operator=(pb.castTo<unsigned char>()); return *this; }
00343
00344 Primitive& operator=(const Primitive& p) { operator=(p.val); return *this; }
00345 Primitive& operator+=(unsigned char v) { prevVal=val; val+=v; fireValueChanged(prevVal==val); return *this; }
00346 Primitive& operator-=(unsigned char v) { prevVal=val; val-=v; fireValueChanged(prevVal==val); return *this; }
00347 Primitive& operator*=(unsigned char v) { prevVal=val; val*=v; fireValueChanged(prevVal==val); return *this; }
00348 Primitive& operator/=(unsigned char v) { prevVal=val; val/=v; fireValueChanged(prevVal==val); return *this; }
00349
00350 const unsigned char& operator*() const { return val; }
00351
00352 const unsigned char* operator->() const { return &val; }
00353 operator unsigned char() const { return val; }
00354
00355 void setNumeric(bool isNum) { numeric=isNum; }
00356 bool getNumeric() const { return numeric; }
00357
00358 void loadXML(xmlNode* node);
00359 void saveXML(xmlNode* node) const;
00360 void set(const std::string& str);
00361 using PrimitiveBase::set;
00362 std::string get() const {
00363 if(numeric) {
00364 std::stringstream sstr;
00365 sstr << (int)val;
00366 return sstr.str();
00367 } else
00368 return std::string(1,val);
00369 }
00370
00371
00372
00373 virtual bool operator==(const PrimitiveBase& other) {
00374 if(const Primitive* p = dynamic_cast<const Primitive*>(&other))
00375 return p->val == val;
00376 else
00377 return p->get() == get();
00378 }
00379
00380 virtual long toLong() const { return static_cast<long>(val); }
00381 virtual double toDouble() const { return static_cast<double>(val); }
00382
00383
00384 PLIST_CLONE_DEF(Primitive<unsigned char>,new Primitive<unsigned char>(val));
00385
00386 const unsigned char& getPreviousValue() const { return prevVal; }
00387
00388 protected:
00389 unsigned char val;
00390 unsigned char prevVal;
00391 bool numeric;
00392 };
00393
00394
00395
00396
00397 template<>
00398 class Primitive<std::string> : public PrimitiveBase, public std::string {
00399 public:
00400 template<typename U, typename V> struct conversion_policy { typedef typename U::template ConversionTo<V> value_conversion; };
00401 Primitive() : PrimitiveBase(), std::string(), prevVal() {}
00402 Primitive(const std::string& v) : PrimitiveBase(), std::string(v), prevVal() {}
00403 Primitive(const std::string& v, size_type off, size_type count=npos) : PrimitiveBase(), std::string(v,off,count), prevVal() {}
00404 Primitive(const char* v, size_type count) : PrimitiveBase(), std::string(v,count), prevVal() {}
00405 Primitive(const char* v) : PrimitiveBase(), std::string(v), prevVal() {}
00406 Primitive(size_type count, char v) : PrimitiveBase(), std::string(count,v), prevVal() {}
00407 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; }
00408 Primitive& operator=(const char* v) { prevVal=*this; std::string::operator=(v); fireValueChanged(prevVal==*this); return *this; }
00409 Primitive& operator=(char v) { prevVal=*this; std::string::operator=(v); fireValueChanged(prevVal==*this); return *this; }
00410 virtual Primitive& operator=(const PrimitiveBase& pb) { if(dynamic_cast<const Primitive*>(&pb)!=this) operator=(pb.toString()); return *this; }
00411
00412 Primitive& operator=(const Primitive& p) { operator=(static_cast<const std::string&>(p)); return *this; }
00413
00414 const std::string& operator*() const { return *this; }
00415
00416 const std::string* operator->() const { return this; }
00417
00418
00419 void loadXML(xmlNode* node);
00420 void saveXML(xmlNode* node) const;
00421 void set(const std::string& str) { operator=(str); }
00422 using PrimitiveBase::set;
00423 std::string get() const { return *this; }
00424
00425
00426
00427 virtual bool operator==(const PrimitiveBase& other) {
00428 return other.get() == *this;
00429 }
00430
00431 virtual bool toBool() const;
00432 virtual char toChar() const;
00433 virtual long toLong() const;
00434 virtual double toDouble() const;
00435
00436 void clear() { prevVal=*this; std::string::clear(); fireValueChanged(prevVal==*this); }
00437 void resize(size_type n, char c) { prevVal=*this; std::string::resize(n,c); fireValueChanged(prevVal==*this); }
00438
00439
00440
00441 PLIST_CLONE_DEF(Primitive<std::string>,new Primitive<std::string>(get()));
00442
00443 const std::string& getPreviousValue() const { return prevVal; }
00444
00445 protected:
00446 std::string prevVal;
00447 };
00448
00449 extern template class Primitive<short>;
00450 extern template class Primitive<unsigned short>;
00451 extern template class Primitive<int>;
00452 extern template class Primitive<unsigned int>;
00453 extern template class Primitive<long>;
00454 extern template class Primitive<unsigned long>;
00455 extern template class Primitive<float>;
00456 extern template class Primitive<double>;
00457
00458
00459
00460
00461
00462 class NamedEnumerationBase : public PrimitiveBase {
00463 public:
00464 NamedEnumerationBase() : PrimitiveBase(), strictValue(true) {}
00465 NamedEnumerationBase(const NamedEnumerationBase& ne) : PrimitiveBase(ne), strictValue(ne.strictValue) {}
00466 NamedEnumerationBase& operator=(const std::string& v) { set(v); return *this; }
00467 NamedEnumerationBase& operator=(const NamedEnumerationBase& ne) { PrimitiveBase::operator=(ne); return *this; }
00468 virtual NamedEnumerationBase& operator=(const PrimitiveBase& pb)=0;
00469
00470 virtual void set(long x)=0;
00471 using PrimitiveBase::set;
00472
00473
00474 virtual void getPreferredNames(std::map<int,std::string>& names) const=0;
00475
00476 virtual void getAllNames(std::map<std::string,int>& names) const=0;
00477
00478 std::string getDescription(bool preferredOnly=true);
00479 void setStrict(bool strict) { strictValue=strict; }
00480 bool getStrict() const { return strictValue; }
00481
00482 protected:
00483 bool strictValue;
00484 };
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523 template<typename T>
00524 class NamedEnumeration : public NamedEnumerationBase {
00525 public:
00526 template<typename U, typename V> struct conversion_policy { typedef typename U::template ConversionTo<V> value_conversion; };
00527 NamedEnumeration() : NamedEnumerationBase(), val(), prevVal() {}
00528 NamedEnumeration(const NamedEnumeration& ne) : NamedEnumerationBase(ne), val(ne.val), prevVal() {}
00529 NamedEnumeration(const T& v, const char * const* enumnames) : NamedEnumerationBase(), val(v), prevVal() { setNames(enumnames); }
00530 NamedEnumeration(const T& v) : NamedEnumerationBase(), val(v), prevVal() {}
00531 NamedEnumeration& operator=(const T& v) { if(&v==&prevVal) std::swap(val,prevVal); else { prevVal=val; val=v; } fireValueChanged(prevVal==val); return *this; }
00532 NamedEnumeration& operator=(const std::string& v) { set(v); return *this; }
00533 NamedEnumeration& operator=(const NamedEnumeration& ne) { operator=(ne.val); return *this; }
00534
00535 const T& operator*() const { return val; }
00536 operator T() const { return val; }
00537 static void setNames(const char * const* enumnames);
00538 static const std::map<T,std::string>& getPreferredNames() { return valsToNames; }
00539 static const std::map<std::string,T>& getAllNames() { return namesToVals; }
00540 static void clearNames();
00541 static void addNameForVal(const std::string& enumname, const T& v);
00542 static void setPreferredNameForVal(const std::string& enumname, const T& v);
00543
00544
00545 virtual NamedEnumeration& operator=(const PrimitiveBase& pb) {
00546 if(dynamic_cast<const NamedEnumeration*>(&pb)==this)
00547 return *this;
00548 if(const std::string* str = dynamic_cast<const std::string*>(&pb))
00549 set(*str);
00550 else {
00551 T tv=static_cast<T>(pb.toLong());
00552 if(strictValue && valsToNames.find(tv)==valsToNames.end())
00553 throw bad_format(NULL, "NamedEnumeration unable to assign arbitrary integer value because strict checking is requested");
00554 val=tv;
00555 }
00556 return *this;
00557 }
00558
00559
00560 void loadXML(xmlNode* node) {
00561 if(node==NULL)
00562 return;
00563 if(xNodeHasName(node,"true") || xNodeHasName(node,"false")) {
00564 std::string name=(const char*)xNodeGetName(node);
00565 std::cerr << "Warning: plist NamedEnumeration should use <string>" << name << "</string>, not <" << name << "/>" << std::endl;
00566 try {
00567 set(name);
00568 } catch(const bad_format& err) {
00569 throw bad_format(node,err.what());
00570 }
00571 } else if(xNodeHasName(node,"integer") || xNodeHasName(node,"real") || xNodeHasName(node,"string")) {
00572 xmlChar * cont=xmlNodeGetContent(node);
00573 try {
00574 set((const char*)cont);
00575 } catch(const bad_format& err) {
00576 xmlFree(cont);
00577 throw bad_format(node,err.what());
00578 } catch(...) {
00579 xmlFree(cont);
00580 throw;
00581 }
00582 xmlFree(cont);
00583 } else
00584 throw bad_format(node,"Error: plist NamedEnumeration must be numeric or valid string");
00585 }
00586
00587 void saveXML(xmlNode* node) const {
00588 if(node==NULL)
00589 return;
00590 std::string name;
00591 if(getNameForVal(val,name)) {
00592 xmlNodeSetName(node,(const xmlChar*)"string");
00593 } else {
00594 xmlNodeSetName(node,(const xmlChar*)"integer");
00595 }
00596 xmlNodeSetContent(node,(const xmlChar*)name.c_str());
00597 }
00598 void set(const std::string& str) {
00599 prevVal=val;
00600 if(!getValForName(str,val))
00601 throw bad_format(NULL,"Error: plist::NamedEnumeration must be numeric or valid string (cannot be '"+str+"')");
00602 fireValueChanged(prevVal==val);
00603 }
00604 void set(long x) {
00605 T tv;
00606 if(!convert(x,tv)) {
00607 std::stringstream ss;
00608 ss << "Error: plist::NamedEnumeration must correspond to valid string (cannot be '" << x << "')";
00609 throw bad_format(NULL,ss.str());
00610 }
00611 prevVal=val;
00612 val=tv;
00613 fireValueChanged(prevVal==val);
00614 }
00615 using NamedEnumerationBase::set;
00616 std::string get() const {
00617 std::string name;
00618 getNameForVal(val,name);
00619 return name;
00620 }
00621
00622
00623
00624 virtual bool operator==(const PrimitiveBase& other) {
00625 if(const NamedEnumeration* p = dynamic_cast<const NamedEnumeration*>(&other))
00626 return p->val == val;
00627 else
00628 return p->get() == get();
00629 }
00630
00631 virtual long toLong() const { return static_cast<long>(val); }
00632 virtual double toDouble() const { return static_cast<double>(val); }
00633
00634
00635 PLIST_CLONE_DEF(NamedEnumeration<T>,new NamedEnumeration<T>(*this));
00636
00637 const T& getPreviousValue() const { return prevVal; }
00638
00639 protected:
00640
00641 virtual void getPreferredNames(std::map<int,std::string>& names) const;
00642
00643 virtual void getAllNames(std::map<std::string,int>& names) const;
00644
00645
00646 bool convert(long x, T& v) const {
00647 T tv=static_cast<T>(x);
00648 if(strictValue && valsToNames.find(tv)==valsToNames.end())
00649 return false;
00650 v=tv;
00651 return true;
00652 }
00653
00654 bool getValForName(std::string name, T& v) const {
00655 std::transform(name.begin(), name.end(), name.begin(), (int(*)(int)) std::toupper);
00656 typename std::map<std::string,T>::const_iterator vit=namesToVals.find(name);
00657 if(vit!=namesToVals.end())
00658 v=vit->second;
00659 else {
00660 long iv;
00661 if(sscanf(name.c_str(),"%ld",&iv)==0)
00662 return false;
00663 if(!convert(iv,v))
00664 return false;
00665 }
00666 return true;
00667 }
00668
00669 bool getNameForVal(const T& v, std::string& name) const {
00670 typename std::map<T,std::string>::const_iterator nit=valsToNames.find(v);
00671 if(nit!=valsToNames.end()) {
00672 name=nit->second;
00673 return true;
00674 }
00675 std::stringstream str;
00676 str << v;
00677 name=str.str();
00678 return false;
00679 }
00680 T val;
00681 T prevVal;
00682
00683
00684
00685 static std::map<std::string,T> namesToVals;
00686
00687
00688 static std::map<T,std::string> valsToNames;
00689 };
00690
00691 PLIST_CLONE_IMPT(T,NamedEnumeration,new NamedEnumeration<T>(*this));
00692
00693 #ifdef USE_GLOBAL_PLIST_STATICS
00694 template<typename T> std::map<std::string,T> plist::NamedEnumeration<T>::namesToVals;
00695 template<typename T> std::map<T,std::string> plist::NamedEnumeration<T>::valsToNames;
00696 #endif
00697
00698
00699
00700 #define INSTANTIATE_ALL_NAMEDENUMERATION_STATICS() \
00701 namespace plist { \
00702 template<typename T> std::map<std::string,T> NamedEnumeration<T>::namesToVals; \
00703 template<typename T> std::map<T,std::string> NamedEnumeration<T>::valsToNames; \
00704 }
00705
00706
00707
00708 #define INSTANTIATE_NAMEDENUMERATION_STATICS(T) \
00709 namespace plist { \
00710 template<> std::map<std::string,T> NamedEnumeration<T>::namesToVals = std::map<std::string,T>(); \
00711 template<> std::map<T,std::string> NamedEnumeration<T>::valsToNames = std::map<T,std::string>(); \
00712 }
00713
00714 template<typename T> void NamedEnumeration<T>::setNames(const char * const* enumnames) {
00715
00716 size_t incnt=0;
00717 while(enumnames[incnt]!=NULL)
00718 ++incnt;
00719 bool differ=false;
00720 if(incnt!=valsToNames.size() || incnt!=namesToVals.size())
00721 differ=true;
00722 else {
00723 for(size_t i=0; enumnames[i]!=NULL; ++i) {
00724 std::string name=enumnames[i];
00725 typename std::map<T,std::string>::const_iterator v2nit=valsToNames.find(static_cast<T>(i));
00726 if(v2nit==valsToNames.end() || v2nit->second!=name) {
00727 differ=true;
00728 break;
00729 }
00730 std::transform(name.begin(), name.end(), name.begin(), (int(*)(int)) std::toupper);
00731 typename std::map<std::string,T>::const_iterator n2vit=namesToVals.find(name);
00732 if(n2vit==namesToVals.end() || n2vit->second!=static_cast<T>(i)) {
00733 differ=true;
00734 break;
00735 }
00736 }
00737 }
00738 if(differ) {
00739
00740 std::map<std::string,T> newNamesToVals;
00741 std::map<T,std::string> newValsToNames;
00742 for(size_t i=0; enumnames[i]!=NULL; ++i) {
00743 std::string name=enumnames[i];
00744 newValsToNames[static_cast<T>(i)]=name;
00745 std::transform(name.begin(), name.end(), name.begin(), (int(*)(int)) std::toupper);
00746 newNamesToVals[name]=static_cast<T>(i);
00747 }
00748 namesToVals.swap(newNamesToVals);
00749 valsToNames.swap(newValsToNames);
00750 }
00751 }
00752 template<typename T> void NamedEnumeration<T>::clearNames() {
00753 namesToVals.clear();
00754 valsToNames.clear();
00755 }
00756 template<typename T> void NamedEnumeration<T>::addNameForVal(const std::string& enumname, const T& v) {
00757 if(valsToNames.find(v)==valsToNames.end())
00758 valsToNames[v]=enumname;
00759 std::string name=enumname;
00760 std::transform(name.begin(), name.end(), name.begin(), (int(*)(int)) std::toupper);
00761 namesToVals[name]=v;
00762 }
00763 template<typename T> void NamedEnumeration<T>::setPreferredNameForVal(const std::string& enumname, const T& v) {
00764 valsToNames[v]=enumname;
00765 addNameForVal(enumname,v);
00766 }
00767
00768 template<typename T> void NamedEnumeration<T>::getPreferredNames(std::map<int,std::string>& names) const {
00769 names.clear();
00770 for(typename std::map<T,std::string>::const_iterator it=valsToNames.begin(); it!=valsToNames.end(); ++it)
00771 names.insert(std::pair<int,std::string>(it->first,it->second));
00772 }
00773 template<typename T> void NamedEnumeration<T>::getAllNames(std::map<std::string,int>& names) const {
00774 names.clear();
00775 for(typename std::map<std::string,T>::const_iterator it=namesToVals.begin(); it!=namesToVals.end(); ++it)
00776 names.insert(std::pair<std::string,int>(it->first,it->second));
00777 }
00778
00779 }
00780
00781
00782
00783
00784
00785
00786
00787 #endif