data.cc 24 KB

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