data.cc 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090
  1. // Copyright (C) 2010-2017 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 <iomanip>
  15. #include <string>
  16. #include <sstream>
  17. #include <fstream>
  18. #include <cerrno>
  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) const {
  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 (word == "true") {
  402. return (Element::create(true, Element::Position(file, line,
  403. start_pos)));
  404. } else if (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 (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 'f':
  587. in.putback(c);
  588. --pos;
  589. element = fromStringstreamBool(in, file, line, pos);
  590. el_read = true;
  591. break;
  592. case 'n':
  593. in.putback(c);
  594. --pos;
  595. element = fromStringstreamNull(in, file, line, pos);
  596. el_read = true;
  597. break;
  598. case '"':
  599. in.putback('"');
  600. --pos;
  601. element = fromStringstreamString(in, file, line, pos);
  602. el_read = true;
  603. break;
  604. case '[':
  605. element = fromStringstreamList(in, file, line, pos);
  606. el_read = true;
  607. break;
  608. case '{':
  609. element = fromStringstreamMap(in, file, line, pos);
  610. el_read = true;
  611. break;
  612. case EOF:
  613. break;
  614. default:
  615. throwJSONError(std::string("error: unexpected character ") + std::string(1, c), file, line, pos);
  616. break;
  617. }
  618. }
  619. if (el_read) {
  620. return (element);
  621. } else {
  622. isc_throw(JSONError, "nothing read");
  623. }
  624. }
  625. ElementPtr
  626. Element::fromJSON(const std::string& in, bool preproc) {
  627. std::stringstream ss;
  628. ss << in;
  629. int line = 1, pos = 1;
  630. stringstream filtered;
  631. if (preproc) {
  632. preprocess(ss, filtered);
  633. }
  634. ElementPtr result(fromJSON(preproc ? filtered : ss, "<string>", line, pos));
  635. skipChars(ss, WHITESPACE, line, pos);
  636. // ss must now be at end
  637. if (ss.peek() != EOF) {
  638. throwJSONError("Extra data", "<string>", line, pos);
  639. }
  640. return result;
  641. }
  642. ElementPtr
  643. Element::fromJSONFile(const std::string& file_name,
  644. bool preproc) {
  645. // zero out the errno to be safe
  646. errno = 0;
  647. std::ifstream infile(file_name.c_str(), std::ios::in | std::ios::binary);
  648. if (!infile.is_open())
  649. {
  650. const char* error = strerror(errno);
  651. isc_throw(InvalidOperation, "failed to read file '" << file_name
  652. << "': " << error);
  653. }
  654. return (fromJSON(infile, file_name, preproc));
  655. }
  656. // to JSON format
  657. void
  658. IntElement::toJSON(std::ostream& ss) const {
  659. ss << intValue();
  660. }
  661. void
  662. DoubleElement::toJSON(std::ostream& ss) const {
  663. ss << doubleValue();
  664. }
  665. void
  666. BoolElement::toJSON(std::ostream& ss) const {
  667. if (boolValue()) {
  668. ss << "true";
  669. } else {
  670. ss << "false";
  671. }
  672. }
  673. void
  674. NullElement::toJSON(std::ostream& ss) const {
  675. ss << "null";
  676. }
  677. void
  678. StringElement::toJSON(std::ostream& ss) const {
  679. ss << "\"";
  680. const std::string& str = stringValue();
  681. for (size_t i = 0; i < str.size(); ++i) {
  682. const char c = str[i];
  683. // Escape characters as defined in JSON spec
  684. // Note that we do not escape forward slash; this
  685. // is allowed, but not mandatory.
  686. switch (c) {
  687. case '"':
  688. ss << '\\' << c;
  689. break;
  690. case '\\':
  691. ss << '\\' << c;
  692. break;
  693. case '\b':
  694. ss << '\\' << 'b';
  695. break;
  696. case '\f':
  697. ss << '\\' << 'f';
  698. break;
  699. case '\n':
  700. ss << '\\' << 'n';
  701. break;
  702. case '\r':
  703. ss << '\\' << 'r';
  704. break;
  705. case '\t':
  706. ss << '\\' << 't';
  707. break;
  708. default:
  709. if ((c >= 0) && (c < 0x20)) {
  710. std::ostringstream esc;
  711. esc << "\\u"
  712. << hex
  713. << setw(4)
  714. << setfill('0')
  715. << (static_cast<unsigned>(c) & 0xff);
  716. ss << esc.str();
  717. } else {
  718. ss << c;
  719. }
  720. }
  721. }
  722. ss << "\"";
  723. }
  724. void
  725. ListElement::toJSON(std::ostream& ss) const {
  726. ss << "[ ";
  727. const std::vector<ElementPtr>& v = listValue();
  728. for (std::vector<ElementPtr>::const_iterator it = v.begin();
  729. it != v.end(); ++it) {
  730. if (it != v.begin()) {
  731. ss << ", ";
  732. }
  733. (*it)->toJSON(ss);
  734. }
  735. ss << " ]";
  736. }
  737. void
  738. MapElement::toJSON(std::ostream& ss) const {
  739. ss << "{ ";
  740. const std::map<std::string, ConstElementPtr>& m = mapValue();
  741. for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
  742. it != m.end(); ++it) {
  743. if (it != m.begin()) {
  744. ss << ", ";
  745. }
  746. ss << "\"" << (*it).first << "\": ";
  747. if ((*it).second) {
  748. (*it).second->toJSON(ss);
  749. } else {
  750. ss << "None";
  751. }
  752. }
  753. ss << " }";
  754. }
  755. // throws when one of the types in the path (except the one
  756. // we're looking for) is not a MapElement
  757. // returns 0 if it could simply not be found
  758. // should that also be an exception?
  759. ConstElementPtr
  760. MapElement::find(const std::string& id) const {
  761. const size_t sep = id.find('/');
  762. if (sep == std::string::npos) {
  763. return (get(id));
  764. } else {
  765. ConstElementPtr ce = get(id.substr(0, sep));
  766. if (ce) {
  767. // ignore trailing slash
  768. if (sep + 1 != id.size()) {
  769. return (ce->find(id.substr(sep + 1)));
  770. } else {
  771. return (ce);
  772. }
  773. } else {
  774. return (ElementPtr());
  775. }
  776. }
  777. }
  778. ElementPtr
  779. Element::fromWire(const std::string& s) {
  780. std::stringstream ss;
  781. ss << s;
  782. int line = 0, pos = 0;
  783. return (fromJSON(ss, "<wire>", line, pos));
  784. }
  785. ElementPtr
  786. Element::fromWire(std::stringstream& in, int) {
  787. //
  788. // Check protocol version
  789. //
  790. //for (int i = 0 ; i < 4 ; ++i) {
  791. // const unsigned char version_byte = get_byte(in);
  792. // if (PROTOCOL_VERSION[i] != version_byte) {
  793. // throw DecodeError("Protocol version incorrect");
  794. // }
  795. //}
  796. //length -= 4;
  797. int line = 0, pos = 0;
  798. return (fromJSON(in, "<wire>", line, pos));
  799. }
  800. void
  801. MapElement::set(const std::string& key, ConstElementPtr value) {
  802. m[key] = value;
  803. }
  804. bool
  805. MapElement::find(const std::string& id, ConstElementPtr& t) const {
  806. try {
  807. ConstElementPtr p = find(id);
  808. if (p) {
  809. t = p;
  810. return (true);
  811. }
  812. } catch (const TypeError&) {
  813. // ignore
  814. }
  815. return (false);
  816. }
  817. bool
  818. IntElement::equals(const Element& other) const {
  819. return (other.getType() == Element::integer) &&
  820. (i == other.intValue());
  821. }
  822. bool
  823. DoubleElement::equals(const Element& other) const {
  824. return (other.getType() == Element::real) &&
  825. (d == other.doubleValue());
  826. }
  827. bool
  828. BoolElement::equals(const Element& other) const {
  829. return (other.getType() == Element::boolean) &&
  830. (b == other.boolValue());
  831. }
  832. bool
  833. NullElement::equals(const Element& other) const {
  834. return (other.getType() == Element::null);
  835. }
  836. bool
  837. StringElement::equals(const Element& other) const {
  838. return (other.getType() == Element::string) &&
  839. (s == other.stringValue());
  840. }
  841. bool
  842. ListElement::equals(const Element& other) const {
  843. if (other.getType() == Element::list) {
  844. const size_t s = size();
  845. if (s != other.size()) {
  846. return (false);
  847. }
  848. for (size_t i = 0; i < s; ++i) {
  849. if (!get(i)->equals(*other.get(i))) {
  850. return (false);
  851. }
  852. }
  853. return (true);
  854. } else {
  855. return (false);
  856. }
  857. }
  858. bool
  859. MapElement::equals(const Element& other) const {
  860. if (other.getType() == Element::map) {
  861. const std::map<std::string, ConstElementPtr>& m = mapValue();
  862. for (std::map<std::string, ConstElementPtr>::const_iterator it =
  863. m.begin();
  864. it != m.end() ; ++it) {
  865. if (other.contains((*it).first)) {
  866. if (!get((*it).first)->equals(*other.get((*it).first))) {
  867. return (false);
  868. }
  869. } else {
  870. return (false);
  871. }
  872. }
  873. // quickly walk through the other map too, to see if there's
  874. // anything in there that we don't have. We don't need to
  875. // compare those elements; if one of them is missing we
  876. // differ (and if it's not missing the loop above has checked
  877. // it)
  878. std::map<std::string, ConstElementPtr>::const_iterator it;
  879. for (it = other.mapValue().begin();
  880. it != other.mapValue().end();
  881. ++it) {
  882. if (!contains((*it).first)) {
  883. return (false);
  884. }
  885. }
  886. return (true);
  887. } else {
  888. return (false);
  889. }
  890. }
  891. bool
  892. isNull(ConstElementPtr p) {
  893. return (!p);
  894. }
  895. void
  896. removeIdentical(ElementPtr a, ConstElementPtr b) {
  897. if (!b) {
  898. return;
  899. }
  900. if (a->getType() != Element::map || b->getType() != Element::map) {
  901. isc_throw(TypeError, "Non-map Elements passed to removeIdentical");
  902. }
  903. // As maps do not allow entries with multiple keys, we can either iterate
  904. // over a checking for identical entries in b or vice-versa. As elements
  905. // are removed from a if a match is found, we choose to iterate over b to
  906. // avoid problems with element removal affecting the iterator.
  907. const std::map<std::string, ConstElementPtr>& m = b->mapValue();
  908. for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
  909. it != m.end() ; ++it) {
  910. if (a->contains((*it).first)) {
  911. if (a->get((*it).first)->equals(*b->get((*it).first))) {
  912. a->remove((*it).first);
  913. }
  914. }
  915. }
  916. }
  917. ConstElementPtr
  918. removeIdentical(ConstElementPtr a, ConstElementPtr b) {
  919. ElementPtr result = Element::createMap();
  920. if (!b) {
  921. return (result);
  922. }
  923. if (a->getType() != Element::map || b->getType() != Element::map) {
  924. isc_throw(TypeError, "Non-map Elements passed to removeIdentical");
  925. }
  926. const std::map<std::string, ConstElementPtr>& m = a->mapValue();
  927. for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
  928. it != m.end() ; ++it) {
  929. if (!b->contains((*it).first) ||
  930. !a->get((*it).first)->equals(*b->get((*it).first))) {
  931. result->set((*it).first, (*it).second);
  932. }
  933. }
  934. return (result);
  935. }
  936. void
  937. merge(ElementPtr element, ConstElementPtr other) {
  938. if (element->getType() != Element::map ||
  939. other->getType() != Element::map) {
  940. isc_throw(TypeError, "merge arguments not MapElements");
  941. }
  942. const std::map<std::string, ConstElementPtr>& m = other->mapValue();
  943. for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
  944. it != m.end() ; ++it) {
  945. if ((*it).second && (*it).second->getType() != Element::null) {
  946. element->set((*it).first, (*it).second);
  947. } else if (element->contains((*it).first)) {
  948. element->remove((*it).first);
  949. }
  950. }
  951. }
  952. void Element::preprocess(std::istream& in, std::stringstream& out) {
  953. std::string line;
  954. while (std::getline(in, line)) {
  955. // If this is a comments line, replace it with empty line
  956. // (so the line numbers will still match
  957. if (!line.empty() && line[0] == '#') {
  958. line = "";
  959. }
  960. // getline() removes end line charaters. Unfortunately, we need
  961. // it for getting the line numbers right (in case we report an
  962. // error.
  963. out << line;
  964. out << "\n";
  965. }
  966. }
  967. }
  968. }