add buffer read/write functions with cursors

This commit is contained in:
2026-10-16 14:25:18 +02:00
parent c475e8b4fe
commit 945cc56d98
4 changed files with 299 additions and 0 deletions
+5
View File
@@ -19,6 +19,11 @@ extern "C" {
#define BRAVAIS_NO_TIMEOUT UINT64_MAX #define BRAVAIS_NO_TIMEOUT UINT64_MAX
#define BRAVAIS_MAX_DATAGRAM_SIZE 1500
#define BRAVAIS_MAX_PLAINTEXT_SIZE 65535
#define BRAVAIS_KEY_LENGTH 32 // For X25519 private and public - do PQC later
typedef enum { typedef enum {
// Error codes; Generally <0 = error, 0 = success // Error codes; Generally <0 = error, 0 = success
BRAVAIS_EMPTY = 1, // Nothing to emit right now BRAVAIS_EMPTY = 1, // Nothing to emit right now
+208
View File
@@ -0,0 +1,208 @@
#include "buf.h"
#include "intutils.h"
// Internal claim functions to avoid code duplication in the cursor functions
static const uint8_t* rcur_claim(bravais_rcur_t* cur, size_t n) {
if (cur->failed || n > cur->len - cur->pos) {
cur->failed = true;
return nullptr;
}
if (cur->base == nullptr) {
return nullptr;
}
const uint8_t* start = cur->base + cur->pos;
cur->pos += n;
return start;
}
static uint8_t* wcur_claim(bravais_wcur_t* cur, size_t n) {
if (cur->failed || n > cur->len - cur->pos) {
cur->failed = true;
return nullptr;
}
if (cur->base == nullptr) {
return nullptr;
}
uint8_t* start = cur->base + cur->pos;
cur->pos += n;
return start;
}
void bravais_rcur_init(bravais_rcur_t* cur, const uint8_t* buf, size_t len) {
cur->buf = buf;
cur->len = len;
cur->pos = 0;
cur->failed = false;
}
uint8_t bravais_rcur_u8(bravais_rcur_t* cur) {
const uint8_t* ptr = rcur_claim(cur, 1);
if (ptr == nullptr) {
return 0;
}
return ptr[0];
}
uint16_t bravais_rcur_u16(bravais_rcur_t* cur) {
const uint8_t* ptr = rcur_claim(cur, 2);
if (ptr == nullptr) {
return 0;
}
// Assemble from bytes in big-endian order
uint16_t val = (uint16_t)((ptr[0] << 8) | ptr[1]);
return val;
}
uint32_t bravais_rcur_u32(bravais_rcur_t* cur) {
const uint8_t* ptr = rcur_claim(cur, 4);
if (ptr == nullptr) {
return 0;
}
// Assemble from bytes in big-endian order
uint32_t val = (uint32_t)((ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3]);
return val;
}
uint64_t bravais_rcur_u64(bravais_rcur_t* cur) {
const uint8_t* ptr = rcur_claim(cur, 8);
if (ptr == nullptr) {
return 0;
}
// Assemble from bytes in big-endian order
uint64_t val = ((uint64_t)ptr[0] << 56)
| ((uint64_t)ptr[1] << 48)
| ((uint64_t)ptr[2] << 40)
| ((uint64_t)ptr[3] << 32)
| ((uint64_t)ptr[4] << 24)
| ((uint64_t)ptr[5] << 16)
| ((uint64_t)ptr[6] << 8)
| ((uint64_t)ptr[7]);
return val;
}
void bravais_rcur_bytes(bravais_rcur_t* cur, uint8_t* outBuf, size_t len) {
if (len <= 0) { return; }
const uint8_t* ptr = rcur_claim(cur, len);
if (ptr == nullptr) {
memset(outBuf, 0, len);
return;
}
memcpy(outBuf, ptr, len);
}
const uint8_t* bravais_rcur_slice(bravais_rcur_t* cur, size_t len) {
return rcur_claim(cur, len);
}
void bravais_rcur_skip(bravais_rcur_t* cur, size_t len) {
(void)rcur_claim(cur, len);
}
size_t bravais_rcur_remaining(const bravais_rcur_t* cur) {
if (cur->failed) {
return 0;
}
return cur->len - cur->pos;
}
bool bravais_rcur_ok(const bravais_rcur_t* cur) {
return !cur->failed;
}
void bravais_wcur_init(bravais_wcur_t* cur, uint8_t* buf, size_t len) {
cur->buf = buf;
cur->len = len;
cur->pos = 0;
cur->failed = false;
}
void bravais_wcur_u8(bravais_wcur_t* cur, uint8_t val) {
uint8_t* ptr = wcur_claim(cur, 1);
if (ptr == nullptr) {
return;
}
ptr[0] = val;
}
void bravais_wcur_u16(bravais_wcur_t* cur, uint16_t val) {
uint8_t* ptr = wcur_claim(cur, 2);
if (ptr == nullptr) {
return;
}
// Assemble into bytes in big-endian order
ptr[0] = (uint8_t)(val >> 8);
ptr[1] = (uint8_t)(val);
}
void bravais_wcur_u32(bravais_wcur_t* cur, uint32_t val) {
uint8_t* ptr = wcur_claim(cur, 4);
if (ptr == nullptr) {
return;
}
ptr[0] = (uint8_t)(val >> 24);
ptr[1] = (uint8_t)(val >> 16);
ptr[2] = (uint8_t)(val >> 8);
ptr[3] = (uint8_t)(val);
}
void bravais_wcur_u64(bravais_wcur_t* cur, uint64_t val) {
uint8_t* ptr = wcur_claim(cur, 8);
if (ptr == nullptr) {
return;
}
ptr[0] = (uint8_t)(val >> 56);
ptr[1] = (uint8_t)(val >> 48);
ptr[2] = (uint8_t)(val >> 40);
ptr[3] = (uint8_t)(val >> 32);
ptr[4] = (uint8_t)(val >> 24);
ptr[5] = (uint8_t)(val >> 16);
ptr[6] = (uint8_t)(val >> 8);
ptr[7] = (uint8_t)(val);
}
void bravais_wcur_bytes(bravais_wcur_t* cur, const uint8_t* val, size_t len) {
if (len <= 0) { return; }
uint8_t* ptr = wcur_claim(cur, len);
if (ptr == nullptr) {
return;
}
memcpy(ptr, val, len);
}
size_t bravais_wcur_written(const bravais_wcur_t* cur) {
return cur->pos;
}
size_t bravais_wcur_remaining(const bravais_wcur_t* cur) {
if (cur->failed) {
return 0;
}
return cur->len - cur->pos;
}
bool bravais_wcur_ok(const bravais_wcur_t* cur) {
return !cur->failed;
}
+54
View File
@@ -0,0 +1,54 @@
// buf.h
// Bounds-checked cursors over a buffer/byte range.
//
// Sticky-failure flags - if an op runs past the end, it sets a "failed" flag and returns a no-op zero value.
// Check with bravais_<w/r>cur_ok() at the end of a serialization/deserialization operation to see if it succeeded.
//
// Multi-byte integer serialization is big-endian, as per the network order convention. Variable-length might live somewhere else later.
//
// A slice gets returned by bravais_rcur_slice() and points into the underlying buffer.
#ifndef BRAVAIS_BUF_H
#define BRAVAIS_BUF_H
#include <stddef.h>
#include <stdint.h>
typedef struct {
const uint8_t* buf;
size_t len;
size_t pos;
bool failed;
} bravais_rcur_t;
typedef struct {
uint8_t* buf;
size_t len;
size_t pos;
bool failed;
} bravais_wcur_t;
// Reader cursor functions
void bravais_rcur_init(bravais_rcur_t* cur, const uint8_t* buf, size_t len);
uint8_t bravais_rcur_u8(bravais_rcur_t* cur);
uint16_t bravais_rcur_u16(bravais_rcur_t* cur);
uint32_t bravais_rcur_u32(bravais_rcur_t* cur);
uint64_t bravais_rcur_u64(bravais_rcur_t* cur);
void bravais_rcur_bytes(bravais_rcur_t* cur, uint8_t* outBuf, size_t len); // zero-fills on failure
const uint8_t* bravais_rcur_slice(bravais_rcur_t* cur, size_t len); // returns NULL on failure, borrows
void bravais_rcur_skip(bravais_rcur_t* cur, size_t len); // skips bytes, sets failed on overflow
size_t bravais_rcur_remaining(const bravais_rcur_t* cur); // How many bytes are left to read
bool bravais_rcur_ok(const bravais_rcur_t* cur);
// Writer cursor functions
void bravais_wcur_init(bravais_wcur_t* cur, uint8_t* buf, size_t len);
void bravais_wcur_u8(bravais_wcur_t* cur, uint8_t val);
void bravais_wcur_u16(bravais_wcur_t* cur, uint16_t val);
void bravais_wcur_u32(bravais_wcur_t* cur, uint32_t val);
void bravais_wcur_u64(bravais_wcur_t* cur, uint64_t val);
void bravais_wcur_bytes(bravais_wcur_t* cur, const uint8_t* val, size_t len);
size_t bravais_wcur_written(const bravais_wcur_t* cur); // How many bytes have been written so far
size_t bravais_wcur_remaining(const bravais_wcur_t* cur); // How many bytes are left to write
bool bravais_wcur_ok(const bravais_wcur_t* cur);
#endif // BRAVAIS_BUF_H
+32
View File
@@ -0,0 +1,32 @@
// intutils.h
// Utilities for integers (byte order flipping for now)
#ifndef BRAVAIS_INTUTILS_H
#define BRAVAIS_INTUTILS_H
#include <stddef.h>
#include <stdint.h>
static inline uint16_t bravais_bswap16(uint16_t x) {
return (uint16_t)((x << 8) | (x >> 8));
}
static inline uint32_t bravais_bswap32(uint32_t x) {
return (uint32_t)(((x & 0x000000FF) << 24) |
((x & 0x0000FF00) << 8) |
((x & 0x00FF0000) >> 8) |
((x & 0xFF000000) >> 24));
}
static inline uint64_t bravais_bswap64(uint64_t x) {
return (uint64_t)(((x & 0x00000000000000FFULL) << 56) |
((x & 0x000000000000FF00ULL) << 40) |
((x & 0x0000000000FF0000ULL) << 24) |
((x & 0x00000000FF000000ULL) << 8) |
((x & 0x000000FF00000000ULL) >> 8) |
((x & 0x0000FF0000000000ULL) >> 24) |
((x & 0x00FF000000000000ULL) >> 40) |
((x & 0xFF00000000000000ULL) >> 56));
}
#endif // BRAVAIS_INTUTILS_H