src/json.c

changeset 1067
7799addf475f
parent 1065
6eb7b54975ee
child 1072
c89283cd559b
equal deleted inserted replaced
1066:8610f87a6b14 1067:7799addf475f
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29 #include "cx/json.h" 29 #include "cx/json.h"
30 #include "cx/compare.h"
30 31
31 #include <string.h> 32 #include <string.h>
32 #include <ctype.h> 33 #include <ctype.h>
33 #include <assert.h> 34 #include <assert.h>
34 #include <stdio.h> 35 #include <stdio.h>
38 * RFC 8259 39 * RFC 8259
39 * https://tools.ietf.org/html/rfc8259 40 * https://tools.ietf.org/html/rfc8259
40 */ 41 */
41 42
42 static CxJsonValue cx_json_value_nothing = {.type = CX_JSON_NOTHING}; 43 static CxJsonValue cx_json_value_nothing = {.type = CX_JSON_NOTHING};
44
45 static int json_cmp_objvalue(const void *l, const void *r) {
46 const CxJsonObjValue *left = l;
47 const CxJsonObjValue *right = r;
48 return cx_strcmp(cx_strcast(left->name), cx_strcast(right->name));
49 }
50
51 static CxJsonObjValue *json_find_objvalue(const CxJsonValue *obj, cxstring name) {
52 assert(obj->type == CX_JSON_OBJECT);
53 CxJsonObjValue kv_dummy;
54 kv_dummy.name = cx_mutstrn((char*) name.ptr, name.length);
55 size_t index = cx_array_binary_search(
56 obj->value.object.values,
57 obj->value.object.values_size,
58 sizeof(CxJsonObjValue),
59 &kv_dummy,
60 json_cmp_objvalue
61 );
62 if (index == obj->value.object.values_size) {
63 return NULL;
64 } else {
65 return &obj->value.object.values[index];
66 }
67 }
68
69 static int json_add_objvalue(CxJsonValue *obj, CxJsonObjValue member) {
70 assert(obj->type == CX_JSON_OBJECT);
71 CxArrayReallocator value_realloc = cx_array_reallocator(obj->allocator, NULL);
72 return cx_array_simple_add_sorted_a(
73 &value_realloc, obj->value.object.values,
74 member, json_cmp_objvalue
75 );
76 }
43 77
44 static void token_destroy(CxJsonToken *token) { 78 static void token_destroy(CxJsonToken *token) {
45 if (token->allocated) { 79 if (token->allocated) {
46 cx_strfree(&token->content); 80 cx_strfree(&token->content);
47 } 81 }
292 if (v == NULL) return NULL; // LCOV_EXCL_LINE 326 if (v == NULL) return NULL; // LCOV_EXCL_LINE
293 327
294 // initialize the value 328 // initialize the value
295 if (type == CX_JSON_ARRAY) { 329 if (type == CX_JSON_ARRAY) {
296 cx_array_initialize_a(json->allocator, v->value.array.array, 16); 330 cx_array_initialize_a(json->allocator, v->value.array.array, 16);
297 if (v->value.array.array == NULL) { // LCOV_EXCL_START 331 if (v->value.array.array == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE
298 cxFree(json->allocator, v);
299 return NULL;
300 } // LCOV_EXCL_STOP
301 } else if (type == CX_JSON_OBJECT) { 332 } else if (type == CX_JSON_OBJECT) {
302 cx_array_initialize_a(json->allocator, v->value.object.values, 16); 333 cx_array_initialize_a(json->allocator, v->value.object.values, 16);
303 if (v->value.object.values == NULL) { // LCOV_EXCL_START 334 if (v->value.object.values == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE
304 cxFree(json->allocator, v);
305 return NULL;
306 } // LCOV_EXCL_STOP
307 } else { 335 } else {
308 memset(v, 0, sizeof(CxJsonValue)); 336 memset(v, 0, sizeof(CxJsonValue));
309 } 337 }
310 v->type = type; 338 v->type = type;
311 v->allocator = json->allocator; 339 v->allocator = json->allocator;
312 340
313 // add the new value to a possible parent 341 // add the new value to a possible parent
314 CxArrayReallocator value_realloc = cx_array_reallocator(json->allocator, NULL);
315 if (json->vbuf_size > 0) { 342 if (json->vbuf_size > 0) {
316 CxJsonValue *parent = json->vbuf[json->vbuf_size - 1]; 343 CxJsonValue *parent = json->vbuf[json->vbuf_size - 1];
344 assert(parent != NULL);
317 if (parent->type == CX_JSON_ARRAY) { 345 if (parent->type == CX_JSON_ARRAY) {
318 cx_array_simple_add_a(&value_realloc, parent->value.array.array, v); 346 CxArrayReallocator value_realloc = cx_array_reallocator(json->allocator, NULL);
347 if (cx_array_simple_add_a(&value_realloc, parent->value.array.array, v)) {
348 goto create_json_value_exit_error; // LCOV_EXCL_LINE
349 }
319 } else if (parent->type == CX_JSON_OBJECT) { 350 } else if (parent->type == CX_JSON_OBJECT) {
320 assert(parent->value.object.values_size > 0); 351 // the member was already created after parsing the name
321 assert(parent->value.object.values[parent->value.object.values_size - 1].value == NULL); 352 assert(json->uncompleted_member.name.ptr != NULL);
322 parent->value.object.values[parent->value.object.values_size - 1].value = v; 353 json->uncompleted_member.value = v;
354 if (json_add_objvalue(parent, json->uncompleted_member)) {
355 goto create_json_value_exit_error; // LCOV_EXCL_LINE
356 }
357 json->uncompleted_member.name = (cxmutstr) {NULL, 0};
323 } else { 358 } else {
324 assert(false); // LCOV_EXCL_LINE 359 assert(false); // LCOV_EXCL_LINE
325 } 360 }
326 } 361 }
327 362
328 // add the new value to the stack, if it is an array or object 363 // add the new value to the stack, if it is an array or object
329 if (type == CX_JSON_ARRAY || type == CX_JSON_OBJECT) { 364 if (type == CX_JSON_ARRAY || type == CX_JSON_OBJECT) {
330 CxArrayReallocator vbuf_realloc = cx_array_reallocator(NULL, json->vbuf_internal); 365 CxArrayReallocator vbuf_realloc = cx_array_reallocator(NULL, json->vbuf_internal);
331 if (cx_array_simple_add_a(&vbuf_realloc, json->vbuf, v)) { 366 if (cx_array_simple_add_a(&vbuf_realloc, json->vbuf, v)) {
332 // LCOV_EXCL_START 367 goto create_json_value_exit_error; // LCOV_EXCL_LINE
333 cxFree(json->allocator, v); 368 }
334 return NULL;
335 } // LCOV_EXCL_STOP
336 } 369 }
337 370
338 // if currently no value is parsed, this is now the value of interest 371 // if currently no value is parsed, this is now the value of interest
339 if (json->parsed == NULL) { 372 if (json->parsed == NULL) {
340 json->parsed = v; 373 json->parsed = v;
341 } 374 }
342 375
343 return v; 376 return v;
377 // LCOV_EXCL_START
378 create_json_value_exit_error:
379 cxFree(json->allocator, v);
380 return NULL;
381 // LCOV_EXCL_STOP
344 } 382 }
345 383
346 #define JP_STATE_VALUE_BEGIN 0 384 #define JP_STATE_VALUE_BEGIN 0
347 #define JP_STATE_VALUE_END 10 385 #define JP_STATE_VALUE_END 10
348 #define JP_STATE_VALUE_BEGIN_OBJ 1 386 #define JP_STATE_VALUE_BEGIN_OBJ 1
528 // add new entry 566 // add new entry
529 cxmutstr name = unescape_string(json->allocator, token.content); 567 cxmutstr name = unescape_string(json->allocator, token.content);
530 if (name.ptr == NULL) { 568 if (name.ptr == NULL) {
531 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE 569 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
532 } 570 }
533 CxJsonObjValue kv = {name, NULL}; 571 assert(json->uncompleted_member.name.ptr == NULL);
572 json->uncompleted_member.name = name;
534 assert(json->vbuf_size > 0); 573 assert(json->vbuf_size > 0);
535 CxJsonValue *parent = json->vbuf[json->vbuf_size - 1];
536 assert(parent != NULL);
537 assert(parent->type == CX_JSON_OBJECT);
538 CxArrayReallocator value_realloc = cx_array_reallocator(json->allocator, NULL);
539 if (cx_array_simple_add_a(&value_realloc, parent->value.object.values, kv)) {
540 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
541 }
542 574
543 // next state 575 // next state
544 json_add_state(json, JP_STATE_OBJ_COLON); 576 json_add_state(json, JP_STATE_OBJ_COLON);
545 return_rec(CX_JSON_NO_ERROR); 577 return_rec(CX_JSON_NO_ERROR);
546 } 578 }
793 obj->value.object.values[i].value = child; 825 obj->value.object.values[i].value = child;
794 return 0; 826 return 0;
795 } 827 }
796 } 828 }
797 829
798 CxArrayReallocator value_realloc = cx_array_reallocator(obj->allocator, NULL);
799 assert(obj->type == CX_JSON_OBJECT);
800 cxmutstr k = cx_strdup_a(obj->allocator, name); 830 cxmutstr k = cx_strdup_a(obj->allocator, name);
801 if (k.ptr == NULL) return -1; 831 if (k.ptr == NULL) return -1;
802 CxJsonObjValue kv = {k, child}; 832 CxJsonObjValue kv = {k, child};
803 return cx_array_simple_add_a(&value_realloc, obj->value.object.values, kv); 833 return json_add_objvalue(obj, kv);
804 } 834 }
805 835
806 CxJsonValue* cxJsonObjPutObj(CxJsonValue* obj, cxstring name) { 836 CxJsonValue* cxJsonObjPutObj(CxJsonValue* obj, cxstring name) {
807 CxJsonValue* v = cxJsonCreateObj(obj->allocator); 837 CxJsonValue* v = cxJsonCreateObj(obj->allocator);
808 if (v == NULL) return NULL; 838 if (v == NULL) return NULL;
891 921
892 return iter; 922 return iter;
893 } 923 }
894 924
895 CxJsonValue *cx_json_obj_get_cxstr(const CxJsonValue *value, cxstring name) { 925 CxJsonValue *cx_json_obj_get_cxstr(const CxJsonValue *value, cxstring name) {
896 const CxJsonObject *obj = &(value->value.object); 926 CxJsonObjValue *member = json_find_objvalue(value, name);
897 // TODO: think about sorting the object so that we can use binary search here 927 if (member == NULL) {
898 for (size_t i = 0; i < obj->values_size; i++) { 928 return &cx_json_value_nothing;
899 if (0 == cx_strcmp(name, cx_strcast(obj->values[i].name))) { 929 } else {
900 return obj->values[i].value; 930 return member->value;
901 } 931 }
902 } 932 }
903 return &cx_json_value_nothing;
904 }

mercurial