2023-10-10 09:35:43 +00:00
|
|
|
///
|
|
|
|
/// \file TLV.h
|
|
|
|
/// \author K. Isom <kyle@imap.cc>
|
|
|
|
/// \date 2023-10-06
|
|
|
|
/// \brief TLV.h implements basic tag-length-value records.
|
|
|
|
///
|
|
|
|
/// TLV implements tag-length-value (TLV) records. Each record can have
|
|
|
|
/// a maximum length of 253 bytes; each TLV record occupies a fixed 255
|
|
|
|
/// bytes in memory. TLV records don't allocate memory.
|
|
|
|
///
|
|
|
|
/// This system uses an Arena as a backing store.
|
|
|
|
///
|
|
|
|
|
2023-10-06 03:13:46 +00:00
|
|
|
#ifndef KIMODEM_TLV_H
|
|
|
|
#define KIMODEM_TLV_H
|
|
|
|
|
|
|
|
#include <cstdint>
|
2023-10-10 09:35:43 +00:00
|
|
|
#include <array>
|
2023-10-06 03:13:46 +00:00
|
|
|
|
|
|
|
#include "Arena.h"
|
|
|
|
|
2023-10-09 22:23:23 +00:00
|
|
|
|
2023-10-10 09:35:43 +00:00
|
|
|
namespace klib {
|
|
|
|
namespace TLV {
|
2023-10-06 03:13:46 +00:00
|
|
|
|
|
|
|
#ifndef TLV_MAX_LEN
|
2023-10-10 09:35:43 +00:00
|
|
|
static constexpr size_t TLV_MAX_LEN = 253;
|
2023-10-06 03:13:46 +00:00
|
|
|
#endif
|
|
|
|
|
2023-10-10 09:35:43 +00:00
|
|
|
static constexpr uint8_t TAG_EMPTY = 0;
|
2023-10-06 03:13:46 +00:00
|
|
|
|
|
|
|
|
2023-10-10 09:35:43 +00:00
|
|
|
/// Record describes a tag-length-value record.
|
|
|
|
///
|
|
|
|
/// TLV records occupy a fixed size in memory, which can be controlled with the
|
|
|
|
/// TLV_MAX_LEN define. If this isn't defined, it defaults to a size of 253.
|
|
|
|
/// When writen to an Arena, it occupies Len + 2 bytes. The strings
|
|
|
|
/// are not null-terminated in the arena.
|
2023-10-06 03:13:46 +00:00
|
|
|
struct Record {
|
2023-10-10 09:35:43 +00:00
|
|
|
/// A Tag is used to identify the type of this record.
|
|
|
|
uint8_t Tag;
|
|
|
|
/// Len describes the number of bytes stored in #Val.
|
|
|
|
uint8_t Len;
|
|
|
|
/// Val contains the data in the record.
|
|
|
|
uint8_t Val[TLV_MAX_LEN];
|
2023-10-06 03:13:46 +00:00
|
|
|
};
|
|
|
|
|
2023-10-10 09:35:43 +00:00
|
|
|
/// WriteToMemory writes the TLV record into the arena at the location pointed
|
|
|
|
/// to in the arena.
|
|
|
|
///
|
|
|
|
/// \param arena The backing memory store.
|
|
|
|
/// \param cursor Pointer into the arena's memory.
|
|
|
|
/// \param rec A TLV record to be serialized.
|
|
|
|
/// \return A pointer the memory after the record.
|
|
|
|
uint8_t *WriteToMemory(Arena &arena, uint8_t *cursor, Record &rec);
|
|
|
|
|
|
|
|
/// ReadFromMemory reads a record from the memory pointed to by the cursor.
|
|
|
|
///
|
|
|
|
/// \param rec The TLV record to be filled in.
|
|
|
|
/// \param cursor A pointer into an arena's memory store.
|
|
|
|
void ReadFromMemory(Record &rec, uint8_t *cursor);
|
|
|
|
|
|
|
|
/// SetRecord sets a record.
|
|
|
|
///
|
|
|
|
/// \param rec The record to be set.
|
|
|
|
/// \param tag The record's tag.
|
|
|
|
/// \param length The record's length.
|
|
|
|
/// \param data The data to fill the record with.
|
|
|
|
void SetRecord(Record &rec, uint8_t tag, uint8_t length, const char *data);
|
|
|
|
|
|
|
|
/// DeleteRecord removes the record from the arena. All records ahead of this
|
|
|
|
/// record are shifted backwards so that there are no gaps.
|
|
|
|
void DeleteRecord(Arena &arena, uint8_t *cursor);
|
2023-10-06 03:13:46 +00:00
|
|
|
|
2023-10-06 06:08:35 +00:00
|
|
|
/*
|
2023-10-09 22:23:23 +00:00
|
|
|
* returns a pointer to memory where the record was found,
|
|
|
|
* e.g. LocateTag(...)[0] is the tag of the found record.
|
|
|
|
* FindTag will call LocateTag and then SkipRecord if the
|
|
|
|
* tag was found.
|
|
|
|
*/
|
2023-10-10 09:35:43 +00:00
|
|
|
/// FindTag finds the next occurrence of the record's tag.
|
|
|
|
///
|
|
|
|
/// The record must have a tag set, which tells FindTag which tag to look for.
|
|
|
|
/// If found, it fills the record. \see LocateTag.
|
|
|
|
///
|
|
|
|
/// \param arena The backing memory for the TLV store.
|
|
|
|
/// \param cursor A pointer to memory inside the arena; if it's NULL, the
|
|
|
|
/// search starts at the beginning of the arena.
|
|
|
|
/// \param rec The record to be filled.
|
|
|
|
/// \return If the tag is found, a cursor pointing to the next record is
|
|
|
|
/// returned; otherwise nullptr is returned.
|
|
|
|
uint8_t *FindTag(Arena &arena, uint8_t *cursor, Record &rec);
|
|
|
|
|
|
|
|
/// LocateTag operates similarly to FindTag, but the cursor points to the
|
|
|
|
/// beginning of the found record.
|
|
|
|
///
|
|
|
|
/// \param arena The backing memory for the TLV store.
|
|
|
|
/// \param cursor A pointer to memory inside the arena; if it's NULL, the
|
|
|
|
/// search starts at the beginning of the arena.
|
|
|
|
/// \param rec The record to be filled.
|
|
|
|
/// \return If the tag is found, a cursor pointing to the record is
|
|
|
|
/// returned; otherwise nullptr is returned.
|
|
|
|
uint8_t *LocateTag(Arena &arena, uint8_t *cursor, Record &rec);
|
|
|
|
|
|
|
|
/// FindEmpty finds a pointer the next available empty space.
|
|
|
|
///
|
|
|
|
/// \return A cursor to the start of empty space in the arena, or nullptr
|
|
|
|
/// if there is no more empty space available.
|
|
|
|
///
|
|
|
|
/// \param arena The backing memory for the TLV store.
|
|
|
|
/// \param cursor A pointer to memory inside the arena; if it's NULL, the
|
|
|
|
/// search starts at the beginning of the arena.
|
|
|
|
/// \return If the arena has space available, a cursor pointing the start
|
|
|
|
/// of empty space; otherwise, nullptr is returned.
|
|
|
|
uint8_t *FindEmpty(Arena &arena, uint8_t *cursor);
|
|
|
|
|
|
|
|
/// SkipRecord skips the cursor to the next record.
|
|
|
|
///
|
|
|
|
/// \param rec The record that should be skipped.
|
|
|
|
/// \param cursor A pointer to the record in the arena.
|
|
|
|
/// \return The pointer to the next record in the arena.
|
|
|
|
uint8_t *SkipRecord(Record &rec, uint8_t *cursor);
|
2023-10-06 03:13:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
} // namespace TLV
|
2023-10-09 22:23:23 +00:00
|
|
|
} // namespace klib
|
2023-10-06 03:13:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
#endif
|