1
/* $Id: json.cpp 4761 2014-02-24 09:02:44Z nanang $ */
3
* Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
#include <pjsua2/json.hpp>
20
#include <pjlib-util/errno.h>
21
#include <pj/file_io.h>
24
#define THIS_FILE "json.cpp"
29
/* Json node operations */
30
static bool jsonNode_hasUnread(const ContainerNode*);
31
static string jsonNode_unreadName(const ContainerNode*n)
33
static float jsonNode_readNumber(const ContainerNode*,
36
static bool jsonNode_readBool(const ContainerNode*,
39
static string jsonNode_readString(const ContainerNode*,
42
static StringVector jsonNode_readStringVector(const ContainerNode*,
45
static ContainerNode jsonNode_readContainer(const ContainerNode*,
48
static ContainerNode jsonNode_readArray(const ContainerNode*,
51
static void jsonNode_writeNumber(ContainerNode*,
55
static void jsonNode_writeBool(ContainerNode*,
59
static void jsonNode_writeString(ContainerNode*,
63
static void jsonNode_writeStringVector(ContainerNode*,
65
const StringVector &value)
67
static ContainerNode jsonNode_writeNewContainer(ContainerNode*,
70
static ContainerNode jsonNode_writeNewArray(ContainerNode*,
74
static container_node_op json_op =
81
&jsonNode_readStringVector,
82
&jsonNode_readContainer,
84
&jsonNode_writeNumber,
86
&jsonNode_writeString,
87
&jsonNode_writeStringVector,
88
&jsonNode_writeNewContainer,
89
&jsonNode_writeNewArray
92
///////////////////////////////////////////////////////////////////////////////
93
JsonDocument::JsonDocument()
96
pj_caching_pool_init(&cp, NULL, 0);
97
pool = pj_pool_create(&cp.factory, "jsondoc", 512, 512, NULL);
99
PJSUA2_RAISE_ERROR(PJ_ENOMEM);
102
JsonDocument::~JsonDocument()
105
pj_pool_release(pool);
106
pj_caching_pool_destroy(&cp);
109
void JsonDocument::initRoot() const
111
rootNode.op = &json_op;
112
rootNode.data.doc = (void*)this;
113
rootNode.data.data1 = (void*)root;
114
rootNode.data.data2 = root->value.children.next;
117
void JsonDocument::loadFile(const string &filename) throw(Error)
120
PJSUA2_RAISE_ERROR3(PJ_EINVALIDOP, "JsonDocument.loadString()",
121
"Document already initialized");
123
if (!pj_file_exists(filename.c_str()))
124
PJSUA2_RAISE_ERROR(PJ_ENOTFOUND);
126
pj_ssize_t size = (pj_ssize_t)pj_file_size(filename.c_str());
129
char *buffer = (char*)pj_pool_alloc(pool, size+1);
130
pj_oshandle_t fd = 0;
133
pj_json_err_info err_info;
137
status = pj_file_open(pool, filename.c_str(), PJ_O_RDONLY, &fd);
138
if (status != PJ_SUCCESS)
141
status = pj_file_read(fd, buffer, &size);
142
if (status != PJ_SUCCESS)
153
parse_size = (unsigned)size;
154
root = pj_json_parse(pool, buffer, &parse_size, &err_info);
156
pj_ansi_snprintf(err_msg, sizeof(err_msg),
157
"JSON parsing failed: syntax error in file '%s' at "
159
filename.c_str(), err_info.line, err_info.col);
160
PJ_LOG(1,(THIS_FILE, err_msg));
161
status = PJLIB_UTIL_EINJSON;
172
PJSUA2_RAISE_ERROR3(status, "loadFile()", err_msg);
174
PJSUA2_RAISE_ERROR(status);
177
void JsonDocument::loadString(const string &input) throw(Error)
180
PJSUA2_RAISE_ERROR3(PJ_EINVALIDOP, "JsonDocument.loadString()",
181
"Document already initialized");
183
unsigned size = (unsigned)input.size();
184
char *buffer = (char*)pj_pool_alloc(pool, size+1);
185
unsigned parse_size = (unsigned)size;
186
pj_json_err_info err_info;
188
pj_memcpy(buffer, input.c_str(), size);
190
root = pj_json_parse(pool, buffer, &parse_size, &err_info);
194
pj_ansi_snprintf(err_msg, sizeof(err_msg),
195
"JSON parsing failed at line %d column %d",
196
err_info.line, err_info.col);
197
PJ_LOG(1,(THIS_FILE, err_msg));
198
PJSUA2_RAISE_ERROR3(PJLIB_UTIL_EINJSON, "loadString()", err_msg);
203
struct save_file_data
208
static pj_status_t json_file_writer(const char *s,
212
save_file_data *sd = (save_file_data*)user_data;
213
pj_ssize_t ssize = (pj_ssize_t)size;
214
return pj_file_write(sd->fd, s, &ssize);
217
void JsonDocument::saveFile(const string &filename) throw(Error)
219
struct save_file_data sd;
222
/* Make sure root container has been created */
225
status = pj_file_open(pool, filename.c_str(), PJ_O_WRONLY, &sd.fd);
226
if (status != PJ_SUCCESS)
227
PJSUA2_RAISE_ERROR(status);
229
status = pj_json_writef(root, &json_file_writer, &sd.fd);
230
pj_file_close(sd.fd);
232
if (status != PJ_SUCCESS)
233
PJSUA2_RAISE_ERROR(status);
236
struct save_string_data
241
static pj_status_t json_string_writer(const char *s,
245
save_string_data *sd = (save_string_data*)user_data;
246
sd->output.append(s, size);
250
string JsonDocument::saveString() throw(Error)
252
struct save_string_data sd;
255
/* Make sure root container has been created */
258
status = pj_json_writef(root, &json_string_writer, &sd);
259
if (status != PJ_SUCCESS)
260
PJSUA2_RAISE_ERROR(status);
265
ContainerNode & JsonDocument::getRootContainer() const
268
root = allocElement();
269
pj_json_elem_obj(root, NULL);
276
pj_json_elem* JsonDocument::allocElement() const
278
return (pj_json_elem*)pj_pool_alloc(pool, sizeof(pj_json_elem));
281
pj_pool_t *JsonDocument::getPool()
286
///////////////////////////////////////////////////////////////////////////////
287
struct json_node_data
291
pj_json_elem *childPtr;
294
static bool jsonNode_hasUnread(const ContainerNode *node)
296
json_node_data *jdat = (json_node_data*)&node->data;
297
return jdat->childPtr != (pj_json_elem*)&jdat->jnode->value.children;
300
static void json_verify(struct json_node_data *jdat,
303
pj_json_val_type type)
305
if (jdat->childPtr == (pj_json_elem*)&jdat->jnode->value.children)
306
PJSUA2_RAISE_ERROR3(PJ_EEOF, op, "No unread element");
308
/* If name is specified, then check if the names match, except
309
* when the node name itself is empty and the parent node is
310
* an array, then ignore the checking (JSON doesn't allow array
311
* elements to have name).
313
if (name.size() && name.compare(0, name.size(),
314
jdat->childPtr->name.ptr,
315
jdat->childPtr->name.slen) &&
316
jdat->childPtr->name.slen &&
317
jdat->jnode->type != PJ_JSON_VAL_ARRAY)
320
pj_ansi_snprintf(err_msg, sizeof(err_msg),
321
"Name mismatch: expecting '%s' got '%.*s'",
322
name.c_str(), (int)jdat->childPtr->name.slen,
323
jdat->childPtr->name.ptr);
324
PJSUA2_RAISE_ERROR3(PJLIB_UTIL_EINJSON, op, err_msg);
327
if (type != PJ_JSON_VAL_NULL && jdat->childPtr->type != type) {
329
pj_ansi_snprintf(err_msg, sizeof(err_msg),
330
"Type mismatch: expecting %d got %d",
331
type, jdat->childPtr->type);
332
PJSUA2_RAISE_ERROR3(PJLIB_UTIL_EINJSON, op, err_msg);
336
static string jsonNode_unreadName(const ContainerNode *node)
339
json_node_data *jdat = (json_node_data*)&node->data;
340
json_verify(jdat, "unreadName()", "", PJ_JSON_VAL_NULL);
341
return pj2Str(jdat->childPtr->name);
344
static float jsonNode_readNumber(const ContainerNode *node,
348
json_node_data *jdat = (json_node_data*)&node->data;
349
json_verify(jdat, "readNumber()", name, PJ_JSON_VAL_NUMBER);
350
jdat->childPtr = jdat->childPtr->next;
351
return jdat->childPtr->prev->value.num;
354
static bool jsonNode_readBool(const ContainerNode *node,
358
json_node_data *jdat = (json_node_data*)&node->data;
359
json_verify(jdat, "readBool()", name, PJ_JSON_VAL_BOOL);
360
jdat->childPtr = jdat->childPtr->next;
361
return PJ2BOOL(jdat->childPtr->prev->value.is_true);
364
static string jsonNode_readString(const ContainerNode *node,
368
json_node_data *jdat = (json_node_data*)&node->data;
369
json_verify(jdat, "readString()", name, PJ_JSON_VAL_STRING);
370
jdat->childPtr = jdat->childPtr->next;
371
return pj2Str(jdat->childPtr->prev->value.str);
374
static StringVector jsonNode_readStringVector(const ContainerNode *node,
378
json_node_data *jdat = (json_node_data*)&node->data;
379
json_verify(jdat, "readStringVector()", name, PJ_JSON_VAL_ARRAY);
382
pj_json_elem *child = jdat->childPtr->value.children.next;
383
while (child != (pj_json_elem*)&jdat->childPtr->value.children) {
384
if (child->type != PJ_JSON_VAL_STRING) {
386
pj_ansi_snprintf(err_msg, sizeof(err_msg),
387
"Elements not string but type %d",
389
PJSUA2_RAISE_ERROR3(PJLIB_UTIL_EINJSON, "readStringVector()",
392
result.push_back(pj2Str(child->value.str));
396
jdat->childPtr = jdat->childPtr->next;
400
static ContainerNode jsonNode_readContainer(const ContainerNode *node,
404
json_node_data *jdat = (json_node_data*)&node->data;
405
json_verify(jdat, "readContainer()", name, PJ_JSON_VAL_OBJ);
407
ContainerNode json_node;
409
json_node.op = &json_op;
410
json_node.data.doc = (void*)jdat->doc;
411
json_node.data.data1 = (void*)jdat->childPtr;
412
json_node.data.data2 = (void*)jdat->childPtr->value.children.next;
414
jdat->childPtr = jdat->childPtr->next;
418
static ContainerNode jsonNode_readArray(const ContainerNode *node,
422
json_node_data *jdat = (json_node_data*)&node->data;
423
json_verify(jdat, "readArray()", name, PJ_JSON_VAL_ARRAY);
425
ContainerNode json_node;
427
json_node.op = &json_op;
428
json_node.data.doc = (void*)jdat->doc;
429
json_node.data.data1 = (void*)jdat->childPtr;
430
json_node.data.data2 = (void*)jdat->childPtr->value.children.next;
432
jdat->childPtr = jdat->childPtr->next;
436
static pj_str_t alloc_name(JsonDocument *doc, const string &name)
439
pj_strdup2(doc->getPool(), &new_name, name.c_str());
443
static void jsonNode_writeNumber(ContainerNode *node,
448
json_node_data *jdat = (json_node_data*)&node->data;
449
pj_json_elem *el = jdat->doc->allocElement();
450
pj_str_t nm = alloc_name(jdat->doc, name);
451
pj_json_elem_number(el, &nm, num);
452
pj_json_elem_add(jdat->jnode, el);
455
static void jsonNode_writeBool(ContainerNode *node,
460
json_node_data *jdat = (json_node_data*)&node->data;
461
pj_json_elem *el = jdat->doc->allocElement();
462
pj_str_t nm = alloc_name(jdat->doc, name);
463
pj_json_elem_bool(el, &nm, value);
464
pj_json_elem_add(jdat->jnode, el);
467
static void jsonNode_writeString(ContainerNode *node,
472
json_node_data *jdat = (json_node_data*)&node->data;
473
pj_json_elem *el = jdat->doc->allocElement();
474
pj_str_t nm = alloc_name(jdat->doc, name);
476
pj_strdup2(jdat->doc->getPool(), &new_val, value.c_str());
477
pj_json_elem_string(el, &nm, &new_val);
479
pj_json_elem_add(jdat->jnode, el);
482
static void jsonNode_writeStringVector(ContainerNode *node,
484
const StringVector &value)
487
json_node_data *jdat = (json_node_data*)&node->data;
488
pj_json_elem *el = jdat->doc->allocElement();
489
pj_str_t nm = alloc_name(jdat->doc, name);
491
pj_json_elem_array(el, &nm);
492
for (unsigned i=0; i<value.size(); ++i) {
495
pj_strdup2(jdat->doc->getPool(), &new_val, value[i].c_str());
496
pj_json_elem *child = jdat->doc->allocElement();
497
pj_json_elem_string(child, NULL, &new_val);
498
pj_json_elem_add(el, child);
501
pj_json_elem_add(jdat->jnode, el);
504
static ContainerNode jsonNode_writeNewContainer(ContainerNode *node,
508
json_node_data *jdat = (json_node_data*)&node->data;
509
pj_json_elem *el = jdat->doc->allocElement();
510
pj_str_t nm = alloc_name(jdat->doc, name);
512
pj_json_elem_obj(el, &nm);
513
pj_json_elem_add(jdat->jnode, el);
515
ContainerNode json_node;
517
json_node.op = &json_op;
518
json_node.data.doc = (void*)jdat->doc;
519
json_node.data.data1 = (void*)el;
520
json_node.data.data2 = (void*)el->value.children.next;
525
static ContainerNode jsonNode_writeNewArray(ContainerNode *node,
529
json_node_data *jdat = (json_node_data*)&node->data;
530
pj_json_elem *el = jdat->doc->allocElement();
531
pj_str_t nm = alloc_name(jdat->doc, name);
533
pj_json_elem_array(el, &nm);
534
pj_json_elem_add(jdat->jnode, el);
536
ContainerNode json_node;
538
json_node.op = &json_op;
539
json_node.data.doc = (void*)jdat->doc;
540
json_node.data.data1 = (void*)el;
541
json_node.data.data2 = (void*)el->value.children.next;