started cundump.c:cosmoD_undump(); minor fixes

This commit is contained in:
CPunch 2023-05-25 21:12:21 -05:00 committed by cpunch
parent 65d37838cd
commit 395f352c6e
4 changed files with 217 additions and 7 deletions

View File

@ -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);

View File

@ -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

194
src/cundump.c Normal file
View File

@ -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;
}

14
src/cundump.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef COSMO_UNDUMP_H
#define COSMO_UNDUMP_H
#include "cobj.h"
#include "cosmo.h"
#include <stdio.h>
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