use crate::error::Result;
use crate::types::BLOCK_SIZE;
use std::io::{Read, Seek, SeekFrom, Write};
pub fn read_data_block<R: Read>(reader: &mut R, n: usize) -> Result<Vec<u8>> {
if n == 0 {
return Ok(Vec::new());
}
let padded = padded_size(n);
let mut buf = vec![0u8; padded];
reader.read_exact(&mut buf)?;
buf.truncate(n);
Ok(buf)
}
pub fn write_data_block<W: Write>(writer: &mut W, data: &[u8]) -> Result<()> {
if data.is_empty() {
return Ok(());
}
writer.write_all(data)?;
let remainder = data.len() % BLOCK_SIZE;
if remainder != 0 {
let padding = BLOCK_SIZE - remainder;
let zeros = vec![0u8; padding];
writer.write_all(&zeros)?;
}
Ok(())
}
pub fn skip_data_block<R: Read + Seek>(reader: &mut R, n: usize) -> Result<()> {
if n == 0 {
return Ok(());
}
let padded = padded_size(n);
reader.seek(SeekFrom::Current(padded as i64))?;
Ok(())
}
pub fn pad_to_block(data: &[u8]) -> Vec<u8> {
if data.is_empty() {
return Vec::new();
}
let ps = padded_size(data.len());
let mut out = Vec::with_capacity(ps);
out.extend_from_slice(data);
out.resize(ps, 0);
out
}
pub fn padded_size(n: usize) -> usize {
if n == 0 {
return 0;
}
let remainder = n % BLOCK_SIZE;
if remainder == 0 {
n
} else {
n + BLOCK_SIZE - remainder
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn padded_size_exact() {
assert_eq!(padded_size(2880), 2880);
assert_eq!(padded_size(5760), 5760);
}
#[test]
fn padded_size_rounded() {
assert_eq!(padded_size(1), 2880);
assert_eq!(padded_size(2881), 5760);
}
#[test]
fn padded_size_zero() {
assert_eq!(padded_size(0), 0);
}
#[test]
fn write_read_round_trip() {
let data = vec![42u8; 1000];
let mut buf = Vec::new();
write_data_block(&mut buf, &data).unwrap();
assert_eq!(buf.len(), 2880);
let mut cursor = std::io::Cursor::new(&buf);
let read_back = read_data_block(&mut cursor, 1000).unwrap();
assert_eq!(read_back, data);
}
}