data.cc 24 KB

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