add buffer read/write functions with cursors
This commit is contained in:
@@ -19,6 +19,11 @@ extern "C" {
|
||||
|
||||
#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 {
|
||||
// Error codes; Generally <0 = error, 0 = success
|
||||
BRAVAIS_EMPTY = 1, // Nothing to emit right now
|
||||
|
||||
+208
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user