use std::io::Write;
use super::{decode_v_byte, encode_v_byte, read_byte, write_byte, DecodeError, IndexEncodingVersion};
const SEQUENCE_HEADER: u8 = 0xd0;
pub fn encode_index_sequence(buffer: &mut [u8], indices: &[u32], version: IndexEncodingVersion) -> usize {
let buffer_len = buffer.len();
if buffer_len < 1 + indices.len() + 4 {
return 0;
}
let version: u8 = version.into();
let mut data = buffer;
write_byte(&mut data, SEQUENCE_HEADER | (version as u8));
let mut last: [u32; 2] = [0; 2];
let mut current = 0;
for index in indices {
if data.len() < 4 {
return 0;
}
let cd = (*index).wrapping_sub(last[current]) as i32;
current ^= if cd.abs() >= 30 { 1 } else { 0 };
let d = index.wrapping_sub(last[current]);
let v = (d << 1) ^ (((d as i32) >> 31) as u32);
encode_v_byte(&mut data, (v << 1) | (current as u32));
last[current] = *index;
}
if data.len() < 4 {
return 0;
}
data.write(&[0; 4]).unwrap();
buffer_len - data.len()
}
pub fn encode_index_sequence_bound(index_count: usize, vertex_count: usize) -> usize {
let mut vertex_bits = 1;
while vertex_bits < 32 && vertex_count > (1 << vertex_bits) {
vertex_bits += 1;
}
let vertex_groups = (vertex_bits + 1 + 1 + 6) / 7;
return 1 + index_count * vertex_groups + 4;
}
pub fn decode_index_sequence<T>(destination: &mut [T], buffer: &[u8]) -> Result<(), DecodeError>
where
T: From<u32>,
{
if buffer.len() < 1 + destination.len() + 4 {
return Err(DecodeError::UnexpectedEof);
}
let mut data = buffer;
let first = read_byte(&mut data);
if (first & 0xf0) != SEQUENCE_HEADER {
return Err(DecodeError::InvalidHeader);
}
let version = first & 0x0f;
if version > 1 {
return Err(DecodeError::UnsupportedVersion);
}
let mut last: [u32; 2] = Default::default();
for i in 0..destination.len() {
let mut v = decode_v_byte(&mut data);
let current = (v & 1) as usize;
v >>= 1;
let d = (v >> 1) ^ (-((v & 1) as i32) as u32);
let index = last[current].wrapping_add(d);
last[current] = index;
destination[i] = T::from(index);
}
if data.len() == 4 {
Ok(())
} else {
Err(DecodeError::ExtraBytes)
}
}
#[cfg(test)]
mod test {
use super::*;
const INDEX_SEQUENCE: [u32; 6] = [0, 1, 51, 2, 49, 1000];
const INDEX_SEQUENCE_V1: [u8; 13] = [
0xd1, 0x00, 0x04, 0xcd, 0x01, 0x04, 0x07, 0x98, 0x1f, 0x00, 0x00, 0x00, 0x00,
];
#[test]
fn test_decode_index_sequence() {
let mut decoded: [u32; INDEX_SEQUENCE.len()] = Default::default();
assert!(decode_index_sequence(&mut decoded, &INDEX_SEQUENCE_V1).is_ok());
assert_eq!(decoded, INDEX_SEQUENCE);
}
#[test]
fn test_decode_index_sequence_16() {
let buffer = encode_test_index_sequence();
#[derive(Clone, Copy, Default)]
struct U16(u16);
impl From<u32> for U16 {
fn from(index: u32) -> Self {
Self { 0: index as u16 }
}
}
let mut decoded = [U16::default(); INDEX_SEQUENCE.len()];
assert!(decode_index_sequence(&mut decoded, &buffer).is_ok());
assert!(decoded.iter().enumerate().all(|(i, v)| v.0 as u32 == INDEX_SEQUENCE[i]));
}
fn encode_test_index_sequence() -> Vec<u8> {
let mut buffer: Vec<u8> = Vec::new();
buffer.resize_with(
encode_index_sequence_bound(INDEX_SEQUENCE.len(), 1001),
Default::default,
);
let written = encode_index_sequence(&mut buffer, &INDEX_SEQUENCE, IndexEncodingVersion::V1);
buffer.resize_with(written, Default::default);
buffer
}
#[test]
fn test_encode_index_sequence_memory_safe() {
let mut buffer = encode_test_index_sequence();
for i in 0..=buffer.len() {
let result = encode_index_sequence(&mut buffer[0..i], &INDEX_SEQUENCE, IndexEncodingVersion::V1);
if i == buffer.len() {
assert_eq!(result, buffer.len());
} else {
assert_eq!(result, 0);
}
}
}
#[test]
fn test_decode_index_sequence_memory_safe() {
let buffer = encode_test_index_sequence();
let mut decoded: [u32; INDEX_SEQUENCE.len()] = Default::default();
for i in 0..=buffer.len() {
let result = decode_index_sequence(&mut decoded, &buffer[0..i]);
if i == buffer.len() {
assert!(result.is_ok());
} else {
assert!(result.is_err());
}
}
}
#[test]
fn test_decode_index_sequence_reject_extra_bytes() {
let mut buffer = encode_test_index_sequence();
buffer.push(0);
let mut decoded: [u32; INDEX_SEQUENCE.len()] = Default::default();
assert!(decode_index_sequence(&mut decoded, &buffer).is_err());
}
#[test]
fn test_decode_index_sequence_reject_malformed_headers() {
let mut buffer = encode_test_index_sequence();
buffer[0] = 0;
let mut decoded: [u32; INDEX_SEQUENCE.len()] = Default::default();
assert!(decode_index_sequence(&mut decoded, &buffer).is_err());
}
#[test]
fn test_decode_index_sequence_reject_invalid_version() {
let mut buffer = encode_test_index_sequence();
buffer[0] |= 0x0f;
let mut decoded: [u32; INDEX_SEQUENCE.len()] = Default::default();
assert!(decode_index_sequence(&mut decoded, &buffer).is_err());
}
#[test]
fn test_encode_index_sequence_empty() {
let mut buffer = Vec::new();
buffer.resize_with(encode_index_sequence_bound(0, 0), Default::default);
let written = encode_index_sequence(&mut buffer, &[], IndexEncodingVersion::V1);
buffer.resize_with(written, Default::default);
assert!(decode_index_sequence::<u32>(&mut [], &buffer).is_ok());
}
}