use std::{
convert::TryFrom,
fmt::{Debug, Display},
io::{Read, Write},
ops::Deref,
str::FromStr,
};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum FieldType {
Tag,
Type,
Length,
Value,
LengthAndValue, TypeAndLengthAndValue, }
impl Default for FieldType {
fn default() -> Self {
Self::Tag
}
}
impl Display for FieldType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
FieldType::Tag => f.write_str("Tag"),
FieldType::Type => f.write_str("Type"),
FieldType::Length => f.write_str("Length"),
FieldType::Value => f.write_str("Value"),
FieldType::LengthAndValue => f.write_str("LengthAndValue"),
FieldType::TypeAndLengthAndValue => f.write_str("TypeAndLengthAndValue"),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ByteOffset(pub u64);
impl std::ops::Deref for ByteOffset {
type Target = u64;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<&u64> for ByteOffset {
fn from(v: &u64) -> Self {
ByteOffset(*v)
}
}
impl From<u64> for ByteOffset {
fn from(v: u64) -> Self {
ByteOffset(v)
}
}
impl TryFrom<usize> for ByteOffset {
type Error = ();
fn try_from(value: usize) -> std::result::Result<Self, Self::Error> {
if value < (u64::MAX as usize) {
Ok(ByteOffset(value as u64))
} else {
Err(())
}
}
}
impl<T> From<&std::io::Cursor<T>> for ByteOffset {
fn from(cursor: &std::io::Cursor<T>) -> Self {
ByteOffset(cursor.position())
}
}
impl<T> From<std::io::Cursor<T>> for ByteOffset {
fn from(cursor: std::io::Cursor<T>) -> Self {
ByteOffset(cursor.position())
}
}
#[derive(Debug)]
#[allow(clippy::enum_variant_names)]
pub enum Error {
IoError(std::io::Error),
InvalidTtlvTag(String),
UnexpectedTtlvField {
expected: FieldType,
actual: FieldType,
},
UnsupportedTtlvType(u8),
InvalidTtlvType(u8),
InvalidTtlvValueLength {
expected: u32,
actual: u32,
r#type: TtlvType,
},
InvalidTtlvValue(TtlvType),
InvalidStateMachineOperation,
}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Error::IoError(e)
}
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct TtlvTag(u32);
impl TtlvTag {
pub fn read<T: Read>(src: &mut T) -> Result<Self> {
let mut raw_item_tag = [0u8; 3];
src.read_exact(&mut raw_item_tag)?;
Ok(TtlvTag::from(raw_item_tag))
}
pub fn write<T: Write>(&self, dst: &mut T) -> Result<()> {
dst.write_all(&<[u8; 3]>::from(self)).map_err(Error::IoError)
}
}
impl Debug for TtlvTag {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("0x{:0X}", &self.0))
}
}
impl Deref for TtlvTag {
type Target = u32;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl FromStr for TtlvTag {
type Err = Error;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
let v =
u32::from_str_radix(s.trim_start_matches("0x"), 16).map_err(|_| Error::InvalidTtlvTag(s.to_string()))?;
Ok(TtlvTag(v))
}
}
impl std::fmt::Display for TtlvTag {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "0x{:06X}", self)
}
}
impl std::fmt::UpperHex for TtlvTag {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:X}", self.0)
}
}
impl From<TtlvTag> for [u8; 3] {
fn from(tag: TtlvTag) -> Self {
<[u8; 3]>::from(&tag)
}
}
impl From<&TtlvTag> for [u8; 3] {
fn from(tag: &TtlvTag) -> Self {
let b: [u8; 4] = tag.to_be_bytes();
[b[1], b[2], b[3]]
}
}
impl From<[u8; 3]> for TtlvTag {
fn from(b: [u8; 3]) -> Self {
TtlvTag(u32::from_be_bytes([0x00u8, b[0], b[1], b[2]]))
}
}
impl From<&[u8; 3]> for TtlvTag {
fn from(b: &[u8; 3]) -> Self {
TtlvTag(u32::from_be_bytes([0x00u8, b[0], b[1], b[2]]))
}
}
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum TtlvType {
Structure = 0x01,
Integer = 0x02,
LongInteger = 0x03,
BigInteger = 0x04,
Enumeration = 0x05,
Boolean = 0x06,
TextString = 0x07,
ByteString = 0x08,
DateTime = 0x09,
}
impl TtlvType {
pub fn read<T: Read>(src: &mut T) -> Result<Self> {
let mut raw_item_type = [0u8; 1];
src.read_exact(&mut raw_item_type)?;
TtlvType::try_from(raw_item_type[0])
}
pub fn write<T: Write>(&self, dst: &mut T) -> Result<()> {
dst.write_all(&[*self as u8]).map_err(Error::IoError)
}
}
impl std::fmt::Display for TtlvType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TtlvType::Structure => f.write_str("Structure (0x01)"),
TtlvType::Integer => f.write_str("Integer (0x02)"),
TtlvType::LongInteger => f.write_str("LongInteger (0x03)"),
TtlvType::BigInteger => f.write_str("BigInteger (0x04)"),
TtlvType::Enumeration => f.write_str("Enumeration (0x05)"),
TtlvType::Boolean => f.write_str("Boolean (0x06)"),
TtlvType::TextString => f.write_str("TextString (0x07)"),
TtlvType::ByteString => f.write_str("ByteString (0x08)"),
TtlvType::DateTime => f.write_str("DateTime (0x09)"),
}
}
}
impl TryFrom<u8> for TtlvType {
type Error = Error;
fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
match value {
0x01 => Ok(TtlvType::Structure),
0x02 => Ok(TtlvType::Integer),
0x03 => Ok(TtlvType::LongInteger),
0x04 => Ok(TtlvType::BigInteger),
0x05 => Ok(TtlvType::Enumeration),
0x06 => Ok(TtlvType::Boolean),
0x07 => Ok(TtlvType::TextString),
0x08 => Ok(TtlvType::ByteString),
0x09 => Ok(TtlvType::DateTime),
0x0A => Err(Error::UnsupportedTtlvType(0x0A)),
_ => Err(Error::InvalidTtlvType(value)),
}
}
}
impl From<TtlvType> for [u8; 1] {
fn from(item_type: TtlvType) -> Self {
[item_type as u8]
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct TtlvLength(u32);
impl TtlvLength {
pub fn new(value: u32) -> Self {
Self(value)
}
pub fn read<T: Read>(src: &mut T) -> Result<Self> {
let mut value_length = [0u8; 4];
src.read_exact(&mut value_length)?;
Ok(Self(u32::from_be_bytes(value_length)))
}
pub fn write<T: Write>(&self, dst: &mut T) -> Result<()> {
dst.write_all(&self.0.to_be_bytes()).map_err(Error::IoError)
}
}
impl Debug for TtlvLength {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("0x{:0X}", &self.0))
}
}
impl Deref for TtlvLength {
type Target = u32;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::fmt::Display for TtlvLength {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "0x{:08X}", self)
}
}
impl std::fmt::UpperHex for TtlvLength {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:X}", self.0)
}
}
pub trait SerializableTtlvType: Sized + Deref {
const TTLV_TYPE: TtlvType;
fn ttlv_type(&self) -> TtlvType {
Self::TTLV_TYPE
}
fn calc_pad_bytes(value_len: u32) -> u32 {
let remainder = value_len % 8;
if remainder == 0 {
0
} else {
8 - remainder
}
}
fn read_pad_bytes<T: Read>(src: &mut T, value_len: u32) -> Result<()> {
let num_pad_bytes = Self::calc_pad_bytes(value_len) as usize;
if num_pad_bytes > 0 {
let mut dst = [0u8; 8];
src.read_exact(&mut dst[..num_pad_bytes])?;
}
Ok(())
}
fn write_pad_bytes<T: Write>(dst: &mut T, value_len: u32) -> Result<()> {
let num_pad_bytes = Self::calc_pad_bytes(value_len) as usize;
if num_pad_bytes > 0 {
const PADDING_BYTES: [u8; 8] = [0; 8];
dst.write_all(&PADDING_BYTES[..num_pad_bytes])?;
}
Ok(())
}
fn read<T: Read>(src: &mut T) -> Result<Self> {
let mut value_len = [0u8; 4];
src.read_exact(&mut value_len)?; let value_len = u32::from_be_bytes(value_len);
let v = Self::read_value(src, value_len)?; Self::read_pad_bytes(src, value_len)?; Ok(v)
}
fn write<T: Write>(&self, dst: &mut T) -> Result<()> {
dst.write_all(&[Self::TTLV_TYPE as u8])?; let value_len = self.write_length_and_value(dst)?; Self::write_pad_bytes(dst, value_len) }
fn read_value<T: Read>(src: &mut T, value_len: u32) -> Result<Self>;
fn write_length_and_value<T: Write>(&self, dst: &mut T) -> Result<u32>;
}
macro_rules! define_fixed_value_length_serializable_ttlv_type {
($(#[$meta:meta])* $NEW_TYPE_NAME:ident, $TTLV_ITEM_TYPE:expr, $RUST_TYPE:ty, $TTLV_VALUE_LEN:literal) => {
#[derive(Clone, Debug)]
$(#[$meta])*
pub struct $NEW_TYPE_NAME(pub $RUST_TYPE);
impl $NEW_TYPE_NAME {
const TTLV_FIXED_VALUE_LENGTH: u32 = $TTLV_VALUE_LEN;
}
impl Deref for $NEW_TYPE_NAME {
type Target = $RUST_TYPE;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl SerializableTtlvType for $NEW_TYPE_NAME {
const TTLV_TYPE: TtlvType = $TTLV_ITEM_TYPE;
fn read_value<T: Read>(src: &mut T, value_len: u32) -> Result<Self> {
if value_len != Self::TTLV_FIXED_VALUE_LENGTH {
Err(Error::InvalidTtlvValueLength {
expected: Self::TTLV_FIXED_VALUE_LENGTH,
actual: value_len,
r#type: Self::TTLV_TYPE,
})
} else {
let mut dst = [0u8; Self::TTLV_FIXED_VALUE_LENGTH as usize];
src.read_exact(&mut dst)?;
let v: $RUST_TYPE = <$RUST_TYPE>::from_be_bytes(dst);
Ok($NEW_TYPE_NAME(v))
}
}
fn write_length_and_value<T: Write>(&self, dst: &mut T) -> Result<u32> {
dst.write_all(&Self::TTLV_FIXED_VALUE_LENGTH.to_be_bytes())?; dst.write_all(&self.0.to_be_bytes())?; Ok(Self::TTLV_FIXED_VALUE_LENGTH)
}
}
};
}
define_fixed_value_length_serializable_ttlv_type!(
TtlvInteger,
TtlvType::Integer,
i32,
4
);
define_fixed_value_length_serializable_ttlv_type!(
TtlvLongInteger,
TtlvType::LongInteger,
i64,
8
);
#[derive(Clone, Debug)]
pub struct TtlvBigInteger(pub Vec<u8>);
impl Deref for TtlvBigInteger {
type Target = Vec<u8>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl SerializableTtlvType for TtlvBigInteger {
const TTLV_TYPE: TtlvType = TtlvType::BigInteger;
fn read_value<T: Read>(src: &mut T, value_len: u32) -> Result<Self> {
let mut dst = vec![0; value_len as usize];
src.read_exact(&mut dst)?;
Ok(TtlvBigInteger(dst))
}
fn write_length_and_value<T: Write>(&self, dst: &mut T) -> Result<u32> {
let v = self.0.as_slice();
let v_len = v.len() as u32;
let num_pad_bytes = Self::calc_pad_bytes(v_len);
let v_len = v_len + num_pad_bytes;
dst.write_all(&v_len.to_be_bytes())?; let pad_byte = if v_len > 0 && v[0] & 0b1000_0000 == 0b1000_0000 {
0b1111_1111
} else {
0b0000_0000
};
for _ in 1..=num_pad_bytes {
dst.write_all(&[pad_byte])?;
}
dst.write_all(v)?; Ok(v_len)
}
}
define_fixed_value_length_serializable_ttlv_type!(
TtlvEnumeration,
TtlvType::Enumeration,
u32,
4
);
#[derive(Clone, Debug)]
pub struct TtlvBoolean(pub bool);
impl TtlvBoolean {
const TTLV_FIXED_VALUE_LENGTH: u32 = 8;
}
impl Deref for TtlvBoolean {
type Target = bool;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl SerializableTtlvType for TtlvBoolean {
const TTLV_TYPE: TtlvType = TtlvType::Boolean;
fn read_value<T: Read>(src: &mut T, value_len: u32) -> Result<Self> {
if value_len != Self::TTLV_FIXED_VALUE_LENGTH {
Err(Error::InvalidTtlvValueLength {
expected: Self::TTLV_FIXED_VALUE_LENGTH,
actual: value_len,
r#type: Self::TTLV_TYPE,
})
} else {
let mut dst = [0u8; Self::TTLV_FIXED_VALUE_LENGTH as usize];
src.read_exact(&mut dst)?;
match u64::from_be_bytes(dst) {
0 => Ok(TtlvBoolean(false)),
1 => Ok(TtlvBoolean(true)),
_ => Err(Error::InvalidTtlvValue(Self::TTLV_TYPE)),
}
}
}
fn write_length_and_value<T: Write>(&self, dst: &mut T) -> Result<u32> {
let v = match self.0 {
true => 1u64,
false => 0u64,
};
dst.write_all(&Self::TTLV_FIXED_VALUE_LENGTH.to_be_bytes())?; dst.write_all(&v.to_be_bytes())?; Ok(Self::TTLV_FIXED_VALUE_LENGTH)
}
}
#[derive(Clone, Debug)]
pub struct TtlvTextString(pub String);
impl Deref for TtlvTextString {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl SerializableTtlvType for TtlvTextString {
const TTLV_TYPE: TtlvType = TtlvType::TextString;
fn read_value<T: Read>(src: &mut T, value_len: u32) -> Result<Self> {
let mut dst = vec![0; value_len as usize];
src.read_exact(&mut dst)?;
let new_str = String::from_utf8(dst).map_err(|_| Error::InvalidTtlvValue(Self::TTLV_TYPE))?;
Ok(TtlvTextString(new_str))
}
fn write_length_and_value<T: Write>(&self, dst: &mut T) -> Result<u32> {
let v = self.0.as_bytes();
let v_len = v.len() as u32;
dst.write_all(&v_len.to_be_bytes())?; dst.write_all(v)?; Ok(v_len)
}
}
#[derive(Clone, Debug)]
pub struct TtlvByteString(pub Vec<u8>);
impl Deref for TtlvByteString {
type Target = Vec<u8>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl SerializableTtlvType for TtlvByteString {
const TTLV_TYPE: TtlvType = TtlvType::ByteString;
fn read_value<T: Read>(src: &mut T, value_len: u32) -> Result<Self> {
let mut dst = vec![0; value_len as usize];
src.read_exact(&mut dst)?;
Ok(TtlvByteString(dst))
}
fn write_length_and_value<T: Write>(&self, dst: &mut T) -> Result<u32> {
let v = self.0.as_slice();
let v_len = v.len() as u32;
dst.write_all(&v_len.to_be_bytes())?; dst.write_all(v)?; Ok(v_len)
}
}
define_fixed_value_length_serializable_ttlv_type!(
TtlvDateTime,
TtlvType::DateTime,
i64,
8
);
#[allow(dead_code)]
pub type TtlvInterval = TtlvEnumeration;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TtlvStateMachineMode {
Deserializing,
Serializing,
}
pub struct TtlvStateMachine {
mode: TtlvStateMachineMode,
expected_next_field_type: FieldType,
ignore_next_tag: bool,
}
impl TtlvStateMachine {
pub fn new(mode: TtlvStateMachineMode) -> Self {
Self {
mode,
expected_next_field_type: FieldType::default(),
ignore_next_tag: false,
}
}
pub fn advance(&mut self, next_field_type: FieldType) -> std::result::Result<bool, Error> {
use TtlvStateMachineMode as Mode;
let next_expected_next_field_type = match (self.mode, self.expected_next_field_type, next_field_type) {
(_, FieldType::Tag, FieldType::Tag) => FieldType::Type,
(_, FieldType::Type, FieldType::Type) => FieldType::Length,
(Mode::Serializing, FieldType::Type, FieldType::TypeAndLengthAndValue) => FieldType::Tag,
(_, FieldType::Length, FieldType::Length) => FieldType::Value,
(Mode::Deserializing, FieldType::Length, FieldType::LengthAndValue) => FieldType::Tag,
(_, FieldType::Value, FieldType::Value) => FieldType::Tag,
(_, FieldType::Value, FieldType::Tag) => FieldType::Type,
(Mode::Serializing, FieldType::Type, FieldType::Tag) if self.ignore_next_tag => {
self.ignore_next_tag = false;
FieldType::Type
}
(_, expected, actual) => {
return Err(Error::UnexpectedTtlvField { expected, actual });
}
};
if self.mode == Mode::Deserializing || next_expected_next_field_type != self.expected_next_field_type {
self.expected_next_field_type = next_expected_next_field_type;
Ok(true)
} else {
Ok(false)
}
}
pub fn ignore_next_tag(&mut self) -> std::result::Result<(), Error> {
if matches!(self.mode, TtlvStateMachineMode::Serializing) {
self.ignore_next_tag = true;
Ok(())
} else {
Err(Error::InvalidStateMachineOperation)
}
}
pub fn reset(&mut self) {
self.expected_next_field_type = FieldType::default();
self.ignore_next_tag = false;
}
}