Skip to main content

mozjpeg/
errormgr.rs

1use crate::ffi;
2use crate::ffi::jpeg_common_struct;
3use std::borrow::Cow;
4use std::mem;
5use std::os::raw::c_int;
6
7pub use crate::ffi::jpeg_error_mgr as ErrorMgr;
8
9#[allow(clippy::unnecessary_box_returns)]
10pub(crate) fn unwinding_error_mgr() -> Box<ErrorMgr> {
11    unsafe {
12        let mut err = Box::new(mem::zeroed());
13        ffi::jpeg_std_error(&mut err);
14        err.error_exit = Some(unwind_error_exit);
15        err.emit_message = Some(silence_message);
16        err
17    }
18}
19
20#[cold]
21fn formatted_message(prefix: &str, cinfo: &mut jpeg_common_struct) -> String {
22    unsafe {
23        let err = cinfo.err.as_ref().unwrap();
24        match err.format_message {
25            Some(fmt) => {
26                let mut buffer = mem::zeroed();
27                let correct_fn_type = mem::transmute::<
28                    unsafe extern "C-unwind" fn(cinfo: &mut jpeg_common_struct, buffer: &[u8; 80]),
29                    unsafe extern "C-unwind" fn(cinfo: &mut jpeg_common_struct, buffer: &mut [u8; 80])>(fmt);
30                (correct_fn_type)(cinfo, &mut buffer);
31                let buf = buffer.split(|&c| c == 0).next().unwrap_or_default();
32                let msg = String::from_utf8_lossy(buf);
33                let mut out = String::with_capacity(prefix.len() + msg.len());
34                push_str_in_cap(&mut out, prefix);
35                push_str_in_cap(&mut out, &msg);
36                out
37            },
38            None => format!("{}code {}", prefix, err.msg_code),
39        }
40    }
41}
42
43fn push_str_in_cap(out: &mut String, s: &str) {
44    let needs_to_grow = s.len() > out.capacity().wrapping_sub(out.len());
45    if !needs_to_grow {
46        out.push_str(s);
47    }
48}
49
50#[cold]
51extern "C-unwind" fn silence_message(_cinfo: &mut jpeg_common_struct, _level: c_int) {
52}
53
54#[cold]
55extern "C-unwind" fn unwind_error_exit(cinfo: &mut jpeg_common_struct) {
56    let msg = formatted_message("libjpeg fatal error: ", cinfo);
57    // avoids calling panic handler
58    std::panic::resume_unwind(Box::new(msg));
59}