Sun, 04 Jan 2026 17:45:50 +0100
implement json child obj deserialization
| dbutils/json.c | file | annotate | diff | comparison | revisions | |
| dbutils/json.h | file | annotate | diff | comparison | revisions | |
| test/json.c | file | annotate | diff | comparison | revisions | |
| test/json.h | file | annotate | diff | comparison | revisions | |
| test/main.c | file | annotate | diff | comparison | revisions |
--- a/dbutils/json.c Sat Jan 03 18:19:58 2026 +0100 +++ b/dbutils/json.c Sun Jan 04 17:45:50 2026 +0100 @@ -131,17 +131,25 @@ /* --------------- Json to Obj deserialization functions --------------------*/ -void* dbuJsonToObject(DBUClass *type, const CxAllocator *a, CxJsonValue *value) { +static void* jsonToObj(DBUClass *type, const CxAllocator *a, CxJsonValue *value, int depth, int *error) { if(!cxJsonIsObject(value)) { + *error = 1; + return NULL; + } + if(depth > DBU_JSON_MAX_DEPTH) { + *error = 2; return NULL; } if(!a) { a = cxDefaultAllocator; } - + void *obj = cxMalloc(a, type->obj_size); if(obj) { memset(obj, 0, type->obj_size); + } else { + *error = 3; + return NULL; } char buf[64]; @@ -151,7 +159,10 @@ cx_foreach(CxMapEntry *, entry, i) { DBUField *field = cxMapGet(type->fields, entry->key); if(!field) { - continue; + field = cxMapGet(type->obj_fields, entry->key); + if(!field) { + continue; + } } len = 0; @@ -194,13 +205,26 @@ case CX_JSON_STRING: { cxmutstr str = child->string; if(field->initValue(field, a, obj, str.ptr, str.length)) { + *error = 3; free(obj); // TODO: improve obj cleanup return NULL; } break; } case CX_JSON_OBJECT: { - // TODO + if(field->objType && field->initObjValue) { + void *child_obj = jsonToObj(field->objType, a, child, depth+1, error); + if(child_obj) { + field->initObjValue(field, a, obj, child_obj); + } else { + free(obj); // TODO: improve obj cleanup + return NULL; + } + } else { + *error = 4; + free(obj); // TODO: improve obj cleanup + return NULL; + } break; } case CX_JSON_ARRAY: { @@ -214,10 +238,17 @@ if(field->initValue(field, a, obj, buf, len)) { // TODO: completely cleanup obj free(obj); + *error = 3; return NULL; } } } + *error = 0; return obj; } + +void* dbuJsonToObject(DBUClass *type, const CxAllocator *a, CxJsonValue *value) { + int error; + return jsonToObj(type, a, value, 0, &error); +}
--- a/dbutils/json.h Sat Jan 03 18:19:58 2026 +0100 +++ b/dbutils/json.h Sun Jan 04 17:45:50 2026 +0100 @@ -35,7 +35,7 @@ extern "C" { #endif - +#define DBU_JSON_MAX_DEPTH 512 #ifdef __cplusplus
--- a/test/json.c Sat Jan 03 18:19:58 2026 +0100 +++ b/test/json.c Sun Jan 04 17:45:50 2026 +0100 @@ -358,3 +358,26 @@ free(obj); } } + +CX_TEST(testJsonToObjectWithObjChild) { + const char *jsonStr = + "{" + "\"test3\":\"testJsonToObjectWithObjChild\"," + "\"test2\":{ \"name\":\"Test2 Object\", \"i\":-1234567 }" + "}"; + + CxJsonValue *json; + cxJsonFromString(NULL, jsonStr, &json); + + CX_TEST_DO { + Test3 *obj = dbuJsonToObject(test3_class, NULL, json); + + CX_TEST_ASSERT(obj); + CX_TEST_ASSERT(!cx_strcmp(obj->test3, "testJsonToObjectWithObjChild")); + CX_TEST_ASSERT(obj->test2 != NULL); + CX_TEST_ASSERT(!cx_strcmp(obj->test2->name, "Test2 Object")); + CX_TEST_ASSERT(obj->test2->i == -1234567); + + free(obj); + } +}
--- a/test/json.h Sat Jan 03 18:19:58 2026 +0100 +++ b/test/json.h Sun Jan 04 17:45:50 2026 +0100 @@ -45,6 +45,7 @@ CX_TEST(testObjectToJsonChildList); CX_TEST(testJsonToSimpleObject); +CX_TEST(testJsonToObjectWithObjChild); #ifdef __cplusplus
--- a/test/main.c Sat Jan 03 18:19:58 2026 +0100 +++ b/test/main.c Sun Jan 04 17:45:50 2026 +0100 @@ -145,6 +145,7 @@ cx_test_register(suite, testObjectToJsonChildObj); cx_test_register(suite, testObjectToJsonChildList); cx_test_register(suite, testJsonToSimpleObject); + cx_test_register(suite, testJsonToObjectWithObjChild); cx_test_run_stdout(suite);