/** * @file json_helpers.c * @brief Implements the json helpers subsystem. */ #include #include #include #include #include #include #include #include akerr_ErrorContext *akgl_get_json_object_value(json_t *obj, char *key, json_t **dest) { PREPARE_ERROR(errctx); FAIL_ZERO_RETURN(errctx, obj, AKERR_NULLPOINTER, "NULL object pointer"); FAIL_ZERO_RETURN(errctx, key, AKERR_NULLPOINTER, "NULL key string"); FAIL_ZERO_RETURN(errctx, dest, AKERR_NULLPOINTER, "NULL destination pointer"); json_t *value = json_object_get(obj, key); FAIL_ZERO_RETURN(errctx, value, AKERR_KEY, "Key %s not found in object", key); FAIL_ZERO_RETURN(errctx, (json_is_object(value)), AKERR_TYPE, "Key %s in object has incorrect type", key); *dest = value; SUCCEED_RETURN(errctx); } akerr_ErrorContext *akgl_get_json_boolean_value(json_t *obj, char *key, bool *dest) { PREPARE_ERROR(errctx); FAIL_ZERO_RETURN(errctx, obj, AKERR_NULLPOINTER, "NULL object pointer"); FAIL_ZERO_RETURN(errctx, key, AKERR_NULLPOINTER, "NULL key string"); FAIL_ZERO_RETURN(errctx, dest, AKERR_NULLPOINTER, "NULL destination pointer"); json_t *value = json_object_get(obj, key); FAIL_ZERO_RETURN(errctx, value, AKERR_KEY, "Key %s not found in object", key); FAIL_ZERO_RETURN(errctx, (json_is_boolean(value)), AKERR_TYPE, "Key %s in object has incorrect type", key); *dest = json_boolean_value(value); SUCCEED_RETURN(errctx); } akerr_ErrorContext *akgl_get_json_integer_value(json_t *obj, char *key, int *dest) { PREPARE_ERROR(errctx); FAIL_ZERO_RETURN(errctx, obj, AKERR_NULLPOINTER, "NULL object pointer"); FAIL_ZERO_RETURN(errctx, key, AKERR_NULLPOINTER, "NULL key string"); FAIL_ZERO_RETURN(errctx, dest, AKERR_NULLPOINTER, "NULL destination pointer"); json_t *value = json_object_get(obj, key); FAIL_ZERO_RETURN(errctx, value, AKERR_KEY, "Key %s not found in object", key); FAIL_ZERO_RETURN(errctx, (json_is_integer(value)), AKERR_TYPE, "Key %s in object has incorrect type", key); *dest = json_integer_value(value); SUCCEED_RETURN(errctx); } akerr_ErrorContext *akgl_get_json_number_value(json_t *obj, char *key, float32_t *dest) { PREPARE_ERROR(errctx); FAIL_ZERO_RETURN(errctx, obj, AKERR_NULLPOINTER, "NULL pointer reference"); FAIL_ZERO_RETURN(errctx, key, AKERR_NULLPOINTER, "NULL key string"); FAIL_ZERO_RETURN(errctx, dest, AKERR_NULLPOINTER, "NULL destination pointer"); json_t *value = json_object_get(obj, key); FAIL_ZERO_RETURN(errctx, value, AKERR_KEY, "Key %s not found in object", key); FAIL_ZERO_RETURN(errctx, (json_is_number(value)), AKERR_TYPE, "Key %s in object has incorrect type", key); *dest = json_number_value(value); SUCCEED_RETURN(errctx); } akerr_ErrorContext *akgl_get_json_double_value(json_t *obj, char *key, float64_t *dest) { PREPARE_ERROR(errctx); FAIL_ZERO_RETURN(errctx, obj, AKERR_NULLPOINTER, "NULL pointer reference"); FAIL_ZERO_RETURN(errctx, key, AKERR_NULLPOINTER, "NULL key string"); FAIL_ZERO_RETURN(errctx, dest, AKERR_NULLPOINTER, "NULL destination pointer"); json_t *value = json_object_get(obj, key); FAIL_ZERO_RETURN(errctx, value, AKERR_KEY, "Key %s not found in object", key); FAIL_ZERO_RETURN(errctx, (json_is_number(value)), AKERR_TYPE, "Key %s in object has incorrect type", key); *dest = json_number_value(value); SUCCEED_RETURN(errctx); } akerr_ErrorContext *akgl_get_json_string_value(json_t *obj, char *key, akgl_String **dest) { json_t *value = NULL; PREPARE_ERROR(errctx); FAIL_ZERO_RETURN(errctx, obj, AKERR_NULLPOINTER, "NULL pointer reference"); FAIL_ZERO_RETURN(errctx, key, AKERR_NULLPOINTER, "NULL key string"); FAIL_ZERO_RETURN(errctx, dest, AKERR_NULLPOINTER, "NULL destination pointer"); value = json_object_get(obj, key); FAIL_ZERO_RETURN(errctx, value, AKERR_KEY, "Key %s not found in object", key); FAIL_ZERO_RETURN(errctx, (json_is_string(value)), AKERR_TYPE, "Key %s in object has incorrect type", key); ATTEMPT { if ( *dest == NULL ) { CATCH(errctx, akgl_heap_next_string(dest)); CATCH(errctx, akgl_string_initialize(*dest, NULL)); } // FINISH(errctx, true), not false. With `false` a failed // akgl_heap_next_string was swallowed and the strncpy below ran through // the pointer it never set, so an exhausted string pool arrived as a // segfault inside strncpy rather than as AKGL_ERR_HEAP. } CLEANUP { } PROCESS(errctx) { } FINISH(errctx, true); strncpy((char *)&(*dest)->data, json_string_value(value), AKGL_MAX_STRING_LENGTH); SUCCEED_RETURN(errctx); } akerr_ErrorContext *akgl_get_json_array_value(json_t *obj, char *key, json_t **dest) { PREPARE_ERROR(errctx); FAIL_ZERO_RETURN(errctx, obj, AKERR_NULLPOINTER, "NULL pointer reference"); FAIL_ZERO_RETURN(errctx, key, AKERR_NULLPOINTER, "NULL key string"); FAIL_ZERO_RETURN(errctx, dest, AKERR_NULLPOINTER, "NULL destination pointer"); json_t *value = json_object_get(obj, key); FAIL_ZERO_RETURN(errctx, value, AKERR_KEY, "Key %s not found in object", key); FAIL_ZERO_RETURN(errctx, (json_is_array(value)), AKERR_TYPE, "Key %s in object has incorrect type", key); *dest = value; SUCCEED_RETURN(errctx); } akerr_ErrorContext *akgl_get_json_array_index_object(json_t *array, int index, json_t **dest) { PREPARE_ERROR(errctx); FAIL_ZERO_RETURN(errctx, array, AKERR_NULLPOINTER, "NULL pointer reference"); FAIL_ZERO_RETURN(errctx, dest, AKERR_NULLPOINTER, "NULL destination pointer"); json_t *value = json_array_get(array, index); FAIL_ZERO_RETURN(errctx, value, AKERR_OUTOFBOUNDS, "Index %d out of bounds for array", index); FAIL_ZERO_RETURN(errctx, (json_is_object(value)), AKERR_TYPE, "Index %d in object has incorrect type", index); *dest = value; SUCCEED_RETURN(errctx); } akerr_ErrorContext *akgl_get_json_array_index_integer(json_t *array, int index, int *dest) { PREPARE_ERROR(errctx); FAIL_ZERO_RETURN(errctx, array, AKERR_NULLPOINTER, "NULL pointer reference"); FAIL_ZERO_RETURN(errctx, dest, AKERR_NULLPOINTER, "NULL destination pointer"); json_t *value = json_array_get(array, index); FAIL_ZERO_RETURN(errctx, value, AKERR_OUTOFBOUNDS, "Index %d out of bounds for array", index); FAIL_ZERO_RETURN(errctx, (json_is_integer(value)), AKERR_TYPE, "Index %d in object has incorrect type", index); *dest = json_integer_value(value); SUCCEED_RETURN(errctx); } akerr_ErrorContext *akgl_get_json_array_index_string(json_t *array, int index, akgl_String **dest) { PREPARE_ERROR(errctx); FAIL_ZERO_RETURN(errctx, array, AKERR_NULLPOINTER, "NULL pointer reference"); FAIL_ZERO_RETURN(errctx, dest, AKERR_NULLPOINTER, "NULL destination pointer"); json_t *value = json_array_get(array, index); FAIL_ZERO_RETURN(errctx, value, AKERR_OUTOFBOUNDS, "Index %d out of bounds for array", index); FAIL_ZERO_RETURN(errctx, (json_is_string(value)), AKERR_TYPE, "Index %d in object has incorrect type", index); ATTEMPT { if ( *dest == NULL ) { CATCH(errctx, akgl_heap_next_string(dest)); CATCH(errctx, akgl_string_initialize(*dest, NULL)); } // FINISH(errctx, true), not false. With `false` a failed // akgl_heap_next_string was swallowed and the strncpy below ran through // the pointer it never set, so an exhausted string pool arrived as a // segfault inside strncpy rather than as AKGL_ERR_HEAP. } CLEANUP { } PROCESS(errctx) { } FINISH(errctx, true); strncpy((char *)&(*dest)->data, json_string_value(value), AKGL_MAX_STRING_LENGTH); SUCCEED_RETURN(errctx); } akerr_ErrorContext *akgl_get_json_with_default(akerr_ErrorContext *e, void *defval, void *dest, uint32_t defsize) { // Two contexts, and the names now say which is which: `e` is the incoming // one being inspected, `errctx` is this function's own. They were `err` and // `e`, which put the incoming context under the name the convention // reserves for exactly that and the local one under a name that reads like // it. PREPARE_ERROR(errctx); if ( e == NULL ) { SUCCEED_RETURN(errctx); } FAIL_ZERO_RETURN(errctx, defval, AKERR_NULLPOINTER, "defval"); FAIL_ZERO_RETURN(errctx, dest, AKERR_NULLPOINTER, "dest"); ATTEMPT { } CLEANUP { } PROCESS(e) { } HANDLE_GROUP(e, AKERR_KEY) { } HANDLE_GROUP(e, AKERR_INDEX) { memcpy(dest, defval, defsize); } FINISH(e, true); SUCCEED_RETURN(errctx); }