~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.2.1/pjsip/src/pjsua2/json.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2015-01-07 14:51:16 UTC
  • mfrom: (4.3.5 sid)
  • Revision ID: package-import@ubuntu.com-20150107145116-yxnafinf4lrdvrmx
Tags: 1.4.1-0.1ubuntu1
* Merge with Debian, remaining changes:
 - Drop soprano, nepomuk build-dep
* Drop ubuntu patches, now upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: json.cpp 4761 2014-02-24 09:02:44Z nanang $ */
 
2
/*
 
3
 * Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
 
4
 *
 
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.
 
9
 *
 
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.
 
14
 *
 
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
 
18
 */
 
19
#include <pjsua2/json.hpp>
 
20
#include <pjlib-util/errno.h>
 
21
#include <pj/file_io.h>
 
22
#include "util.hpp"
 
23
 
 
24
#define THIS_FILE       "json.cpp"
 
25
 
 
26
using namespace pj;
 
27
using namespace std;
 
28
 
 
29
/* Json node operations */
 
30
static bool             jsonNode_hasUnread(const ContainerNode*);
 
31
static string           jsonNode_unreadName(const ContainerNode*n)
 
32
                                            throw(Error);
 
33
static float            jsonNode_readNumber(const ContainerNode*,
 
34
                                            const string&)
 
35
                                              throw(Error);
 
36
static bool             jsonNode_readBool(const ContainerNode*,
 
37
                                          const string&)
 
38
                                          throw(Error);
 
39
static string           jsonNode_readString(const ContainerNode*,
 
40
                                            const string&)
 
41
                                            throw(Error);
 
42
static StringVector     jsonNode_readStringVector(const ContainerNode*,
 
43
                                                  const string&)
 
44
                                                  throw(Error);
 
45
static ContainerNode    jsonNode_readContainer(const ContainerNode*,
 
46
                                               const string &)
 
47
                                               throw(Error);
 
48
static ContainerNode    jsonNode_readArray(const ContainerNode*,
 
49
                                           const string &)
 
50
                                           throw(Error);
 
51
static void             jsonNode_writeNumber(ContainerNode*,
 
52
                                             const string &name,
 
53
                                             float num)
 
54
                                             throw(Error);
 
55
static void             jsonNode_writeBool(ContainerNode*,
 
56
                                           const string &name,
 
57
                                           bool value)
 
58
                                           throw(Error);
 
59
static void             jsonNode_writeString(ContainerNode*,
 
60
                                             const string &name,
 
61
                                             const string &value)
 
62
                                             throw(Error);
 
63
static void             jsonNode_writeStringVector(ContainerNode*,
 
64
                                                   const string &name,
 
65
                                                   const StringVector &value)
 
66
                                                   throw(Error);
 
67
static ContainerNode    jsonNode_writeNewContainer(ContainerNode*,
 
68
                                                   const string &name)
 
69
                                                   throw(Error);
 
70
static ContainerNode    jsonNode_writeNewArray(ContainerNode*,
 
71
                                               const string &name)
 
72
                                               throw(Error);
 
73
 
 
74
static container_node_op json_op =
 
75
{
 
76
    &jsonNode_hasUnread,
 
77
    &jsonNode_unreadName,
 
78
    &jsonNode_readNumber,
 
79
    &jsonNode_readBool,
 
80
    &jsonNode_readString,
 
81
    &jsonNode_readStringVector,
 
82
    &jsonNode_readContainer,
 
83
    &jsonNode_readArray,
 
84
    &jsonNode_writeNumber,
 
85
    &jsonNode_writeBool,
 
86
    &jsonNode_writeString,
 
87
    &jsonNode_writeStringVector,
 
88
    &jsonNode_writeNewContainer,
 
89
    &jsonNode_writeNewArray
 
90
};
 
91
 
 
92
///////////////////////////////////////////////////////////////////////////////
 
93
JsonDocument::JsonDocument()
 
94
: root(NULL)
 
95
{
 
96
    pj_caching_pool_init(&cp, NULL, 0);
 
97
    pool = pj_pool_create(&cp.factory, "jsondoc", 512, 512, NULL);
 
98
    if (!pool)
 
99
        PJSUA2_RAISE_ERROR(PJ_ENOMEM);
 
100
}
 
101
 
 
102
JsonDocument::~JsonDocument()
 
103
{
 
104
    if (pool)
 
105
        pj_pool_release(pool);
 
106
    pj_caching_pool_destroy(&cp);
 
107
}
 
108
 
 
109
void JsonDocument::initRoot() const
 
110
{
 
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;
 
115
}
 
116
 
 
117
void JsonDocument::loadFile(const string &filename) throw(Error)
 
118
{
 
119
    if (root)
 
120
        PJSUA2_RAISE_ERROR3(PJ_EINVALIDOP, "JsonDocument.loadString()",
 
121
                            "Document already initialized");
 
122
 
 
123
    if (!pj_file_exists(filename.c_str()))
 
124
        PJSUA2_RAISE_ERROR(PJ_ENOTFOUND);
 
125
 
 
126
    pj_ssize_t size = (pj_ssize_t)pj_file_size(filename.c_str());
 
127
    pj_status_t status;
 
128
 
 
129
    char *buffer = (char*)pj_pool_alloc(pool, size+1);
 
130
    pj_oshandle_t fd = 0;
 
131
    unsigned parse_size;
 
132
    char err_msg[120];
 
133
    pj_json_err_info err_info;
 
134
 
 
135
    err_msg[0] = '\0';
 
136
 
 
137
    status = pj_file_open(pool, filename.c_str(), PJ_O_RDONLY, &fd);
 
138
    if (status != PJ_SUCCESS)
 
139
        goto on_error;
 
140
 
 
141
    status = pj_file_read(fd, buffer, &size);
 
142
    if (status != PJ_SUCCESS)
 
143
        goto on_error;
 
144
 
 
145
    pj_file_close(fd);
 
146
    fd = NULL;
 
147
 
 
148
    if (size <= 0) {
 
149
        status = PJ_EEOF;
 
150
        goto on_error;
 
151
    }
 
152
 
 
153
    parse_size = (unsigned)size;
 
154
    root = pj_json_parse(pool, buffer, &parse_size, &err_info);
 
155
    if (root == NULL) {
 
156
        pj_ansi_snprintf(err_msg, sizeof(err_msg),
 
157
                         "JSON parsing failed: syntax error in file '%s' at "
 
158
                         "line %d column %d",
 
159
                         filename.c_str(), err_info.line, err_info.col);
 
160
        PJ_LOG(1,(THIS_FILE, err_msg));
 
161
        status = PJLIB_UTIL_EINJSON;
 
162
        goto on_error;
 
163
    }
 
164
 
 
165
    initRoot();
 
166
    return;
 
167
 
 
168
on_error:
 
169
    if (fd)
 
170
        pj_file_close(fd);
 
171
    if (err_msg[0])
 
172
        PJSUA2_RAISE_ERROR3(status, "loadFile()", err_msg);
 
173
    else
 
174
        PJSUA2_RAISE_ERROR(status);
 
175
}
 
176
 
 
177
void JsonDocument::loadString(const string &input) throw(Error)
 
178
{
 
179
    if (root)
 
180
        PJSUA2_RAISE_ERROR3(PJ_EINVALIDOP, "JsonDocument.loadString()",
 
181
                            "Document already initialized");
 
182
 
 
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;
 
187
 
 
188
    pj_memcpy(buffer, input.c_str(), size);
 
189
 
 
190
    root = pj_json_parse(pool, buffer, &parse_size, &err_info);
 
191
    if (root == NULL) {
 
192
        char err_msg[80];
 
193
 
 
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);
 
199
    }
 
200
    initRoot();
 
201
}
 
202
 
 
203
struct save_file_data
 
204
{
 
205
    pj_oshandle_t fd;
 
206
};
 
207
 
 
208
static pj_status_t json_file_writer(const char *s,
 
209
                                    unsigned size,
 
210
                                    void *user_data)
 
211
{
 
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);
 
215
}
 
216
 
 
217
void JsonDocument::saveFile(const string &filename) throw(Error)
 
218
{
 
219
    struct save_file_data sd;
 
220
    pj_status_t status;
 
221
 
 
222
    /* Make sure root container has been created */
 
223
    getRootContainer();
 
224
 
 
225
    status = pj_file_open(pool, filename.c_str(), PJ_O_WRONLY, &sd.fd);
 
226
    if (status != PJ_SUCCESS)
 
227
        PJSUA2_RAISE_ERROR(status);
 
228
 
 
229
    status = pj_json_writef(root, &json_file_writer, &sd.fd);
 
230
    pj_file_close(sd.fd);
 
231
 
 
232
    if (status != PJ_SUCCESS)
 
233
        PJSUA2_RAISE_ERROR(status);
 
234
}
 
235
 
 
236
struct save_string_data
 
237
{
 
238
    string      output;
 
239
};
 
240
 
 
241
static pj_status_t json_string_writer(const char *s,
 
242
                                      unsigned size,
 
243
                                      void *user_data)
 
244
{
 
245
    save_string_data *sd = (save_string_data*)user_data;
 
246
    sd->output.append(s, size);
 
247
    return PJ_SUCCESS;
 
248
}
 
249
 
 
250
string JsonDocument::saveString() throw(Error)
 
251
{
 
252
    struct save_string_data sd;
 
253
    pj_status_t status;
 
254
 
 
255
    /* Make sure root container has been created */
 
256
    getRootContainer();
 
257
 
 
258
    status = pj_json_writef(root, &json_string_writer, &sd);
 
259
    if (status != PJ_SUCCESS)
 
260
        PJSUA2_RAISE_ERROR(status);
 
261
 
 
262
    return sd.output;
 
263
}
 
264
 
 
265
ContainerNode & JsonDocument::getRootContainer() const
 
266
{
 
267
    if (!root) {
 
268
        root = allocElement();
 
269
        pj_json_elem_obj(root, NULL);
 
270
        initRoot();
 
271
    }
 
272
 
 
273
    return rootNode;
 
274
}
 
275
 
 
276
pj_json_elem* JsonDocument::allocElement() const
 
277
{
 
278
    return (pj_json_elem*)pj_pool_alloc(pool, sizeof(pj_json_elem));
 
279
}
 
280
 
 
281
pj_pool_t *JsonDocument::getPool()
 
282
{
 
283
    return pool;
 
284
}
 
285
 
 
286
///////////////////////////////////////////////////////////////////////////////
 
287
struct json_node_data
 
288
{
 
289
    JsonDocument        *doc;
 
290
    pj_json_elem        *jnode;
 
291
    pj_json_elem        *childPtr;
 
292
};
 
293
 
 
294
static bool jsonNode_hasUnread(const ContainerNode *node)
 
295
{
 
296
    json_node_data *jdat = (json_node_data*)&node->data;
 
297
    return jdat->childPtr != (pj_json_elem*)&jdat->jnode->value.children;
 
298
}
 
299
 
 
300
static void json_verify(struct json_node_data *jdat,
 
301
                        const char *op,
 
302
                        const string &name,
 
303
                        pj_json_val_type type)
 
304
{
 
305
    if (jdat->childPtr == (pj_json_elem*)&jdat->jnode->value.children)
 
306
        PJSUA2_RAISE_ERROR3(PJ_EEOF, op, "No unread element");
 
307
 
 
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).
 
312
     */
 
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)
 
318
    {
 
319
        char err_msg[80];
 
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);
 
325
    }
 
326
 
 
327
    if (type != PJ_JSON_VAL_NULL && jdat->childPtr->type != type) {
 
328
        char err_msg[80];
 
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);
 
333
    }
 
334
}
 
335
 
 
336
static string jsonNode_unreadName(const ContainerNode *node)
 
337
                                  throw(Error)
 
338
{
 
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);
 
342
}
 
343
 
 
344
static float jsonNode_readNumber(const ContainerNode *node,
 
345
                                 const string &name)
 
346
                                 throw(Error)
 
347
{
 
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;
 
352
}
 
353
 
 
354
static bool jsonNode_readBool(const ContainerNode *node,
 
355
                              const string &name)
 
356
                              throw(Error)
 
357
{
 
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);
 
362
}
 
363
 
 
364
static string jsonNode_readString(const ContainerNode *node,
 
365
                                  const string &name)
 
366
                                  throw(Error)
 
367
{
 
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);
 
372
}
 
373
 
 
374
static StringVector jsonNode_readStringVector(const ContainerNode *node,
 
375
                                              const string &name)
 
376
                                              throw(Error)
 
377
{
 
378
    json_node_data *jdat = (json_node_data*)&node->data;
 
379
    json_verify(jdat, "readStringVector()", name, PJ_JSON_VAL_ARRAY);
 
380
 
 
381
    StringVector result;
 
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) {
 
385
            char err_msg[80];
 
386
            pj_ansi_snprintf(err_msg, sizeof(err_msg),
 
387
                             "Elements not string but type %d",
 
388
                             child->type);
 
389
            PJSUA2_RAISE_ERROR3(PJLIB_UTIL_EINJSON, "readStringVector()",
 
390
                                err_msg);
 
391
        }
 
392
        result.push_back(pj2Str(child->value.str));
 
393
        child = child->next;
 
394
    }
 
395
 
 
396
    jdat->childPtr = jdat->childPtr->next;
 
397
    return result;
 
398
}
 
399
 
 
400
static ContainerNode jsonNode_readContainer(const ContainerNode *node,
 
401
                                            const string &name)
 
402
                                            throw(Error)
 
403
{
 
404
    json_node_data *jdat = (json_node_data*)&node->data;
 
405
    json_verify(jdat, "readContainer()", name, PJ_JSON_VAL_OBJ);
 
406
 
 
407
    ContainerNode json_node;
 
408
 
 
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;
 
413
 
 
414
    jdat->childPtr = jdat->childPtr->next;
 
415
    return json_node;
 
416
}
 
417
 
 
418
static ContainerNode jsonNode_readArray(const ContainerNode *node,
 
419
                                        const string &name)
 
420
                                        throw(Error)
 
421
{
 
422
    json_node_data *jdat = (json_node_data*)&node->data;
 
423
    json_verify(jdat, "readArray()", name, PJ_JSON_VAL_ARRAY);
 
424
 
 
425
    ContainerNode json_node;
 
426
 
 
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;
 
431
 
 
432
    jdat->childPtr = jdat->childPtr->next;
 
433
    return json_node;
 
434
}
 
435
 
 
436
static pj_str_t alloc_name(JsonDocument *doc, const string &name)
 
437
{
 
438
    pj_str_t new_name;
 
439
    pj_strdup2(doc->getPool(), &new_name, name.c_str());
 
440
    return new_name;
 
441
}
 
442
 
 
443
static void jsonNode_writeNumber(ContainerNode *node,
 
444
                                 const string &name,
 
445
                                 float num)
 
446
                                 throw(Error)
 
447
{
 
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);
 
453
}
 
454
 
 
455
static void jsonNode_writeBool(ContainerNode *node,
 
456
                               const string &name,
 
457
                               bool value)
 
458
                               throw(Error)
 
459
{
 
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);
 
465
}
 
466
 
 
467
static void jsonNode_writeString(ContainerNode *node,
 
468
                                 const string &name,
 
469
                                 const string &value)
 
470
                                 throw(Error)
 
471
{
 
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);
 
475
    pj_str_t new_val;
 
476
    pj_strdup2(jdat->doc->getPool(), &new_val, value.c_str());
 
477
    pj_json_elem_string(el, &nm, &new_val);
 
478
 
 
479
    pj_json_elem_add(jdat->jnode, el);
 
480
}
 
481
 
 
482
static void jsonNode_writeStringVector(ContainerNode *node,
 
483
                                       const string &name,
 
484
                                       const StringVector &value)
 
485
                                       throw(Error)
 
486
{
 
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);
 
490
 
 
491
    pj_json_elem_array(el, &nm);
 
492
    for (unsigned i=0; i<value.size(); ++i) {
 
493
        pj_str_t new_val;
 
494
 
 
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);
 
499
    }
 
500
 
 
501
    pj_json_elem_add(jdat->jnode, el);
 
502
}
 
503
 
 
504
static ContainerNode jsonNode_writeNewContainer(ContainerNode *node,
 
505
                                                const string &name)
 
506
                                                throw(Error)
 
507
{
 
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);
 
511
 
 
512
    pj_json_elem_obj(el, &nm);
 
513
    pj_json_elem_add(jdat->jnode, el);
 
514
 
 
515
    ContainerNode json_node;
 
516
 
 
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;
 
521
 
 
522
    return json_node;
 
523
}
 
524
 
 
525
static ContainerNode jsonNode_writeNewArray(ContainerNode *node,
 
526
                                            const string &name)
 
527
                                            throw(Error)
 
528
{
 
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);
 
532
 
 
533
    pj_json_elem_array(el, &nm);
 
534
    pj_json_elem_add(jdat->jnode, el);
 
535
 
 
536
    ContainerNode json_node;
 
537
 
 
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;
 
542
 
 
543
    return json_node;
 
544
}