Stream abstraction, [WIP] integer (de)serealization

This commit is contained in:
Vftdan 2024-10-23 14:09:28 +02:00
parent 9df451de61
commit 1fc696dc51
5 changed files with 318 additions and 0 deletions

View File

@ -0,0 +1,83 @@
#ifndef COMMON_UTIL_BYTE_SERDES_H_
#define COMMON_UTIL_BYTE_SERDES_H_
#include "common/util/byte_stream.h"
#include <assert.h>
HEADER_FN void
byteser_bytes_lcrop(AbstractOutputByteStream *stream, ByteSlice bytes, size_t size, uint8_t pad_value)
{
ByteSlice pad_slc = VAR_BYTE_SLICE_CONST(pad_value);
while (size > bytes.length) {
byte_stream_write(stream, pad_slc);
--size;
}
byte_slice_advance_inplace(&bytes, bytes.length - size);
if (bytes.data && bytes.length) {
byte_stream_write(stream, bytes);
}
}
HEADER_FN void
byteser_net_integral_signed(AbstractOutputByteStream *stream, intmax_t value, size_t size)
{
int8_t buf[sizeof(value)];
for (size_t i = 0; i < sizeof(buf); ++i) {
buf[size - i - 1] = value & 0xFF;
value >>= 8;
}
byteser_bytes_lcrop(stream, VAR_BYTE_SLICE_CONST(buf), size, value < 0 ? -1 : 0);
}
HEADER_FN void
byteser_net_integral_unsigned(AbstractOutputByteStream *stream, uintmax_t value, size_t size)
{
uint8_t buf[sizeof(value)];
for (size_t i = 0; i < sizeof(buf); ++i) {
buf[size - i - 1] = value & 0xFF;
value >>= 8;
}
byteser_bytes_lcrop(stream, VAR_BYTE_SLICE_CONST(buf), size, 0);
}
// TODO finish deserialization
HEADER_FN bool
bytedeser_net_integral_signed(AbstractInputByteStream *stream, intmax_t *value_ptr, size_t size)
{
*value_ptr = 0;
int8_t buf[sizeof(*value_ptr)] = {0,};
int8_t dummy;
MutByteSlice dummy_slc = VAR_BYTE_SLICE_MUT(dummy);
while (size > sizeof(buf)) {
byte_stream_read_to(stream, dummy_slc);
--size;
}
MutByteSlice buf_slc = VAR_BYTE_SLICE_MUT(buf);
byte_slice_advance_inplace(&buf_slc.as_ByteSlice, buf_slc.length - size);
if (!buf_slc.data || !buf_slc.length) {
return true; // Successfully read 0 bytes
}
if (byte_stream_is_end(stream)) {
return false; // Failed to read bytes
}
if (byte_stream_read_to(stream, buf_slc) != buf_slc.length) {
return false; // Failed to read enough bytes
}
assert(buf_slc.data - (uint8_t*) buf < (ssize_t) sizeof(buf));
int8_t sign = *(int8_t*) buf_slc.data < 0 ? -1 : 0;
for (int8_t *ptr = buf; (uint8_t*) ptr != buf_slc.data; ++ptr) {
*ptr = sign;
}
intmax_t value = 0;
for (size_t i = 0; i < sizeof(buf); ++i) {
value <<= 8;
value |= 0xFF & (intmax_t) buf[i];
}
*value_ptr = value;
return true;
}
#endif /* end of include guard: COMMON_UTIL_BYTE_SERDES_H_ */

View File

@ -0,0 +1,60 @@
#ifndef COMMON_UTIL_BYTE_SLICE_H_
#define COMMON_UTIL_BYTE_SLICE_H_
#include "common/defs.h"
typedef struct {
const uint8_t *data;
size_t length;
} ByteSlice;
typedef union {
struct {
uint8_t *data;
size_t length;
};
ByteSlice as_ByteSlice;
} MutByteSlice;
#define EMPTY_BYTE_SLICE (ByteSlice) { .data = NULL, .length = 0 }
#define EMPTY_MUT_BYTE_SLICE (MutByteSlice) { .data = NULL, .length = 0 }
#define VAR_BYTE_SLICE_CONST(x) (ByteSlice) { .data = (const void*) &(x), .length = sizeof(x) }
#define VAR_BYTE_SLICE_MUT(x) (MutByteSlice) { .data = (void*) &(x), .length = sizeof(x) }
HEADER_FN void
byte_slice_advance_inplace(ByteSlice *self, size_t amount)
{
if (amount >= self->length) {
*self = EMPTY_BYTE_SLICE;
return;
}
self->length -= amount;
self->data += amount;
}
HEADER_FN MutByteSlice
byte_slice_alloc(size_t length)
{
if (!length) {
return EMPTY_MUT_BYTE_SLICE;
}
uint8_t *data = T_ALLOC(length, uint8_t);
if (!data) {
return EMPTY_MUT_BYTE_SLICE;
}
return (MutByteSlice) {
.data = data,
.length = length,
};
}
HEADER_FN MutByteSlice
byte_slice_free(MutByteSlice slice)
{
if (slice.data) {
free(slice.data);
}
return EMPTY_MUT_BYTE_SLICE;
}
#endif /* end of include guard: COMMON_UTIL_BYTE_SLICE_H_ */

View File

@ -0,0 +1,81 @@
#include "byte_stream.h"
typedef struct {
AbstractInputByteStream as_AbstractInputByteStream;
FILE *file;
} FileInputByteStream;
typedef struct {
AbstractOutputByteStream as_AbstractOutputByteStream;
FILE *file;
} FileOutputByteStream;
static size_t
file_steam_read(AbstractInputByteStream *self, MutByteSlice buf)
{
return fread(buf.data, 1, buf.length, DOWNCAST(FileInputByteStream, AbstractInputByteStream, self)->file);
}
static bool
file_steam_is_end(AbstractInputByteStream *self)
{
FILE *file = DOWNCAST(FileInputByteStream, AbstractInputByteStream, self)->file;
return (feof(file) || ferror(file)) ? true : false;
}
static void
file_steam_write(AbstractOutputByteStream *self, ByteSlice bytes)
{
fwrite(bytes.data, 1, bytes.length, DOWNCAST(FileOutputByteStream, AbstractOutputByteStream, self)->file);
}
static void
file_input_stream_destroy(AbstractInputByteStream *self)
{
free(self);
}
static void
file_output_stream_destroy(AbstractOutputByteStream *self)
{
free(self);
}
AbstractInputByteStream *file_as_input_byte_stream(FILE *file)
{
if (!file) {
return NULL;
}
FileInputByteStream *self = T_ALLOC(1, FileInputByteStream);
if (self == NULL) {
return NULL;
}
*self = (FileInputByteStream) {
.as_AbstractInputByteStream = {
.read = &file_steam_read,
.is_end = &file_steam_is_end,
.destroy = &file_input_stream_destroy,
},
.file = file,
};
return &self->as_AbstractInputByteStream;
}
AbstractOutputByteStream *file_as_output_byte_stream(FILE *file)
{
if (!file) {
return NULL;
}
FileOutputByteStream *self = T_ALLOC(1, FileOutputByteStream);
if (self == NULL) {
return NULL;
}
*self = (FileOutputByteStream) {
.as_AbstractOutputByteStream = {
.write = &file_steam_write,
.destroy = &file_output_stream_destroy,
},
.file = file,
};
return &self->as_AbstractOutputByteStream;
}

View File

@ -0,0 +1,93 @@
#ifndef COMMON_UTIL_BYTE_STREAM_H_
#define COMMON_UTIL_BYTE_STREAM_H_
#include "common/util/byte_slice.h"
#include <stdio.h>
typedef struct abstract_input_byte_stream AbstractInputByteStream;
typedef struct abstract_output_byte_stream AbstractOutputByteStream;
struct abstract_input_byte_stream {
size_t (*read)(AbstractInputByteStream *self, MutByteSlice buf);
bool (*is_end)(AbstractInputByteStream *self);
void (*destroy)(AbstractInputByteStream *self);
};
struct abstract_output_byte_stream {
void (*write)(AbstractOutputByteStream *self, ByteSlice bytes);
void (*destroy)(AbstractOutputByteStream *self);
};
// file is borrowed, not moved
AbstractInputByteStream *file_as_input_byte_stream(FILE *file);
AbstractOutputByteStream *file_as_output_byte_stream(FILE *file);
HEADER_FN size_t
byte_stream_read_to(AbstractInputByteStream *stream, MutByteSlice buf)
{
if (!stream->read) {
return 0;
}
return stream->read(stream, buf);
}
HEADER_FN MutByteSlice
byte_stream_read_alloc(AbstractInputByteStream *stream, size_t amount)
{
if (!stream->read) {
return EMPTY_MUT_BYTE_SLICE;
}
MutByteSlice buf = byte_slice_alloc(amount);
if (!buf.data) {
return EMPTY_MUT_BYTE_SLICE;
}
size_t actual = stream->read(stream, buf);
if (actual < buf.length) {
buf.length = actual;
}
return buf;
}
HEADER_FN bool
byte_stream_is_end(AbstractInputByteStream *stream)
{
if (!stream->read) {
return true;
}
if (!stream->is_end) {
return false;
}
return stream->is_end(stream);
}
HEADER_FN void
byte_stream_write(AbstractOutputByteStream *stream, ByteSlice bytes)
{
if (!stream->write) {
return;
}
return stream->write(stream, bytes);
}
HEADER_FN void
input_byte_stream_destroy(AbstractInputByteStream *stream)
{
if (!stream->destroy) {
free(stream);
return;
}
stream->destroy(stream);
}
HEADER_FN void
output_byte_stream_destroy(AbstractOutputByteStream *stream)
{
if (!stream->destroy) {
free(stream);
return;
}
stream->destroy(stream);
}
#endif /* end of include guard: COMMON_UTIL_BYTE_STREAM_H_ */

View File

@ -2,6 +2,7 @@
#include <stdio.h> #include <stdio.h>
#include "common/util/hash_table.h" #include "common/util/hash_table.h"
#include "common/util/byte_serdes.h"
int int
main(int argc, char **argv) main(int argc, char **argv)