use crate::error::EozinError::{self, *};
use crate::base::{
DecoderConstructor, EozinDecoderCore, LevelInfo, ReadCommand::*, ReadConsumer, Tile,
MAX_ALLOCATION, MAX_LOOP_COUNT
};
use crate::dynamic_decoder::{self, SlideFormat};
use std::{
fs::File,
io::{BufReader, Read, Seek, SeekFrom},
marker::PhantomData,
path::Path,
};
pub struct DynamicDecoder<R: Read + Seek> {
decoder: DynamicDecoderBase<R>,
}
impl<R: Read + Seek> DynamicDecoder<R> {
pub fn new(r: R) -> Result<DynamicDecoder<R>, EozinError> {
let decoder = DynamicDecoderBase::new(r)?;
Ok(DynamicDecoder { decoder })
}
pub fn read_tile(&mut self, lv: usize, x: usize, y: usize) -> Result<Tile, EozinError> {
self.decoder.read_tile(lv, x, y)
}
pub fn read_tile_as_bytes(
&mut self,
lv: usize,
x: usize,
y: usize,
) -> Result<Vec<u8>, EozinError> {
self.decoder.read_tile_as_bytes(lv, x, y)
}
pub fn level_count(&self) -> usize {
self.decoder.level_count()
}
pub fn dimensions(&self) -> (u64, u64) {
self.decoder.dimensions()
}
pub fn level_dimensions(&self) -> Vec<(u64, u64)> {
self.decoder.level_dimensions()
}
pub fn level_tile_sizes(&self) -> Vec<(u64, u64)> {
self.decoder.level_tile_sizes()
}
pub fn level_tile_ranges(&self) -> Vec<(usize, usize)> {
self.decoder.level_tile_ranges()
}
pub fn slide_format(&self) -> SlideFormat {
self.decoder.slide_format()
}
}
impl DynamicDecoder<BufReader<File>> {
pub fn with_path<P: AsRef<Path>>(
path: P,
) -> Result<DynamicDecoder<BufReader<File>>, EozinError> {
let decoder = DynamicDecoderBase::with_path(path)?;
Ok(DynamicDecoder { decoder })
}
}
struct EozinDecoder<R, D, C>
where
R: Read + Seek,
D: EozinDecoderCore,
C: DecoderConstructor,
{
pub(crate) decoder: D,
pub(crate) r: R,
_c: PhantomData<C>,
}
#[allow(dead_code)]
impl<R, D, C> EozinDecoder<R, D, C>
where
R: Read + Seek,
D: EozinDecoderCore,
C: DecoderConstructor<Output = D>,
{
fn new(mut r: R) -> Result<EozinDecoder<R, D, C>, EozinError> {
let decoder = excecute_read::<_, C>(&mut r, C::Input::default())?;
Ok(EozinDecoder {
decoder,
r,
_c: PhantomData,
})
}
fn read_tile_as_bytes(&mut self, lv: usize, x: usize, y: usize) -> Result<Vec<u8>, EozinError> {
let ri = self.decoder.read_tile(lv, x, y)?;
let img = excecute_read::<_, D::ReadTile>(&mut self.r, ri)?;
Ok(img)
}
fn read_tile(&mut self, lv: usize, x: usize, y: usize) -> Result<Tile, EozinError> {
let buf = self.read_tile_as_bytes(lv, x, y)?;
let image_type = self
.decoder
.get_level(lv)
.map(|l| l.image_type)
.ok_or(EozinError::UnexpectedStep)?;
let (width, height) = self
.decoder
.tile_size(lv, x, y)
.and_then(|(w, h)| w.try_into().ok().zip(h.try_into().ok()))
.ok_or(EozinError::UnexpectedStep)?;
Ok(Tile {
buf,
image_type,
width,
height,
})
}
fn level_count(&self) -> usize {
self.decoder.level_count()
}
fn get_level(&self, i: usize) -> Option<LevelInfo> {
self.decoder.get_level(i)
}
fn dimensions(&self) -> (u64, u64) {
self.decoder.dimensions()
}
fn level_dimensions(&self) -> Vec<(u64, u64)> {
self.decoder.level_dimensions()
}
fn level_tile_sizes(&self) -> Vec<(u64, u64)> {
self.decoder.level_tile_sizes()
}
fn level_tile_ranges(&self) -> Vec<(usize, usize)> {
self.decoder.level_tile_ranges()
}
}
#[allow(dead_code)]
impl<D, C> EozinDecoder<BufReader<File>, D, C>
where
D: EozinDecoderCore,
C: DecoderConstructor<Output = D>,
{
fn with_path<P: AsRef<Path>>(
path: P,
) -> Result<EozinDecoder<BufReader<File>, D, C>, EozinError> {
let file = File::open(path)?;
let reader = BufReader::new(file);
Self::new(reader)
}
}
type DynamicDecoderBase<R> =
EozinDecoder<R, dynamic_decoder::DynamicDecoder, dynamic_decoder::DynamicDecoderConstructor>;
#[allow(dead_code)]
impl<R: Read + Seek> DynamicDecoderBase<R> {
pub fn slide_format(&self) -> SlideFormat {
self.decoder.slide_format()
}
}
fn excecute_read<R, C>(mut r: &mut R, input: C::Input) -> Result<C::Output, EozinError>
where
R: Read + Seek,
C: ReadConsumer<ErrorKind = EozinError>,
{
let (mut c, mut cmd) = C::dispatch(input);
for _ in 0..MAX_LOOP_COUNT {
match cmd {
NoCmd => return c.receive(&[]),
ReadBytes { offset, count } => {
let buf = read_bytes(&mut r, offset, count)?;
return c.receive(&buf);
}
ReadBytesStep { offset, count } => {
let buf = read_bytes(&mut r, offset, count)?;
cmd = c.step(&buf)?;
}
}
}
Err(UnableToAllocateLargeSize)
}
fn read_bytes<R: Read + Seek>(
data: &mut R,
offset: u64,
count: u64,
) -> Result<Vec<u8>, EozinError> {
if count > MAX_ALLOCATION {
return Err(UnableToAllocateLargeSize);
}
let mut buffer = vec![0_u8; count as usize];
data.seek(SeekFrom::Start(offset))?;
let l = data.read(&mut buffer)?;
if l == count as usize {
Ok(buffer)
} else {
Err(UnexpectedStep)
}
}