json.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. /*
  2. * Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. */
  18. #include <pjsua2/json.hpp>
  19. #include <pjlib-util/errno.h>
  20. #include <pj/file_io.h>
  21. #include "util.hpp"
  22. #define THIS_FILE "json.cpp"
  23. using namespace pj;
  24. using namespace std;
  25. /* Json node operations */
  26. static bool jsonNode_hasUnread(const ContainerNode*);
  27. static string jsonNode_unreadName(const ContainerNode*n)
  28. PJSUA2_THROW(Error);
  29. static float jsonNode_readNumber(const ContainerNode*,
  30. const string&)
  31. PJSUA2_THROW(Error);
  32. static bool jsonNode_readBool(const ContainerNode*,
  33. const string&)
  34. PJSUA2_THROW(Error);
  35. static string jsonNode_readString(const ContainerNode*,
  36. const string&)
  37. PJSUA2_THROW(Error);
  38. static StringVector jsonNode_readStringVector(const ContainerNode*,
  39. const string&)
  40. PJSUA2_THROW(Error);
  41. static ContainerNode jsonNode_readContainer(const ContainerNode*,
  42. const string &)
  43. PJSUA2_THROW(Error);
  44. static ContainerNode jsonNode_readArray(const ContainerNode*,
  45. const string &)
  46. PJSUA2_THROW(Error);
  47. static void jsonNode_writeNumber(ContainerNode*,
  48. const string &name,
  49. float num)
  50. PJSUA2_THROW(Error);
  51. static void jsonNode_writeBool(ContainerNode*,
  52. const string &name,
  53. bool value)
  54. PJSUA2_THROW(Error);
  55. static void jsonNode_writeString(ContainerNode*,
  56. const string &name,
  57. const string &value)
  58. PJSUA2_THROW(Error);
  59. static void jsonNode_writeStringVector(ContainerNode*,
  60. const string &name,
  61. const StringVector &value)
  62. PJSUA2_THROW(Error);
  63. static ContainerNode jsonNode_writeNewContainer(ContainerNode*,
  64. const string &name)
  65. PJSUA2_THROW(Error);
  66. static ContainerNode jsonNode_writeNewArray(ContainerNode*,
  67. const string &name)
  68. PJSUA2_THROW(Error);
  69. static container_node_op json_op =
  70. {
  71. &jsonNode_hasUnread,
  72. &jsonNode_unreadName,
  73. &jsonNode_readNumber,
  74. &jsonNode_readBool,
  75. &jsonNode_readString,
  76. &jsonNode_readStringVector,
  77. &jsonNode_readContainer,
  78. &jsonNode_readArray,
  79. &jsonNode_writeNumber,
  80. &jsonNode_writeBool,
  81. &jsonNode_writeString,
  82. &jsonNode_writeStringVector,
  83. &jsonNode_writeNewContainer,
  84. &jsonNode_writeNewArray
  85. };
  86. ///////////////////////////////////////////////////////////////////////////////
  87. JsonDocument::JsonDocument()
  88. : root(NULL)
  89. {
  90. pj_caching_pool_init(&cp, NULL, 0);
  91. pool = pj_pool_create(&cp.factory, "jsondoc", 512, 512, NULL);
  92. if (!pool)
  93. PJSUA2_RAISE_ERROR(PJ_ENOMEM);
  94. }
  95. JsonDocument::~JsonDocument()
  96. {
  97. if (pool)
  98. pj_pool_release(pool);
  99. pj_caching_pool_destroy(&cp);
  100. }
  101. void JsonDocument::initRoot() const
  102. {
  103. rootNode.op = &json_op;
  104. rootNode.data.doc = (void*)this;
  105. rootNode.data.data1 = (void*)root;
  106. rootNode.data.data2 = root->value.children.next;
  107. }
  108. void JsonDocument::loadFile(const string &filename) PJSUA2_THROW(Error)
  109. {
  110. if (root)
  111. PJSUA2_RAISE_ERROR3(PJ_EINVALIDOP, "JsonDocument.loadString()",
  112. "Document already initialized");
  113. if (!pj_file_exists(filename.c_str()))
  114. PJSUA2_RAISE_ERROR(PJ_ENOTFOUND);
  115. pj_ssize_t size = (pj_ssize_t)pj_file_size(filename.c_str());
  116. if (size <= 0)
  117. PJSUA2_RAISE_ERROR(PJ_ETOOSMALL);
  118. pj_status_t status;
  119. char *buffer = (char*)pj_pool_alloc(pool, size+1);
  120. pj_oshandle_t fd = 0;
  121. unsigned parse_size;
  122. char err_msg[120];
  123. pj_json_err_info err_info;
  124. err_msg[0] = '\0';
  125. status = pj_file_open(pool, filename.c_str(), PJ_O_RDONLY, &fd);
  126. if (status != PJ_SUCCESS)
  127. goto on_error;
  128. status = pj_file_read(fd, buffer, &size);
  129. if (status != PJ_SUCCESS)
  130. goto on_error;
  131. pj_file_close(fd);
  132. fd = NULL;
  133. if (size <= 0) {
  134. status = PJ_EEOF;
  135. goto on_error;
  136. }
  137. parse_size = (unsigned)size;
  138. root = pj_json_parse(pool, buffer, &parse_size, &err_info);
  139. if (root == NULL) {
  140. pj_ansi_snprintf(err_msg, sizeof(err_msg),
  141. "JSON parsing failed: syntax error in file '%s' at "
  142. "line %d column %d",
  143. filename.c_str(), err_info.line, err_info.col);
  144. PJ_LOG(1,(THIS_FILE, "%s", err_msg));
  145. status = PJLIB_UTIL_EINJSON;
  146. goto on_error;
  147. }
  148. initRoot();
  149. return;
  150. on_error:
  151. if (fd)
  152. pj_file_close(fd);
  153. if (err_msg[0])
  154. PJSUA2_RAISE_ERROR3(status, "loadFile()", err_msg);
  155. else
  156. PJSUA2_RAISE_ERROR(status);
  157. }
  158. void JsonDocument::loadString(const string &input) PJSUA2_THROW(Error)
  159. {
  160. if (root)
  161. PJSUA2_RAISE_ERROR3(PJ_EINVALIDOP, "JsonDocument.loadString()",
  162. "Document already initialized");
  163. unsigned size = (unsigned)input.size();
  164. char *buffer = (char*)pj_pool_alloc(pool, size+1);
  165. unsigned parse_size = (unsigned)size;
  166. pj_json_err_info err_info;
  167. pj_memcpy(buffer, input.c_str(), size);
  168. root = pj_json_parse(pool, buffer, &parse_size, &err_info);
  169. if (root == NULL) {
  170. char err_msg[80];
  171. pj_ansi_snprintf(err_msg, sizeof(err_msg),
  172. "JSON parsing failed at line %d column %d",
  173. err_info.line, err_info.col);
  174. PJ_LOG(1,(THIS_FILE, "%s", err_msg));
  175. PJSUA2_RAISE_ERROR3(PJLIB_UTIL_EINJSON, "loadString()", err_msg);
  176. }
  177. initRoot();
  178. }
  179. struct save_file_data
  180. {
  181. pj_oshandle_t fd;
  182. };
  183. static pj_status_t json_file_writer(const char *s,
  184. unsigned size,
  185. void *user_data)
  186. {
  187. save_file_data *sd = (save_file_data*)user_data;
  188. pj_ssize_t ssize = (pj_ssize_t)size;
  189. return pj_file_write(sd->fd, s, &ssize);
  190. }
  191. void JsonDocument::saveFile(const string &filename) PJSUA2_THROW(Error)
  192. {
  193. struct save_file_data sd;
  194. pj_status_t status;
  195. /* Make sure root container has been created */
  196. getRootContainer();
  197. status = pj_file_open(pool, filename.c_str(), PJ_O_WRONLY, &sd.fd);
  198. if (status != PJ_SUCCESS)
  199. PJSUA2_RAISE_ERROR(status);
  200. status = pj_json_writef(root, &json_file_writer, &sd.fd);
  201. pj_file_close(sd.fd);
  202. if (status != PJ_SUCCESS)
  203. PJSUA2_RAISE_ERROR(status);
  204. }
  205. struct save_string_data
  206. {
  207. string output;
  208. };
  209. static pj_status_t json_string_writer(const char *s,
  210. unsigned size,
  211. void *user_data)
  212. {
  213. save_string_data *sd = (save_string_data*)user_data;
  214. sd->output.append(s, size);
  215. return PJ_SUCCESS;
  216. }
  217. string JsonDocument::saveString() PJSUA2_THROW(Error)
  218. {
  219. struct save_string_data sd;
  220. pj_status_t status;
  221. /* Make sure root container has been created */
  222. getRootContainer();
  223. status = pj_json_writef(root, &json_string_writer, &sd);
  224. if (status != PJ_SUCCESS)
  225. PJSUA2_RAISE_ERROR(status);
  226. return sd.output;
  227. }
  228. ContainerNode & JsonDocument::getRootContainer() const
  229. {
  230. if (!root) {
  231. root = allocElement();
  232. pj_json_elem_obj(root, NULL);
  233. initRoot();
  234. }
  235. return rootNode;
  236. }
  237. pj_json_elem* JsonDocument::allocElement() const
  238. {
  239. return (pj_json_elem*)pj_pool_alloc(pool, sizeof(pj_json_elem));
  240. }
  241. pj_pool_t *JsonDocument::getPool()
  242. {
  243. return pool;
  244. }
  245. ///////////////////////////////////////////////////////////////////////////////
  246. struct json_node_data
  247. {
  248. JsonDocument *doc;
  249. pj_json_elem *jnode;
  250. pj_json_elem *childPtr;
  251. };
  252. static bool jsonNode_hasUnread(const ContainerNode *node)
  253. {
  254. json_node_data *jdat = (json_node_data*)&node->data;
  255. return jdat->childPtr != (pj_json_elem*)&jdat->jnode->value.children;
  256. }
  257. static void json_verify(struct json_node_data *jdat,
  258. const char *op,
  259. const string &name,
  260. pj_json_val_type type)
  261. {
  262. if (jdat->childPtr == (pj_json_elem*)&jdat->jnode->value.children)
  263. PJSUA2_RAISE_ERROR3(PJ_EEOF, op, "No unread element");
  264. /* If name is specified, then check if the names match, except
  265. * when the node name itself is empty and the parent node is
  266. * an array, then ignore the checking (JSON doesn't allow array
  267. * elements to have name).
  268. */
  269. if (jdat->jnode->type != PJ_JSON_VAL_ARRAY &&
  270. name.size() && jdat->childPtr->name.slen &&
  271. name.compare(0, name.size(), jdat->childPtr->name.ptr,
  272. jdat->childPtr->name.slen))
  273. {
  274. char err_msg[80];
  275. pj_ansi_snprintf(err_msg, sizeof(err_msg),
  276. "Name mismatch: expecting '%s' got '%.*s'",
  277. name.c_str(), (int)jdat->childPtr->name.slen,
  278. jdat->childPtr->name.ptr);
  279. PJSUA2_RAISE_ERROR3(PJLIB_UTIL_EINJSON, op, err_msg);
  280. }
  281. if (type != PJ_JSON_VAL_NULL && jdat->childPtr->type != type) {
  282. char err_msg[80];
  283. pj_ansi_snprintf(err_msg, sizeof(err_msg),
  284. "Type mismatch: expecting %d got %d",
  285. type, jdat->childPtr->type);
  286. PJSUA2_RAISE_ERROR3(PJLIB_UTIL_EINJSON, op, err_msg);
  287. }
  288. }
  289. static string jsonNode_unreadName(const ContainerNode *node)
  290. PJSUA2_THROW(Error)
  291. {
  292. json_node_data *jdat = (json_node_data*)&node->data;
  293. json_verify(jdat, "unreadName()", "", PJ_JSON_VAL_NULL);
  294. return pj2Str(jdat->childPtr->name);
  295. }
  296. static float jsonNode_readNumber(const ContainerNode *node,
  297. const string &name)
  298. PJSUA2_THROW(Error)
  299. {
  300. json_node_data *jdat = (json_node_data*)&node->data;
  301. json_verify(jdat, "readNumber()", name, PJ_JSON_VAL_NUMBER);
  302. jdat->childPtr = jdat->childPtr->next;
  303. return jdat->childPtr->prev->value.num;
  304. }
  305. static bool jsonNode_readBool(const ContainerNode *node,
  306. const string &name)
  307. PJSUA2_THROW(Error)
  308. {
  309. json_node_data *jdat = (json_node_data*)&node->data;
  310. json_verify(jdat, "readBool()", name, PJ_JSON_VAL_BOOL);
  311. jdat->childPtr = jdat->childPtr->next;
  312. return PJ2BOOL(jdat->childPtr->prev->value.is_true);
  313. }
  314. static string jsonNode_readString(const ContainerNode *node,
  315. const string &name)
  316. PJSUA2_THROW(Error)
  317. {
  318. json_node_data *jdat = (json_node_data*)&node->data;
  319. json_verify(jdat, "readString()", name, PJ_JSON_VAL_STRING);
  320. jdat->childPtr = jdat->childPtr->next;
  321. return pj2Str(jdat->childPtr->prev->value.str);
  322. }
  323. static StringVector jsonNode_readStringVector(const ContainerNode *node,
  324. const string &name)
  325. PJSUA2_THROW(Error)
  326. {
  327. json_node_data *jdat = (json_node_data*)&node->data;
  328. json_verify(jdat, "readStringVector()", name, PJ_JSON_VAL_ARRAY);
  329. StringVector result;
  330. pj_json_elem *child = jdat->childPtr->value.children.next;
  331. while (child != (pj_json_elem*)&jdat->childPtr->value.children) {
  332. if (child->type != PJ_JSON_VAL_STRING) {
  333. char err_msg[80];
  334. pj_ansi_snprintf(err_msg, sizeof(err_msg),
  335. "Elements not string but type %d",
  336. child->type);
  337. PJSUA2_RAISE_ERROR3(PJLIB_UTIL_EINJSON, "readStringVector()",
  338. err_msg);
  339. }
  340. result.push_back(pj2Str(child->value.str));
  341. child = child->next;
  342. }
  343. jdat->childPtr = jdat->childPtr->next;
  344. return result;
  345. }
  346. static ContainerNode jsonNode_readContainer(const ContainerNode *node,
  347. const string &name)
  348. PJSUA2_THROW(Error)
  349. {
  350. json_node_data *jdat = (json_node_data*)&node->data;
  351. json_verify(jdat, "readContainer()", name, PJ_JSON_VAL_OBJ);
  352. ContainerNode json_node;
  353. json_node.op = &json_op;
  354. json_node.data.doc = (void*)jdat->doc;
  355. json_node.data.data1 = (void*)jdat->childPtr;
  356. json_node.data.data2 = (void*)jdat->childPtr->value.children.next;
  357. jdat->childPtr = jdat->childPtr->next;
  358. return json_node;
  359. }
  360. static ContainerNode jsonNode_readArray(const ContainerNode *node,
  361. const string &name)
  362. PJSUA2_THROW(Error)
  363. {
  364. json_node_data *jdat = (json_node_data*)&node->data;
  365. json_verify(jdat, "readArray()", name, PJ_JSON_VAL_ARRAY);
  366. ContainerNode json_node;
  367. json_node.op = &json_op;
  368. json_node.data.doc = (void*)jdat->doc;
  369. json_node.data.data1 = (void*)jdat->childPtr;
  370. json_node.data.data2 = (void*)jdat->childPtr->value.children.next;
  371. jdat->childPtr = jdat->childPtr->next;
  372. return json_node;
  373. }
  374. static pj_str_t alloc_name(JsonDocument *doc, const string &name)
  375. {
  376. pj_str_t new_name;
  377. pj_strdup2(doc->getPool(), &new_name, name.c_str());
  378. return new_name;
  379. }
  380. static void jsonNode_writeNumber(ContainerNode *node,
  381. const string &name,
  382. float num)
  383. PJSUA2_THROW(Error)
  384. {
  385. json_node_data *jdat = (json_node_data*)&node->data;
  386. pj_json_elem *el = jdat->doc->allocElement();
  387. pj_str_t nm = alloc_name(jdat->doc, name);
  388. pj_json_elem_number(el, &nm, num);
  389. pj_json_elem_add(jdat->jnode, el);
  390. }
  391. static void jsonNode_writeBool(ContainerNode *node,
  392. const string &name,
  393. bool value)
  394. PJSUA2_THROW(Error)
  395. {
  396. json_node_data *jdat = (json_node_data*)&node->data;
  397. pj_json_elem *el = jdat->doc->allocElement();
  398. pj_str_t nm = alloc_name(jdat->doc, name);
  399. pj_json_elem_bool(el, &nm, value);
  400. pj_json_elem_add(jdat->jnode, el);
  401. }
  402. static void jsonNode_writeString(ContainerNode *node,
  403. const string &name,
  404. const string &value)
  405. PJSUA2_THROW(Error)
  406. {
  407. json_node_data *jdat = (json_node_data*)&node->data;
  408. pj_json_elem *el = jdat->doc->allocElement();
  409. pj_str_t nm = alloc_name(jdat->doc, name);
  410. pj_str_t new_val;
  411. pj_str_t str_val;
  412. pj_strset(&str_val, (char*)value.data(), value.size());
  413. pj_strdup(jdat->doc->getPool(), &new_val, &str_val);
  414. pj_json_elem_string(el, &nm, &new_val);
  415. pj_json_elem_add(jdat->jnode, el);
  416. }
  417. static void jsonNode_writeStringVector(ContainerNode *node,
  418. const string &name,
  419. const StringVector &value)
  420. PJSUA2_THROW(Error)
  421. {
  422. json_node_data *jdat = (json_node_data*)&node->data;
  423. pj_json_elem *el = jdat->doc->allocElement();
  424. pj_str_t nm = alloc_name(jdat->doc, name);
  425. pj_json_elem_array(el, &nm);
  426. for (unsigned i=0; i<value.size(); ++i) {
  427. pj_str_t new_val;
  428. pj_str_t str_val;
  429. pj_strset(&str_val, (char*)value[i].data(), value[i].size());
  430. pj_strdup(jdat->doc->getPool(), &new_val, &str_val);
  431. pj_json_elem *child = jdat->doc->allocElement();
  432. pj_json_elem_string(child, NULL, &new_val);
  433. pj_json_elem_add(el, child);
  434. }
  435. pj_json_elem_add(jdat->jnode, el);
  436. }
  437. static ContainerNode jsonNode_writeNewContainer(ContainerNode *node,
  438. const string &name)
  439. PJSUA2_THROW(Error)
  440. {
  441. json_node_data *jdat = (json_node_data*)&node->data;
  442. pj_json_elem *el = jdat->doc->allocElement();
  443. pj_str_t nm = alloc_name(jdat->doc, name);
  444. pj_json_elem_obj(el, &nm);
  445. pj_json_elem_add(jdat->jnode, el);
  446. ContainerNode json_node;
  447. json_node.op = &json_op;
  448. json_node.data.doc = (void*)jdat->doc;
  449. json_node.data.data1 = (void*)el;
  450. json_node.data.data2 = (void*)el->value.children.next;
  451. return json_node;
  452. }
  453. static ContainerNode jsonNode_writeNewArray(ContainerNode *node,
  454. const string &name)
  455. PJSUA2_THROW(Error)
  456. {
  457. json_node_data *jdat = (json_node_data*)&node->data;
  458. pj_json_elem *el = jdat->doc->allocElement();
  459. pj_str_t nm = alloc_name(jdat->doc, name);
  460. pj_json_elem_array(el, &nm);
  461. pj_json_elem_add(jdat->jnode, el);
  462. ContainerNode json_node;
  463. json_node.op = &json_op;
  464. json_node.data.doc = (void*)jdat->doc;
  465. json_node.data.data1 = (void*)el;
  466. json_node.data.data2 = (void*)el->value.children.next;
  467. return json_node;
  468. }