scsl/TLV.cc

152 lines
2.5 KiB
C++

#include <cstring>
#include "TLV.h"
#define REC_SIZE(x) ((std::size_t)x.Len + 2)
namespace TLV {
static bool
space_available(Arena &arena, uint8_t *cursor, uint8_t len)
{
uintptr_t remaining = 0;
if (cursor == NULL) {
return false;
}
remaining = (uintptr_t)cursor - (uintptr_t)arena.store;
remaining = arena.size - remaining;
return ((size_t)remaining >= ((size_t)len+2));
}
uint8_t *
write_to_memory(Arena &arena, uint8_t *cursor, Record &rec)
{
// If cursor is NULL, the user needs us to select an empty
// slot for the record. If we can't find one, that's an
// error.
//
// If, however, the user gives us a cursor, we'll trust it
// (though space_available will sanity check that cursor).
if (cursor == NULL) {
cursor = find_empty(arena, cursor);
if (cursor == NULL) {
return NULL;
}
}
if (!space_available(arena, cursor, rec.Len)) {
return NULL;
}
memcpy(cursor, &rec, REC_SIZE(rec));
cursor = skip_record(rec, cursor);
return cursor;
}
void
set_record(Record &rec, uint8_t tag, uint8_t len, const char *val)
{
uint8_t trail = TLV_MAX_LEN-len;
rec.Tag = tag;
rec.Len = len;
memcpy(rec.Val, val, len);
memset(rec.Val+len, 0, trail);
}
void
read_from_memory(Record &rec, uint8_t *cursor)
{
rec.Tag = cursor[0];
rec.Len = cursor[1];
memcpy(rec.Val, cursor+2, rec.Len);
}
/*
* returns a pointer to memory where the record was found,
* e.g. find_tag(...)[0] is the tag of the found record.
*/
uint8_t *
find_tag(Arena &arena, uint8_t *cursor, Record &rec)
{
uint8_t tag, len;
if (cursor == NULL) {
cursor = arena.store;
}
while ((tag = cursor[0]) != rec.Tag) {
len = cursor[1];
if (!space_available(arena, cursor, len)) {
return NULL;
}
cursor += len;
cursor += 2;
}
if (tag != rec.Tag) {
return NULL;
}
if (tag != TAG_EMPTY) {
read_from_memory(rec, cursor);
cursor = skip_record(rec, cursor);
}
return cursor;
}
uint8_t *
find_empty(Arena &arena, uint8_t *cursor) {
Record rec;
rec.Tag = TAG_EMPTY;
return find_tag(arena, cursor, rec);
}
uint8_t *
skip_record(Record &rec, uint8_t *cursor)
{
return (uint8_t *)((uintptr_t)cursor + rec.Len + 2);
}
void
delete_record(Arena &arena, uint8_t *cursor)
{
//
if (cursor == NULL) {
return;
}
uint8_t len = cursor[1] + 2;
uint8_t *stop = arena.store + arena.size;
stop -= len;
while (cursor != stop) {
cursor[0] = cursor[len];
cursor++;
}
stop += len;
while (cursor != stop) {
cursor[0] = 0;
cursor++;
}
}
} // namespace TLV