data.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883
  1. // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. // $Id$
  15. #include "config.h"
  16. #include "data.h"
  17. #include <cassert>
  18. #include <climits>
  19. #include <cstdio>
  20. #include <iostream>
  21. #include <string>
  22. #include <sstream>
  23. #include <boost/algorithm/string.hpp> // for iequals
  24. #include <cmath>
  25. using namespace std;
  26. namespace isc {
  27. namespace data {
  28. std::string
  29. Element::str()
  30. {
  31. std::stringstream ss;
  32. toJSON(ss);
  33. return ss.str();
  34. }
  35. std::string
  36. Element::toWire()
  37. {
  38. std::stringstream ss;
  39. toJSON(ss);
  40. return ss.str();
  41. }
  42. void
  43. Element::toWire(std::ostream& ss)
  44. {
  45. toJSON(ss);
  46. }
  47. //
  48. // The following methods are effectively empty, and their parameters are
  49. // unused. To silence compilers that warn unused function parameters,
  50. // we specify a (compiler dependent) special keyword when available.
  51. // It's defined in config.h, and to avoid including this header file from
  52. // installed files we define the methods here.
  53. //
  54. bool
  55. Element::getValue(long int& t UNUSED_PARAM) {
  56. return false;
  57. }
  58. bool
  59. Element::getValue(double& t UNUSED_PARAM) {
  60. return false;
  61. }
  62. bool
  63. Element::getValue(bool& t UNUSED_PARAM) {
  64. return false;
  65. }
  66. bool
  67. Element::getValue(std::string& t UNUSED_PARAM) {
  68. return false;
  69. }
  70. bool
  71. Element::getValue(std::vector<ElementPtr>& t UNUSED_PARAM) {
  72. return false;
  73. }
  74. bool
  75. Element::getValue(std::map<std::string, ElementPtr>& t UNUSED_PARAM) {
  76. return false;
  77. }
  78. bool
  79. Element::setValue(const long int v UNUSED_PARAM) {
  80. return false;
  81. }
  82. bool
  83. Element::setValue(const double v UNUSED_PARAM) {
  84. return false;
  85. }
  86. bool
  87. Element::setValue(const bool t UNUSED_PARAM) {
  88. return false;
  89. }
  90. bool
  91. Element::setValue(const std::string& v UNUSED_PARAM) {
  92. return false;
  93. }
  94. bool
  95. Element::setValue(const std::vector<ElementPtr>& v UNUSED_PARAM) {
  96. return false;
  97. }
  98. bool
  99. Element::setValue(const std::map<std::string, ElementPtr>& v UNUSED_PARAM)
  100. {
  101. return false;
  102. }
  103. ElementPtr
  104. Element::get(const int i UNUSED_PARAM) {
  105. isc_throw(TypeError, "get(int) called on a non-list Element");
  106. }
  107. void
  108. Element::set(const size_t i UNUSED_PARAM, ElementPtr element UNUSED_PARAM) {
  109. isc_throw(TypeError, "set(int, element) called on a non-list Element");
  110. }
  111. void
  112. Element::add(ElementPtr element UNUSED_PARAM) {
  113. isc_throw(TypeError, "add() called on a non-list Element");
  114. }
  115. void
  116. Element::remove(const int i UNUSED_PARAM) {
  117. isc_throw(TypeError, "remove(int) called on a non-list Element");
  118. }
  119. size_t
  120. Element::size() {
  121. isc_throw(TypeError, "size() called on a non-list Element");
  122. }
  123. ElementPtr
  124. Element::get(const std::string& name UNUSED_PARAM) {
  125. isc_throw(TypeError, "get(string) called on a non-map Element");
  126. }
  127. void
  128. Element::set(const std::string& name UNUSED_PARAM,
  129. ElementPtr element UNUSED_PARAM)
  130. {
  131. isc_throw(TypeError, "set(name, element) called on a non-map Element");
  132. }
  133. void
  134. Element::remove(const std::string& name UNUSED_PARAM) {
  135. isc_throw(TypeError, "remove(string) called on a non-map Element");
  136. }
  137. bool
  138. Element::contains(const std::string& name UNUSED_PARAM) {
  139. isc_throw(TypeError, "contains(string) called on a non-map Element");
  140. }
  141. ElementPtr
  142. Element::find(const std::string& identifier UNUSED_PARAM) {
  143. isc_throw(TypeError, "find(string) called on a non-map Element");
  144. }
  145. bool
  146. Element::find(const std::string& identifier UNUSED_PARAM,
  147. ElementPtr& t UNUSED_PARAM)
  148. {
  149. return false;
  150. }
  151. namespace {
  152. inline void
  153. throwJSONError(const std::string& error, const std::string& file, int line, int pos)
  154. {
  155. std::stringstream ss;
  156. ss << error << " in " + file + ":" << line << ":" << pos;
  157. isc_throw(JSONError, ss.str());
  158. }
  159. }
  160. std::ostream& operator <<(std::ostream &out, const isc::data::ElementPtr& e) {
  161. return out << e->str();
  162. }
  163. bool operator==(const isc::data::ElementPtr a, const isc::data::ElementPtr b) {
  164. return a->equals(b);
  165. };
  166. //
  167. // factory functions
  168. //
  169. ElementPtr
  170. Element::create() {
  171. return ElementPtr(new NullElement());
  172. }
  173. ElementPtr
  174. Element::create(const long int i) {
  175. return ElementPtr(new IntElement(i));
  176. }
  177. ElementPtr
  178. Element::create(const double d) {
  179. return ElementPtr(new DoubleElement(d));
  180. }
  181. ElementPtr
  182. Element::create(const std::string& s) {
  183. return ElementPtr(new StringElement(s));
  184. }
  185. ElementPtr
  186. Element::create(const bool b) {
  187. return ElementPtr(new BoolElement(b));
  188. }
  189. ElementPtr
  190. Element::createList() {
  191. return ElementPtr(new ListElement());
  192. }
  193. ElementPtr
  194. Element::createMap() {
  195. return ElementPtr(new MapElement());
  196. }
  197. //
  198. // helper functions for fromJSON factory
  199. //
  200. namespace {
  201. bool
  202. char_in(const char c, const char *chars) {
  203. for (size_t i = 0; i < strlen(chars); ++i) {
  204. if (chars[i] == c) {
  205. return true;
  206. }
  207. }
  208. return false;
  209. }
  210. void
  211. skip_chars(std::istream &in, const char *chars, int& line, int& pos) {
  212. char c = in.peek();
  213. while (char_in(c, chars) && c != EOF) {
  214. if (c == '\n') {
  215. ++line;
  216. pos = 1;
  217. } else {
  218. ++pos;
  219. }
  220. in.get();
  221. c = in.peek();
  222. }
  223. }
  224. // skip on the input stream to one of the characters in chars
  225. // if another character is found this function returns false
  226. // unless that character is specified in the optional may_skip
  227. //
  228. // the character found is left on the stream
  229. void
  230. skip_to(std::istream &in, const std::string& file, int& line,
  231. int& pos, const char* chars, const char* may_skip="")
  232. {
  233. char c = in.get();
  234. ++pos;
  235. while (c != EOF) {
  236. if (c == '\n') {
  237. pos = 1;
  238. ++line;
  239. }
  240. if (char_in(c, may_skip)) {
  241. c = in.get();
  242. ++pos;
  243. } else if (char_in(c, chars)) {
  244. while(char_in(in.peek(), may_skip)) {
  245. if (in.peek() == '\n') {
  246. pos = 1;
  247. ++line;
  248. }
  249. in.get();
  250. ++pos;
  251. }
  252. in.putback(c);
  253. --pos;
  254. return;
  255. } else {
  256. throwJSONError(std::string("'") + c + "' read, one of \"" + chars + "\" expected", file, line, pos);
  257. }
  258. }
  259. throwJSONError(std::string("EOF read, one of \"") + chars + "\" expected", file, line, pos);
  260. }
  261. // TODO: Should we check for all other official escapes here (and
  262. // error on the rest)?
  263. std::string
  264. str_from_stringstream(std::istream &in, const std::string& file, const int line,
  265. int& pos) throw (JSONError)
  266. {
  267. char c = 0;
  268. std::stringstream ss;
  269. c = in.get();
  270. ++pos;
  271. if (c == '"') {
  272. c = in.get();
  273. ++pos;
  274. } else {
  275. throwJSONError("String expected", file, line, pos);
  276. }
  277. while (c != EOF && c != '"') {
  278. ss << c;
  279. if (c == '\\' && in.peek() == '"') {
  280. ss << in.get();
  281. ++pos;
  282. }
  283. c = in.get();
  284. ++pos;
  285. }
  286. return ss.str();
  287. }
  288. std::string
  289. word_from_stringstream(std::istream &in, int& pos) {
  290. std::stringstream ss;
  291. while (isalpha(in.peek())) {
  292. ss << (char) in.get();
  293. }
  294. pos += ss.str().size();
  295. return ss.str();
  296. }
  297. static std::string
  298. number_from_stringstream(std::istream &in, int& pos) {
  299. std::stringstream ss;
  300. while (isdigit(in.peek()) || in.peek() == '+' || in.peek() == '-' ||
  301. in.peek() == '.' || in.peek() == 'e' || in.peek() == 'E') {
  302. ss << (char) in.get();
  303. }
  304. pos += ss.str().size();
  305. return ss.str();
  306. }
  307. // Should we change from IntElement and DoubleElement to NumberElement
  308. // that can also hold an e value? (and have specific getters if the
  309. // value is larger than an int can handle)
  310. ElementPtr
  311. from_stringstream_number(std::istream &in, int &pos) {
  312. long int i = 0;
  313. double d = 0.0;
  314. bool is_double = false;
  315. char *endptr;
  316. std::string number = number_from_stringstream(in, pos);
  317. i = strtol(number.c_str(), &endptr, 10);
  318. if (*endptr != '\0') {
  319. d = strtod(number.c_str(), &endptr);
  320. is_double = true;
  321. if (*endptr != '\0') {
  322. isc_throw(JSONError, std::string("Bad number: ") + number);
  323. } else {
  324. if (d == HUGE_VAL || d == -HUGE_VAL) {
  325. isc_throw(JSONError, std::string("Number overflow: ") + number);
  326. }
  327. }
  328. } else {
  329. if (i == LONG_MAX || i == LONG_MIN) {
  330. isc_throw(JSONError, std::string("Number overflow: ") + number);
  331. }
  332. }
  333. if (is_double) {
  334. return Element::create(d);
  335. } else {
  336. return Element::create(i);
  337. }
  338. }
  339. ElementPtr
  340. from_stringstream_bool(std::istream &in, const std::string& file,
  341. const int line, int& pos)
  342. {
  343. const std::string word = word_from_stringstream(in, pos);
  344. if (boost::iequals(word, "True")) {
  345. return Element::create(true);
  346. } else if (boost::iequals(word, "False")) {
  347. return Element::create(false);
  348. } else {
  349. throwJSONError(std::string("Bad boolean value: ") + word, file, line, pos);
  350. // above is a throw shortcurt, return empty is never reached
  351. return ElementPtr();
  352. }
  353. }
  354. ElementPtr
  355. from_stringstream_null(std::istream &in, const std::string& file,
  356. const int line, int& pos)
  357. {
  358. const std::string word = word_from_stringstream(in, pos);
  359. if (boost::iequals(word, "null")) {
  360. return Element::create();
  361. } else {
  362. throwJSONError(std::string("Bad null value: ") + word, file, line, pos);
  363. return ElementPtr();
  364. }
  365. }
  366. ElementPtr
  367. from_stringstream_string(std::istream& in, const std::string& file, int& line, int& pos)
  368. {
  369. return Element::create(str_from_stringstream(in, file, line, pos));
  370. }
  371. ElementPtr
  372. from_stringstream_list(std::istream &in, const std::string& file, int& line, int& pos)
  373. {
  374. char c = 0;
  375. ElementPtr list = Element::createList();
  376. ElementPtr cur_list_element;
  377. skip_chars(in, " \t\n", line, pos);
  378. while (c != EOF && c != ']') {
  379. if (in.peek() != ']') {
  380. cur_list_element = Element::fromJSON(in, file, line, pos);
  381. list->add(cur_list_element);
  382. skip_to(in, file, line, pos, ",]", " \t\n");
  383. }
  384. c = in.get();
  385. pos++;
  386. }
  387. return list;
  388. }
  389. ElementPtr
  390. from_stringstream_map(std::istream &in, const std::string& file, int& line,
  391. int& pos)
  392. {
  393. ElementPtr map = Element::createMap();
  394. skip_chars(in, " \t\n", line, pos);
  395. char c = in.peek();
  396. if (c == '}') {
  397. // empty map, skip closing curly
  398. c = in.get();
  399. } else {
  400. while (c != EOF && c != '}') {
  401. std::string key = str_from_stringstream(in, file, line, pos);
  402. skip_to(in, file, line, pos, ":", " \t\n");
  403. // skip the :
  404. in.get();
  405. pos++;
  406. ElementPtr value = Element::fromJSON(in, file, line, pos);
  407. map->set(key, value);
  408. skip_to(in, file, line, pos, ",}", " \t\n");
  409. c = in.get();
  410. pos++;
  411. }
  412. }
  413. return map;
  414. }
  415. }
  416. std::string
  417. Element::typeToName(Element::types type)
  418. {
  419. switch(type) {
  420. case Element::integer:
  421. return std::string("integer");
  422. case Element::real:
  423. return std::string("real");
  424. case Element::boolean:
  425. return std::string("boolean");
  426. case Element::string:
  427. return std::string("string");
  428. case Element::list:
  429. return std::string("list");
  430. case Element::map:
  431. return std::string("map");
  432. case Element::null:
  433. return std::string("null");
  434. case Element::any:
  435. return std::string("any");
  436. default:
  437. return std::string("unknown");
  438. }
  439. }
  440. Element::types
  441. Element::nameToType(const std::string& type_name) {
  442. if (type_name == "integer") {
  443. return Element::integer;
  444. } else if (type_name == "real") {
  445. return Element::real;
  446. } else if (type_name == "boolean") {
  447. return Element::boolean;
  448. } else if (type_name == "string") {
  449. return Element::string;
  450. } else if (type_name == "list") {
  451. return Element::list;
  452. } else if (type_name == "map") {
  453. return Element::map;
  454. } else if (type_name == "null") {
  455. return Element::null;
  456. } else if (type_name == "any") {
  457. return Element::any;
  458. } else {
  459. isc_throw(TypeError, type_name + " is not a valid type name");
  460. }
  461. }
  462. ElementPtr
  463. Element::fromJSON(std::istream& in) throw(JSONError) {
  464. int line = 1, pos = 1;
  465. return fromJSON(in, "<istream>", line, pos);
  466. }
  467. ElementPtr
  468. Element::fromJSON(std::istream& in, const std::string& file_name) throw(JSONError)
  469. {
  470. int line = 1, pos = 1;
  471. return fromJSON(in, file_name, line, pos);
  472. }
  473. ElementPtr
  474. Element::fromJSON(std::istream &in, const std::string& file, int& line, int& pos) throw(JSONError)
  475. {
  476. char c = 0;
  477. ElementPtr element;
  478. bool el_read = false;
  479. skip_chars(in, " \n\t", line, pos);
  480. while (c != EOF && !el_read) {
  481. c = in.get();
  482. pos++;
  483. switch(c) {
  484. case '1':
  485. case '2':
  486. case '3':
  487. case '4':
  488. case '5':
  489. case '6':
  490. case '7':
  491. case '8':
  492. case '9':
  493. case '0':
  494. case '-':
  495. case '+':
  496. case '.':
  497. in.putback(c);
  498. element = from_stringstream_number(in, pos);
  499. el_read = true;
  500. break;
  501. case 't':
  502. case 'T':
  503. case 'f':
  504. case 'F':
  505. in.putback(c);
  506. element = from_stringstream_bool(in, file, line, pos);
  507. el_read = true;
  508. break;
  509. case 'n':
  510. case 'N':
  511. in.putback(c);
  512. element = from_stringstream_null(in, file, line, pos);
  513. el_read = true;
  514. break;
  515. case '"':
  516. in.putback('"');
  517. element = from_stringstream_string(in, file, line, pos);
  518. el_read = true;
  519. break;
  520. case '[':
  521. element = from_stringstream_list(in, file, line, pos);
  522. el_read = true;
  523. break;
  524. case '{':
  525. element = from_stringstream_map(in, file, line, pos);
  526. el_read = true;
  527. break;
  528. case EOF:
  529. break;
  530. default:
  531. throwJSONError(std::string("error: unexpected character ") + c, file, line, pos);
  532. break;
  533. }
  534. }
  535. if (el_read) {
  536. return element;
  537. } else {
  538. isc_throw(JSONError, "nothing read");
  539. }
  540. }
  541. ElementPtr
  542. Element::fromJSON(const std::string &in) {
  543. std::stringstream ss;
  544. ss << in;
  545. return fromJSON(ss, "<string>");
  546. }
  547. // to JSON format
  548. void
  549. IntElement::toJSON(std::ostream& ss)
  550. {
  551. ss << intValue();
  552. }
  553. void
  554. DoubleElement::toJSON(std::ostream& ss)
  555. {
  556. ss << doubleValue();
  557. }
  558. void
  559. BoolElement::toJSON(std::ostream& ss)
  560. {
  561. if (boolValue()) {
  562. ss << "true";
  563. } else {
  564. ss << "false";
  565. }
  566. }
  567. void
  568. NullElement::toJSON(std::ostream& ss)
  569. {
  570. ss << "null";
  571. }
  572. void
  573. StringElement::toJSON(std::ostream& ss)
  574. {
  575. ss << "\"";
  576. ss << stringValue();
  577. ss << "\"";
  578. }
  579. void
  580. ListElement::toJSON(std::ostream& ss)
  581. {
  582. ss << "[ ";
  583. const std::vector<ElementPtr>& v = listValue();
  584. for (std::vector<ElementPtr>::const_iterator it = v.begin();
  585. it != v.end(); ++it) {
  586. if (it != v.begin()) {
  587. ss << ", ";
  588. }
  589. (*it)->toJSON(ss);
  590. }
  591. ss << " ]";
  592. }
  593. void
  594. MapElement::toJSON(std::ostream& ss)
  595. {
  596. ss << "{ ";
  597. const std::map<std::string, ElementPtr>& m = mapValue();
  598. for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
  599. it != m.end(); ++it) {
  600. if (it != m.begin()) {
  601. ss << ", ";
  602. }
  603. ss << "\"" << (*it).first << "\": ";
  604. if ((*it).second) {
  605. (*it).second->toJSON(ss);
  606. } else {
  607. ss << "None";
  608. }
  609. }
  610. ss << " }";
  611. }
  612. // throws when one of the types in the path (except the one
  613. // we're looking for) is not a MapElement
  614. // returns 0 if it could simply not be found
  615. // should that also be an exception?
  616. ElementPtr
  617. MapElement::find(const std::string& id) {
  618. const size_t sep = id.find('/');
  619. if (sep == std::string::npos) {
  620. return get(id);
  621. } else {
  622. ElementPtr ce = get(id.substr(0, sep));
  623. if (ce) {
  624. // ignore trailing slash
  625. if (sep + 1 != id.size()) {
  626. return ce->find(id.substr(sep + 1));
  627. } else {
  628. return ce;
  629. }
  630. } else {
  631. return ElementPtr();
  632. }
  633. }
  634. }
  635. ElementPtr
  636. Element::fromWire(const std::string& s) {
  637. std::stringstream ss;
  638. ss << s;
  639. int line = 0, pos = 0;
  640. return fromJSON(ss, "<wire>", line, pos);
  641. }
  642. ElementPtr
  643. Element::fromWire(std::stringstream& in, int length) {
  644. //
  645. // Check protocol version
  646. //
  647. //for (int i = 0 ; i < 4 ; ++i) {
  648. // const unsigned char version_byte = get_byte(in);
  649. // if (PROTOCOL_VERSION[i] != version_byte) {
  650. // throw DecodeError("Protocol version incorrect");
  651. // }
  652. //}
  653. //length -= 4;
  654. int line = 0, pos = 0;
  655. return fromJSON(in, "<wire>", line, pos);
  656. }
  657. void
  658. MapElement::set(const std::string& key, ElementPtr value) {
  659. m[key] = value;
  660. }
  661. bool
  662. MapElement::find(const std::string& id, ElementPtr& t) {
  663. try {
  664. ElementPtr p = find(id);
  665. if (p) {
  666. t = p;
  667. return true;
  668. }
  669. } catch (const TypeError& e) {
  670. // ignore
  671. }
  672. return false;
  673. }
  674. bool
  675. IntElement::equals(ElementPtr other) {
  676. return (other->getType() == Element::integer) &&
  677. (i == other->intValue());
  678. }
  679. bool
  680. DoubleElement::equals(ElementPtr other) {
  681. return (other->getType() == Element::real) &&
  682. (d == other->doubleValue());
  683. }
  684. bool
  685. BoolElement::equals(ElementPtr other) {
  686. return (other->getType() == Element::boolean) &&
  687. (b == other->boolValue());
  688. }
  689. bool
  690. NullElement::equals(ElementPtr other) {
  691. return other->getType() == Element::null;
  692. }
  693. bool
  694. StringElement::equals(ElementPtr other) {
  695. return (other->getType() == Element::string) &&
  696. (s == other->stringValue());
  697. }
  698. bool
  699. ListElement::equals(ElementPtr other) {
  700. if (other->getType() == Element::list) {
  701. const int s = size();
  702. if (s != other->size()) {
  703. return false;
  704. }
  705. for (int i = 0; i < s; ++i) {
  706. if (!get(i)->equals(other->get(i))) {
  707. return false;
  708. }
  709. }
  710. return true;
  711. } else {
  712. return false;
  713. }
  714. }
  715. bool
  716. MapElement::equals(ElementPtr other) {
  717. if (other->getType() == Element::map) {
  718. std::map<std::string, ElementPtr> m = mapValue();
  719. for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
  720. it != m.end() ; ++it) {
  721. if (other->contains((*it).first)) {
  722. if (!get((*it).first)->equals(other->get((*it).first))) {
  723. return false;
  724. }
  725. } else {
  726. return false;
  727. }
  728. }
  729. // quickly walk through the other map too, to see if there's
  730. // anything in there that we don't have. We don't need to
  731. // compare those elements; if one of them is missing we
  732. // differ (and if it's not missing the loop above has checked
  733. // it)
  734. m = other->mapValue();
  735. for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
  736. it != m.end() ; ++it) {
  737. if (!contains((*it).first)) {
  738. return false;
  739. }
  740. }
  741. return true;
  742. } else {
  743. return false;
  744. }
  745. }
  746. bool
  747. isNull(ElementPtr p) {
  748. return !p;
  749. }
  750. void
  751. removeIdentical(ElementPtr a, const ElementPtr b) {
  752. if (!b) {
  753. return;
  754. }
  755. if (a->getType() != Element::map || b->getType() != Element::map) {
  756. isc_throw(TypeError, "Non-map Elements passed to removeIdentical");
  757. }
  758. std::map<std::string, ElementPtr> m = a->mapValue();
  759. for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
  760. it != m.end() ; ++it) {
  761. if (b->contains((*it).first)) {
  762. if (a->get((*it).first)->equals(b->get((*it).first))) {
  763. a->remove((*it).first);
  764. }
  765. }
  766. }
  767. }
  768. void
  769. merge(ElementPtr element, const ElementPtr other) {
  770. if (element->getType() != Element::map ||
  771. other->getType() != Element::map) {
  772. isc_throw(TypeError, "merge arguments not MapElements");
  773. }
  774. std::map<std::string, ElementPtr> m = other->mapValue();
  775. for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
  776. it != m.end() ; ++it) {
  777. if ((*it).second && (*it).second->getType() != Element::null) {
  778. element->set((*it).first, (*it).second);
  779. } else if (element->contains((*it).first)) {
  780. element->remove((*it).first);
  781. }
  782. }
  783. }
  784. }
  785. }