From f116efa02c37173efff4de3b18005bb312210eee Mon Sep 17 00:00:00 2001 From: CPunch Date: Thu, 25 May 2023 21:12:21 -0500 Subject: [PATCH] started cundump.c:cosmoD_undump(); minor fixes --- src/cdump.c | 15 ++-- src/cdump.h | 1 + src/cundump.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/cundump.h | 14 ++++ 4 files changed, 217 insertions(+), 7 deletions(-) create mode 100644 src/cundump.c create mode 100644 src/cundump.h diff --git a/src/cdump.c b/src/cdump.c index 8e12ca8..3f37e25 100644 --- a/src/cdump.c +++ b/src/cdump.c @@ -92,18 +92,12 @@ static void writeCObjFunction(DumpState *dstate, CObjFunction *obj) writeVector(dstate, obj->chunk.lineInfo, sizeof(int) * obj->chunk.count); /* write constants */ + writeSize(dstate, obj->chunk.constants.count); for (int i = 0; i < obj->chunk.constants.count; i++) { writeCValue(dstate, obj->chunk.constants.values[i]); } } -#define WRITE_VAR(dstate, type, expression) \ - { \ - type _tmp = expression; \ - writeBlock(dstate, &_tmp, sizeof(_tmp)); \ - break; \ - } - static void writeCObj(DumpState *dstate, CObj *obj) { /* @@ -132,6 +126,13 @@ static void writeCObj(DumpState *dstate, CObj *obj) } } +#define WRITE_VAR(dstate, type, expression) \ + { \ + type _tmp = expression; \ + writeBlock(dstate, &_tmp, sizeof(_tmp)); \ + break; \ + } + static void writeCValue(DumpState *dstate, CValue val) { CosmoType t = GET_TYPE(val); diff --git a/src/cdump.h b/src/cdump.h index a914e0b..43a10dc 100644 --- a/src/cdump.h +++ b/src/cdump.h @@ -13,6 +13,7 @@ typedef int (*cosmo_Writer)(CState *state, const void *data, size_t size, const bool cosmoD_isBigEndian(); +/* returns non-zero on error */ int cosmoD_dump(CState *state, CObjFunction *func, cosmo_Writer writer, const void *userData); #endif \ No newline at end of file diff --git a/src/cundump.c b/src/cundump.c new file mode 100644 index 0000000..33e752f --- /dev/null +++ b/src/cundump.c @@ -0,0 +1,194 @@ +#include "cdump.h" +#include "cundump.h" +#include "cvm.h" +#include "cchunk.h" + +typedef struct +{ + CState *state; + const void *userData; + cosmo_Reader reader; + int readerStatus; +} UndumpState; + +#define check(e) if (!e) return false; + +static void initUndumpState(CState *state, UndumpState *udstate, cosmo_Reader reader, + const void *userData) +{ + udstate->state = state; + udstate->userData = userData; + udstate->reader = reader; + udstate->readerStatus = 0; +} + +static bool readBlock(UndumpState *udstate, void *data, size_t size) +{ + if (udstate->readerStatus == 0) { + udstate->readerStatus = udstate->reader(udstate->state, data, size, udstate->userData); + } + + return udstate->readerStatus == 0; +} + +static bool readu8(UndumpState *udstate, uint8_t *d) +{ + return readBlock(udstate, d, sizeof(uint8_t)); +} + +static bool readu16(UndumpState *udstate, uint16_t *d) +{ + return readBlock(udstate, d, sizeof(uint16_t)); +} + +static bool readSize(UndumpState *udstate, size_t *d) +{ + return readBlock(udstate, d, sizeof(size_t)); +} + +static bool readVector(UndumpState *udstate, void **data, size_t *size) +{ + check(readSize(udstate, size)); + *data = cosmoM_malloc(udstate->state, *size); + return readBlock(udstate, *data, *size); +} + +#define checku8(udstate, d, tmp) \ + check(readu8(udstate, &tmp)); \ + if (d != tmp) { \ + cosmoV_error(udstate->state, "bad header!"); \ + return false; \ + } + +static bool checkHeader(UndumpState *udstate) { + char magic[COSMO_MAGIC_LEN]; + uint8_t tmp; + + /* check header */ + readBlock(udstate, magic, COSMO_MAGIC_LEN); + if (memcmp(magic, COSMO_MAGIC, COSMO_MAGIC_LEN) != 0) { + cosmoV_error(udstate->state, "bad header!"); + return false; + } + + /* after the magic, we read some platform information */ + checku8(udstate, cosmoD_isBigEndian(), tmp); + checku8(udstate, sizeof(cosmo_Number), tmp); + checku8(udstate, sizeof(size_t), tmp); + checku8(udstate, sizeof(int), tmp); + + return true; +} + +#undef checku8 + +static bool readCObjString(UndumpState *udstate, CObjString **str) +{ + size_t size; + char *data; + + check(readu32(udstate, &size)); + if (size == 0) { /* empty string */ + *str = NULL; + return true; + } + + *data = cosmoM_malloc(udstate->state, size+1); + check(readBlock(udstate, (void *)&data, size)); + data[size] = '\0'; /* add NULL-terminator */ + + *str = cosmoO_takeString(udstate->state, data, size); + return true; +} + +static bool readCObjFunction(UndumpState *udstate, CObjFunction **func) { + *func = cosmoO_newFunction(udstate->state); + + check(readCObjString(udstate, &(*func)->name)); + check(readCObjString(udstate, &(*func)->module)); + + check(readu32(udstate, &(*func)->args)); + check(readu32(udstate, &(*func)->upvals)); + check(readu8(udstate, &(*func)->variadic)); + + /* read chunk info */ + check(readVector(udstate, (void **)&(*func)->chunk.buf, &(*func)->chunk.count)); + check(readVector(udstate, (void **)&(*func)->chunk.lineInfo, &(*func)->chunk.count)); + + /* read constants */ + size_t constants; + check(readSize(udstate, &constants)); + for (int i = 0; i < constants; i++) { + CValue val; + check(readCValue(udstate, &val)); + addConstant(udstate->state, &(*func)->chunk, val); + } + + return true; +} + +static bool readCObj(UndumpState *udstate, CObj **obj) +{ + uint8_t type; + check(readu8(udstate, &type)); + + switch (type) { + case COBJ_STRING: + return readCObjString(udstate, (CObjString **)obj); + case COBJ_FUNCTION: + return readCObjFunction(udstate, (CObjFunction **)obj); + default: + cosmoV_error(udstate->state, "unknown object type!"); + return false; + } + + return true; +} + +#define READ_VAR(udstate, val, type, creator) \ + { \ + type _tmp; \ + check(readBlock(udstate, &_tmp, sizeof(type))); \ + *val = creator(_tmp); \ + break; \ + } + +static bool readCValue(UndumpState *udstate, CValue *val) { + uint8_t type; + check(readu8(udstate, &type)); + + switch (type) { + case COSMO_TNUMBER: + READ_VAR(udstate, val, cosmo_Number, cosmoV_newNumber) + case COSMO_TBOOLEAN: + READ_VAR(udstate, val, bool, cosmoV_newBoolean) + case COSMO_TREF: { + CObj *obj; + check(readCObj(udstate, (CObj **)&obj)); + *val = cosmoV_newRef(obj); + break; + } + case COSMO_TNIL: + *val = cosmoV_newNil(); + break; + default: + break; + } + + return true; +} + +int cosmoD_undump(CState *state, CObjFunction *func, cosmo_Reader writer, const void *userData) { + UndumpState udstate; + initUndumpState(state, &udstate, writer, userData); + + if (!checkHeader(&udstate)) { + return 1; + } + + if (!readCObjFunction(&udstate, &func)) { + return 1; + } + + return udstate.readerStatus; +} \ No newline at end of file diff --git a/src/cundump.h b/src/cundump.h new file mode 100644 index 0000000..282f5bc --- /dev/null +++ b/src/cundump.h @@ -0,0 +1,14 @@ +#ifndef COSMO_UNDUMP_H +#define COSMO_UNDUMP_H + +#include "cobj.h" +#include "cosmo.h" + +#include + +typedef int (*cosmo_Reader)(CState *state, void *data, size_t size, const void *ud); + +/* returns non-zero on error */ +int cosmoD_undump(CState *state, CObjFunction *func, cosmo_Reader writer, const void *userData); + +#endif \ No newline at end of file