data.cc 28 KB

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