335 lines
6.9 KiB
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;
|
|
}
|