power_play/src/byteio.c

335 lines
6.9 KiB
C

#include "byteio.h"
#include "memory.h"
#include "arena.h"
/* ========================== *
* Writer
* ========================== */
INTERNAL b32 write_check_overflow(struct byte_writer *bw, i64 amount)
{
b32 overflowed = bw->overflowed;
if (overflowed || amount < 0) {
overflowed = true;
bw->overflowed = true;
} else {
u8 *end = bw->buff.text + bw->buff.len;
u8 *new_pos = bw->at + amount;
i64 new_space_left = end - new_pos;
if (new_space_left < 0) {
struct arena *arena = bw->arena;
if (arena) {
if ((arena->base + arena->pos) == end) {
arena_push_array(arena, u8, -new_space_left);
bw->buff.len += -new_space_left;
} else {
/* Writer memory must be contiguous in arena */
overflowed = true;
bw->overflowed = true;
}
} else {
overflowed = true;
bw->overflowed = true;
}
}
}
ASSERT(!overflowed);
return overflowed;
}
INTERNAL void write(struct byte_writer *bw, void *v, u64 size)
{
if (write_check_overflow(bw, size)) {
return;
}
MEMCPY(bw->at, v, size);
bw->at += size;
}
struct byte_writer bw_from_buffer(struct string buff)
{
struct byte_writer bw = ZI;
bw.buff = buff;
bw.at = buff.text;
return bw;
}
/* Returns a writer that will allocate to arena instead of overflowing (writes must stay contiguous in arena) */
struct byte_writer bw_from_arena(struct arena *arena)
{
struct byte_writer bw = ZI;
bw.arena = arena;
bw.buff.text = arena->base + arena->pos;
bw.buff.len = 0;
bw.at = bw.buff.text;
return bw;
}
/* Seeks forward and returns a new writer pointing to the skipped bytes */
struct byte_writer bw_branch(struct byte_writer *bw, u64 size)
{
struct string buff = STRING(size, bw->at);
struct byte_writer branch = bw_from_buffer(buff);
bw_seek(bw, size);
branch.overflowed = bw->overflowed;
return branch;
}
void bw_seek(struct byte_writer *bw, u64 amount)
{
if (write_check_overflow(bw, amount)) {
return;
}
bw->at += amount;
}
void bw_seek_to(struct byte_writer *bw, u64 pos)
{
if (write_check_overflow(bw, (i64)pos - (i64)(bw->at - bw->buff.text))) {
return;
}
bw->at = bw->buff.text + pos;
}
void bw_write_buffer(struct byte_writer *bw, struct string buff)
{
write(bw, buff.text, buff.len);
}
void bw_write_u8(struct byte_writer *bw, u8 v)
{
write(bw, &v, sizeof(v));
}
void bw_write_u16(struct byte_writer *bw, u16 v)
{
write(bw, &v, sizeof(v));
}
void bw_write_u32(struct byte_writer *bw, u32 v)
{
write(bw, &v, sizeof(v));
}
void bw_write_u64(struct byte_writer *bw, u64 v)
{
write(bw, &v, sizeof(v));
}
void bw_write_i8(struct byte_writer *bw, i8 v)
{
write(bw, &v, sizeof(v));
}
void bw_write_i16(struct byte_writer *bw, i16 v)
{
write(bw, &v, sizeof(v));
}
void bw_write_i32(struct byte_writer *bw, i32 v)
{
write(bw, &v, sizeof(v));
}
void bw_write_i64(struct byte_writer *bw, i64 v)
{
write(bw, &v, sizeof(v));
}
void bw_write_var_uint(struct byte_writer *bw, u64 v)
{
/* TODO: real varint write */
bw_write_u64(bw, v);
}
void bw_write_var_sint(struct byte_writer *bw, i64 v)
{
/* TODO: real varint write */
bw_write_i64(bw, v);
}
void bw_write_f32(struct byte_writer *bw, f32 v)
{
write(bw, &v, sizeof(v));
}
void bw_write_f64(struct byte_writer *bw, f64 v)
{
write(bw, &v, sizeof(v));
}
void bw_write_v2(struct byte_writer *bw, struct v2 v)
{
bw_write_f32(bw, v.x);
bw_write_f32(bw, v.y);
}
void bw_write_string(struct byte_writer *bw, struct string str)
{
bw_write_var_uint(bw, str.len);
bw_write_buffer(bw, str);
}
/* ========================== *
* Reader
* ========================== */
INTERNAL b32 read_check_overflow(struct byte_reader *br, i64 amount)
{
b32 overflowed = br->overflowed;
if (overflowed || amount < 0 || (br->at + amount) > (br->buff.text + br->buff.len) ){
ASSERT(false);
br->overflowed = true;
overflowed = true;
}
return overflowed;
}
INTERNAL void read(struct byte_reader *br, void *dst, u64 size)
{
if (read_check_overflow(br, size)) {
MEMZERO(dst, size);
}
MEMCPY(dst, br->at, size);
br->at += size;
}
struct byte_reader br_from_buffer(struct string buff)
{
struct byte_reader br = ZI;
br.buff = buff;
br.at = buff.text;
return br;
}
/* Returns pointer to old position, or NULL on overflow */
void *br_seek(struct byte_reader *br, u64 amount)
{
if (read_check_overflow(br, amount)) {
return NULL;
}
void *ptr = br->at;
br->at += amount;
return ptr;
}
/* Returns pointer to old position, or NULL on overflow */
void *br_seek_to(struct byte_reader *br, u64 pos)
{
if (read_check_overflow(br, (i64)pos - (i64)(br->at - br->buff.text))) {
return NULL;
}
void *ptr = br->at;
br->at = br->buff.text + pos;
return ptr;
}
/* Will fill buff with zeroes on overflow */
void br_read_to_buffer(struct byte_reader *br, struct string buff)
{
read(br, buff.text, buff.len);
}
u8 br_read_u8(struct byte_reader *br)
{
u8 res;
read(br, &res, sizeof(res));
return res;
}
u16 br_read_u16(struct byte_reader *br)
{
u16 res;
read(br, &res, sizeof(res));
return res;
}
u32 br_read_u32(struct byte_reader *br)
{
u32 res;
read(br, &res, sizeof(res));
return res;
}
u64 br_read_u64(struct byte_reader *br)
{
u64 res;
read(br, &res, sizeof(res));
return res;
}
i8 br_read_i8(struct byte_reader *br)
{
i8 res;
read(br, &res, sizeof(res));
return res;
}
i16 br_read_i16(struct byte_reader *br)
{
i16 res = 0;
read(br, &res, sizeof(res));
return res;
}
i32 br_read_i32(struct byte_reader *br)
{
i32 res = 0;
read(br, &res, sizeof(res));
return res;
}
i64 br_read_i64(struct byte_reader *br)
{
i64 res;
read(br, &res, sizeof(res));
return res;
}
u64 br_read_var_uint(struct byte_reader *br)
{
/* TODO: real variable length read */
return br_read_u64(br);
}
i64 br_read_var_sint(struct byte_reader *br)
{
/* TODO: real variable length read */
return br_read_i64(br);
}
f32 br_read_f32(struct byte_reader *br)
{
f32 res;
read(br, &res, sizeof(res));
return res;
}
f64 br_read_f64(struct byte_reader *br)
{
f64 res;
read(br, &res, sizeof(res));
return res;
}
struct v2 br_read_v2(struct byte_reader *br)
{
struct v2 res;
res.x = br_read_f32(br);
res.y = br_read_f32(br);
return res;
}
struct string br_read_string(struct arena *arena, struct byte_reader *br)
{
struct string res = ZI;
u64 len = br_read_var_uint(br);
u8 *text = br_seek(br, len);
if (text != NULL) {
res.len = len;
res.text = arena_push_array(arena, u8, len);
MEMCPY(res.text, text, len);
}
return res;
}