PageRenderTime 57ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/modules/cloud-init/json.cc

https://gitlab.com/jforge/osv
C++ | 695 lines | 503 code | 94 blank | 98 comment | 124 complexity | 4945c35b947b26557e18e4305cd4fd81 MD5 | raw file
Possible License(s): BSD-3-Clause, 0BSD, MPL-2.0-no-copyleft-exception
  1. /* Copyright (c) 2013 Dropbox, Inc.
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to deal
  5. * in the Software without restriction, including without limitation the rights
  6. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. * copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. * THE SOFTWARE.
  20. */
  21. #include "json.hh"
  22. #include <cassert>
  23. #include <cstdlib>
  24. #include <cstdio>
  25. #include <limits>
  26. namespace json11 {
  27. static const int max_depth = 200;
  28. using std::string;
  29. using std::vector;
  30. using std::map;
  31. using std::make_shared;
  32. using std::initializer_list;
  33. using std::move;
  34. /* * * * * * * * * * * * * * * * * * * *
  35. * Serialization
  36. */
  37. static void dump(std::nullptr_t, string &out) {
  38. out += "null";
  39. }
  40. static void dump(double value, string &out) {
  41. char buf[32];
  42. snprintf(buf, sizeof buf, "%.17g", value);
  43. out += buf;
  44. }
  45. static void dump(int value, string &out) {
  46. char buf[32];
  47. snprintf(buf, sizeof buf, "%d", value);
  48. out += buf;
  49. }
  50. static void dump(bool value, string &out) {
  51. out += value ? "true" : "false";
  52. }
  53. static void dump(const string &value, string &out) {
  54. out += '"';
  55. for (size_t i = 0; i < value.length(); i++) {
  56. const char ch = value[i];
  57. if (ch == '\\') {
  58. out += "\\\\";
  59. } else if (ch == '"') {
  60. out += "\\\"";
  61. } else if (ch == '\b') {
  62. out += "\\b";
  63. } else if (ch == '\f') {
  64. out += "\\f";
  65. } else if (ch == '\n') {
  66. out += "\\n";
  67. } else if (ch == '\r') {
  68. out += "\\r";
  69. } else if (ch == '\t') {
  70. out += "\\t";
  71. } else if (static_cast<uint8_t>(ch) <= 0x1f) {
  72. char buf[8];
  73. snprintf(buf, sizeof buf, "\\u%04x", ch);
  74. out += buf;
  75. } else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i+1]) == 0x80
  76. && static_cast<uint8_t>(value[i+2]) == 0xa8) {
  77. out += "\\u2028";
  78. i += 2;
  79. } else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i+1]) == 0x80
  80. && static_cast<uint8_t>(value[i+2]) == 0xa9) {
  81. out += "\\u2029";
  82. i += 2;
  83. } else {
  84. out += ch;
  85. }
  86. }
  87. out += '"';
  88. }
  89. static void dump(const Json::array &values, string &out) {
  90. bool first = true;
  91. out += "[";
  92. for (auto &value : values) {
  93. if (!first)
  94. out += ", ";
  95. value.dump(out);
  96. first = false;
  97. }
  98. out += "]";
  99. }
  100. static void dump(const Json::object &values, string &out) {
  101. bool first = true;
  102. out += "{";
  103. for (const std::pair<string, Json> &kv : values) {
  104. if (!first)
  105. out += ", ";
  106. dump(kv.first, out);
  107. out += ": ";
  108. kv.second.dump(out);
  109. first = false;
  110. }
  111. out += "}";
  112. }
  113. void Json::dump(string &out) const {
  114. m_ptr->dump(out);
  115. }
  116. /* * * * * * * * * * * * * * * * * * * *
  117. * Value wrappers
  118. */
  119. template <Json::Type tag, typename T>
  120. class Value : public JsonValue {
  121. protected:
  122. // Constructors
  123. explicit Value(const T &value) : m_value(value) {}
  124. explicit Value(T &&value) : m_value(move(value)) {}
  125. // Get type tag
  126. Json::Type type() const override {
  127. return tag;
  128. }
  129. // Comparisons
  130. bool equals(const JsonValue * other) const override {
  131. return m_value == reinterpret_cast<const Value<tag, T> *>(other)->m_value;
  132. }
  133. bool less(const JsonValue * other) const override {
  134. return m_value < reinterpret_cast<const Value<tag, T> *>(other)->m_value;
  135. }
  136. const T m_value;
  137. void dump(string &out) const override { json11::dump(m_value, out); }
  138. };
  139. class JsonDouble final : public Value<Json::NUMBER, double> {
  140. double number_value() const override { return m_value; }
  141. int int_value() const override { return static_cast<int>(m_value); }
  142. bool equals(const JsonValue * other) const override { return m_value == other->number_value(); }
  143. bool less(const JsonValue * other) const override { return m_value < other->number_value(); }
  144. public:
  145. explicit JsonDouble(double value) : Value(value) {}
  146. };
  147. class JsonInt final : public Value<Json::NUMBER, int> {
  148. double number_value() const override { return m_value; }
  149. int int_value() const override { return m_value; }
  150. bool equals(const JsonValue * other) const override { return m_value == other->number_value(); }
  151. bool less(const JsonValue * other) const override { return m_value < other->number_value(); }
  152. public:
  153. explicit JsonInt(int value) : Value(value) {}
  154. };
  155. class JsonBoolean final : public Value<Json::BOOL, bool> {
  156. bool bool_value() const override { return m_value; }
  157. public:
  158. explicit JsonBoolean(bool value) : Value(value) {}
  159. };
  160. class JsonString final : public Value<Json::STRING, string> {
  161. const string &string_value() const override { return m_value; }
  162. public:
  163. explicit JsonString(const string &value) : Value(value) {}
  164. explicit JsonString(string &&value) : Value(move(value)) {}
  165. };
  166. class JsonArray final : public Value<Json::ARRAY, Json::array> {
  167. const Json::array &array_items() const override { return m_value; }
  168. const Json & operator[](size_t i) const override;
  169. public:
  170. explicit JsonArray(const Json::array &value) : Value(value) {}
  171. explicit JsonArray(Json::array &&value) : Value(move(value)) {}
  172. };
  173. class JsonObject final : public Value<Json::OBJECT, Json::object> {
  174. const Json::object &object_items() const override { return m_value; }
  175. const Json & operator[](const string &key) const override;
  176. public:
  177. explicit JsonObject(const Json::object &value) : Value(value) {}
  178. explicit JsonObject(Json::object &&value) : Value(move(value)) {}
  179. };
  180. class JsonNull final : public Value<Json::NUL, std::nullptr_t> {
  181. public:
  182. JsonNull() : Value(nullptr) {}
  183. };
  184. /* * * * * * * * * * * * * * * * * * * *
  185. * Static globals - static-init-safe
  186. */
  187. struct Statics {
  188. const std::shared_ptr<JsonValue> null = make_shared<JsonNull>();
  189. const std::shared_ptr<JsonValue> t = make_shared<JsonBoolean>(true);
  190. const std::shared_ptr<JsonValue> f = make_shared<JsonBoolean>(false);
  191. const string empty_string;
  192. const vector<Json> empty_vector;
  193. const map<string, Json> empty_map;
  194. Statics() {}
  195. };
  196. const Statics & statics() {
  197. static const Statics s {};
  198. return s;
  199. }
  200. const Json & static_null() {
  201. // This has to be separate, not in Statics, because Json() accesses statics().null.
  202. static const Json json_null;
  203. return json_null;
  204. }
  205. /* * * * * * * * * * * * * * * * * * * *
  206. * Constructors
  207. */
  208. Json::Json() noexcept : m_ptr(statics().null) {}
  209. Json::Json(std::nullptr_t) noexcept : m_ptr(statics().null) {}
  210. Json::Json(double value) : m_ptr(make_shared<JsonDouble>(value)) {}
  211. Json::Json(int value) : m_ptr(make_shared<JsonInt>(value)) {}
  212. Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) {}
  213. Json::Json(const string &value) : m_ptr(make_shared<JsonString>(value)) {}
  214. Json::Json(string &&value) : m_ptr(make_shared<JsonString>(move(value))) {}
  215. Json::Json(const char * value) : m_ptr(make_shared<JsonString>(value)) {}
  216. Json::Json(const Json::array &values) : m_ptr(make_shared<JsonArray>(values)) {}
  217. Json::Json(Json::array &&values) : m_ptr(make_shared<JsonArray>(move(values))) {}
  218. Json::Json(const Json::object &values) : m_ptr(make_shared<JsonObject>(values)) {}
  219. Json::Json(Json::object &&values) : m_ptr(make_shared<JsonObject>(move(values))) {}
  220. /* * * * * * * * * * * * * * * * * * * *
  221. * Accessors
  222. */
  223. Json::Type Json::type() const { return m_ptr->type(); }
  224. double Json::number_value() const { return m_ptr->number_value(); }
  225. int Json::int_value() const { return m_ptr->int_value(); }
  226. bool Json::bool_value() const { return m_ptr->bool_value(); }
  227. const string & Json::string_value() const { return m_ptr->string_value(); }
  228. const vector<Json> & Json::array_items() const { return m_ptr->array_items(); }
  229. const map<string, Json> & Json::object_items() const { return m_ptr->object_items(); }
  230. const Json & Json::operator[] (size_t i) const { return (*m_ptr)[i]; }
  231. const Json & Json::operator[] (const string &key) const { return (*m_ptr)[key]; }
  232. double JsonValue::number_value() const { return 0; }
  233. int JsonValue::int_value() const { return 0; }
  234. bool JsonValue::bool_value() const { return false; }
  235. const string & JsonValue::string_value() const { return statics().empty_string; }
  236. const vector<Json> & JsonValue::array_items() const { return statics().empty_vector; }
  237. const map<string, Json> & JsonValue::object_items() const { return statics().empty_map; }
  238. const Json & JsonValue::operator[] (size_t) const { return static_null(); }
  239. const Json & JsonValue::operator[] (const string &) const { return static_null(); }
  240. const Json & JsonObject::operator[] (const string &key) const {
  241. auto iter = m_value.find(key);
  242. return (iter == m_value.end()) ? static_null() : iter->second;
  243. }
  244. const Json & JsonArray::operator[] (size_t i) const {
  245. if (i >= m_value.size()) return static_null();
  246. else return m_value[i];
  247. }
  248. /* * * * * * * * * * * * * * * * * * * *
  249. * Comparison
  250. */
  251. bool Json::operator== (const Json &other) const {
  252. if (m_ptr->type() != other.m_ptr->type())
  253. return false;
  254. return m_ptr->equals(other.m_ptr.get());
  255. }
  256. bool Json::operator< (const Json &other) const {
  257. if (m_ptr->type() != other.m_ptr->type())
  258. return m_ptr->type() < other.m_ptr->type();
  259. return m_ptr->less(other.m_ptr.get());
  260. }
  261. /* * * * * * * * * * * * * * * * * * * *
  262. * Parsing
  263. */
  264. /* esc(c)
  265. *
  266. * Format char c suitable for printing in an error message.
  267. */
  268. static inline string esc(char c) {
  269. char buf[12];
  270. if (static_cast<uint8_t>(c) >= 0x20 && static_cast<uint8_t>(c) <= 0x7f) {
  271. snprintf(buf, sizeof buf, "'%c' (%d)", c, c);
  272. } else {
  273. snprintf(buf, sizeof buf, "(%d)", c);
  274. }
  275. return string(buf);
  276. }
  277. static inline bool in_range(long x, long lower, long upper) {
  278. return (x >= lower && x <= upper);
  279. }
  280. /* JsonParser
  281. *
  282. * Object that tracks all state of an in-progress parse.
  283. */
  284. struct JsonParser {
  285. /* State
  286. */
  287. const string &str;
  288. size_t i;
  289. string &err;
  290. bool failed;
  291. /* fail(msg, err_ret = Json())
  292. *
  293. * Mark this parse as failed.
  294. */
  295. Json fail(string &&msg) {
  296. return fail(move(msg), Json());
  297. }
  298. template <typename T>
  299. T fail(string &&msg, const T err_ret) {
  300. if (!failed)
  301. err = std::move(msg);
  302. failed = true;
  303. return err_ret;
  304. }
  305. /* consume_whitespace()
  306. *
  307. * Advance until the current character is non-whitespace.
  308. */
  309. void consume_whitespace() {
  310. while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || str[i] == '\t')
  311. i++;
  312. }
  313. /* get_next_token()
  314. *
  315. * Return the next non-whitespace character. If the end of the input is reached,
  316. * flag an error and return 0.
  317. */
  318. char get_next_token() {
  319. consume_whitespace();
  320. if (i == str.size())
  321. return fail("unexpected end of input", 0);
  322. return str[i++];
  323. }
  324. /* encode_utf8(pt, out)
  325. *
  326. * Encode pt as UTF-8 and add it to out.
  327. */
  328. void encode_utf8(long pt, string & out) {
  329. if (pt < 0)
  330. return;
  331. if (pt < 0x80) {
  332. out += pt;
  333. } else if (pt < 0x800) {
  334. out += (pt >> 6) | 0xC0;
  335. out += (pt & 0x3F) | 0x80;
  336. } else if (pt < 0x10000) {
  337. out += (pt >> 12) | 0xE0;
  338. out += ((pt >> 6) & 0x3F) | 0x80;
  339. out += (pt & 0x3F) | 0x80;
  340. } else {
  341. out += (pt >> 18) | 0xF0;
  342. out += ((pt >> 12) & 0x3F) | 0x80;
  343. out += ((pt >> 6) & 0x3F) | 0x80;
  344. out += (pt & 0x3F) | 0x80;
  345. }
  346. }
  347. /* parse_string()
  348. *
  349. * Parse a string, starting at the current position.
  350. */
  351. string parse_string() {
  352. string out;
  353. long last_escaped_codepoint = -1;
  354. while (true) {
  355. if (i == str.size())
  356. return fail("unexpected end of input in string", "");
  357. char ch = str[i++];
  358. if (ch == '"') {
  359. encode_utf8(last_escaped_codepoint, out);
  360. return out;
  361. }
  362. if (in_range(ch, 0, 0x1f))
  363. return fail("unescaped " + esc(ch) + " in string", "");
  364. // The usual case: non-escaped characters
  365. if (ch != '\\') {
  366. encode_utf8(last_escaped_codepoint, out);
  367. last_escaped_codepoint = -1;
  368. out += ch;
  369. continue;
  370. }
  371. // Handle escapes
  372. if (i == str.size())
  373. return fail("unexpected end of input in string", "");
  374. ch = str[i++];
  375. if (ch == 'u') {
  376. // Extract 4-byte escape sequence
  377. string esc = str.substr(i, 4);
  378. for (int j = 0; j < 4; j++) {
  379. if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F')
  380. && !in_range(esc[j], '0', '9'))
  381. return fail("bad \\u escape: " + esc, "");
  382. }
  383. long codepoint = strtol(esc.data(), nullptr, 16);
  384. // JSON specifies that characters outside the BMP shall be encoded as a pair
  385. // of 4-hex-digit \u escapes encoding their surrogate pair components. Check
  386. // whether we're in the middle of such a beast: the previous codepoint was an
  387. // escaped lead (high) surrogate, and this is a trail (low) surrogate.
  388. if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF)
  389. && in_range(codepoint, 0xDC00, 0xDFFF)) {
  390. // Reassemble the two surrogate pairs into one astral-plane character, per
  391. // the UTF-16 algorithm.
  392. encode_utf8((((last_escaped_codepoint - 0xD800) << 10)
  393. | (codepoint - 0xDC00)) + 0x10000, out);
  394. last_escaped_codepoint = -1;
  395. } else {
  396. encode_utf8(last_escaped_codepoint, out);
  397. last_escaped_codepoint = codepoint;
  398. }
  399. i += 4;
  400. continue;
  401. }
  402. encode_utf8(last_escaped_codepoint, out);
  403. last_escaped_codepoint = -1;
  404. if (ch == 'b') {
  405. out += '\b';
  406. } else if (ch == 'f') {
  407. out += '\f';
  408. } else if (ch == 'n') {
  409. out += '\n';
  410. } else if (ch == 'r') {
  411. out += '\r';
  412. } else if (ch == 't') {
  413. out += '\t';
  414. } else if (ch == '"' || ch == '\\' || ch == '/') {
  415. out += ch;
  416. } else {
  417. return fail("invalid escape character " + esc(ch), "");
  418. }
  419. }
  420. }
  421. /* parse_number()
  422. *
  423. * Parse a double.
  424. */
  425. Json parse_number() {
  426. size_t start_pos = i;
  427. if (str[i] == '-')
  428. i++;
  429. // Integer part
  430. if (str[i] == '0') {
  431. i++;
  432. if (in_range(str[i], '0', '9'))
  433. return fail("leading 0s not permitted in numbers");
  434. } else if (in_range(str[i], '1', '9')) {
  435. i++;
  436. while (in_range(str[i], '0', '9'))
  437. i++;
  438. } else {
  439. return fail("invalid " + esc(str[i]) + " in number");
  440. }
  441. if (str[i] != '.' && str[i] != 'e' && str[i] != 'E'
  442. && (i - start_pos) <= static_cast<size_t>(std::numeric_limits<int>::digits10)) {
  443. return std::atoi(str.c_str() + start_pos);
  444. }
  445. // Decimal part
  446. if (str[i] == '.') {
  447. i++;
  448. if (!in_range(str[i], '0', '9'))
  449. return fail("at least one digit required in fractional part");
  450. while (in_range(str[i], '0', '9'))
  451. i++;
  452. }
  453. // Exponent part
  454. if (str[i] == 'e' || str[i] == 'E') {
  455. i++;
  456. if (str[i] == '+' || str[i] == '-')
  457. i++;
  458. if (!in_range(str[i], '0', '9'))
  459. return fail("at least one digit required in exponent");
  460. while (in_range(str[i], '0', '9'))
  461. i++;
  462. }
  463. return std::atof(str.c_str() + start_pos);
  464. }
  465. /* expect(str, res)
  466. *
  467. * Expect that 'str' starts at the character that was just read. If it does, advance
  468. * the input and return res. If not, flag an error.
  469. */
  470. Json expect(const string &expected, Json res) {
  471. assert(i != 0);
  472. i--;
  473. const string found = str.substr(i, expected.length());
  474. if (expected == found) {
  475. i += expected.length();
  476. return res;
  477. } else {
  478. return fail("parse error: expected " + expected + ", got " + found);
  479. }
  480. }
  481. /* parse_json()
  482. *
  483. * Parse a JSON object.
  484. */
  485. Json parse_json(int depth) {
  486. if (depth > max_depth) {
  487. return fail("exceeded maximum nesting depth");
  488. }
  489. char ch = get_next_token();
  490. if (failed)
  491. return Json();
  492. if (ch == '-' || (ch >= '0' && ch <= '9')) {
  493. i--;
  494. return parse_number();
  495. }
  496. if (ch == 't')
  497. return expect("true", true);
  498. if (ch == 'f')
  499. return expect("false", false);
  500. if (ch == 'n')
  501. return expect("null", Json());
  502. if (ch == '"')
  503. return parse_string();
  504. if (ch == '{') {
  505. map<string, Json> data;
  506. ch = get_next_token();
  507. if (ch == '}')
  508. return data;
  509. while (1) {
  510. if (ch != '"')
  511. return fail("expected '\"' in object, got " + esc(ch));
  512. string key = parse_string();
  513. if (failed)
  514. return Json();
  515. ch = get_next_token();
  516. if (ch != ':')
  517. return fail("expected ':' in object, got " + esc(ch));
  518. data[std::move(key)] = parse_json(depth + 1);
  519. if (failed)
  520. return Json();
  521. ch = get_next_token();
  522. if (ch == '}')
  523. break;
  524. if (ch != ',')
  525. return fail("expected ',' in object, got " + esc(ch));
  526. ch = get_next_token();
  527. }
  528. return data;
  529. }
  530. if (ch == '[') {
  531. vector<Json> data;
  532. ch = get_next_token();
  533. if (ch == ']')
  534. return data;
  535. while (1) {
  536. i--;
  537. data.push_back(parse_json(depth + 1));
  538. if (failed)
  539. return Json();
  540. ch = get_next_token();
  541. if (ch == ']')
  542. break;
  543. if (ch != ',')
  544. return fail("expected ',' in list, got " + esc(ch));
  545. ch = get_next_token();
  546. (void)ch;
  547. }
  548. return data;
  549. }
  550. return fail("expected value, got " + esc(ch));
  551. }
  552. };
  553. Json Json::parse(const string &in, string &err) {
  554. JsonParser parser { in, 0, err, false };
  555. Json result = parser.parse_json(0);
  556. // Check for any trailing garbage
  557. parser.consume_whitespace();
  558. if (parser.i != in.size())
  559. return parser.fail("unexpected trailing " + esc(in[parser.i]));
  560. return result;
  561. }
  562. // Documented in json11.hpp
  563. vector<Json> Json::parse_multi(const string &in, string &err) {
  564. JsonParser parser { in, 0, err, false };
  565. vector<Json> json_vec;
  566. while (parser.i != in.size() && !parser.failed) {
  567. json_vec.push_back(parser.parse_json(0));
  568. // Check for another object
  569. parser.consume_whitespace();
  570. }
  571. return json_vec;
  572. }
  573. /* * * * * * * * * * * * * * * * * * * *
  574. * Shape-checking
  575. */
  576. bool Json::has_shape(const shape & types, string & err) const {
  577. if (!is_object()) {
  578. err = "expected JSON object, got " + dump();
  579. return false;
  580. }
  581. for (auto & item : types) {
  582. if ((*this)[item.first].type() != item.second) {
  583. err = "bad type for " + item.first + " in " + dump();
  584. return false;
  585. }
  586. }
  587. return true;
  588. }
  589. } // namespace json11