grib/decoder/jpeg2000/
ext.rs

1/*!
2This code is based on src/lib.rs from [jp2k](https://crates.io/crates/jp2k) (https://github.com/kardeiz/jp2k), version 0.3.1, which was previously forked from https://framagit.org/leoschwarz/jpeg2000-rust before its GPL-v3 relicensing.
3
4
5## Original warnings and license statement
6
7### Warning
8Please be advised that using C code means this crate is likely vulnerable to various memory exploits, e.g. see [http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-8332](CVE-2016-8332) for an actual example from the past.
9
10As soon as someone writes an efficient JPEG2000 decoder in pure Rust you should probably switch over to that.
11
12### License
13You can use the Rust code in the directories `src` and `openjp2-sys/src` under the terms of either the MIT license (`LICENSE-MIT` file) or the Apache license (`LICENSE-APACHE` file). Please note that this will link statically to OpenJPEG, which has its own license which you can find at `openjpeg-sys/libopenjpeg/LICENSE` (you might have to check out the git submodule first).
14*/
15
16use std::{
17    os::raw::c_void,
18    ptr::{self, NonNull},
19};
20
21use openjpeg_sys as opj;
22use opj::OPJ_CODEC_FORMAT;
23
24use crate::decoder::jpeg2000::Jpeg2000CodeStreamDecodeError;
25
26pub(crate) struct Stream(pub(crate) *mut opj::opj_stream_t);
27
28impl Drop for Stream {
29    fn drop(&mut self) {
30        unsafe {
31            opj::opj_stream_destroy(self.0);
32        }
33    }
34}
35
36impl Stream {
37    pub(crate) fn from_bytes(buf: &[u8]) -> Result<Self, Jpeg2000CodeStreamDecodeError> {
38        #[derive(Debug)]
39        struct SliceWithOffset<'a> {
40            buf: &'a [u8],
41            offset: usize,
42        }
43
44        unsafe extern "C" fn opj_stream_free_user_data_fn(p_user_data: *mut c_void) {
45            drop(Box::from_raw(p_user_data as *mut SliceWithOffset))
46        }
47
48        unsafe extern "C" fn opj_stream_read_fn(
49            p_buffer: *mut c_void,
50            p_nb_bytes: usize,
51            p_user_data: *mut c_void,
52        ) -> usize {
53            if p_buffer.is_null() {
54                return 0;
55            }
56
57            let user_data = p_user_data as *mut SliceWithOffset;
58
59            #[allow(clippy::needless_borrow)]
60            let len = (&(*user_data).buf).len();
61
62            let offset = (*user_data).offset;
63
64            let bytes_left = len - offset;
65
66            let bytes_read = std::cmp::min(bytes_left, p_nb_bytes);
67
68            #[allow(clippy::needless_borrow)]
69            let slice = &(&(*user_data).buf)[offset..offset + bytes_read];
70
71            std::ptr::copy_nonoverlapping(slice.as_ptr(), p_buffer as *mut u8, bytes_read);
72
73            (*user_data).offset += bytes_read;
74
75            bytes_read
76        }
77
78        let buf_len = buf.len();
79        let user_data = Box::new(SliceWithOffset { buf, offset: 0 });
80
81        let ptr = unsafe {
82            let jp2_stream = opj::opj_stream_default_create(1);
83            opj::opj_stream_set_read_function(jp2_stream, Some(opj_stream_read_fn));
84            opj::opj_stream_set_user_data_length(jp2_stream, buf_len as u64);
85            opj::opj_stream_set_user_data(
86                jp2_stream,
87                Box::into_raw(user_data) as *mut c_void,
88                Some(opj_stream_free_user_data_fn),
89            );
90            jp2_stream
91        };
92
93        Ok(Self(ptr))
94    }
95}
96
97pub(crate) struct Codec(pub(crate) NonNull<opj::opj_codec_t>);
98
99impl Drop for Codec {
100    fn drop(&mut self) {
101        unsafe {
102            opj::opj_destroy_codec(self.0.as_ptr());
103        }
104    }
105}
106
107impl Codec {
108    pub(crate) fn j2k() -> Result<Self, Jpeg2000CodeStreamDecodeError> {
109        Self::create(OPJ_CODEC_FORMAT::OPJ_CODEC_J2K)
110    }
111
112    pub(crate) fn create(format: OPJ_CODEC_FORMAT) -> Result<Self, Jpeg2000CodeStreamDecodeError> {
113        NonNull::new(unsafe { opj::opj_create_decompress(format) })
114            .map(Self)
115            .ok_or(Jpeg2000CodeStreamDecodeError::DecoderSetupError)
116    }
117}
118
119#[derive(Debug)]
120pub(crate) struct Image(pub(crate) *mut opj::opj_image_t);
121
122impl Drop for Image {
123    fn drop(&mut self) {
124        unsafe {
125            opj::opj_image_destroy(self.0);
126        }
127    }
128}
129
130impl Image {
131    pub(crate) fn new() -> Self {
132        Image(ptr::null_mut())
133    }
134
135    pub(crate) fn width(&self) -> u32 {
136        unsafe { (*self.0).x1 - (*self.0).x0 }
137    }
138
139    pub(crate) fn height(&self) -> u32 {
140        unsafe { (*self.0).y1 - (*self.0).y0 }
141    }
142
143    pub(crate) fn num_components(&self) -> u32 {
144        unsafe { (*self.0).numcomps }
145    }
146
147    pub(crate) fn components(&self) -> &[opj::opj_image_comp_t] {
148        let comps_len = self.num_components();
149        unsafe { std::slice::from_raw_parts((*self.0).comps, comps_len as usize) }
150    }
151
152    pub(crate) fn factor(&self) -> u32 {
153        unsafe { (*(*self.0).comps).factor }
154    }
155}
156
157pub(crate) fn value_for_discard_level(u: u32, discard_level: u32) -> u32 {
158    let div = 1 << discard_level;
159    let quot = u / div;
160    let rem = u % div;
161    if rem > 0 {
162        quot + 1
163    } else {
164        quot
165    }
166}