use crate::error::{NiftiError, Result};
use byteordered::{ByteOrdered, Endian};
use std::io::{ErrorKind as IoErrorKind, Read};
#[derive(Debug, Default, PartialEq, Clone, Copy)]
pub struct Extender([u8; 4]);
impl Extender {
pub fn from_reader<S: Read>(mut source: S) -> Result<Self> {
let mut extension = [0u8; 4];
source.read_exact(&mut extension)?;
Ok(extension.into())
}
pub fn from_reader_optional<S: Read>(mut source: S) -> Result<Option<Self>> {
let mut extension = [0u8; 4];
match source.read_exact(&mut extension) {
Ok(()) => Ok(Some(extension.into())),
Err(ref e) if e.kind() == IoErrorKind::UnexpectedEof => Ok(None),
Err(e) => Err(NiftiError::from(e)),
}
}
pub fn has_extensions(&self) -> bool {
self.0[0] != 0
}
pub fn as_bytes(&self) -> &[u8; 4] {
&self.0
}
}
impl From<[u8; 4]> for Extender {
fn from(extender: [u8; 4]) -> Self {
Extender(extender)
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct Extension {
esize: i32,
ecode: i32,
edata: Vec<u8>,
}
impl Extension {
pub fn new(ecode: i32, edata: Vec<u8>) -> Self {
let esize = 8 + edata.len() as i32;
Extension {
esize,
ecode,
edata,
}
}
pub fn from_str(ecode: i32, edata: &str) -> Self {
let esize = 8 + edata.len() as i32;
let padded_esize = (esize + 15) & !15;
let mut edata = edata.as_bytes().to_vec();
edata.resize(padded_esize as usize - 8, 0);
Extension::new(ecode, edata)
}
pub fn size(&self) -> i32 {
self.esize
}
pub fn code(&self) -> i32 {
self.ecode
}
pub fn data(&self) -> &Vec<u8> {
&self.edata
}
pub fn into_data(self) -> Vec<u8> {
self.edata
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct ExtensionSequence {
extender: Extender,
extensions: Vec<Extension>,
}
impl IntoIterator for ExtensionSequence {
type Item = Extension;
type IntoIter = ::std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.extensions.into_iter()
}
}
impl<'a> IntoIterator for &'a ExtensionSequence {
type Item = &'a Extension;
type IntoIter = ::std::slice::Iter<'a, Extension>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl ExtensionSequence {
pub fn new(extender: Extender, extensions: Vec<Extension>) -> Self {
ExtensionSequence {
extender,
extensions,
}
}
pub fn from_reader<S, E>(
extender: Extender,
mut source: ByteOrdered<S, E>,
len: usize,
) -> Result<Self>
where
S: Read,
E: Endian,
{
let mut extensions = Vec::new();
if extender.has_extensions() {
let mut offset = 0;
while offset < len {
let esize = source.read_i32()?;
let ecode = source.read_i32()?;
let data_size = (esize as usize).saturating_sub(8);
let mut edata = Vec::new();
edata
.try_reserve_exact(data_size)
.map_err(|e| NiftiError::ReserveExtended(data_size, e))?;
let nb_bytes_written = (&mut source)
.take(data_size as u64)
.read_to_end(&mut edata)?;
if nb_bytes_written != data_size {
return Err(NiftiError::IncompatibleLength(nb_bytes_written, data_size));
}
extensions.push(Extension::new(ecode, edata));
offset += esize as usize;
}
}
Ok(ExtensionSequence {
extender,
extensions,
})
}
pub fn iter(&self) -> ::std::slice::Iter<Extension> {
self.extensions.iter()
}
pub fn is_empty(&self) -> bool {
self.extensions.is_empty()
}
pub fn len(&self) -> usize {
self.extensions.len()
}
pub fn bytes_on_disk(&self) -> usize {
self.extensions
.iter()
.map(|e| e.size() as usize)
.sum::<usize>()
}
pub fn extender(&self) -> Extender {
self.extender
}
}