use std::vec;
const RBUF_ALIGN: u32 = 64;
pub fn collate_buffers(buffers: &[Vec<u8>]) -> Vec<u8> {
let mut result = Vec::new();
let write_u32_at = |u: u32, pos: usize, result: &mut Vec<u8>| {
result[pos] = (u >> 24) as u8;
result[pos + 1] = (u >> 16) as u8;
result[pos + 2] = (u >> 8) as u8;
result[pos + 3] = u as u8;
};
let mut size = 16 + 8 * buffers.len() as u32;
let mut buffer_cursor = round_up(size, RBUF_ALIGN);
for buf in buffers {
size = round_up(size, RBUF_ALIGN);
size += buf.len() as u32;
}
size = round_up(size, RBUF_ALIGN);
result.resize(size as usize, 0);
write_u32_at(
('R' as u32) << 24 | ('B' as u32) << 16 | ('U' as u32) << 8 | ('F' as u32) << 0,
0,
&mut result,
);
write_u32_at(100, 4, &mut result);
write_u32_at(buffers.len() as u32, 8, &mut result);
write_u32_at(size, 12, &mut result);
let mut cursor = 16;
for buf in buffers {
write_u32_at(buffer_cursor, cursor, &mut result);
write_u32_at(buf.len() as u32, cursor + 4, &mut result);
cursor += 8;
buffer_cursor += buf.len() as u32;
buffer_cursor = round_up(buffer_cursor, RBUF_ALIGN);
}
assert!(buffer_cursor == size);
buffer_cursor = round_up(16 + 8 * buffers.len() as u32, RBUF_ALIGN);
for buf in buffers {
result[buffer_cursor as usize..(buffer_cursor as usize + buf.len())].copy_from_slice(buf);
buffer_cursor += buf.len() as u32;
buffer_cursor = round_up(buffer_cursor, RBUF_ALIGN);
}
result
}
fn round_up(value: u32, alignment: u32) -> u32 {
(value + alignment - 1) & !(alignment - 1)
}
pub fn read_buffer(data: &[u8]) -> Vec<Vec<u8>> {
let read_u32_at = |data: &[u8], pos: usize| -> u32 {
((data[pos] as u32) << 24)
| ((data[pos + 1] as u32) << 16)
| ((data[pos + 2] as u32) << 8)
| (data[pos + 3] as u32)
};
let magic = read_u32_at(data, 0);
let version = read_u32_at(data, 4);
let num_buffers = read_u32_at(data, 8) as usize;
let file_size = read_u32_at(data, 12);
assert!(
magic == (('R' as u32) << 24 | ('B' as u32) << 16 | ('U' as u32) << 8 | ('F' as u32) << 0)
);
assert!(version == 100);
assert!(file_size == data.len() as u32);
let mut buffers = Vec::with_capacity(num_buffers);
let mut cursor = 16;
for _ in 0..num_buffers {
let buffer_offset = read_u32_at(data, cursor) as usize;
let buffer_size = read_u32_at(data, cursor + 4) as usize;
cursor += 8;
let buffer = data[buffer_offset..buffer_offset + buffer_size].to_vec();
buffers.push(buffer);
}
buffers
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn buffer_code() {
let buffers = vec![vec![1, 2, 3], vec![4, 5, 6]];
let collated = collate_buffers(&buffers);
let read_buffers = read_buffer(&collated);
assert_eq!(buffers, read_buffers);
println!("Buffers successfully collated and read back!");
}
}