use super::file::{PKHeader, PKEntry};
use super::parser;
use crate::core::reader::{FileResult, FileError};
use crate::sd0::stream::{SegmentedStream, SegmentedError};
use std::io::{Read, Seek, BufRead, SeekFrom};
use std::io::{Result as IoResult, Error as IoError, ErrorKind};
use std::convert::TryFrom;
use std::error::Error;
use std::marker::{Send,Sync};
use std::fmt::{Display, Formatter, Error as FmtError};
pub struct PackFile<'a, T> {
inner: &'a mut T,
}
pub struct PackEntryAccessor<'b, 'a, T> {
base_addr: u32,
count: u32,
file: &'b mut PackFile<'a, T>,
}
pub struct PackStreamReader<'b, 'a, T> {
base_addr: u32,
offset: u32,
size: u32,
file: &'b mut PackFile<'a, T>,
}
#[derive(Debug)]
pub enum StreamError {
Segmented(SegmentedError),
}
impl<'a,T> PackFile<'a,T>
where T: Seek + BufRead {
pub fn open<'b: 'a>(inner: &'b mut T) -> Self {
PackFile{inner}
}
pub fn check_magic(&mut self) -> FileResult<()> {
let mut magic_bytes: [u8;4] = [0;4];
self.inner.seek(SeekFrom::Start(0)).map_err(FileError::Seek)?;
self.inner.read_exact(&mut magic_bytes).map_err(FileError::Read)?;
let (_rest, _magic) = parser::parse_pk_magic(&magic_bytes)?;
Ok(())
}
pub fn get_header(&mut self) -> FileResult<PKHeader> {
let mut header_bytes: [u8;8] = [0;8];
self.inner.seek(SeekFrom::End(-8)).map_err(FileError::Seek)?;
self.inner.read_exact(&mut header_bytes).map_err(FileError::Read)?;
let (_rest, header) = parser::parse_pk_header(&header_bytes)?;
Ok(header)
}
pub fn get_entry(&mut self, addr: u32) -> FileResult<PKEntry> {
let mut entry_bytes: [u8;100] = [0;100];
self.inner.seek(SeekFrom::Start(u64::from(addr))).map_err(FileError::Seek)?;
self.inner.read_exact(&mut entry_bytes).map_err(FileError::Read)?;
let (_rest, entry) = parser::parse_pk_entry(&entry_bytes)?;
Ok(entry)
}
pub fn get_entry_accessor<'b>(&'b mut self, addr: u32) -> FileResult<PackEntryAccessor<'b,'a, T>> {
let mut count_bytes: [u8;4] = [0; 4];
self.inner.seek(SeekFrom::Start(u64::from(addr))).map_err(FileError::Seek)?;
self.inner.read_exact(&mut count_bytes).map_err(FileError::Read)?;
let count = u32::from_le_bytes(count_bytes);
Ok(PackEntryAccessor::<'b,'a>{base_addr: addr + 4, count, file: self})
}
pub fn get_entry_list(&mut self, addr: u32) -> FileResult<Vec<PKEntry>> {
let mut bytes: Vec<u8> = Vec::new();
self.inner.seek(SeekFrom::Start(u64::from(addr))).map_err(FileError::Seek)?;
self.inner.read_to_end(&mut bytes).map_err(FileError::Read)?;
let (_rest, entry_list) = parser::parse_pk_entry_list(&bytes)?;
Ok(entry_list)
}
pub fn get_file_stream<'b>(&'b mut self, entry: PKEntry) -> PackStreamReader<'b,'a,T> {
let base_addr = entry.file_data_addr;
let size = if entry.is_compressed[0] == 0 {
entry.orig_file_size
} else {
entry.compr_file_size
};
PackStreamReader::<'b,'a,T>{file: self, base_addr, offset: 0, size}
}
pub fn get_file_data<'c, 'b: 'c>(&'b mut self, entry: PKEntry) -> Result<Box<Read + 'c>, StreamError> {
let is_compr = entry.is_compressed[0] > 0;
let file_stream = self.get_file_stream(entry);
Ok(if is_compr {
let compr_stream = SegmentedStream::try_from(file_stream).map_err(StreamError::Segmented)?;
Box::new(compr_stream)
} else {
Box::new(file_stream)
})
}
}
impl<'b, 'a, T> PackEntryAccessor<'b, 'a, T>
where T: Seek + BufRead {
pub fn get_file_mut(&'b mut self) -> &'b mut PackFile<'a, T> {
self.file
}
pub fn get_entry(&mut self, index: u32) -> Option<FileResult<PKEntry>> {
if index <= self.count {
Some(self.file.get_entry(self.base_addr + index * 100))
} else {
None
}
}
pub fn get_root_entry(&mut self) -> Option<FileResult<PKEntry>> {
self.get_entry(self.count / 2)
}
}
fn other_io_err<'a, E>(e: E) -> IoError
where E: Into<Box<dyn Error + Send + Sync>>
{
IoError::new(ErrorKind::Other, e)
}
impl<'b, 'a, T> Read for PackStreamReader<'b, 'a, T>
where T: Seek + BufRead {
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
let pos = u64::from(self.base_addr + self.offset);
self.file.inner.seek(SeekFrom::Start(pos))?;
let buf_len = buf.len();
let offset = usize::try_from(self.offset).map_err(other_io_err)?;
let size = usize::try_from(self.size).map_err(other_io_err)?;
if offset + buf_len > size {
let max = size - offset;
self.file.inner.read(&mut buf[..max])
} else {
self.file.inner.read(buf)
}.and_then(|n| {
self.offset += u32::try_from(n).map_err(other_io_err)?; Ok(n)})
}
}
#[derive(Debug)]
pub enum SeekError {
Negative(i64),
OutOfBounds(u64, u64),
}
impl Display for SeekError {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
SeekError::Negative(n) => write!(f, "{} < 0", n),
SeekError::OutOfBounds(o, s) => write!(f, "{} > {}", o, s),
}
}
}
impl Error for SeekError {
}
impl<'b, 'a, T> PackStreamReader<'b, 'a, T>
where T: Seek + BufRead {
fn seek_to_pos(&mut self, n: u64) -> IoResult<u64> {
if n > self.size.into() {
self.offset = self.size;
let e = SeekError::OutOfBounds(n, self.size.into());
Err(IoError::new(ErrorKind::Other, e))
} else {
self.offset = u32::try_from(n).map_err(|e| IoError::new(ErrorKind::Other, e))?;
Ok(n)
}
}
fn seek_to(&mut self, n: i64) -> IoResult<u64> {
if n < 0 {
self.offset = self.size;
let e = SeekError::Negative(n);
Err(IoError::new(ErrorKind::Other, e))
} else {
self.seek_to_pos(u64::try_from(n).map_err(|e| IoError::new(ErrorKind::Other, e))?)
}
}
}
impl<'b, 'a, T> Seek for PackStreamReader<'b, 'a, T>
where T: Seek + BufRead {
fn seek(&mut self, to: SeekFrom) -> IoResult<u64> {
match to {
SeekFrom::Start(n) => self.seek_to_pos(n),
SeekFrom::Current(n) => self.seek_to(i64::from(self.offset) + n),
SeekFrom::End(n) => self.seek_to(i64::from(self.size) + n),
}
}
}