diff --git a/crates/sesam-vitale/src/main.rs b/crates/sesam-vitale/src/main.rs index 77bd4e9..dfe2455 100644 --- a/crates/sesam-vitale/src/main.rs +++ b/crates/sesam-vitale/src/main.rs @@ -1,5 +1,6 @@ mod ssvlib_demo; mod libssv; +mod ssv_memory; fn main() { ssvlib_demo::demo(); diff --git a/crates/sesam-vitale/src/ssv_memory.rs b/crates/sesam-vitale/src/ssv_memory.rs new file mode 100644 index 0000000..1031ec2 --- /dev/null +++ b/crates/sesam-vitale/src/ssv_memory.rs @@ -0,0 +1,119 @@ +/** + * Provide functions to manipulate raw memory from SSV library. + */ + +// TODO : Est-ce qu'on pourrait/devrait définir un type custom pour représenter les tableaux de bytes ? + +#[derive(PartialEq, Debug)] +pub struct ElementSize { + pub size: usize, + pub pad: usize, +} + +#[derive(PartialEq, Debug)] +pub enum MemoryParsingError<'a> { + MemoryIsEmpty(&'a str), + MemoryIsNotValid(&'a str), +} + +pub fn read_element_size(bytes: &[u8]) -> Result { + /* Longueur: + * - si le bit de poids fort du premier octet est à 0, la longueur est codée sur un octet + * - si le bit de poids fort du premier octet est à 1, les 7 bits de poids faible codent le nombre d'octets utilisés pour coder la longueur + */ + if bytes.len() == 0 { + return Err(MemoryParsingError::MemoryIsEmpty("Empty bytes input")); + } + + let mut element_size = ElementSize { size: 0, pad: 1 }; + if bytes[0] & 0b1000_0000 == 0 { + // Size coded on 1 byte + element_size.size = bytes[0] as usize; + } else { + // Size coded on N bytes + // N are the 7 lower bits of the first byte + let size_bytes_len = (bytes[0] & 0b0111_1111) as usize; + if size_bytes_len > bytes.len() - 1 { + return Err(MemoryParsingError::MemoryIsNotValid( + "Invalid memory: not enough bytes to read the size", + )); + } else if size_bytes_len > 4 { + return Err(MemoryParsingError::MemoryIsNotValid( + "Invalid memory: size is too big", + )); + } + let size_bytes = &bytes[1..1 + size_bytes_len]; + + // u32::from_be_bytes() requires a 4 bytes array + let mut padded_bytes = [0u8; 4]; + padded_bytes[size_bytes_len..].copy_from_slice(&size_bytes); + + element_size.size = u32::from_be_bytes(padded_bytes) as usize; + element_size.pad += size_bytes_len; + } + Ok(element_size) +} + +#[cfg(test)] +mod test_read_element_size { + use super::*; + + #[test] + fn short_size() { + let bytes = [0b_0000_0001_u8]; + let element_size = read_element_size(&bytes).unwrap(); + assert_eq!(element_size.size, 1); + assert_eq!(element_size.pad, 1); + + let bytes = [0b_0100_0000_u8]; + let element_size = read_element_size(&bytes).unwrap(); + assert_eq!(element_size.size, 64); + assert_eq!(element_size.pad, 1); + } + + #[test] + fn long_size() { + let bytes = [0b_1000_0010_u8, 0b_0000_0001_u8, 0b_0100_0000_u8]; + let element_size = read_element_size(&bytes).unwrap(); + assert_eq!(element_size.size, 320); + assert_eq!(element_size.pad, 3); + } + + #[test] + fn null_size() { + let bytes = []; + let toto = "toto"; + // Expect an error + assert_eq!( + read_element_size(&bytes), + Err(MemoryParsingError::MemoryIsEmpty("Empty bytes input")), + ); + } + + #[test] + fn invalid_memory() { + let bytes = [0b_1000_0001_u8]; + assert_eq!( + read_element_size(&bytes), + Err(MemoryParsingError::MemoryIsNotValid( + "Invalid memory: not enough bytes to read the size" + )), + ); + + let bytes = [0b_1000_0010_u8, 1]; + assert_eq!( + read_element_size(&bytes), + Err(MemoryParsingError::MemoryIsNotValid( + "Invalid memory: not enough bytes to read the size" + )), + ); + + let bytes = [0b_1000_0101_u8, 1, 1, 1, 1, 1]; + assert_eq!( + read_element_size(&bytes), + Err(MemoryParsingError::MemoryIsNotValid( + "Invalid memory: size is too big" + )), + ); + } +}