use no_std_io2::io::{ErrorKind, SeekFrom};
use crate::MAGIC_SIZE_BYTES;
use crate::error::CpioError;
use crate::newc::{NEWC_CRC_MAGIC, NEWC_MAGIC};
use crate::odc::ODC_MAGIC;
use crate::read_seek::ReadSeek;
const PAD_SCAN_CHUNK: usize = 512;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum SegmentFormat {
Odc,
Newc,
NewcCrc,
}
impl SegmentFormat {
#[must_use]
pub fn from_magic(magic: &[u8]) -> Option<Self> {
match magic {
_ if magic == ODC_MAGIC => Some(Self::Odc),
_ if magic == NEWC_MAGIC => Some(Self::Newc),
_ if magic == NEWC_CRC_MAGIC => Some(Self::NewcCrc),
_ => None,
}
}
}
pub fn next_segment_offset<R: ReadSeek>(
reader: &mut R,
from: u64,
) -> Result<Option<u64>, CpioError> {
reader.seek(SeekFrom::Start(from))?;
let mut position = from;
let mut buf = [0u8; PAD_SCAN_CHUNK];
loop {
let read = match reader.read(&mut buf) {
Ok(0) => return Ok(None),
Ok(read) => read,
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e.into()),
};
if let Some(index) = buf[..read].iter().position(|&byte| byte != 0) {
return Ok(Some(position + index as u64));
}
position += read as u64;
}
}
pub fn segment_format<R: ReadSeek>(
reader: &mut R,
offset: u64,
) -> Result<Option<SegmentFormat>, CpioError> {
reader.seek(SeekFrom::Start(offset))?;
let mut magic = [0u8; MAGIC_SIZE_BYTES];
let mut filled = 0;
while filled < MAGIC_SIZE_BYTES {
match reader.read(&mut magic[filled..]) {
Ok(0) => return Ok(None),
Ok(read) => filled += read,
Err(e) if e.kind() == ErrorKind::Interrupted => (),
Err(e) => return Err(e.into()),
}
}
Ok(SegmentFormat::from_magic(&magic))
}