data.cc 28 KB

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