plist.hGo to the documentation of this file.00001
00002 #ifndef INCLUDED_PListSupport_h_
00003 #define INCLUDED_PListSupport_h_
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "XMLLoadSave.h"
00030 #include <exception>
00031 #include <string>
00032 #include <iostream>
00033 #include <iomanip>
00034 #include <sstream>
00035 #include <map>
00036 #include <list>
00037
00038
00039 namespace plist {
00040
00041
00042 class Listener {
00043 public:
00044
00045 virtual ~Listener() {}
00046 };
00047
00048 class PrimitiveBase;
00049
00050 class PrimitiveListener : public Listener {
00051 public:
00052
00053
00054
00055
00056 virtual void plistValueChanged(const PrimitiveBase& pl)=0;
00057 };
00058
00059 class ObjectBase;
00060 class Dictionary;
00061
00062 class DictionaryListener : public Listener {
00063 public:
00064
00065 virtual void plistDictionaryEntryAdded(Dictionary& , ObjectBase& ) {}
00066
00067 virtual void plistDictionaryEntryRemoved(Dictionary& , ObjectBase& ) {}
00068 };
00069
00070
00071
00072
00073 class ObjectBase : public XMLLoadSave {
00074 public:
00075 ObjectBase();
00076 virtual ~ObjectBase()=0;
00077
00078 protected:
00079
00080 virtual void setParseTree(xmlDoc * doc) const;
00081 virtual xmlNode* FindRootXMLElement(xmlDoc* doc) const;
00082
00083
00084
00085
00086 typedef unsigned char xChar;
00087 static int xStrEqual(const xChar* a, const xChar* b);
00088 static int xStrCaseEqual(const xChar* a, const xChar* b);
00089 static xChar* xNodeGetContent(xmlNode* node);
00090 static void xNodeSetContent(xmlNode* node, const xChar* content);
00091 static const xChar* xNodeGetName(xmlNode* node);
00092 static bool xNodeHasName(xmlNode* node, const char* name);
00093 static void xNodeSetName(xmlNode* node, const xChar* name);
00094 static xmlAttr* xHasProperty(xmlNode* node, const xChar* name);
00095 static xChar* xGetProperty(xmlNode* node, const xChar* name);
00096 static long xGetLineNo(xmlNode* node);
00097 static void xFree(void* ptr);
00098
00099 };
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118 class Dictionary : public ObjectBase {
00119 friend std::ostream& operator<<(std::ostream& os, const Dictionary& d);
00120 public:
00121
00122 Dictionary() : ObjectBase(), dictionaryListeners(), warnUnused(true), dict(), comments() {autoFormat=false;}
00123
00124 Dictionary(const Dictionary& d) : ObjectBase(d), dictionaryListeners(), warnUnused(d.warnUnused), dict(d.dict), comments(d.comments) {}
00125
00126 Dictionary& operator=(const Dictionary& d) { if(&d==this) return *this; ObjectBase::operator=(d); warnUnused=d.warnUnused; dict=d.dict; comments=d.comments; return *this; }
00127
00128 virtual ~Dictionary();
00129
00130
00131 void addEntry(const std::string& name, ObjectBase& val);
00132
00133 void addEntry(const std::string& name, ObjectBase& val, const std::string& comment);
00134
00135 void setEntry(const std::string& name, ObjectBase& val) { dict[name]=&val; }
00136
00137 void setComment(const std::string& name, const std::string& comment) { comments[name]=comment; }
00138
00139 const std::string& getComment(const std::string& name) const;
00140
00141 void removeEntry(const std::string& name) { dict.erase(name); }
00142
00143 ObjectBase* findEntry(const std::string& name) const;
00144
00145 void LoadXML(xmlNode* node);
00146 void SaveXML(xmlNode* node) const;
00147
00148 void setUnusedWarning(bool b) { warnUnused=b; }
00149 bool getUnusedWarning() { return warnUnused; }
00150
00151
00152 virtual void addDictionaryListener(DictionaryListener* vl);
00153
00154 virtual void removeDictionaryListener(DictionaryListener* vl);
00155
00156 protected:
00157
00158 virtual void fireEntryAdded(ObjectBase& val);
00159
00160 virtual void fireEntryRemoved(ObjectBase& val);
00161
00162 std::list<DictionaryListener*>* dictionaryListeners;
00163
00164
00165 unsigned int getLongestKeyLen() const;
00166
00167 bool warnUnused;
00168
00169
00170 typedef std::map<std::string,ObjectBase*> dict_t;
00171
00172 dict_t dict;
00173
00174
00175 typedef std::map<std::string,std::string> comments_t;
00176
00177
00178 comments_t comments;
00179 };
00180
00181 std::ostream& operator<<(std::ostream& os, const Dictionary& d);
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196 class PrimitiveBase : public ObjectBase {
00197 public:
00198
00199 PrimitiveBase() : ObjectBase(), primitiveListeners() {}
00200
00201 PrimitiveBase(const PrimitiveBase& pb) : ObjectBase(pb), primitiveListeners() {}
00202
00203 PrimitiveBase& operator=(const PrimitiveBase& pb) { ObjectBase::operator=(pb); return *this; }
00204
00205 ~PrimitiveBase();
00206
00207
00208 virtual void set(const std::string& str)=0;
00209
00210 virtual std::string get() const=0;
00211
00212
00213 virtual void addPrimitiveListener(PrimitiveListener* vl);
00214
00215 virtual void removePrimitiveListener(PrimitiveListener* vl);
00216
00217 protected:
00218
00219 virtual void fireValueChanged() const;
00220
00221 std::list<PrimitiveListener*>* primitiveListeners;
00222 };
00223
00224 inline std::ostream& operator<<(std::ostream& os, const PrimitiveBase& pb) {
00225 return os << pb.get();
00226 }
00227
00228 inline std::istream& operator>>(std::istream& is, PrimitiveBase& pb) {
00229 std::string s;
00230 is >> s;
00231 pb.set(s);
00232 return is;
00233 }
00234
00235
00236
00237
00238
00239
00240
00241 template<typename T>
00242 class Primitive : public PrimitiveBase {
00243 public:
00244 Primitive() : ObjectBase(), val() {}
00245 Primitive(const T& v) : ObjectBase(), val(v) {}
00246 Primitive& operator=(const T& v) { val=v; fireValueChanged(); return *this; }
00247
00248 const T& operator*() const { return val; }
00249
00250 const T* operator->() const { return &val; }
00251 operator T() const { return val; }
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268 protected:
00269 T val;
00270 };
00271
00272
00273
00274
00275
00276
00277 template<>
00278 class Primitive<bool> : public PrimitiveBase {
00279 public:
00280 Primitive() : PrimitiveBase(), val() {}
00281 Primitive(const bool& v) : PrimitiveBase(), val(v) {}
00282 Primitive& operator=(const bool& v) { val=v; fireValueChanged(); return *this; }
00283
00284 const bool& operator*() const { return val; }
00285
00286 const bool* operator->() const { return &val; }
00287 operator bool() const { return val; }
00288 void LoadXML(xmlNode* node) {
00289 if(node==NULL)
00290 return;
00291 if(xNodeHasName(node,"true")) {
00292 val=true;
00293 fireValueChanged();
00294 } else if(xNodeHasName(node,"false")) {
00295 val=false;
00296 fireValueChanged();
00297 } else if(xNodeHasName(node,"integer") || xNodeHasName(node,"real")) {
00298 xChar * cont=xNodeGetContent(node);
00299 std::stringstream str((char*)cont);
00300 str >> val;
00301 xFree(cont);
00302 fireValueChanged();
00303 } else if(xNodeHasName(node,"string")) {
00304 xChar * cont=xNodeGetContent(node);
00305 try {
00306 set((char*)cont);
00307 std::cerr << "Warning: plist boolean expects value of '<true/>', '<false/>', or numeric. String value of '" << (char*)cont << "' is not recommended." << std::endl;
00308 } catch(const bad_format& err) {
00309 xFree(cont);
00310 throw bad_format(node,err.what());
00311 } catch(...) {
00312 xFree(cont);
00313 throw;
00314 }
00315 xFree(cont);
00316 } else
00317 throw bad_format(node,"Error: plist boolean must be 'true', 'false', or numeric type");
00318 }
00319 void SaveXML(xmlNode* node) const {
00320 if(node==NULL)
00321 return;
00322 xNodeSetName(node,(const xChar*)(val?"true":"false"));
00323 xNodeSetContent(node,NULL);
00324 }
00325 void set(const std::string& str) {
00326 if(str=="true" || str=="yes" || str=="on")
00327 val=true;
00328 else if(str=="false" || str=="no" || str=="off")
00329 val=false;
00330 else {
00331 float t;
00332 if(sscanf(str.c_str(),"%g",&t)==0)
00333 throw bad_format(NULL,"Error: plist boolean must be 'true', 'false', or numeric type");
00334 val=t;
00335 }
00336 fireValueChanged();
00337 }
00338 std::string get() const {
00339 return val?"true":"false";
00340 }
00341 protected:
00342 bool val;
00343 };
00344
00345
00346
00347
00348 template<>
00349 class Primitive<char> : public PrimitiveBase {
00350 public:
00351 Primitive() : PrimitiveBase(), val(), numeric(false) {}
00352 Primitive(const char& v, bool isNum=false) : PrimitiveBase(), val(v), numeric(isNum) {}
00353 Primitive& operator=(const char& v) { val=v; fireValueChanged(); return *this; }
00354 Primitive& operator+=(const char& v) { val+=v; fireValueChanged(); return *this; }
00355 Primitive& operator-=(const char& v) { val-=v; fireValueChanged(); return *this; }
00356 Primitive& operator*=(const char& v) { val*=v; fireValueChanged(); return *this; }
00357 Primitive& operator/=(const char& v) { val/=v; fireValueChanged(); return *this; }
00358
00359 const char& operator*() const { return val; }
00360
00361 const char* operator->() const { return &val; }
00362 operator char() const { return val; }
00363 void setNumeric(bool isNum) { numeric=isNum; }
00364 bool getNumeric() const { return numeric; }
00365 void LoadXML(xmlNode* node) {
00366 if(node==NULL)
00367 return;
00368 xChar* cont=xNodeGetContent(node);
00369 try {
00370 if(xNodeHasName(node,"string")) {
00371 set((char*)cont);
00372 } else if(xNodeHasName(node,"integer")) {
00373 val=strtol((const char*)cont,NULL,0);
00374 fireValueChanged();
00375 } else if(xNodeHasName(node,"real")) {
00376 val=(char)strtod((const char*)cont,NULL);
00377 fireValueChanged();
00378 } else if(xNodeHasName(node,"true")) {
00379 val=true;
00380 fireValueChanged();
00381 } else if(xNodeHasName(node,"false")) {
00382 val=false;
00383 fireValueChanged();
00384 } else {
00385 throw bad_format(node,"Error: plist char must be either a string or integer");
00386 }
00387 } catch(const bad_format& err) {
00388 xFree(cont);
00389 throw bad_format(node,err.what());
00390 } catch(...) {
00391 xFree(cont);
00392 throw;
00393 }
00394 xFree(cont);
00395 }
00396 void SaveXML(xmlNode* node) const {
00397 if(node==NULL)
00398 return;
00399 if(numeric) {
00400 xNodeSetName(node,(const xChar*)"integer");
00401 std::stringstream str;
00402 str << (int)val;
00403 xNodeSetContent(node,(const xChar*)str.str().c_str());
00404 } else {
00405 xNodeSetName(node,(const xChar*)"string");
00406 xChar str[2] = {val,'\0'};
00407 xNodeSetContent(node,(const xChar*)str);
00408 }
00409 }
00410 void set(const std::string& str) {
00411 if(str.size()==0)
00412 throw bad_format(NULL,"Error: plist char must have non-empty content");
00413 val=str[0];
00414 if(str.size()!=1)
00415 std::cerr << "Warning: plist expected single char, found multi-char string '" << str << "'" << std::endl;
00416 fireValueChanged();
00417 }
00418 std::string get() const {
00419 return std::string(1,val);
00420 }
00421 protected:
00422 char val;
00423 bool numeric;
00424 };
00425
00426
00427
00428
00429 template<>
00430 class Primitive<unsigned char> : public PrimitiveBase {
00431 public:
00432 Primitive() : PrimitiveBase(), val(), numeric(false) {}
00433 Primitive(const unsigned char& v, bool isNum=false) : PrimitiveBase(), val(v), numeric(isNum) {}
00434 Primitive& operator=(const unsigned char& v) { val=v; fireValueChanged(); return *this; }
00435 Primitive& operator+=(const unsigned char& v) { val+=v; fireValueChanged(); return *this; }
00436 Primitive& operator-=(const unsigned char& v) { val-=v; fireValueChanged(); return *this; }
00437 Primitive& operator*=(const unsigned char& v) { val*=v; fireValueChanged(); return *this; }
00438 Primitive& operator/=(const unsigned char& v) { val/=v; fireValueChanged(); return *this; }
00439
00440 const unsigned char& operator*() const { return val; }
00441
00442 const unsigned char* operator->() const { return &val; }
00443 operator unsigned char() const { return val; }
00444 void setNumeric(bool isNum) { numeric=isNum; }
00445 bool getNumeric() const { return numeric; }
00446 void LoadXML(xmlNode* node) {
00447 if(node==NULL)
00448 return;
00449 xChar* cont=xNodeGetContent(node);
00450 try {
00451 if(xNodeHasName(node,"string")) {
00452 set((char*)cont);
00453 } else if(xNodeHasName(node,"integer")) {
00454 val=strtol((const char*)cont,NULL,0);
00455 fireValueChanged();
00456 } else if(xNodeHasName(node,"real")) {
00457 val=(char)strtod((const char*)cont,NULL);
00458 fireValueChanged();
00459 } else if(xNodeHasName(node,"true")) {
00460 val=true;
00461 fireValueChanged();
00462 } else if(xNodeHasName(node,"false")) {
00463 val=false;
00464 fireValueChanged();
00465 } else {
00466 throw bad_format(node,"Error: plist unsigned char must be either a string or integer");
00467 }
00468 } catch(const bad_format& err) {
00469 xFree(cont);
00470 throw bad_format(node,err.what());
00471 } catch(...) {
00472 xFree(cont);
00473 throw;
00474 }
00475 xFree(cont);
00476 }
00477 void SaveXML(xmlNode* node) const {
00478 if(node==NULL)
00479 return;
00480 if(numeric) {
00481 xNodeSetName(node,(const xChar*)"integer");
00482 std::stringstream str;
00483 str << (int)val;
00484 xNodeSetContent(node,(const xChar*)str.str().c_str());
00485 } else {
00486 xNodeSetName(node,(const xChar*)"string");
00487 xChar str[2] = {val,'\0'};
00488 xNodeSetContent(node,(const xChar*)str);
00489 }
00490 }
00491 void set(const std::string& str) {
00492 if(str.size()==0)
00493 throw bad_format(NULL,"Error: plist char must have non-empty content");
00494 val=str[0];
00495 if(str.size()!=1)
00496 std::cerr << "Warning: plist expected single char, found multi-char string '" << str << "'" << std::endl;
00497 }
00498 std::string get() const {
00499 return std::string(1,val);
00500 }
00501 protected:
00502 unsigned char val;
00503 bool numeric;
00504 };
00505
00506
00507
00508 #define PLIST_OBJECT_SPECIALIZATION(T,PRIM) \
00509 template<> \
00510 class Primitive<T> : public PrimitiveBase { \
00511 public: \
00512 Primitive() : PrimitiveBase(), val() {} \
00513 Primitive(const T& v) : PrimitiveBase(), val(v) {} \
00514 Primitive& operator=(const T& v) { val=v; fireValueChanged(); return *this; } \
00515 Primitive& operator+=(const T& v) { val+=v; fireValueChanged(); return *this; } \
00516 Primitive& operator-=(const T& v) { val-=v; fireValueChanged(); return *this; } \
00517 Primitive& operator*=(const T& v) { val*=v; fireValueChanged(); return *this; } \
00518 Primitive& operator/=(const T& v) { val/=v; fireValueChanged(); return *this; } \
00519 \
00520 const T& operator*() const { return val; } \
00521 \
00522 const T* operator->() const { return &val; } \
00523 operator T() const { return val; } \
00524 void LoadXML(xmlNode* node) { \
00525 if(node==NULL) \
00526 return; \
00527 bool bt=xNodeHasName(node,"true"); \
00528 bool bf=xNodeHasName(node,"false"); \
00529 if(!bt && !bf && !xNodeHasName(node,"integer") && !xNodeHasName(node,"real") && !xNodeHasName(node,"string")) \
00530 throw bad_format(node,"Error: plist "#T" expects "PRIM" type"); \
00531 if(!xNodeHasName(node,PRIM)) \
00532 std::cerr << "Warning: plist expected "PRIM" got " << (const char*)xNodeGetName(node) << ", trying to convert. (line " << xGetLineNo(node) << ")" << std::endl; \
00533 if(bt) \
00534 val = true; \
00535 else if(bf) \
00536 val = false; \
00537 else { \
00538 xChar * cont=xNodeGetContent(node); \
00539 std::stringstream str((const char*)cont); \
00540 str >> val; \
00541 xFree(cont); \
00542 } \
00543 fireValueChanged(); \
00544 } \
00545 void SaveXML(xmlNode* node) const { \
00546 if(node==NULL) \
00547 return; \
00548 xNodeSetName(node,(const xChar*)PRIM); \
00549 std::stringstream str; \
00550 str <<std::setprecision(128)<< val; \
00551 xNodeSetContent(node,(const xChar*)str.str().c_str()); \
00552 } \
00553 void set(const std::string& str) { \
00554 std::stringstream sstr(str); \
00555 sstr >> val; \
00556 fireValueChanged(); \
00557 } \
00558 std::string get() const { \
00559 std::stringstream sstr; \
00560 sstr <<std::setprecision(128)<< val; \
00561 return sstr.str(); \
00562 } \
00563 protected: \
00564 T val; \
00565 }
00566
00567 PLIST_OBJECT_SPECIALIZATION(short,"integer");
00568 PLIST_OBJECT_SPECIALIZATION(unsigned short,"integer");
00569 PLIST_OBJECT_SPECIALIZATION(int,"integer");
00570 PLIST_OBJECT_SPECIALIZATION(unsigned int,"integer");
00571 PLIST_OBJECT_SPECIALIZATION(long,"integer");
00572 PLIST_OBJECT_SPECIALIZATION(unsigned long,"integer");
00573 PLIST_OBJECT_SPECIALIZATION(long long,"integer");
00574 PLIST_OBJECT_SPECIALIZATION(unsigned long long,"integer");
00575 PLIST_OBJECT_SPECIALIZATION(float,"real");
00576 PLIST_OBJECT_SPECIALIZATION(double,"real");
00577
00578
00579
00580 template<>
00581 class Primitive<std::string> : public PrimitiveBase, public std::string {
00582 public:
00583 Primitive() : PrimitiveBase(), std::string() {}
00584 Primitive(const std::string& v) : PrimitiveBase(), std::string(v) {}
00585 Primitive& operator=(const std::string& v) { std::string::operator=(v); fireValueChanged(); return *this; }
00586
00587 const std::string& operator*() const { return *this; }
00588
00589 const std::string* operator->() const { return this; }
00590
00591 void LoadXML(xmlNode* node) {
00592 if(node==NULL)
00593 return;
00594 if(xNodeHasName(node,"string")) {
00595 xChar * cont=xNodeGetContent(node);
00596 *this=(char*)cont;
00597 xFree(cont);
00598 } else {
00599 if(xNodeHasName(node,"integer") || xNodeHasName(node,"real")) {
00600 xChar * cont=xNodeGetContent(node);
00601 *this=(char*)cont;
00602 xFree(cont);
00603 } else if(xNodeHasName(node,"true"))
00604 *this="true";
00605 else if(xNodeHasName(node,"false"))
00606 *this="false";
00607 else
00608 throw bad_format(node,"Error: plist string must be 'true', 'false', or numeric type");
00609 std::cerr << "Warning: plist string expected, found " << (const char*)xNodeGetName(node) << " on line " << xGetLineNo(node) << std::endl;
00610 fireValueChanged();
00611 }
00612 }
00613 void SaveXML(xmlNode* node) const {
00614 if(node==NULL)
00615 return;
00616 xNodeSetName(node,(const xChar*)"string");
00617 xNodeSetContent(node,(const xChar*)c_str());
00618 }
00619 void set(const std::string& str) {
00620 *this=str;
00621 fireValueChanged();
00622 }
00623 std::string get() const {
00624 return *this;
00625 }
00626 };
00627
00628
00629
00630
00631
00632
00633
00634 template<typename T>
00635 class NamedEnumeration : public PrimitiveBase {
00636 public:
00637 NamedEnumeration() : PrimitiveBase(), val(), names(NULL), max(0) {}
00638 NamedEnumeration(const NamedEnumeration& ne) : PrimitiveBase(ne), val(ne.val), names(ne.names), max(ne.max) {}
00639 NamedEnumeration(const T& v, const char * const* enumnames, unsigned int maxval) : PrimitiveBase(), val(v), names(enumnames), max(maxval) {}
00640 NamedEnumeration(const T& v) : PrimitiveBase(), val(v), names(NULL), max(0) {}
00641 NamedEnumeration& operator=(const T& v) { val=v; fireValueChanged(); return *this; }
00642 NamedEnumeration& operator=(const std::string& v) { set(v); return *this; }
00643 NamedEnumeration& operator=(const NamedEnumeration& ne) { PrimitiveBase::operator=(ne); val=ne.val; return *this; }
00644
00645 const T& operator*() const { return val; }
00646 operator T() const { return val; }
00647 void setNames(const char * const* enumnames, unsigned int maxval) { names=enumnames; max=maxval; }
00648 const char* const* getNames() const { return names; }
00649 const char* getName(unsigned int i) const { return names[i]; }
00650 unsigned int getMax() const { return max; }
00651
00652 void LoadXML(xmlNode* node) {
00653 if(node==NULL)
00654 return;
00655 if(xNodeHasName(node,"true") || xNodeHasName(node,"false")) {
00656 std::string name=(const char*)xNodeGetName(node);
00657 unsigned int i=findName(name.c_str());
00658 if(i==-1U)
00659 throw bad_format(node,("Error: plist NamedEnumeration cannot be '"+name+"'").c_str());
00660 val=static_cast<T>(i);
00661 std::cerr << "Warning: plist NamedEnumeration should use <string>" << name << "</string>, not <" << name << "/>" << std::endl;
00662 } else if(xNodeHasName(node,"integer") || xNodeHasName(node,"real") || xNodeHasName(node,"string")) {
00663 xChar * cont=xNodeGetContent(node);
00664 try {
00665 set((char*)cont);
00666 } catch(const bad_format& err) {
00667 xFree(cont);
00668 throw bad_format(node,err.what());
00669 } catch(...) {
00670 xFree(cont);
00671 throw;
00672 }
00673 xFree(cont);
00674 } else
00675 throw bad_format(node,"Error: plist NamedEnumeration must be numeric or valid string");
00676 }
00677 void SaveXML(xmlNode* node) const {
00678 if(node==NULL)
00679 return;
00680 if(names!=NULL && names[val]!=NULL && val>0 && (unsigned int)val<max) {
00681 xNodeSetName(node,(const xChar*)"string");
00682 } else {
00683 xNodeSetName(node,(const xChar*)"integer");
00684 }
00685 xNodeSetContent(node,(const xChar*)get().c_str());
00686 }
00687 void set(const std::string& str) {
00688 unsigned int i=findName(str.c_str());
00689 if(i==-1U) {
00690 if(sscanf(str.c_str(),"%d",&i)==0)
00691 throw bad_format(NULL,"Error: plist NamedEnumeration must be numeric or valid string");
00692 }
00693 val=static_cast<T>(i);
00694 fireValueChanged();
00695 }
00696 std::string get() const {
00697 if(names!=NULL && names[val]!=NULL && val>=0 && (unsigned int)val<max)
00698 return names[val];
00699 std::stringstream str;
00700 str << val;
00701 return str.str();
00702 }
00703 protected:
00704
00705 unsigned int findName(const char* name) {
00706 if(name==NULL || names==NULL)
00707 return -1U;
00708 for(unsigned int i=0; i<max; i++)
00709 if(names[i] && strcmp(name,names[i])==0)
00710 return i;
00711 return -1U;
00712 }
00713 T val;
00714 const char * const* names;
00715 unsigned int max;
00716 };
00717
00718
00719 inline std::ostream& operator<<(std::ostream& os, const ObjectBase& pb) {
00720 if(const PrimitiveBase * pbp=dynamic_cast<const PrimitiveBase*>(&pb))
00721 os << *pbp;
00722 else if(const Dictionary * dp=dynamic_cast<const Dictionary*>(&pb))
00723 os << *dp;
00724 else
00725 os << "[Unknown ObjectBase subclass, edit " << __FILE__ << ":" << __LINE__ << "]";
00726 return os;
00727 }
00728
00729 }
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742 #endif
|