#![deny(unsafe_code)]
#![cfg_attr(feature = "platform_independent", forbid(unsafe_code))]
pub use decoder::{ColorTransform, Decoder, ImageInfo, PixelFormat, PlanarComponent, PlanarImage};
pub use error::{Error, UnsupportedFeature};
pub use parser::CodingProcess;
use std::io;
#[cfg(not(feature = "platform_independent"))]
mod arch;
mod decoder;
mod error;
mod huffman;
pub(crate) mod idct;
mod marker;
mod parser;
mod upsampler;
mod worker;
#[cfg(feature = "std")]
pub fn last_worker_was_immediate() -> bool {
worker::last_worker_was_immediate()
}
pub(crate) struct Buffered<R> {
inner: R,
buf: Box<[u8]>,
pos: usize,
end: usize,
}
impl<R: io::Read> Buffered<R> {
const CAP: usize = 16 * 1024;
pub(crate) fn new(inner: R) -> Self {
Buffered {
inner,
buf: alloc::vec![0u8; Self::CAP].into_boxed_slice(),
pos: 0,
end: 0,
}
}
#[cold]
fn refill(&mut self) -> io::Result<()> {
self.pos = 0;
self.end = 0;
loop {
match self.inner.read(&mut self.buf) {
Ok(n) => {
self.end = n;
return Ok(());
}
Err(e) if e.kind() == io::ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
}
}
}
#[inline]
pub(crate) fn next_byte(&mut self) -> io::Result<u8> {
if self.pos == self.end {
self.refill()?;
if self.pos == self.end {
return Err(io::Error::from(io::ErrorKind::UnexpectedEof));
}
}
let b = self.buf[self.pos];
self.pos += 1;
Ok(b)
}
#[inline]
pub(crate) fn buffered(&self) -> &[u8] {
&self.buf[self.pos..self.end]
}
#[inline]
pub(crate) fn consume(&mut self, n: usize) {
debug_assert!(self.pos + n <= self.end);
self.pos += n;
}
}
impl<R: io::Read> io::Read for Buffered<R> {
fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
if self.pos == self.end {
if out.len() >= self.buf.len() {
return self.inner.read(out);
}
self.refill()?;
if self.pos == self.end {
return Ok(0);
}
}
let n = (self.end - self.pos).min(out.len());
out[..n].copy_from_slice(&self.buf[self.pos..self.pos + n]);
self.pos += n;
Ok(n)
}
}
pub(crate) fn ablate_slow_bytes() -> bool {
use std::sync::OnceLock;
static V: OnceLock<bool> = OnceLock::new();
*V.get_or_init(|| {
std::env::var("RUSTY_JPEG_ABLATE")
.map(|v| v.split(',').any(|t| t == "slowbytes"))
.unwrap_or(false)
})
}
fn read_u8<R: io::Read>(reader: &mut R) -> io::Result<u8> {
let mut buf = [0];
reader.read_exact(&mut buf)?;
Ok(buf[0])
}
fn read_u16_from_be<R: io::Read>(reader: &mut R) -> io::Result<u16> {
let mut buf = [0, 0];
reader.read_exact(&mut buf)?;
Ok(u16::from_be_bytes(buf))
}