data.cc 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118
  1. // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. // $Id$
  15. #include "config.h"
  16. #include "data.h"
  17. #include <cassert>
  18. #include <cstdio>
  19. #include <iostream>
  20. #include <string>
  21. #include <sstream>
  22. #include <boost/algorithm/string.hpp> // for iequals
  23. using namespace std;
  24. namespace {
  25. const unsigned char PROTOCOL_VERSION[4] = { 0x53, 0x6b, 0x61, 0x6e };
  26. const unsigned char ITEM_BLOB = 0x01;
  27. const unsigned char ITEM_HASH = 0x02;
  28. const unsigned char ITEM_LIST = 0x03;
  29. const unsigned char ITEM_NULL = 0x04;
  30. const unsigned char ITEM_BOOL = 0x05;
  31. const unsigned char ITEM_INT = 0x06;
  32. const unsigned char ITEM_REAL = 0x07;
  33. const unsigned char ITEM_UTF8 = 0x08;
  34. const unsigned char ITEM_MASK = 0x0f;
  35. const unsigned char ITEM_LENGTH_32 = 0x00;
  36. const unsigned char ITEM_LENGTH_16 = 0x10;
  37. const unsigned char ITEM_LENGTH_8 = 0x20;
  38. const unsigned char ITEM_LENGTH_MASK = 0x30;
  39. }
  40. namespace isc {
  41. namespace data {
  42. //
  43. // The following methods are effectively empty, and their parameters are
  44. // unused. To silence compilers that warn unused function parameters,
  45. // we specify a (compiler dependent) special keyword when available.
  46. // It's defined in config.h, and to avoid including this header file from
  47. // installed files we define the methods here.
  48. //
  49. bool
  50. Element::getValue(int& t UNUSED_PARAM) {
  51. return false;
  52. }
  53. bool
  54. Element::getValue(double& t UNUSED_PARAM) {
  55. return false;
  56. }
  57. bool
  58. Element::getValue(bool& t UNUSED_PARAM) {
  59. return false;
  60. }
  61. bool
  62. Element::getValue(std::string& t UNUSED_PARAM) {
  63. return false;
  64. }
  65. bool
  66. Element::getValue(std::vector<ElementPtr>& t UNUSED_PARAM) {
  67. return false;
  68. }
  69. bool
  70. Element::getValue(std::map<std::string, ElementPtr>& t UNUSED_PARAM) {
  71. return false;
  72. }
  73. bool
  74. Element::setValue(const int v UNUSED_PARAM) {
  75. return false;
  76. }
  77. bool
  78. Element::setValue(const double v UNUSED_PARAM) {
  79. return false;
  80. }
  81. bool
  82. Element::setValue(const bool t UNUSED_PARAM) {
  83. return false;
  84. }
  85. bool
  86. Element::setValue(const std::string& v UNUSED_PARAM) {
  87. return false;
  88. }
  89. bool
  90. Element::setValue(const std::vector<ElementPtr>& v UNUSED_PARAM) {
  91. return false;
  92. }
  93. bool
  94. Element::setValue(const std::map<std::string, ElementPtr>& v UNUSED_PARAM)
  95. {
  96. return false;
  97. }
  98. ElementPtr
  99. Element::get(const int i UNUSED_PARAM) {
  100. isc_throw(TypeError, "get(int) called on a non-list Element");
  101. }
  102. void
  103. Element::set(const size_t i UNUSED_PARAM, ElementPtr element UNUSED_PARAM) {
  104. isc_throw(TypeError, "set(int, element) called on a non-list Element");
  105. }
  106. void
  107. Element::add(ElementPtr element UNUSED_PARAM) {
  108. isc_throw(TypeError, "add() called on a non-list Element");
  109. }
  110. void
  111. Element::remove(const int i UNUSED_PARAM) {
  112. isc_throw(TypeError, "remove(int) called on a non-list Element");
  113. }
  114. size_t
  115. Element::size() {
  116. isc_throw(TypeError, "size() called on a non-list Element");
  117. }
  118. ElementPtr
  119. Element::get(const std::string& name UNUSED_PARAM) {
  120. isc_throw(TypeError, "get(string) called on a non-map Element");
  121. }
  122. void
  123. Element::set(const std::string& name UNUSED_PARAM,
  124. ElementPtr element UNUSED_PARAM)
  125. {
  126. isc_throw(TypeError, "set(name, element) called on a non-map Element");
  127. }
  128. void
  129. Element::remove(const std::string& name UNUSED_PARAM) {
  130. isc_throw(TypeError, "remove(string) called on a non-map Element");
  131. }
  132. bool
  133. Element::contains(const std::string& name UNUSED_PARAM) {
  134. isc_throw(TypeError, "contains(string) called on a non-map Element");
  135. }
  136. ElementPtr
  137. Element::find(const std::string& identifier UNUSED_PARAM) {
  138. isc_throw(TypeError, "find(string) called on a non-map Element");
  139. }
  140. bool
  141. Element::find(const std::string& identifier UNUSED_PARAM,
  142. ElementPtr& t UNUSED_PARAM)
  143. {
  144. return false;
  145. }
  146. namespace {
  147. inline void
  148. throwParseError(const std::string& error, const std::string& file, int line = 0, int pos = 0)
  149. {
  150. if (line != 0 || pos != 0) {
  151. std::stringstream ss;
  152. ss << error << " in " + file + ":" << line << ":" << pos;
  153. throw ParseError(ss.str());
  154. } else {
  155. throw ParseError(error);
  156. }
  157. }
  158. }
  159. std::ostream& operator <<(std::ostream &out, const isc::data::ElementPtr& e) {
  160. return out << e->str();
  161. }
  162. bool operator==(const isc::data::ElementPtr a, const isc::data::ElementPtr b) {
  163. return a->equals(b);
  164. };
  165. //
  166. // factory functions
  167. //
  168. ElementPtr
  169. Element::create(const int i) {
  170. try {
  171. return ElementPtr(new IntElement(i));
  172. } catch (std::bad_alloc) {
  173. return ElementPtr();
  174. }
  175. }
  176. ElementPtr
  177. Element::create(const double d) {
  178. try {
  179. return ElementPtr(new DoubleElement(d));
  180. } catch (std::bad_alloc) {
  181. return ElementPtr();
  182. }
  183. }
  184. ElementPtr
  185. Element::create(const std::string& s) {
  186. try {
  187. return ElementPtr(new StringElement(s));
  188. } catch (std::bad_alloc) {
  189. return ElementPtr();
  190. }
  191. }
  192. ElementPtr
  193. Element::create(const bool b) {
  194. try {
  195. return ElementPtr(new BoolElement(b));
  196. } catch (std::bad_alloc) {
  197. return ElementPtr();
  198. }
  199. }
  200. ElementPtr
  201. Element::create(const std::vector<ElementPtr>& v) {
  202. try {
  203. return ElementPtr(new ListElement(v));
  204. } catch (std::bad_alloc) {
  205. return ElementPtr();
  206. }
  207. }
  208. ElementPtr
  209. Element::create(const std::map<std::string, ElementPtr>& m) {
  210. for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
  211. it != m.end(); ++it) {
  212. if ((*it).first.length() > 255) {
  213. isc_throw(TypeError, "Map tag is too long");
  214. }
  215. }
  216. try {
  217. return ElementPtr(new MapElement(m));
  218. } catch (std::bad_alloc) {
  219. return ElementPtr();
  220. }
  221. }
  222. //
  223. // helper functions for createFromString factory
  224. //
  225. namespace {
  226. bool
  227. char_in(const char c, const char *chars) {
  228. for (size_t i = 0; i < strlen(chars); ++i) {
  229. if (chars[i] == c) {
  230. return true;
  231. }
  232. }
  233. return false;
  234. }
  235. void
  236. skip_chars(std::istream &in, const char *chars, int& line, int& pos) {
  237. char c = in.peek();
  238. while (char_in(c, chars) && c != EOF) {
  239. if (c == '\n') {
  240. ++line;
  241. pos = 1;
  242. } else {
  243. ++pos;
  244. }
  245. in.get();
  246. c = in.peek();
  247. }
  248. }
  249. // skip on the input stream to one of the characters in chars
  250. // if another character is found this function returns false
  251. // unless that character is specified in the optional may_skip
  252. //
  253. // the character found is left on the stream
  254. void
  255. skip_to(std::istream &in, const std::string& file, int& line,
  256. int& pos, const char* chars, const char* may_skip="")
  257. {
  258. char c = in.get();
  259. ++pos;
  260. while (c != EOF) {
  261. if (c == '\n') {
  262. pos = 1;
  263. ++line;
  264. }
  265. if (char_in(c, may_skip)) {
  266. c = in.get();
  267. ++pos;
  268. } else if (char_in(c, chars)) {
  269. while(char_in(in.peek(), may_skip)) {
  270. if (in.peek() == '\n') {
  271. pos = 1;
  272. ++line;
  273. }
  274. in.get();
  275. ++pos;
  276. }
  277. in.putback(c);
  278. --pos;
  279. return;
  280. } else {
  281. throwParseError(std::string("'") + c + "' read, one of \"" + chars + "\" expected", file, line, pos);
  282. }
  283. }
  284. throwParseError(std::string("EOF read, one of \"") + chars + "\" expected", file, line, pos);
  285. }
  286. std::string
  287. str_from_stringstream(std::istream &in, const std::string& file, const int line,
  288. int& pos) throw (ParseError)
  289. {
  290. char c = 0;
  291. std::stringstream ss;
  292. c = in.get();
  293. ++pos;
  294. if (c == '"') {
  295. c = in.get();
  296. ++pos;
  297. } else {
  298. throwParseError("String expected", file, line, pos);
  299. }
  300. while (c != EOF && c != '"') {
  301. ss << c;
  302. if (c == '\\' && in.peek() == '"') {
  303. ss << in.get();
  304. ++pos;
  305. }
  306. c = in.get();
  307. ++pos;
  308. }
  309. return ss.str();
  310. }
  311. std::string
  312. word_from_stringstream(std::istream &in, int& pos) {
  313. std::stringstream ss;
  314. while (isalpha(in.peek())) {
  315. ss << (char) in.get();
  316. }
  317. pos += ss.str().size();
  318. return ss.str();
  319. }
  320. inline int
  321. count_chars_i(int i) {
  322. int result = 1;
  323. while (i > 10) {
  324. ++result;
  325. i = i / 10;
  326. }
  327. return result;
  328. }
  329. inline int
  330. count_chars_d(double d) {
  331. int result = 1;
  332. while (d < 1.0) {
  333. ++result;
  334. d = d * 10;
  335. }
  336. return result;
  337. }
  338. ElementPtr
  339. from_stringstream_int_or_double(std::istream &in, int &pos) {
  340. int i;
  341. in >> i;
  342. pos += count_chars_i(i);
  343. if (in.peek() == '.') {
  344. double d;
  345. in >> d;
  346. pos += count_chars_d(i);
  347. d += i;
  348. return Element::create(d);
  349. } else {
  350. return Element::create(i);
  351. }
  352. }
  353. ElementPtr
  354. from_stringstream_bool(std::istream &in, const std::string& file,
  355. const int line, int& pos)
  356. {
  357. const std::string word = word_from_stringstream(in, pos);
  358. if (boost::iequals(word, "True")) {
  359. return Element::create(true);
  360. } else if (boost::iequals(word, "False")) {
  361. return Element::create(false);
  362. } else {
  363. throwParseError(std::string("Bad boolean value: ") + word, file, line, pos);
  364. // above is a throw shortcur, return empty is never reached
  365. return ElementPtr();
  366. }
  367. }
  368. ElementPtr
  369. from_stringstream_string(std::istream& in, const std::string& file, int& line, int& pos)
  370. {
  371. return Element::create(str_from_stringstream(in, file, line, pos));
  372. }
  373. ElementPtr
  374. from_stringstream_list(std::istream &in, const std::string& file, int& line, int& pos)
  375. {
  376. char c = 0;
  377. std::vector<ElementPtr> v;
  378. ElementPtr cur_list_element;
  379. skip_chars(in, " \t\n", line, pos);
  380. while (c != EOF && c != ']') {
  381. if (in.peek() != ']') {
  382. cur_list_element = Element::createFromString(in, file, line, pos);
  383. v.push_back(cur_list_element);
  384. skip_to(in, file, line, pos, ",]", " \t\n");
  385. }
  386. c = in.get();
  387. pos++;
  388. }
  389. return Element::create(v);
  390. }
  391. ElementPtr
  392. from_stringstream_map(std::istream &in, const std::string& file, int& line,
  393. int& pos)
  394. {
  395. std::map<std::string, ElementPtr> m;
  396. skip_chars(in, " \t\n", line, pos);
  397. char c = in.peek();
  398. if (c == '}') {
  399. // empty map, skip closing curly
  400. c = in.get();
  401. } else {
  402. while (c != EOF && c != '}') {
  403. std::pair<std::string, ElementPtr> p;
  404. p.first = str_from_stringstream(in, file, line, pos);
  405. if (p.first.length() > 255) {
  406. // Map tag has one-byte length field in wire format, so the
  407. // length cannot exceed 255.
  408. throwParseError("Map tag is too long", file, line, pos);
  409. }
  410. skip_to(in, file, line, pos, ":", " \t\n");
  411. // skip the :
  412. in.get();
  413. pos++;
  414. p.second = Element::createFromString(in, file, line, pos);
  415. m.insert(p);
  416. skip_to(in, file, line, pos, ",}", " \t\n");
  417. c = in.get();
  418. pos++;
  419. }
  420. }
  421. return Element::create(m);
  422. }
  423. }
  424. ElementPtr
  425. Element::createFromString(std::istream& in) throw(ParseError) {
  426. int line = 1, pos = 1;
  427. return createFromString(in, "<istream>", line, pos);
  428. }
  429. ElementPtr
  430. Element::createFromString(std::istream& in, const std::string& file_name) throw(ParseError)
  431. {
  432. int line = 1, pos = 1;
  433. return createFromString(in, file_name, line, pos);
  434. }
  435. ElementPtr
  436. Element::createFromString(std::istream &in, const std::string& file, int& line, int& pos) throw(ParseError)
  437. {
  438. char c = 0;
  439. ElementPtr element;
  440. bool el_read = false;
  441. skip_chars(in, " \n\t", line, pos);
  442. while (c != EOF && !el_read) {
  443. c = in.get();
  444. pos++;
  445. switch(c) {
  446. case '1':
  447. case '2':
  448. case '3':
  449. case '4':
  450. case '5':
  451. case '6':
  452. case '7':
  453. case '8':
  454. case '9':
  455. case '0':
  456. in.putback(c);
  457. element = from_stringstream_int_or_double(in, pos);
  458. el_read = true;
  459. break;
  460. case 't':
  461. case 'T':
  462. case 'f':
  463. case 'F':
  464. in.putback(c);
  465. element = from_stringstream_bool(in, file, line, pos);
  466. el_read = true;
  467. break;
  468. case '"':
  469. in.putback('"');
  470. element = from_stringstream_string(in, file, line, pos);
  471. el_read = true;
  472. break;
  473. case '[':
  474. element = from_stringstream_list(in, file, line, pos);
  475. el_read = true;
  476. break;
  477. case '{':
  478. element = from_stringstream_map(in, file, line, pos);
  479. el_read = true;
  480. break;
  481. case EOF:
  482. break;
  483. default:
  484. throwParseError(std::string("error: unexpected character ") + c, file, line, pos);
  485. break;
  486. }
  487. }
  488. if (el_read) {
  489. return element;
  490. } else {
  491. throw ParseError("nothing read");
  492. }
  493. }
  494. ElementPtr
  495. Element::createFromString(const std::string &in) {
  496. std::stringstream ss;
  497. ss << in;
  498. return createFromString(ss, "<string>");
  499. }
  500. //
  501. // a general to_str() function
  502. //
  503. std::string
  504. IntElement::str() {
  505. std::stringstream ss;
  506. ss << intValue();
  507. return ss.str();
  508. }
  509. std::string
  510. DoubleElement::str() {
  511. std::stringstream ss;
  512. ss << doubleValue();
  513. return ss.str();
  514. }
  515. std::string
  516. BoolElement::str() {
  517. if (b) {
  518. return "True";
  519. } else {
  520. return "False";
  521. }
  522. }
  523. std::string
  524. StringElement::str() {
  525. std::stringstream ss;
  526. ss << "\"";
  527. ss << stringValue();
  528. ss << "\"";
  529. return ss.str();
  530. }
  531. std::string
  532. ListElement::str() {
  533. std::stringstream ss;
  534. ss << "[ ";
  535. const std::vector<ElementPtr>& v = listValue();
  536. for (std::vector<ElementPtr>::const_iterator it = v.begin();
  537. it != v.end(); ++it) {
  538. if (it != v.begin()) {
  539. ss << ", ";
  540. }
  541. ss << (*it)->str();
  542. }
  543. ss << " ]";
  544. return ss.str();
  545. }
  546. std::string
  547. MapElement::str() {
  548. std::stringstream ss;
  549. ss << "{";
  550. const std::map<std::string, ElementPtr>& m = mapValue();
  551. for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
  552. it != m.end(); ++it) {
  553. if (it != m.begin()) {
  554. ss << ", ";
  555. }
  556. ss << "\"" << (*it).first << "\": ";
  557. if ((*it).second) {
  558. ss << (*it).second->str();
  559. } else {
  560. ss << "None";
  561. }
  562. }
  563. ss << "}";
  564. return ss.str();
  565. }
  566. // throws when one of the types in the path (except the one
  567. // we're looking for) is not a MapElement
  568. // returns 0 if it could simply not be found
  569. // should that also be an exception?
  570. ElementPtr
  571. MapElement::find(const std::string& id) {
  572. const size_t sep = id.find('/');
  573. if (sep == std::string::npos) {
  574. return get(id);
  575. } else {
  576. ElementPtr ce = get(id.substr(0, sep));
  577. if (ce) {
  578. // ignore trailing slash
  579. if (sep + 1 != id.size()) {
  580. return ce->find(id.substr(sep + 1));
  581. } else {
  582. return ce;
  583. }
  584. } else {
  585. return ElementPtr();
  586. }
  587. }
  588. }
  589. //
  590. // Decode from wire format.
  591. //
  592. namespace {
  593. ElementPtr decode_element(std::stringstream& in, int& in_length);
  594. unsigned char
  595. get_byte(std::stringstream& in) {
  596. const int c = in.get();
  597. if (c == EOF) {
  598. throw DecodeError("End of data while decoding wire format message");
  599. }
  600. return c;
  601. }
  602. std::string
  603. decode_tag(std::stringstream& in, int& item_length) {
  604. char buf[256];
  605. const int len = get_byte(in);
  606. item_length--;
  607. in.read(buf, len);
  608. if (in.fail()) {
  609. throw DecodeError();
  610. }
  611. buf[len] = 0;
  612. item_length -= len;
  613. return std::string(buf, len);
  614. }
  615. ElementPtr
  616. decode_bool(std::stringstream& in) {
  617. const char c = in.get();
  618. if (c == '1') {
  619. return Element::create(true);
  620. } else {
  621. return Element::create(false);
  622. }
  623. }
  624. ElementPtr
  625. decode_int(std::stringstream& in) {
  626. int me;
  627. return from_stringstream_int_or_double(in, me);
  628. }
  629. ElementPtr
  630. decode_real(std::stringstream& in) {
  631. int me;
  632. return from_stringstream_int_or_double(in, me);
  633. }
  634. ElementPtr
  635. decode_blob(std::stringstream& in, const int item_length) {
  636. vector<char> buf(item_length + 1);
  637. in.read(&buf[0], item_length);
  638. if (in.fail()) {
  639. throw DecodeError();
  640. }
  641. buf[item_length] = 0;
  642. return Element::create(std::string(&buf[0], item_length));
  643. }
  644. ElementPtr
  645. decode_hash(std::stringstream& in, int item_length) {
  646. std::map<std::string, ElementPtr> m;
  647. std::pair<std::string, ElementPtr> p;
  648. while (item_length > 0) {
  649. p.first = decode_tag(in, item_length);
  650. p.second = decode_element(in, item_length);
  651. m.insert(p);
  652. }
  653. return Element::create(m);
  654. }
  655. ElementPtr
  656. decode_list(std::stringstream& in, int item_length) {
  657. std::vector<ElementPtr> v;
  658. while (item_length > 0) {
  659. v.push_back(decode_element(in, item_length));
  660. }
  661. return Element::create(v);
  662. }
  663. ElementPtr
  664. decode_null() {
  665. return Element::create("NULL");
  666. }
  667. ElementPtr
  668. decode_element(std::stringstream& in, int& in_length) {
  669. ElementPtr element;
  670. const unsigned char type_and_length = get_byte(in);
  671. const unsigned char type = type_and_length & ITEM_MASK;
  672. const unsigned char lenbytes = type_and_length & ITEM_LENGTH_MASK;
  673. in_length--;
  674. int item_length = 0;
  675. switch (lenbytes) {
  676. case ITEM_LENGTH_32:
  677. item_length |= get_byte(in);
  678. item_length <<= 8;
  679. item_length |= get_byte(in);
  680. item_length <<= 8;
  681. in_length -= 2; // only 2 here, we will get more later
  682. case ITEM_LENGTH_16:
  683. item_length |= get_byte(in);
  684. item_length <<= 8;
  685. in_length--; // only 1 here
  686. case ITEM_LENGTH_8:
  687. item_length |= get_byte(in);
  688. in_length--;
  689. }
  690. in_length -= item_length;
  691. switch (type) {
  692. case ITEM_BOOL:
  693. element = decode_bool(in);
  694. break;
  695. case ITEM_INT:
  696. element = decode_int(in);
  697. break;
  698. case ITEM_REAL:
  699. element = decode_real(in);
  700. break;
  701. case ITEM_BLOB:
  702. element = decode_blob(in, item_length);
  703. break;
  704. case ITEM_UTF8:
  705. // XXXMLG currently identical to decode_blob
  706. element = decode_blob(in, item_length);
  707. break;
  708. case ITEM_HASH:
  709. element = decode_hash(in, item_length);
  710. break;
  711. case ITEM_LIST:
  712. element = decode_list(in, item_length);
  713. break;
  714. case ITEM_NULL:
  715. element = decode_null();
  716. break;
  717. }
  718. return (element);
  719. }
  720. }
  721. ElementPtr
  722. Element::fromWire(const std::string& s) {
  723. std::stringstream ss;
  724. ss << s;
  725. return fromWire(ss, s.length());
  726. }
  727. ElementPtr
  728. Element::fromWire(std::stringstream& in, int length) {
  729. //
  730. // Check protocol version
  731. //
  732. for (int i = 0 ; i < 4 ; ++i) {
  733. const unsigned char version_byte = get_byte(in);
  734. if (PROTOCOL_VERSION[i] != version_byte) {
  735. throw DecodeError("Protocol version incorrect");
  736. }
  737. }
  738. length -= 4;
  739. return (decode_hash(in, length));
  740. }
  741. //
  742. // Encode into wire format.
  743. //
  744. std::string
  745. encode_length(const unsigned int length, unsigned char type) {
  746. std::stringstream ss;
  747. if (length <= 0x000000ff) {
  748. const unsigned char val = (length & 0x000000ff);
  749. type |= ITEM_LENGTH_8;
  750. ss << type << val;
  751. } else if (length <= 0x0000ffff) {
  752. unsigned char val[2];
  753. val[0] = (length & 0x0000ff00) >> 8;
  754. val[1] = (length & 0x000000ff);
  755. type |= ITEM_LENGTH_16;
  756. ss << type << val[0] << val[1];
  757. } else {
  758. unsigned char val[4];
  759. val[0] = (length & 0xff000000) >> 24;
  760. val[1] = (length & 0x00ff0000) >> 16;
  761. val[2] = (length & 0x0000ff00) >> 8;
  762. val[3] = (length & 0x000000ff);
  763. type |= ITEM_LENGTH_32;
  764. ss << type << val[0] << val[1] << val[2] << val[3];
  765. }
  766. return ss.str();
  767. }
  768. std::string
  769. Element::toWire(const int omit_length) {
  770. std::stringstream ss;
  771. toWire(ss, omit_length);
  772. return ss.str();
  773. }
  774. void
  775. StringElement::toWire(std::stringstream& ss,
  776. const int omit_length UNUSED_PARAM)
  777. {
  778. unsigned int length = stringValue().length();
  779. ss << encode_length(length, ITEM_UTF8) << stringValue();
  780. }
  781. void
  782. IntElement::toWire(std::stringstream& ss,
  783. const int omit_length UNUSED_PARAM)
  784. {
  785. const std::string& s = str();
  786. ss << encode_length(s.length(), ITEM_INT) << s;
  787. }
  788. void
  789. BoolElement::toWire(std::stringstream& ss,
  790. const int omit_length UNUSED_PARAM)
  791. {
  792. ss << encode_length(1, ITEM_BOOL);
  793. if (boolValue()) {
  794. ss << 0x01;
  795. } else {
  796. ss << 0x00;
  797. }
  798. }
  799. void
  800. DoubleElement::toWire(std::stringstream& ss,
  801. const int omit_length UNUSED_PARAM)
  802. {
  803. std::stringstream text;
  804. text << str();
  805. const int length = text.str().length();
  806. ss << encode_length(length, ITEM_REAL) << text.str();
  807. }
  808. void
  809. ListElement::toWire(std::stringstream& ss, const int omit_length) {
  810. std::stringstream ss2;
  811. const std::vector<ElementPtr>& v = listValue();
  812. for (std::vector<ElementPtr>::const_iterator it = v.begin() ;
  813. it != v.end() ; ++it) {
  814. (*it)->toWire(ss2, 0);
  815. }
  816. if (omit_length) {
  817. stringbuf *ss2_buf = ss2.rdbuf();
  818. ss2_buf->pubseekpos(0);
  819. if (ss2_buf->in_avail() > 0) {
  820. ss << ss2_buf;
  821. }
  822. } else {
  823. stringbuf *ss2_buf = ss2.rdbuf();
  824. ss2_buf->pubseekpos(0);
  825. ss << encode_length(ss2_buf->in_avail(), ITEM_LIST);
  826. if (ss2_buf->in_avail() > 0) {
  827. ss << ss2_buf;
  828. }
  829. }
  830. }
  831. void
  832. MapElement::toWire(std::stringstream& ss, int omit_length) {
  833. std::stringstream ss2;
  834. //
  835. // If we don't want the length, we will want the protocol header
  836. //
  837. if (omit_length) {
  838. ss2 << PROTOCOL_VERSION[0] << PROTOCOL_VERSION[1];
  839. ss2 << PROTOCOL_VERSION[2] << PROTOCOL_VERSION[3];
  840. }
  841. const std::map<std::string, ElementPtr>& m = mapValue();
  842. for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
  843. it != m.end(); ++it) {
  844. const size_t taglen = (*it).first.length();
  845. assert(taglen <= 0xff);
  846. const unsigned char val = (taglen & 0x000000ff);
  847. ss2 << val << (*it).first;
  848. (*it).second->toWire(ss2, 0);
  849. }
  850. //
  851. // add length if needed
  852. //
  853. if (omit_length) {
  854. stringbuf *ss2_buf = ss2.rdbuf();
  855. ss2_buf->pubseekpos(0);
  856. if (ss2_buf->in_avail()) {
  857. ss << ss2_buf;
  858. }
  859. } else {
  860. stringbuf *ss2_buf = ss2.rdbuf();
  861. ss2_buf->pubseekpos(0);
  862. ss << encode_length(ss2_buf->in_avail(), ITEM_HASH);
  863. if (ss2_buf->in_avail()) {
  864. ss << ss2_buf;
  865. }
  866. }
  867. }
  868. bool
  869. MapElement::find(const std::string& id, ElementPtr& t) {
  870. try {
  871. ElementPtr p = find(id);
  872. if (p) {
  873. t = p;
  874. return true;
  875. }
  876. } catch (const TypeError& e) {
  877. // ignore
  878. }
  879. return false;
  880. }
  881. bool
  882. IntElement::equals(ElementPtr other) {
  883. return (other->getType() == Element::integer) &&
  884. (i == other->intValue());
  885. }
  886. bool
  887. DoubleElement::equals(ElementPtr other) {
  888. return (other->getType() == Element::real) &&
  889. (d == other->doubleValue());
  890. }
  891. bool
  892. BoolElement::equals(ElementPtr other) {
  893. return (other->getType() == Element::boolean) &&
  894. (b == other->boolValue());
  895. }
  896. bool
  897. StringElement::equals(ElementPtr other) {
  898. return (other->getType() == Element::string) &&
  899. (s == other->stringValue());
  900. }
  901. bool
  902. ListElement::equals(ElementPtr other) {
  903. if (other->getType() == Element::list) {
  904. const int s = size();
  905. if (s != other->size()) {
  906. return false;
  907. }
  908. for (int i = 0; i < s; ++i) {
  909. if (!get(i)->equals(other->get(i))) {
  910. return false;
  911. }
  912. }
  913. return true;
  914. } else {
  915. return false;
  916. }
  917. }
  918. bool
  919. MapElement::equals(ElementPtr other) {
  920. if (other->getType() == Element::map) {
  921. std::map<std::string, ElementPtr> m = mapValue();
  922. for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
  923. it != m.end() ; ++it) {
  924. if (other->contains((*it).first)) {
  925. if (!get((*it).first)->equals(other->get((*it).first))) {
  926. return false;
  927. }
  928. } else {
  929. return false;
  930. }
  931. }
  932. // quickly walk through the other map too, to see if there's
  933. // anything in there that we don't have. We don't need to
  934. // compare those elements; if one of them is missing we
  935. // differ (and if it's not missing the loop above has checked
  936. // it)
  937. m = other->mapValue();
  938. for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
  939. it != m.end() ; ++it) {
  940. if (!contains((*it).first)) {
  941. return false;
  942. }
  943. }
  944. return true;
  945. } else {
  946. return false;
  947. }
  948. }
  949. bool
  950. isNull(ElementPtr p) {
  951. return !p;
  952. }
  953. void
  954. removeIdentical(ElementPtr a, const ElementPtr b) {
  955. if (!b) {
  956. return;
  957. }
  958. if (a->getType() != Element::map || b->getType() != Element::map) {
  959. isc_throw(TypeError, "Non-map Elements passed to removeIdentical");
  960. }
  961. std::map<std::string, ElementPtr> m = a->mapValue();
  962. for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
  963. it != m.end() ; ++it) {
  964. if (b->contains((*it).first)) {
  965. if (a->get((*it).first)->equals(b->get((*it).first))) {
  966. a->remove((*it).first);
  967. }
  968. }
  969. }
  970. }
  971. void
  972. merge(ElementPtr element, const ElementPtr other) {
  973. if (element->getType() != Element::map ||
  974. other->getType() != Element::map) {
  975. isc_throw(TypeError, "merge arguments not MapElements");
  976. }
  977. std::map<std::string, ElementPtr> m = other->mapValue();
  978. for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
  979. it != m.end() ; ++it) {
  980. if ((*it).second) {
  981. element->set((*it).first, (*it).second);
  982. } else if (element->contains((*it).first)) {
  983. element->remove((*it).first);
  984. }
  985. }
  986. }
  987. }
  988. }