use std::{cell::Cell, cmp};
use bytes::Bytes;
use encoding_rs::WINDOWS_1252;
use thiserror::Error;
use super::{decode_number, decode_string};
#[derive(Error, Debug)]
pub enum EoReaderError {
#[error("Chunked reading mode is disabled")]
ChunkedReadingDisabled,
#[error("{0}")]
Other(String),
}
impl From<String> for EoReaderError {
fn from(s: String) -> Self {
Self::Other(s)
}
}
#[derive(Debug)]
pub struct EoReader {
data: Bytes,
position: Cell<usize>,
chunked_reading_mode: Cell<bool>,
chunk_start: Cell<usize>,
next_break: Cell<Option<usize>>,
}
impl EoReader {
pub fn new(data: Bytes) -> Self {
Self {
data,
position: Cell::new(0),
chunked_reading_mode: Cell::new(false),
chunk_start: Cell::new(0),
next_break: Cell::new(None),
}
}
pub fn remaining(&self) -> usize {
let position = self.position.get();
let chunked_reading_mode = self.chunked_reading_mode.get();
if chunked_reading_mode {
let next_break = match self.next_break.get() {
Some(next_break) => next_break,
None => position,
};
next_break - cmp::min(position, next_break)
} else {
self.data.len() - position
}
}
pub fn get_chunked_reading_mode(&self) -> bool {
self.chunked_reading_mode.get()
}
pub fn set_chunked_reading_mode(&self, enabled: bool) {
self.chunked_reading_mode.set(enabled);
let next_break = self.next_break.get();
if next_break.is_none() {
self.next_break.set(Some(self.find_next_break_index()))
}
}
pub fn next_chunk(&self) -> Result<(), EoReaderError> {
let chunked_reading_mode = self.chunked_reading_mode.get();
if !chunked_reading_mode {
return Err(EoReaderError::ChunkedReadingDisabled);
}
let next_break = match self.next_break.get() {
Some(next_break) => next_break,
None => self.position.get(),
};
let mut position = next_break;
self.chunk_start.set(position);
if position < self.data.len() {
position += 1;
}
self.position.set(position);
self.next_break.set(Some(self.find_next_break_index()));
Ok(())
}
fn find_next_break_index(&self) -> usize {
let position = self.position.get();
match self.data.iter().skip(position).position(|b| *b == 0xff) {
Some(index) => position + index,
None => self.data.len(),
}
}
pub fn get_byte(&self) -> u8 {
match self.read_bytes(1) {
Some(buf) => buf[0],
None => 0,
}
}
pub fn get_bytes(&self, length: usize) -> Vec<u8> {
match self.read_bytes(length) {
Some(buf) => buf.to_vec(),
None => Vec::new(),
}
}
pub fn get_char(&self) -> i32 {
match self.read_bytes(1) {
Some(buf) => decode_number(buf),
None => 0,
}
}
pub fn get_short(&self) -> i32 {
match self.read_bytes(2) {
Some(buf) => decode_number(buf),
None => 0,
}
}
pub fn get_three(&self) -> i32 {
match self.read_bytes(3) {
Some(buf) => decode_number(buf),
None => 0,
}
}
pub fn get_int(&self) -> i32 {
match self.read_bytes(4) {
Some(buf) => decode_number(buf),
None => 0,
}
}
pub fn get_string(&self) -> String {
let remaining = self.remaining();
self.get_fixed_string(remaining)
}
pub fn get_fixed_string(&self, length: usize) -> String {
if length == 0 {
return String::new();
}
let buf = match self.read_bytes(length) {
Some(buf) => buf,
None => return String::new(),
};
let (cow, _, _) = WINDOWS_1252.decode(buf);
cow.to_string()
}
pub fn get_encoded_string(&self) -> String {
self.get_fixed_encoded_string(self.remaining())
}
pub fn get_fixed_encoded_string(&self, length: usize) -> String {
if length == 0 {
return String::new();
}
let mut buf = match self.read_bytes(length) {
Some(buf) => buf.to_vec(),
None => return String::new(),
};
decode_string(&mut buf);
let position_of_break = match buf.iter().position(|b| *b == 0xff) {
Some(position_of_break) => position_of_break,
None => length - 1,
};
let (cow, _, _) = WINDOWS_1252.decode(&buf[..position_of_break]);
cow.to_string()
}
fn read_bytes(&self, length: usize) -> Option<&[u8]> {
let position = self.position.get();
let length = cmp::min(length, self.remaining());
let buf = self.data.get(position..position + length)?;
self.position.set(position + length);
Some(buf)
}
}