diff --git a/src/error.rs b/src/error.rs index 95c22a18..0d022812 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,7 +2,7 @@ use std::{error::Error, fmt}; use crate::colors::{BitDepth, ColorType}; -#[derive(Debug, Clone)] +#[derive(Debug)] #[non_exhaustive] pub enum PngError { APNGOutOfOrder, @@ -15,7 +15,9 @@ pub enum PngError { InvalidData, InvalidDepthForType(BitDepth, ColorType), NotPNG, + ReadFailed(String, std::io::Error), TruncatedData, + WriteFailed(String, std::io::Error), Other(Box), } @@ -47,9 +49,11 @@ impl fmt::Display for PngError { write!(f, "Invalid bit depth {d} for color type {c}") } PngError::NotPNG => f.write_str("Invalid header detected; Not a PNG file"), + PngError::ReadFailed(ref s, ref e) => write!(f, "Failed to read from {s}: {e}"), PngError::TruncatedData => { f.write_str("Missing data in the file; the file is truncated") } + PngError::WriteFailed(ref s, ref e) => write!(f, "Failed to write to {s}: {e}"), PngError::Other(ref s) => f.write_str(s), } } diff --git a/src/lib.rs b/src/lib.rs index db8d7a49..edbf33db 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -221,7 +221,7 @@ pub fn optimize(input: &InFile, output: &OutFile, opts: &Options) -> PngResult<( let mut data = Vec::new(); stdin() .read_to_end(&mut data) - .map_err(|e| PngError::new(&format!("Error reading stdin: {e}")))?; + .map_err(|e| PngError::ReadFailed("stdin".into(), e))?; data } }; @@ -270,20 +270,15 @@ pub fn optimize(input: &InFile, output: &OutFile, opts: &Options) -> PngResult<( let mut buffer = BufWriter::new(stdout()); buffer .write_all(&optimized_output) - .map_err(|e| PngError::new(&format!("Unable to write to stdout: {e}")))?; + .map_err(|e| PngError::WriteFailed("stdout".into(), e))?; } (OutFile::Path { path, .. }, _) => { let output_path = path .as_ref() .map(|p| p.as_path()) .unwrap_or_else(|| input.path().unwrap()); - let out_file = File::create(output_path).map_err(|err| { - PngError::new(&format!( - "Unable to write to file {}: {}", - output_path.display(), - err - )) - })?; + let out_file = File::create(output_path) + .map_err(|err| PngError::WriteFailed(output_path.display().to_string(), err))?; if let Some(metadata_input) = &opt_metadata_preserved { copy_permissions(metadata_input, &out_file)?; } @@ -293,13 +288,7 @@ pub fn optimize(input: &InFile, output: &OutFile, opts: &Options) -> PngResult<( .write_all(&optimized_output) // flush BufWriter so IO errors don't get swallowed silently on close() by drop! .and_then(|()| buffer.flush()) - .map_err(|e| { - PngError::new(&format!( - "Unable to write to {}: {}", - output_path.display(), - e - )) - })?; + .map_err(|e| PngError::WriteFailed(output_path.display().to_string(), e))?; // force drop and thereby closing of file handle before modifying any timestamp std::mem::drop(buffer); if let Some(metadata_input) = &opt_metadata_preserved { diff --git a/src/png/mod.rs b/src/png/mod.rs index d7297048..e0f0acae 100644 --- a/src/png/mod.rs +++ b/src/png/mod.rs @@ -1,9 +1,4 @@ -use std::{ - fs::File, - io::{BufReader, Read, Write}, - path::Path, - sync::Arc, -}; +use std::{fs, io::Write, path::Path, sync::Arc}; use bitvec::bitarr; use libdeflater::{CompressionLvl, Compressor}; @@ -62,28 +57,7 @@ impl PngData { } pub fn read_file(filepath: &Path) -> Result, PngError> { - let file = match File::open(filepath) { - Ok(f) => f, - Err(_) => return Err(PngError::new("Failed to open file for reading")), - }; - let file_len = file.metadata().map(|m| m.len() as usize).unwrap_or(0); - let mut reader = BufReader::new(file); - // Check file for PNG header - let mut header = [0; 8]; - if reader.read_exact(&mut header).is_err() { - return Err(PngError::new("Not a PNG file: too small")); - } - if !file_header_is_valid(&header) { - return Err(PngError::new("Invalid PNG header detected")); - } - // Read raw png data into memory - let mut byte_data: Vec = Vec::with_capacity(file_len); - byte_data.extend_from_slice(&header); - match reader.read_to_end(&mut byte_data) { - Ok(_) => (), - Err(_) => return Err(PngError::new("Failed to read from file")), - } - Ok(byte_data) + fs::read(filepath).map_err(|e| PngError::ReadFailed(filepath.display().to_string(), e)) } /// Create a new `PngData` struct by reading a slice