148 lines
5.2 KiB
C
148 lines
5.2 KiB
C
#include "persist.h"
|
|
|
|
#define SAT_PERSIST_MAGIC (0xDEAFB00B)
|
|
#define SAT_PERSIST_VERSION (0x01)
|
|
#define SAT_PERSIST_HEADER (0x10)
|
|
#define SAT_PERSIST_FII_FORUM_LAST_POST_ID (0x10)
|
|
#define SAT_PERSIST_FII_USER_LAST_REGISTER_ID (0x18)
|
|
|
|
// that version number is going to come in useful cuz i want to expand the Persist.dat format
|
|
// v2 should add the ability to define a field by name
|
|
// i'm avoiding using the word "table" because in my eyes that implies a single block of data
|
|
// rather the table should be a linked list with the first entry pointed at from the header
|
|
// this way the existing fields in the v1 format don't have to be moved elsewhere during conversion
|
|
// essentially we got [DEAFB00B 02000000 20000000 00000000] in the header,
|
|
// the pointer to the first entry is at offset 0x08 in the header and should be interpreted as a U32
|
|
// why not a U64? cuz if we're gonna need more than the size a 32-bit integer offers we have worse problems than offset overflows...
|
|
// each entry will have a variable size, starting with a null terminated ascii string, followed by a byte for the type,
|
|
// followed by a U32 pointing to the location of the data, followed by a final U32 pointing to the next entry
|
|
// !!! this would remove the "backwards compatibility" of not having to move the data, but wouldn't it make more sense to
|
|
// !!! [NAME TYPE PNEXT VALUE] rather than [NAME TYPE PNEXT PVALUE]?
|
|
// i do not know how i'd go about values of variable length, perhaps the function that allocates a space in the file can review
|
|
// empty space or some kind of index can be kept, perhaps just add an asterisk saying "do not variable length you will regret"
|
|
// perhaps leave variable length shit for a v3 format
|
|
|
|
sat_persist_ptr sat_persist_alloc(void) {
|
|
sat_persist_ptr ctx = malloc(sizeof(sat_persist));
|
|
memset(ctx, 0, sizeof(sat_persist));
|
|
ctx->lock = malloc(sizeof(mtx_t));
|
|
return ctx;
|
|
}
|
|
|
|
void sat_persist_free(sat_persist_ptr ctx) {
|
|
if(!ctx) return;
|
|
|
|
if(ctx->lock != NULL) {
|
|
mtx_destroy(ctx->lock);
|
|
free(ctx->lock);
|
|
}
|
|
|
|
if(ctx->ownsStream && ctx->stream)
|
|
free(ctx->stream);
|
|
|
|
free(ctx);
|
|
}
|
|
|
|
int sat_persist_create(sat_persist_ptr ctx, FILE *stream, bool ownsStream) {
|
|
if(ctx == NULL) return -10; // TODO: No.
|
|
|
|
int err;
|
|
err = mtx_init(ctx->lock, mtx_timed);
|
|
if(err == thrd_error) return -11;
|
|
|
|
ctx->stream = stream;
|
|
ctx->ownsStream = ownsStream;
|
|
ctx->offset = ftell(stream);
|
|
|
|
err = sat_persist_header_refresh(ctx);
|
|
if(err) return err;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int sat_persist_create_file(sat_persist_ptr ctx, char *path) {
|
|
if(ctx == NULL) return -10; // TODO: No!
|
|
|
|
FILE *stream = fopen(path, "rb+");
|
|
if(stream == NULL) stream = fopen(path, "wb+");
|
|
if(stream == NULL) return errno;
|
|
|
|
fseek(stream, 0, SEEK_SET);
|
|
|
|
return sat_persist_create(ctx, stream, true);
|
|
}
|
|
|
|
void sat_persist_flush(sat_persist_ptr ctx) {
|
|
if(ctx != NULL && ctx->stream != NULL)
|
|
fflush(ctx->stream);
|
|
}
|
|
|
|
int sat_persist_header_refresh(sat_persist_ptr ctx) {
|
|
uint8_t buffer[SAT_PERSIST_HEADER] = {0};
|
|
|
|
uint32_t magic;
|
|
|
|
mtx_lock(ctx->lock);
|
|
size_t read = fread(buffer, sizeof(uint8_t), SAT_PERSIST_HEADER, ctx->stream);
|
|
mtx_unlock(ctx->lock);
|
|
|
|
if(read == 0) {
|
|
sat_pack_u32be(buffer, SAT_PERSIST_MAGIC);
|
|
|
|
buffer[4] = SAT_PERSIST_VERSION;
|
|
|
|
mtx_lock(ctx->lock);
|
|
fseek(ctx->stream, ctx->offset, SEEK_SET);
|
|
fwrite(buffer, sizeof(uint8_t), SAT_PERSIST_HEADER, ctx->stream);
|
|
fflush(ctx->stream);
|
|
mtx_unlock(ctx->lock);
|
|
} else if(read < SAT_PERSIST_HEADER) {
|
|
return -2; // TODO: also no
|
|
} else {
|
|
magic = sat_unpack_u32be(buffer);
|
|
|
|
if(magic != SAT_PERSIST_MAGIC)
|
|
return -3; // TODO: still no
|
|
|
|
if(buffer[4] < 1 || buffer[4] > SAT_PERSIST_VERSION)
|
|
return -4; // TODO: again, no
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
inline uint64_t sat_persist_read_u64(sat_persist_ptr ctx, uint32_t offset) {
|
|
uint8_t buffer[sizeof(uint64_t)] = {0};
|
|
|
|
mtx_lock(ctx->lock);
|
|
fseek(ctx->stream, ctx->offset + offset, SEEK_SET);
|
|
int read = fread(buffer, sizeof(uint8_t), sizeof(uint64_t), ctx->stream); // today we assume things will just work
|
|
mtx_unlock(ctx->lock);
|
|
if(read < 1) return 0;
|
|
|
|
return sat_unpack_u64le(buffer);
|
|
}
|
|
inline void sat_persist_write_u64(sat_persist_ptr ctx, uint32_t offset, uint64_t value) {
|
|
uint8_t buffer[sizeof(uint64_t)] = {0};
|
|
sat_pack_u64le(buffer, value);
|
|
|
|
mtx_lock(ctx->lock);
|
|
fseek(ctx->stream, ctx->offset + offset, SEEK_SET);
|
|
fwrite(buffer, sizeof(uint8_t), sizeof(uint64_t), ctx->stream);
|
|
mtx_unlock(ctx->lock);
|
|
}
|
|
|
|
uint64_t sat_persist_get_fii_forum_last_post_id(sat_persist_ptr ctx) {
|
|
return sat_persist_read_u64(ctx, SAT_PERSIST_FII_FORUM_LAST_POST_ID);
|
|
}
|
|
void sat_persist_set_fii_forum_last_post_id(sat_persist_ptr ctx, uint64_t postId) {
|
|
sat_persist_write_u64(ctx, SAT_PERSIST_FII_FORUM_LAST_POST_ID, postId);
|
|
}
|
|
|
|
uint64_t sat_persist_get_fii_user_last_register_id(sat_persist_ptr ctx) {
|
|
return sat_persist_read_u64(ctx, SAT_PERSIST_FII_USER_LAST_REGISTER_ID);
|
|
}
|
|
void sat_persist_set_fii_user_last_register_id(sat_persist_ptr ctx, uint64_t userId) {
|
|
sat_persist_write_u64(ctx, SAT_PERSIST_FII_USER_LAST_REGISTER_ID, userId);
|
|
}
|