use std::cmp::min;
use crate::utils::{count_leading_line_endings, line_ending};
use crate::error::{PDFError, Result};
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
pub trait Sequence {
fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
fn read_line(&mut self) -> Result<Vec<u8>>;
fn read_line_str(&mut self) -> Result<String>;
fn seek(&mut self, pos: u64) -> Result<u64>;
fn size(&self) -> Result<u64>;
}
pub struct FileSequence {
file: File,
buf: Vec<u8>,
}
impl FileSequence {
pub fn new(file: File) -> Self {
let buf = Vec::new();
Self { file, buf }
}
fn split_line_data(&mut self, index: usize) -> Vec<u8> {
let buf = &mut self.buf;
let line = buf.drain(0..index).collect::<Vec<u8>>();
buf.len();
let crlf_num = count_leading_line_endings(buf);
if crlf_num != 0 {
buf.drain(0..crlf_num as usize);
}
line
}
}
impl Sequence for FileSequence {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if !self.buf.is_empty() {
let len = self.buf.len();
let n = min(len, buf.len());
buf[0..n].copy_from_slice(&self.buf[0..n]);
self.buf.drain(0..n);
return Ok(n);
}
let n = self.file.read(buf)?;
Ok(n)
}
fn read_line(&mut self) -> Result<Vec<u8>> {
let buf = &mut self.buf;
let mut bytes = [0u8; 1024];
let mut tmp = 0;
loop {
let len = buf.len();
for i in tmp..len {
if line_ending(buf[i]) {
let line_data = self.split_line_data(i);
return Ok(line_data);
}
}
tmp = len;
let n = self.file.read(&mut bytes)?;
if n == 0 {
return Err(PDFError::EOFError);
}
let offset = if len == 0 {
count_leading_line_endings(&bytes)
}else {
0u64
} as usize;
buf.extend_from_slice(&bytes[offset..n]);
}
}
fn read_line_str(&mut self) -> Result<String> {
let buf = self.read_line()?;
let text = String::from_utf8(buf)?;
Ok(text)
}
fn seek(&mut self, pos: u64) -> Result<u64> {
if self.size()? < pos {
return Err(PDFError::SeekExceedError);
}
let n = self.file.seek(SeekFrom::Start(pos))?;
self.buf.clear();
Ok(n)
}
fn size(&self) -> Result<u64> {
let n = self.file.metadata()?.len();
Ok(n)
}
}