Scripting: Initial deserialization work

This commit is contained in:
Vicki Pfau 2023-02-05 01:19:54 -08:00
parent 0c6b443065
commit 8b65f3772c
3 changed files with 252 additions and 0 deletions

View File

@ -18,6 +18,8 @@ void mScriptContextAttachStorage(struct mScriptContext* context);
bool mScriptStorageSaveBucket(struct mScriptContext* context, const char* bucket);
bool mScriptStorageSaveBucketVF(struct mScriptContext* context, const char* bucket, struct VFile* vf);
bool mScriptStorageLoadBucket(struct mScriptContext* context, const char* bucket);
bool mScriptStorageLoadBucketVF(struct mScriptContext* context, const char* bucket, struct VFile* vf);
void mScriptStorageGetBucketPath(const char* bucket, char* out);
CXX_GUARD_END

View File

@ -36,6 +36,7 @@ void mScriptStorageContextDeinit(struct mScriptStorageContext*);
struct mScriptStorageBucket* mScriptStorageGetBucket(struct mScriptStorageContext*, const char* name);
static bool mScriptStorageToJson(struct mScriptValue* value, struct json_object** out);
static struct mScriptValue* mScriptStorageFromJson(struct json_object* json);
mSCRIPT_DECLARE_STRUCT(mScriptStorageBucket);
mSCRIPT_DECLARE_STRUCT_METHOD(mScriptStorageBucket, WRAPPER, _get, mScriptStorageBucketGet, 1, CHARP, key);
@ -220,6 +221,7 @@ bool mScriptStorageToJson(struct mScriptValue* value, struct json_object** out)
bool mScriptStorageSaveBucketVF(struct mScriptContext* context, const char* bucketName, struct VFile* vf) {
struct mScriptValue* value = mScriptContextGetGlobal(context, "storage");
if (!value) {
vf->close(vf);
return false;
}
struct mScriptStorageContext* storage = value->value.opaque;
@ -227,12 +229,14 @@ bool mScriptStorageSaveBucketVF(struct mScriptContext* context, const char* buck
struct json_object* rootObj;
bool ok = mScriptStorageToJson(bucket->root, &rootObj);
if (!ok) {
vf->close(vf);
return false;
}
const char* json = json_object_to_json_string_ext(rootObj, JSON_C_TO_STRING_PRETTY_TAB);
if (!json) {
json_object_put(rootObj);
vf->close(vf);
return false;
}
@ -252,6 +256,113 @@ bool mScriptStorageSaveBucket(struct mScriptContext* context, const char* bucket
return mScriptStorageSaveBucketVF(context, bucketName, vf);
}
struct mScriptValue* mScriptStorageFromJson(struct json_object* json) {
enum json_type type = json_object_get_type(json);
struct mScriptValue* value = NULL;
switch (type) {
case json_type_null:
return &mScriptValueNull;
case json_type_int:
value = mScriptValueAlloc(mSCRIPT_TYPE_MS_S64);
value->value.s64 = json_object_get_int64(json);
break;
case json_type_double:
value = mScriptValueAlloc(mSCRIPT_TYPE_MS_F64);
value->value.f64 = json_object_get_double(json);
break;
case json_type_boolean:
value = mScriptValueAlloc(mSCRIPT_TYPE_MS_BOOL);
value->value.u32 = json_object_get_boolean(json);
break;
case json_type_string:
value = mScriptStringCreateFromBytes(json_object_get_string(json), json_object_get_string_len(json));
break;
case json_type_array:
value = mScriptValueAlloc(mSCRIPT_TYPE_MS_LIST);
{
size_t i;
for (i = 0; i < json_object_array_length(json); ++i) {
struct mScriptValue* vval = mScriptStorageFromJson(json_object_array_get_idx(json, i));
if (!vval) {
mScriptValueDeref(value);
value = NULL;
break;
}
mScriptValueWrap(vval, mScriptListAppend(value->value.list));
mScriptValueDeref(vval);
}
}
break;
case json_type_object:
value = mScriptValueAlloc(mSCRIPT_TYPE_MS_TABLE);
{
json_object_object_foreach(json, jkey, jval) {
struct mScriptValue* vval = mScriptStorageFromJson(jval);
if (!vval) {
mScriptValueDeref(value);
value = NULL;
break;
}
struct mScriptValue* vkey = mScriptStringCreateFromUTF8(jkey);
mScriptTableInsert(value, vkey, vval);
mScriptValueDeref(vkey);
mScriptValueDeref(vval);
}
}
break;
}
return value;
}
bool mScriptStorageLoadBucketVF(struct mScriptContext* context, const char* bucketName, struct VFile* vf) {
struct mScriptValue* value = mScriptContextGetGlobal(context, "storage");
if (!value) {
vf->close(vf);
return false;
}
struct mScriptStorageContext* storage = value->value.opaque;
ssize_t size = vf->size(vf);
if (size < 2) {
vf->close(vf);
return false;
}
char* json = calloc(1, size + 1);
if (vf->read(vf, json, size) != size) {
vf->close(vf);
return false;
}
vf->close(vf);
struct json_object* obj = json_tokener_parse(json);
free(json);
if (!obj) {
return false;
}
struct mScriptValue* root = mScriptStorageFromJson(obj);
json_object_put(obj);
if (!root) {
return false;
}
struct mScriptStorageBucket* bucket = mScriptStorageGetBucket(storage, bucketName);
mScriptValueDeref(bucket->root);
bucket->root = root;
return true;
}
bool mScriptStorageLoadBucket(struct mScriptContext* context, const char* bucketName) {
char path[PATH_MAX];
mScriptStorageGetBucketPath(bucketName, path);
struct VFile* vf = VFileOpen(path, O_RDONLY);
if (!vf) {
return false;
}
return mScriptStorageLoadBucketVF(context, bucketName, vf);
}
void mScriptContextAttachStorage(struct mScriptContext* context) {
struct mScriptStorageContext* storage = calloc(1, sizeof(*storage));
struct mScriptValue* value = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(mScriptStorageContext));

View File

@ -324,6 +324,137 @@ M_TEST_DEFINE(serializeNullByteString) {
mScriptContextDeinit(&context);
}
M_TEST_DEFINE(deserializeInt) {
SETUP_LUA;
TEST_PROGRAM("bucket = storage:getBucket('xtest')");
TEST_PROGRAM("assert(bucket)");
TEST_PROGRAM("assert(not bucket.a)");
static const char* json = "{\"a\":1}";
struct VFile* vf = VFileFromConstMemory(json, strlen(json));
assert_true(mScriptStorageLoadBucketVF(&context, "xtest", vf));
TEST_PROGRAM("assert(bucket.a == 1)");
mScriptContextDeinit(&context);
}
M_TEST_DEFINE(deserializeFloat) {
SETUP_LUA;
TEST_PROGRAM("bucket = storage:getBucket('xtest')");
TEST_PROGRAM("assert(bucket)");
TEST_PROGRAM("assert(not bucket.a)");
static const char* json = "{\"a\":0.5}";
struct VFile* vf = VFileFromConstMemory(json, strlen(json));
assert_true(mScriptStorageLoadBucketVF(&context, "xtest", vf));
TEST_PROGRAM("assert(bucket.a == 0.5)");
mScriptContextDeinit(&context);
}
M_TEST_DEFINE(deserializeBool) {
SETUP_LUA;
TEST_PROGRAM("bucket = storage:getBucket('xtest')");
TEST_PROGRAM("assert(bucket)");
TEST_PROGRAM("assert(not bucket.a)");
static const char* json = "{\"a\":true}";
struct VFile* vf = VFileFromConstMemory(json, strlen(json));
assert_true(mScriptStorageLoadBucketVF(&context, "xtest", vf));
TEST_PROGRAM("assert(bucket.a == true)");
mScriptContextDeinit(&context);
}
M_TEST_DEFINE(deserializeNil) {
SETUP_LUA;
TEST_PROGRAM("bucket = storage:getBucket('xtest')");
TEST_PROGRAM("assert(bucket)");
TEST_PROGRAM("assert(not bucket.a)");
static const char* json = "{\"a\":null}";
struct VFile* vf = VFileFromConstMemory(json, strlen(json));
assert_true(mScriptStorageLoadBucketVF(&context, "xtest", vf));
TEST_PROGRAM("assert(bucket.a == nil)");
mScriptContextDeinit(&context);
}
M_TEST_DEFINE(deserializeString) {
SETUP_LUA;
TEST_PROGRAM("bucket = storage:getBucket('xtest')");
TEST_PROGRAM("assert(bucket)");
TEST_PROGRAM("assert(not bucket.a)");
static const char* json = "{\"a\":\"hello\"}";
struct VFile* vf = VFileFromConstMemory(json, strlen(json));
assert_true(mScriptStorageLoadBucketVF(&context, "xtest", vf));
TEST_PROGRAM("assert(bucket.a == 'hello')");
mScriptContextDeinit(&context);
}
M_TEST_DEFINE(deserializeList) {
SETUP_LUA;
TEST_PROGRAM("bucket = storage:getBucket('xtest')");
TEST_PROGRAM("assert(bucket)");
TEST_PROGRAM("assert(not bucket.a)");
static const char* json = "{\"a\":[1,2]}";
struct VFile* vf = VFileFromConstMemory(json, strlen(json));
assert_true(mScriptStorageLoadBucketVF(&context, "xtest", vf));
TEST_PROGRAM("assert(#bucket.a == 2)");
TEST_PROGRAM("assert(bucket.a[1] == 1)");
TEST_PROGRAM("assert(bucket.a[2] == 2)");
mScriptContextDeinit(&context);
}
M_TEST_DEFINE(deserializeTable) {
SETUP_LUA;
TEST_PROGRAM("bucket = storage:getBucket('xtest')");
TEST_PROGRAM("assert(bucket)");
TEST_PROGRAM("assert(not bucket.a)");
static const char* json = "{\"a\":{\"b\":1}}";
struct VFile* vf = VFileFromConstMemory(json, strlen(json));
assert_true(mScriptStorageLoadBucketVF(&context, "xtest", vf));
TEST_PROGRAM("assert(bucket.a.b == 1)");
mScriptContextDeinit(&context);
}
M_TEST_DEFINE(deserializeNullByteString) {
SETUP_LUA;
TEST_PROGRAM("bucket = storage:getBucket('xtest')");
TEST_PROGRAM("assert(bucket)");
TEST_PROGRAM("assert(not bucket.a)");
static const char* json = "{\"a\":\"a\\u0000b\"}";
struct VFile* vf = VFileFromConstMemory(json, strlen(json));
assert_true(mScriptStorageLoadBucketVF(&context, "xtest", vf));
TEST_PROGRAM("assert(bucket.a == 'a\\x00b')");
TEST_PROGRAM("assert(bucket.a ~= 'a\\x00c')");
mScriptContextDeinit(&context);
}
M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptStorage,
cmocka_unit_test(basicInt),
cmocka_unit_test(basicFloat),
@ -342,4 +473,12 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptStorage,
cmocka_unit_test(serializeList),
cmocka_unit_test(serializeTable),
cmocka_unit_test(serializeNullByteString),
cmocka_unit_test(deserializeInt),
cmocka_unit_test(deserializeFloat),
cmocka_unit_test(deserializeBool),
cmocka_unit_test(deserializeNil),
cmocka_unit_test(deserializeString),
cmocka_unit_test(deserializeList),
cmocka_unit_test(deserializeTable),
cmocka_unit_test(deserializeNullByteString),
)