00001
00002
00003
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
00030
00031
00032
00033
00034
00035 #include "objtree.h"
00036
00037 #include <sstream>
00038 #include <stdexcept>
00039
00040 #include "datahash/datahash_util.h"
00041 #include "util/token_stream.h"
00042
00043
00044 namespace objtree {
00045
00046
00047 List::~List(void) throw() { }
00048
00049 Tree::~Tree(void) throw() { }
00050
00051
00052
00053
00054
00055
00056
00057
00058 static void
00059 verifyLowerCase
00060 (
00061 IN const char * p
00062 )
00063 {
00064
00065 if ('*' == *p)
00066 return;
00067 ASSERT(isValidPropertyName(p), "Invalid id/query: '%s'", p);
00068 }
00069
00070
00071
00072 static bool
00073 idMatchesQuery
00074 (
00075 IN const char * id,
00076 IN const char * query
00077 )
00078 {
00079 ASSERT(id, "null id");
00080 ASSERT(query, "null query");
00081
00082
00083 if (!strcmp("*", query))
00084 return true;
00085 if (!strcmp(id, query))
00086 return true;
00087 return false;
00088 }
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098 void
00099 property_t::dump
00100 (
00101 IN const char * title
00102 )
00103 const
00104 throw()
00105 {
00106 ASSERT(title, "null title for property_t dump");
00107
00108 DPRINTF(" %s", title);
00109 for (Dictionary::const_iterator i = this->begin(); i != this->end();
00110 ++i) {
00111 const char * field = i->first.c_str();
00112 const char * value = i->second.c_str();
00113
00114 DPRINTF(" field '%s' --> value '%s'", field, value);
00115 }
00116 }
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126 void
00127 property_set_t::dump
00128 (
00129 IN const char * title
00130 )
00131 const
00132 throw()
00133 {
00134 DPRINTF("property_set_t %s:", title);
00135 for (property_set_t::const_iterator i = this->begin(); i != this->end();
00136 ++i) {
00137 const char * name = i->first.c_str();
00138 const property_t& prop = i->second;
00139 prop.dump(name);
00140 }
00141 }
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151 class ListImpl : public List {
00152 public:
00153 ~ListImpl(void) throw() { }
00154
00155 void initialize(void) throw() { }
00156
00157
00158 virtual bool addObject(IN const char * id);
00159 virtual bool removeObject(IN const char * id);
00160 virtual void getObjects(IN const char * id_query,
00161 OUT VecString& ids);
00162 virtual void getProperties(IN const char * id_query,
00163 OUT property_set_t& pset);
00164 virtual void addProperties(IN const char * id_query,
00165 IN const property_set_t& pset);
00166 virtual void setProperties(IN const char * id_query,
00167 IN const property_set_t& pset);
00168
00169 private:
00170
00171 typedef std::map<std::string, smart_ptr<property_set_t> > obj_map_t;
00172
00173
00174 void getPaths(IN const char * query, OUT VecString& ids);
00175
00176
00177 obj_map_t m_objects;
00178 };
00179
00180
00181
00182
00183
00184
00185
00186
00187 bool
00188 ListImpl::addObject
00189 (
00190 IN const char * id
00191 )
00192 {
00193 ASSERT(id, "null");
00194 verifyLowerCase(id);
00195
00196 obj_map_t::iterator i = m_objects.find(id);
00197 if (m_objects.end() != i)
00198 return false;
00199
00200 smart_ptr<property_set_t> props = new property_set_t;
00201 m_objects[id] = props;
00202
00203 return true;
00204 }
00205
00206
00207
00208 bool
00209 ListImpl::removeObject
00210 (
00211 IN const char * id
00212 )
00213 {
00214 ASSERT(id, "null");
00215 verifyLowerCase(id);
00216
00217 obj_map_t::iterator i = m_objects.find(id);
00218 if (m_objects.end() == i) {
00219 DPRINTF("Can't remove object, not in tree: '%s'", id);
00220 return false;
00221 }
00222 m_objects.erase(i);
00223
00224 return true;
00225 }
00226
00227
00228
00229 void
00230 ListImpl::getObjects
00231 (
00232 IN const char * id_query,
00233 OUT VecString& ids
00234 )
00235 {
00236 verifyLowerCase(id_query);
00237
00238 this->getPaths(id_query, ids);
00239 }
00240
00241
00242
00243 void
00244 ListImpl::getProperties
00245 (
00246 IN const char * id_query,
00247 OUT property_set_t& pset
00248 )
00249 {
00250 verifyLowerCase(id_query);
00251
00252 VecString ids;
00253 this->getPaths(id_query, ids);
00254
00255
00256 SetString invalid;
00257 pset.clear();
00258
00259
00260 for (VecString::iterator i = ids.begin(); i != ids.end(); ++i) {
00261
00262
00263 const property_set_t * ps = m_objects[*i];
00264 ASSERT(ps, "null property set");
00265
00266
00267 for (property_set_t::const_iterator k = ps->begin();
00268 k != ps->end(); ++k) {
00269 const char * name = k->first.c_str();
00270
00271 const property_t * p = &k->second;
00272 ASSERT(p, "null property");
00273
00274
00275 property_t * q = pset.getProperty(name);
00276 if (!q) {
00277
00278 pset[name] = *p;
00279 } else {
00280
00281 if (!strcmp(q->getValue(), p->getValue()))
00282 q->setValue(NULL);
00283 }
00284 }
00285 }
00286 }
00287
00288
00289 void
00290 ListImpl::addProperties
00291 (
00292 IN const char * id_query,
00293 IN const property_set_t& pset
00294 )
00295 {
00296 verifyLowerCase(id_query);
00297
00298
00299 VecString ids;
00300 this->getPaths(id_query, ids);
00301
00302
00303 for (VecString::iterator i = ids.begin(); i != ids.end(); ++i) {
00304
00305 obj_map_t::iterator j = m_objects.find(*i);
00306 ASSERT(m_objects.end() != j, "object not in map?");
00307 property_set_t& ps = *j->second;
00308
00309
00310 for (property_set_t::const_iterator k = pset.begin();
00311 k != pset.end(); ++k) {
00312 const char * name = k->first.c_str();
00313 const property_t * p = &k->second;
00314
00315
00316 ps[name] = *p;
00317 }
00318 }
00319 }
00320
00321
00322
00323 void
00324 ListImpl::setProperties
00325 (
00326 IN const char * id_query,
00327 IN const property_set_t& pset
00328 )
00329 {
00330 verifyLowerCase(id_query);
00331
00332
00333 VecString ids;
00334 this->getPaths(id_query, ids);
00335
00336
00337 for (VecString::iterator i = ids.begin(); i != ids.end(); ++i) {
00338
00339 obj_map_t::iterator k = m_objects.find(*i);
00340 ASSERT(m_objects.end() != k, "Object not in map?");
00341 property_set_t * ps = k->second;
00342 ASSERT(ps, "null");
00343
00344
00345 for (property_set_t::const_iterator j = pset.begin();
00346 j != pset.end(); ++j) {
00347
00348 const char * name = j->first.c_str();
00349 const property_t * p = &j->second;
00350
00351
00352 property_t * q = ps->getProperty(name);
00353 if (!q)
00354 break;
00355
00356
00357 q->setValue(p->getValue());
00358 }
00359 }
00360 }
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370 void
00371 ListImpl::getPaths
00372 (
00373 IN const char * query,
00374 OUT VecString& ids
00375 )
00376 {
00377 ASSERT(query, "null");
00378 verifyLowerCase(query);
00379
00380 ids.clear();
00381
00382 for (obj_map_t::iterator i = m_objects.begin(); i != m_objects.end();
00383 ++i) {
00384 if (idMatchesQuery(i->first.c_str(), query)) {
00385 ids.push_back(i->first);
00386 }
00387 }
00388 }
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398 class TreeImpl : public Tree {
00399 public:
00400 ~TreeImpl(void) throw() { }
00401
00402 void initialize(void) throw() { }
00403
00404
00405 List * getList(IN const char * name);
00406 void getListNames(OUT VecString& names);
00407
00408 private:
00409
00410 typedef std::map<std::string, smart_ptr<List> > map_list_t;
00411
00412
00413 map_list_t m_lists;
00414 };
00415
00416
00417
00418 List *
00419 TreeImpl::getList
00420 (
00421 IN const char * name
00422 )
00423 {
00424 ASSERT(name, "null list name");
00425
00426 map_list_t::iterator i = m_lists.find(name);
00427 if (m_lists.end() == i) {
00428
00429
00430 smart_ptr<List> list = List::create();
00431 ASSERT(list, "failed to create new list for '%s'", name);
00432 m_lists[name] = list;
00433 return list;
00434 }
00435
00436 return i->second;
00437 }
00438
00439
00440
00441 void
00442 TreeImpl::getListNames
00443 (
00444 OUT VecString& names
00445 )
00446 {
00447 names.clear();
00448
00449 for (map_list_t::iterator i = m_lists.begin(); i != m_lists.end(); ++i)
00450 {
00451 names.push_back(i->first);
00452 }
00453 }
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463 bool
00464 isValidPropertyName
00465 (
00466 IN const char * name
00467 )
00468 throw()
00469 {
00470
00471 return isValidHashKeyName(name);
00472 }
00473
00474
00475
00476 bool
00477 isTrue
00478 (
00479 IN const char * text
00480 )
00481 throw()
00482 {
00483 ASSERT(text, "null");
00484
00485
00486 char buffer[6];
00487 for (int i = 0; i < 5; ++i) {
00488 buffer[i] = tolower(text[i]);
00489 }
00490 buffer[5] = 0;
00491
00492
00493 if (!strcmp("0", buffer))
00494 return false;
00495 if (!strcmp("f", buffer))
00496 return false;
00497 if (!strcmp("false", buffer))
00498 return false;
00499
00500 return true;
00501 }
00502
00503
00504
00505 void
00506 persist
00507 (
00508 IN const property_t& p,
00509 OUT std::string& val
00510 )
00511 {
00512 ASSERT(false, "Who is calling persist()?");
00513
00514
00515
00516
00517
00518 }
00519
00520
00521
00522 void
00523 depersist
00524 (
00525 IN const char * text,
00526 OUT property_t& prop
00527 )
00528 {
00529 ASSERT(text, "null");
00530 ASSERT(false, "Who is calling depersist()?");
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546 }
00547
00548
00549
00550 void
00551 save
00552 (
00553 IN std::ostream& stream,
00554 IN const property_set_t& pset
00555 )
00556 {
00557 stream << "{\n";
00558
00559 for (property_set_t::const_iterator i = pset.begin(); i != pset.end();
00560 ++i) {
00561 std::string val;
00562 ASSERT(isValidPropertyName(i->first.c_str()),
00563 "Persisting invalid property name! '%s'", i->first.c_str());
00564 persist(i->second, val);
00565 stream << "\t" << i->first << "\t\"" << val << "\"\n";
00566 }
00567
00568 stream << "}\n";
00569 }
00570
00571
00572
00573 void
00574 load
00575 (
00576 IN std::istream& stream,
00577 OUT property_set_t& pset
00578 )
00579 {
00580 pset.clear();
00581
00582 std::string token;
00583 expectToken(stream, "{");
00584 while (true) {
00585 getNextToken(stream, token);
00586 if ("}" == token)
00587 break;
00588
00589 std::string name = token;
00590 if (!isValidPropertyName(name.c_str())) {
00591 std::ostringstream out;
00592 out << "Invalid property name: " << name;
00593 throw std::runtime_error(out.str().c_str());
00594 }
00595
00596 property_t p;
00597 getNextToken(stream, token);
00598 depersist(token.c_str(), p);
00599
00600 pset[name] = p;
00601 }
00602 }
00603
00604
00605
00606 smart_ptr<Datahash>
00607 getDatahash
00608 (
00609 IN const property_set_t& pset
00610 )
00611 {
00612 smart_ptr<Datahash> hash = Datahash::create();
00613 ASSERT(hash, "failed to create datahash");
00614
00615 for (property_set_t::const_iterator i = pset.begin(); i != pset.end();
00616 ++i) {
00617 const char * name = i->first.c_str();
00618 const property_t& p = i->second;
00619
00620 smart_ptr<Datahash> sub = Datahash::create();
00621 ASSERT(sub, "failed to create subhash");
00622
00623
00624 sub->insert("name", name);
00625 for (Dictionary::const_iterator j = p.begin();
00626 j != p.end(); ++j) {
00627 const char * field = j->first.c_str();
00628 const char * value = j->second.c_str();
00629 sub->insert(field, value);
00630 }
00631 hash->insert("property", sub);
00632 }
00633
00634 return hash;
00635 }
00636
00637
00638
00639 void
00640 getPropertySet
00641 (
00642 IN const Datahash * hash,
00643 OUT property_set_t& pset
00644 )
00645 {
00646 ASSERT(hash, "null");
00647 pset.clear();
00648
00649 Datahash::iterator_t i;
00650 hash->getIterator("property", i);
00651 while (const hash_value_t * phv = hash->getNextElementUnsafe(i)) {
00652 if (eHashDataType_Hash != phv->type)
00653 continue;
00654 const Datahash * sub = phv->hash;
00655
00656 property_t prop;
00657 Datahash::iterator_t j;
00658 sub->getIterator(j);
00659 std::string key;
00660 while (const hash_value_t * phv = sub->getNextElementUnsafe(i, key)) {
00661 const char * field = key.c_str();
00662 if (!strcmp(field, "name"))
00663 continue;
00664 prop.setFieldValue(field, phv->text.c_str());
00665 }
00666 pset[getString(sub, "name")] = prop;
00667 }
00668 }
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678 smart_ptr<List>
00679 List::create
00680 (
00681 void
00682 )
00683 {
00684 smart_ptr<ListImpl> local = new ListImpl;
00685 ASSERT(local, "out of memory");
00686
00687 local->initialize();
00688
00689 return local;
00690 }
00691
00692
00693
00694 smart_ptr<Tree>
00695 Tree::create
00696 (
00697 void
00698 )
00699 {
00700 smart_ptr<TreeImpl> local = new TreeImpl;
00701 ASSERT(local, "out of memory");
00702
00703 local->initialize();
00704
00705 return local;
00706 }
00707
00708
00709
00710 };
00711