_RNvMsg_NvNtCshdzP3jLBsmJ_3png6common1__NtB5_16InternalBitFlags10intersectsCs3aXgM11XBGX_5image: 237| 354k| fn intersects(&self, other) { 238| 354k| self.0 & other.0 != <$T as $crate::Bits>::EMPTY _RNvMsg_NvNtCshdzP3jLBsmJ_3png6common1__NtB5_16InternalBitFlags8containsCs3aXgM11XBGX_5image: 241| 156M| fn contains(&self, other) { 242| 156M| self.0 & other.0 == other.0 _RNvMsy_NvNtCshdzP3jLBsmJ_3png6common1__NtB7_15Transformations10intersectsCs3aXgM11XBGX_5image: 78| 354k| fn intersects(&self, other) { 79| 354k| self.0.intersects(other.0) _RNvMsy_NvNtCshdzP3jLBsmJ_3png6common1__NtB7_15Transformations8containsCs3aXgM11XBGX_5image: 82| 156M| fn contains(&self, other) { 83| 156M| self.0.contains(other.0) _RNvMsg_NvNtCshdzP3jLBsmJ_3png6common1__NtB5_16InternalBitFlags8containsB9_: 241| 9.68k| fn contains(&self, other) { 242| 9.68k| self.0 & other.0 == other.0 _RNvMsy_NvNtCshdzP3jLBsmJ_3png6common1__NtB7_15Transformations8containsB9_: 82| 9.68k| fn contains(&self, other) { 83| 9.68k| self.0.contains(other.0) _RINvNtCs4vLsLh4rAyg_8bytemuck8internal14cast_slice_muthhECs3aXgM11XBGX_5image: 268| 4.47k|pub(crate) unsafe fn cast_slice_mut(a: &mut [A]) -> &mut [B] { 269| 4.47k| match try_cast_slice_mut(a) { 270| 4.47k| Ok(b) => b, 271| 0| Err(e) => something_went_wrong("cast_slice_mut", e), 272| | } 273| 4.47k|} _RINvNtCs4vLsLh4rAyg_8bytemuck8internal14cast_slice_mutthECs3aXgM11XBGX_5image: 268| 1.53k|pub(crate) unsafe fn cast_slice_mut(a: &mut [A]) -> &mut [B] { 269| 1.53k| match try_cast_slice_mut(a) { 270| 1.53k| Ok(b) => b, 271| 0| Err(e) => something_went_wrong("cast_slice_mut", e), 272| | } 273| 1.53k|} _RINvNtCs4vLsLh4rAyg_8bytemuck8internal18try_cast_slice_muthhECs3aXgM11XBGX_5image: 381| 4.47k|pub(crate) unsafe fn try_cast_slice_mut( 382| 4.47k| a: &mut [A], 383| 4.47k|) -> Result<&mut [B], PodCastError> { 384| 4.47k| let input_bytes = core::mem::size_of_val::<[A]>(a); 385| | // Note(Lokathor): everything with `align_of` and `size_of` will optimize away 386| | // after monomorphization. 387| 4.47k| if align_of::() > align_of::() 388| 0| && !is_aligned_to(a.as_ptr() as *const (), align_of::()) 389| | { 390| 0| Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) 391| 4.47k| } else if size_of::() == size_of::() { 392| 4.47k| Ok(unsafe { 393| 4.47k| core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, a.len()) 394| 4.47k| }) 395| 0| } else if (size_of::() != 0 && input_bytes % size_of::() == 0) 396| 0| || (size_of::() == 0 && input_bytes == 0) 397| | { 398| 0| let new_len = 399| 0| if size_of::() != 0 { input_bytes / size_of::() } else { 0 }; 400| 0| Ok(unsafe { 401| 0| core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, new_len) 402| 0| }) 403| | } else { 404| 0| Err(PodCastError::OutputSliceWouldHaveSlop) 405| | } 406| 4.47k|} _RINvNtCs4vLsLh4rAyg_8bytemuck8internal18try_cast_slice_mutthECs3aXgM11XBGX_5image: 381| 1.53k|pub(crate) unsafe fn try_cast_slice_mut( 382| 1.53k| a: &mut [A], 383| 1.53k|) -> Result<&mut [B], PodCastError> { 384| 1.53k| let input_bytes = core::mem::size_of_val::<[A]>(a); 385| | // Note(Lokathor): everything with `align_of` and `size_of` will optimize away 386| | // after monomorphization. 387| 1.53k| if align_of::() > align_of::() 388| 0| && !is_aligned_to(a.as_ptr() as *const (), align_of::()) 389| | { 390| 0| Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned) 391| 1.53k| } else if size_of::() == size_of::() { 392| 0| Ok(unsafe { 393| 0| core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, a.len()) 394| 0| }) 395| 1.53k| } else if (size_of::() != 0 && input_bytes % size_of::() == 0) 396| 0| || (size_of::() == 0 && input_bytes == 0) 397| | { 398| 1.53k| let new_len = 399| 1.53k| if size_of::() != 0 { input_bytes / size_of::() } else { 0 }; 400| 1.53k| Ok(unsafe { 401| 1.53k| core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, new_len) 402| 1.53k| }) 403| | } else { 404| 0| Err(PodCastError::OutputSliceWouldHaveSlop) 405| | } 406| 1.53k|} _RINvCs4vLsLh4rAyg_8bytemuck14cast_slice_muthhECs3aXgM11XBGX_5image: 423| 4.47k|pub fn cast_slice_mut< 424| 4.47k| A: NoUninit + AnyBitPattern, 425| 4.47k| B: NoUninit + AnyBitPattern, 426| 4.47k|>( 427| 4.47k| a: &mut [A], 428| 4.47k|) -> &mut [B] { 429| 4.47k| unsafe { internal::cast_slice_mut(a) } 430| 4.47k|} _RINvCs4vLsLh4rAyg_8bytemuck14cast_slice_mutthECs3aXgM11XBGX_5image: 423| 1.53k|pub fn cast_slice_mut< 424| 1.53k| A: NoUninit + AnyBitPattern, 425| 1.53k| B: NoUninit + AnyBitPattern, 426| 1.53k|>( 427| 1.53k| a: &mut [A], 428| 1.53k|) -> &mut [B] { 429| 1.53k| unsafe { internal::cast_slice_mut(a) } 430| 1.53k|} _RINvYINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShENtNtCs7zV65YDL4Pm_14byteorder_lite2io12ReadBytesExt8read_u16NtBR_12LittleEndianECs3aXgM11XBGX_5image: 109| 1.29k| fn read_u16(&mut self) -> Result { 110| 1.29k| let mut buf = [0; 2]; 111| 1.29k| self.read_exact(&mut buf)?; 112| 1.27k| Ok(T::read_u16(&buf)) 113| 1.29k| } _RINvYINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShENtNtCs7zV65YDL4Pm_14byteorder_lite2io12ReadBytesExt8read_u32NtBR_12LittleEndianECs3aXgM11XBGX_5image: 214| 342| fn read_u32(&mut self) -> Result { 215| 342| let mut buf = [0; 4]; 216| 342| self.read_exact(&mut buf)?; 217| 340| Ok(T::read_u32(&buf)) 218| 342| } _RNvXs1_Cs7zV65YDL4Pm_14byteorder_liteNtB5_12LittleEndianNtB5_9ByteOrder8read_u16Cs3aXgM11XBGX_5image: 2059| 1.27k| fn read_u16(buf: &[u8]) -> u16 { 2060| 1.27k| u16::from_le_bytes(buf[..2].try_into().unwrap()) 2061| 1.27k| } _RNvXs1_Cs7zV65YDL4Pm_14byteorder_liteNtB5_12LittleEndianNtB5_9ByteOrder8read_u32Cs3aXgM11XBGX_5image: 2064| 340| fn read_u32(buf: &[u8]) -> u32 { 2065| 340| u32::from_le_bytes(buf[..4].try_into().unwrap()) 2066| 340| } _RNvNtCs9CIo2vbsQYK_9crc32fast8baseline11update_slow: 61| 895k|pub(crate) fn update_slow(prev: u32, buf: &[u8]) -> u32 { 62| 895k| let mut crc = !prev; 63| | 64| 7.58M| for &byte in buf.iter() { 65| 7.58M| crc = CRC32_TABLE[0][((crc as u8) ^ byte) as usize] ^ (crc >> 8); 66| 7.58M| } 67| | 68| 895k| !crc 69| 895k|} _RNvNtCs9CIo2vbsQYK_9crc32fast8baseline14update_fast_16: 30| 895k|pub(crate) fn update_fast_16(prev: u32, mut buf: &[u8]) -> u32 { 31| | const UNROLL: usize = 4; 32| | const BYTES_AT_ONCE: usize = 16 * UNROLL; 33| | 34| 895k| let mut crc = !prev; 35| | 36| 900k| while buf.len() >= BYTES_AT_ONCE { 37| 24.7k| for _ in 0..UNROLL { 38| 19.7k| crc = CRC32_TABLE[0x0][buf[0xf] as usize] 39| 19.7k| ^ CRC32_TABLE[0x1][buf[0xe] as usize] 40| 19.7k| ^ CRC32_TABLE[0x2][buf[0xd] as usize] 41| 19.7k| ^ CRC32_TABLE[0x3][buf[0xc] as usize] 42| 19.7k| ^ CRC32_TABLE[0x4][buf[0xb] as usize] 43| 19.7k| ^ CRC32_TABLE[0x5][buf[0xa] as usize] 44| 19.7k| ^ CRC32_TABLE[0x6][buf[0x9] as usize] 45| 19.7k| ^ CRC32_TABLE[0x7][buf[0x8] as usize] 46| 19.7k| ^ CRC32_TABLE[0x8][buf[0x7] as usize] 47| 19.7k| ^ CRC32_TABLE[0x9][buf[0x6] as usize] 48| 19.7k| ^ CRC32_TABLE[0xa][buf[0x5] as usize] 49| 19.7k| ^ CRC32_TABLE[0xb][buf[0x4] as usize] 50| 19.7k| ^ CRC32_TABLE[0xc][buf[0x3] as usize ^ ((crc >> 0x18) & 0xFF) as usize] 51| 19.7k| ^ CRC32_TABLE[0xd][buf[0x2] as usize ^ ((crc >> 0x10) & 0xFF) as usize] 52| 19.7k| ^ CRC32_TABLE[0xe][buf[0x1] as usize ^ ((crc >> 0x08) & 0xFF) as usize] 53| 19.7k| ^ CRC32_TABLE[0xf][buf[0x0] as usize ^ (crc & 0xFF) as usize]; 54| 19.7k| buf = &buf[16..]; 55| 19.7k| } 56| | } 57| | 58| 895k| update_slow(!crc, buf) 59| 895k|} _RNvMCs9CIo2vbsQYK_9crc32fastNtB2_6Hasher16new_with_initial: 84| 9.65k| pub fn new_with_initial(init: u32) -> Self { 85| 9.65k| Self::new_with_initial_len(init, 0) 86| 9.65k| } _RNvMCs9CIo2vbsQYK_9crc32fastNtB2_6Hasher20new_with_initial_len: 93| 9.65k| pub fn new_with_initial_len(init: u32, amount: u64) -> Self { 94| 9.65k| Self::internal_new_specialized(init, amount) 95| 9.65k| .unwrap_or_else(|| Self::internal_new_baseline(init, amount)) 96| 9.65k| } _RNvMCs9CIo2vbsQYK_9crc32fastNtB2_6Hasher24internal_new_specialized: 109| 9.65k| pub fn internal_new_specialized(init: u32, amount: u64) -> Option { 110| | { 111| 9.65k| if let Some(state) = specialized::State::new(init) { 112| 9.65k| return Some(Hasher { 113| 9.65k| amount, 114| 9.65k| state: State::Specialized(state), 115| 9.65k| }); 116| 0| } 117| | } 118| 0| None 119| 9.65k| } _RNvMCs9CIo2vbsQYK_9crc32fastNtB2_6Hasher3new: 76| 9.65k| pub fn new() -> Self { 77| 9.65k| Self::new_with_initial(DEFAULT_INIT_STATE) 78| 9.65k| } _RNvMCs9CIo2vbsQYK_9crc32fastNtB2_6Hasher5reset: 139| 83.1k| pub fn reset(&mut self) { 140| 83.1k| self.amount = 0; 141| 83.1k| match self.state { 142| 0| State::Baseline(ref mut state) => state.reset(), 143| 83.1k| State::Specialized(ref mut state) => state.reset(), 144| | } 145| 83.1k| } _RNvMCs9CIo2vbsQYK_9crc32fastNtB2_6Hasher6update: 122| 904k| pub fn update(&mut self, buf: &[u8]) { 123| 904k| self.amount += buf.len() as u64; 124| 904k| match self.state { 125| 0| State::Baseline(ref mut state) => state.update(buf), 126| 904k| State::Specialized(ref mut state) => state.update(buf), 127| | } 128| 904k| } _RNvMCs9CIo2vbsQYK_9crc32fastNtB2_6Hasher8finalize: 131| 77.8k| pub fn finalize(self) -> u32 { 132| 77.8k| match self.state { 133| 0| State::Baseline(state) => state.finalize(), 134| 77.8k| State::Specialized(state) => state.finalize(), 135| | } 136| 77.8k| } _RNvMNtNtCs9CIo2vbsQYK_9crc32fast11specialized9pclmulqdqNtB2_5State3new: 36| 9.65k| pub fn new(state: u32) -> Option { 37| 9.65k| if is_x86_feature_detected!("pclmulqdq") 38| 9.65k| && is_x86_feature_detected!("sse2") 39| 9.65k| && is_x86_feature_detected!("sse4.1") 40| | { 41| | // SAFETY: The conditions above ensure that all 42| | // required instructions are supported by the CPU. 43| 9.65k| Some(Self { state }) 44| | } else { 45| 0| None 46| | } 47| 9.65k| } _RNvMNtNtCs9CIo2vbsQYK_9crc32fast11specialized9pclmulqdqNtB2_5State5reset: 59| 83.1k| pub fn reset(&mut self) { 60| 83.1k| self.state = 0; 61| 83.1k| } _RNvMNtNtCs9CIo2vbsQYK_9crc32fast11specialized9pclmulqdqNtB2_5State6update: 49| 904k| pub fn update(&mut self, buf: &[u8]) { 50| | // SAFETY: The `State::new` constructor ensures that all 51| | // required instructions are supported by the CPU. 52| 904k| self.state = unsafe { calculate(self.state, buf) } 53| 904k| } _RNvMNtNtCs9CIo2vbsQYK_9crc32fast11specialized9pclmulqdqNtB2_5State8finalize: 55| 77.8k| pub fn finalize(self) -> u32 { 56| 77.8k| self.state 57| 77.8k| } _RNvNtNtCs9CIo2vbsQYK_9crc32fast11specialized9pclmulqdq3get: 180| 2.43M|unsafe fn get(a: &mut &[u8]) -> arch::__m128i { 181| 2.43M| debug_assert!(a.len() >= 16); 182| 2.43M| let r = arch::_mm_loadu_si128(a.as_ptr() as *const arch::__m128i); 183| 2.43M| *a = &a[16..]; 184| 2.43M| r 185| 2.43M|} _RNvNtNtCs9CIo2vbsQYK_9crc32fast11specialized9pclmulqdq9calculate: 78| 904k|unsafe fn calculate(crc: u32, mut data: &[u8]) -> u32 { 79| | // In theory we can accelerate smaller chunks too, but for now just rely on 80| | // the fallback implementation as it's too much hassle and doesn't seem too 81| | // beneficial. 82| 904k| if data.len() < 128 { 83| 888k| return crate::baseline::update_fast_16(crc, data); 84| 15.5k| } 85| | 86| | // Step 1: fold by 4 loop 87| 15.5k| let mut x3 = get(&mut data); 88| 15.5k| let mut x2 = get(&mut data); 89| 15.5k| let mut x1 = get(&mut data); 90| 15.5k| let mut x0 = get(&mut data); 91| | 92| | // fold in our initial value, part of the incremental crc checksum 93| 15.5k| x3 = arch::_mm_xor_si128(x3, arch::_mm_cvtsi32_si128(!crc as i32)); 94| | 95| 15.5k| let k1k2 = arch::_mm_set_epi64x(K2, K1); 96| 605k| while data.len() >= 64 { 97| 590k| x3 = reduce128(x3, get(&mut data), k1k2); 98| 590k| x2 = reduce128(x2, get(&mut data), k1k2); 99| 590k| x1 = reduce128(x1, get(&mut data), k1k2); 100| 590k| x0 = reduce128(x0, get(&mut data), k1k2); 101| 590k| } 102| | 103| 15.5k| let k3k4 = arch::_mm_set_epi64x(K4, K3); 104| 15.5k| let mut x = reduce128(x3, x2, k3k4); 105| 15.5k| x = reduce128(x, x1, k3k4); 106| 15.5k| x = reduce128(x, x0, k3k4); 107| | 108| | // Step 2: fold by 1 loop 109| 26.8k| while data.len() >= 16 { 110| 11.3k| x = reduce128(x, get(&mut data), k3k4); 111| 11.3k| } 112| | 113| | // Perform step 3, reduction from 128 bits to 64 bits. This is 114| | // significantly different from the paper and basically doesn't follow it 115| | // at all. It's not really clear why, but implementations of this algorithm 116| | // in Chrome/Linux diverge in the same way. It is beyond me why this is 117| | // different than the paper, maybe the paper has like errata or something? 118| | // Unclear. 119| | // 120| | // It's also not clear to me what's actually happening here and/or why, but 121| | // algebraically what's happening is: 122| | // 123| | // x = (x[0:63] • K4) ^ x[64:127] // 96 bit result 124| | // x = ((x[0:31] as u64) • K5) ^ x[32:95] // 64 bit result 125| | // 126| | // It's... not clear to me what's going on here. The paper itself is pretty 127| | // vague on this part but definitely uses different constants at least. 128| | // It's not clear to me, reading the paper, where the xor operations are 129| | // happening or why things are shifting around. This implementation... 130| | // appears to work though! 131| 15.5k| let x = arch::_mm_xor_si128( 132| 15.5k| arch::_mm_clmulepi64_si128(x, k3k4, 0x10), 133| 15.5k| arch::_mm_srli_si128(x, 8), 134| | ); 135| 15.5k| let x = arch::_mm_xor_si128( 136| 15.5k| arch::_mm_clmulepi64_si128( 137| 15.5k| arch::_mm_and_si128(x, arch::_mm_set_epi32(0, 0, 0, !0)), 138| 15.5k| arch::_mm_set_epi64x(0, K5), 139| | 0x00, 140| | ), 141| 15.5k| arch::_mm_srli_si128(x, 4), 142| | ); 143| | 144| | // Perform a Barrett reduction from our now 64 bits to 32 bits. The 145| | // algorithm for this is described at the end of the paper, and note that 146| | // this also implements the "bit reflected input" variant. 147| 15.5k| let pu = arch::_mm_set_epi64x(U_PRIME, P_X); 148| | 149| | // T1(x) = ⌊(R(x) % x^32)⌋ • μ 150| 15.5k| let t1 = arch::_mm_clmulepi64_si128( 151| 15.5k| arch::_mm_and_si128(x, arch::_mm_set_epi32(0, 0, 0, !0)), 152| 15.5k| pu, 153| | 0x10, 154| | ); 155| | // T2(x) = ⌊(T1(x) % x^32)⌋ • P(x) 156| 15.5k| let t2 = arch::_mm_clmulepi64_si128( 157| 15.5k| arch::_mm_and_si128(t1, arch::_mm_set_epi32(0, 0, 0, !0)), 158| 15.5k| pu, 159| | 0x00, 160| | ); 161| | // We're doing the bit-reflected variant, so get the upper 32-bits of the 162| | // 64-bit result instead of the lower 32-bits. 163| | // 164| | // C(x) = R(x) ^ T2(x) / x^32 165| 15.5k| let c = arch::_mm_extract_epi32(arch::_mm_xor_si128(x, t2), 1) as u32; 166| | 167| 15.5k| if !data.is_empty() { 168| 6.91k| crate::baseline::update_fast_16(!c, data) 169| | } else { 170| 8.58k| !c 171| | } 172| 904k|} _RNvNtNtCs9CIo2vbsQYK_9crc32fast11specialized9pclmulqdq9reduce128: 174| 2.41M|unsafe fn reduce128(a: arch::__m128i, b: arch::__m128i, keys: arch::__m128i) -> arch::__m128i { 175| 2.41M| let t1 = arch::_mm_clmulepi64_si128(a, keys, 0x00); 176| 2.41M| let t2 = arch::_mm_clmulepi64_si128(a, keys, 0x11); 177| 2.41M| arch::_mm_xor_si128(arch::_mm_xor_si128(b, t1), t2) 178| 2.41M|} _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor11fill_buffer: 157| 48.8M| fn fill_buffer(&mut self, input: &mut &[u8]) { 158| 48.8M| if input.len() >= 8 { 159| 48.7M| self.buffer |= u64::from_le_bytes(input[..8].try_into().unwrap()) << self.nbits; 160| 48.7M| *input = &input[(63 - self.nbits as usize) / 8..]; 161| 48.7M| self.nbits |= 56; 162| 48.7M| } else { 163| 122k| let nbytes = input.len().min((63 - self.nbits as usize) / 8); 164| 122k| let mut input_data = [0; 8]; 165| 122k| input_data[..nbytes].copy_from_slice(&input[..nbytes]); 166| 122k| self.buffer |= u64::from_le_bytes(input_data) 167| 122k| .checked_shl(self.nbits as u32) 168| 122k| .unwrap_or(0); 169| 122k| self.nbits += nbytes as u8 * 8; 170| 122k| *input = &input[nbytes..]; 171| 122k| } 172| 48.8M| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor12build_tables: 398| 12.0k| fn build_tables( 399| 12.0k| hlit: usize, 400| 12.0k| code_lengths: &[u8], 401| 12.0k| compression: &mut CompressedBlock, 402| 12.0k| ) -> Result<(), DecompressionError> { 403| | // If there is no code assigned for the EOF symbol then the bitstream is invalid. 404| 12.0k| if code_lengths[256] == 0 { 405| | // TODO: Return a dedicated error in this case. 406| 10| return Err(DecompressionError::BadLiteralLengthHuffmanTree); 407| 12.0k| } 408| | 409| 12.0k| let mut codes = [0; 288]; 410| 12.0k| compression.secondary_table.clear(); 411| 12.0k| if !huffman::build_table( 412| 12.0k| &code_lengths[..hlit], 413| 12.0k| &LITLEN_TABLE_ENTRIES, 414| 12.0k| &mut codes[..hlit], 415| 12.0k| &mut *compression.litlen_table, 416| 12.0k| &mut compression.secondary_table, 417| 12.0k| false, 418| 12.0k| true, 419| 12.0k| ) { 420| 74| return Err(DecompressionError::BadCodeLengthHuffmanTree); 421| 11.9k| } 422| | 423| 11.9k| compression.eof_code = codes[256]; 424| 11.9k| compression.eof_mask = (1 << code_lengths[256]) - 1; 425| 11.9k| compression.eof_bits = code_lengths[256]; 426| | 427| | // Build the distance code table. 428| 11.9k| let lengths = &code_lengths[288..320]; 429| 11.9k| if lengths == [0; 32] { 430| 965| compression.dist_table.fill(0); 431| 965| } else { 432| 11.0k| let mut dist_codes = [0; 32]; 433| 11.0k| if !huffman::build_table( 434| 11.0k| lengths, 435| 11.0k| &tables::DISTANCE_TABLE_ENTRIES, 436| 11.0k| &mut dist_codes, 437| 11.0k| &mut *compression.dist_table, 438| 11.0k| &mut compression.dist_secondary_table, 439| 11.0k| true, 440| 11.0k| false, 441| 11.0k| ) { 442| 117| return Err(DecompressionError::BadDistanceHuffmanTree); 443| 10.9k| } 444| | } 445| | 446| 11.8k| Ok(()) 447| 12.0k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor12consume_bits: 178| 47.8M| fn consume_bits(&mut self, nbits: u8) { 179| 47.8M| debug_assert!(self.nbits >= nbits); 180| 47.8M| self.buffer >>= nbits; 181| 47.8M| self.nbits -= nbits; 182| 47.8M| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor14ignore_adler32: 153| 5.89k| pub fn ignore_adler32(&mut self) { 154| 5.89k| self.ignore_adler32 = true; 155| 5.89k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor15read_compressed: 449| 902k| fn read_compressed( 450| 902k| &mut self, 451| 902k| remaining_input: &mut &[u8], 452| 902k| output: &mut [u8], 453| 902k| mut output_index: usize, 454| 902k| ) -> Result { 455| | // Fast decoding loop. 456| | // 457| | // This loop is optimized for speed and is the main decoding loop for the decompressor, 458| | // which is used when there are at least 8 bytes of input and output data available. It 459| | // assumes that the bitbuffer is full (nbits >= 56) and that litlen_entry has been loaded. 460| | // 461| | // These assumptions enable a few optimizations: 462| | // - Nearly all checks for nbits are avoided. 463| | // - Checking the input size is optimized out in the refill function call. 464| | // - The litlen_entry for the next loop iteration can be loaded in parallel with refilling 465| | // the bit buffer. This is because when the input is non-empty, the bit buffer actually 466| | // has 64-bits of valid data (even though nbits will be in 56..=63). 467| 902k| self.fill_buffer(remaining_input); 468| 902k| let mut litlen_entry = self.compression.litlen_table[(self.buffer & 0xfff) as usize]; 469| 46.0M| while self.state == State::CompressedData 470| 46.0M| && output_index + 8 <= output.len() 471| 46.0M| && remaining_input.len() >= 8 472| | { 473| | // First check whether the next symbol is a literal. This code does up to 2 additional 474| | // table lookups to decode more literals. 475| | let mut bits; 476| 46.0M| let mut litlen_code_bits = litlen_entry as u8; 477| 46.0M| if litlen_entry & LITERAL_ENTRY != 0 { 478| 2.51M| let litlen_entry2 = self.compression.litlen_table 479| 2.51M| [(self.buffer >> litlen_code_bits & 0xfff) as usize]; 480| 2.51M| let litlen_code_bits2 = litlen_entry2 as u8; 481| 2.51M| let litlen_entry3 = self.compression.litlen_table 482| 2.51M| [(self.buffer >> (litlen_code_bits + litlen_code_bits2) & 0xfff) as usize]; 483| 2.51M| let litlen_code_bits3 = litlen_entry3 as u8; 484| 2.51M| let litlen_entry4 = self.compression.litlen_table[(self.buffer 485| 2.51M| >> (litlen_code_bits + litlen_code_bits2 + litlen_code_bits3) 486| 2.51M| & 0xfff) 487| 2.51M| as usize]; 488| | 489| 2.51M| let advance_output_bytes = ((litlen_entry & 0xf00) >> 8) as usize; 490| 2.51M| output[output_index] = (litlen_entry >> 16) as u8; 491| 2.51M| output[output_index + 1] = (litlen_entry >> 24) as u8; 492| 2.51M| output_index += advance_output_bytes; 493| | 494| 2.51M| if litlen_entry2 & LITERAL_ENTRY != 0 { 495| 1.94M| let advance_output_bytes2 = ((litlen_entry2 & 0xf00) >> 8) as usize; 496| 1.94M| output[output_index] = (litlen_entry2 >> 16) as u8; 497| 1.94M| output[output_index + 1] = (litlen_entry2 >> 24) as u8; 498| 1.94M| output_index += advance_output_bytes2; 499| | 500| 1.94M| if litlen_entry3 & LITERAL_ENTRY != 0 { 501| 1.84M| let advance_output_bytes3 = ((litlen_entry3 & 0xf00) >> 8) as usize; 502| 1.84M| output[output_index] = (litlen_entry3 >> 16) as u8; 503| 1.84M| output[output_index + 1] = (litlen_entry3 >> 24) as u8; 504| 1.84M| output_index += advance_output_bytes3; 505| | 506| 1.84M| litlen_entry = litlen_entry4; 507| 1.84M| self.consume_bits(litlen_code_bits + litlen_code_bits2 + litlen_code_bits3); 508| 1.84M| self.fill_buffer(remaining_input); 509| 1.84M| continue; 510| 101k| } else { 511| 101k| self.consume_bits(litlen_code_bits + litlen_code_bits2); 512| 101k| litlen_entry = litlen_entry3; 513| 101k| litlen_code_bits = litlen_code_bits3; 514| 101k| self.fill_buffer(remaining_input); 515| 101k| bits = self.buffer; 516| 101k| } 517| | } else { 518| 575k| self.consume_bits(litlen_code_bits); 519| 575k| bits = self.buffer; 520| 575k| litlen_entry = litlen_entry2; 521| 575k| litlen_code_bits = litlen_code_bits2; 522| 575k| if self.nbits < 48 { 523| 45.7k| self.fill_buffer(remaining_input); 524| 530k| } 525| | } 526| 43.4M| } else { 527| 43.4M| bits = self.buffer; 528| 43.4M| } 529| | 530| | // The next symbol is either a 13+ bit literal, back-reference, or an EOF symbol. 531| 44.1M| let (length_base, length_extra_bits, litlen_code_bits) = 532| 44.1M| if litlen_entry & EXCEPTIONAL_ENTRY == 0 { 533| 43.8M| ( 534| 43.8M| litlen_entry >> 16, 535| 43.8M| (litlen_entry >> 8) as u8, 536| 43.8M| litlen_code_bits, 537| 43.8M| ) 538| 280k| } else if litlen_entry & SECONDARY_TABLE_ENTRY != 0 { 539| 271k| let secondary_table_index = 540| 271k| (litlen_entry >> 16) + ((bits >> 12) as u32 & (litlen_entry & 0xff)); 541| 271k| let secondary_entry = 542| 271k| self.compression.secondary_table[secondary_table_index as usize]; 543| 271k| let litlen_symbol = secondary_entry >> 4; 544| 271k| let litlen_code_bits = (secondary_entry & 0xf) as u8; 545| | 546| 271k| match litlen_symbol { 547| 271k| 0..=255 => { 548| 28.1k| self.consume_bits(litlen_code_bits); 549| 28.1k| litlen_entry = 550| 28.1k| self.compression.litlen_table[(self.buffer & 0xfff) as usize]; 551| 28.1k| self.fill_buffer(remaining_input); 552| 28.1k| output[output_index] = litlen_symbol as u8; 553| 28.1k| output_index += 1; 554| 28.1k| continue; 555| | } 556| | 256 => { 557| 1.58k| self.consume_bits(litlen_code_bits); 558| 1.58k| self.state = match self.last_block { 559| 2| true => State::Checksum, 560| 1.58k| false => State::BlockHeader, 561| | }; 562| 1.58k| break; 563| | } 564| 241k| _ => ( 565| 241k| LEN_SYM_TO_LEN_BASE[litlen_symbol as usize - 257] as u32, 566| 241k| LEN_SYM_TO_LEN_EXTRA[litlen_symbol as usize - 257], 567| 241k| litlen_code_bits, 568| 241k| ), 569| | } 570| 8.96k| } else if litlen_code_bits == 0 { 571| 0| return Err(DecompressionError::InvalidLiteralLengthCode); 572| | } else { 573| 8.96k| self.consume_bits(litlen_code_bits); 574| 8.96k| self.state = match self.last_block { 575| 1.26k| true => State::Checksum, 576| 7.69k| false => State::BlockHeader, 577| | }; 578| 8.96k| break; 579| | }; 580| 44.1M| bits >>= litlen_code_bits; 581| | 582| 44.1M| let length_extra_mask = (1 << length_extra_bits) - 1; 583| 44.1M| let length = length_base as usize + (bits & length_extra_mask) as usize; 584| 44.1M| bits >>= length_extra_bits; 585| | 586| 44.1M| let dist_entry = self.compression.dist_table[(bits & 0x1ff) as usize]; 587| 44.1M| let (dist_base, dist_extra_bits, dist_code_bits) = if dist_entry & LITERAL_ENTRY != 0 { 588| 43.8M| ( 589| 43.8M| (dist_entry >> 16) as u16, 590| 43.8M| (dist_entry >> 8) as u8 & 0xf, 591| 43.8M| dist_entry as u8, 592| 43.8M| ) 593| 257k| } else if dist_entry >> 8 == 0 { 594| 8| return Err(DecompressionError::InvalidDistanceCode); 595| | } else { 596| 257k| let secondary_table_index = 597| 257k| (dist_entry >> 16) + ((bits >> 9) as u32 & (dist_entry & 0xff)); 598| 257k| let secondary_entry = 599| 257k| self.compression.dist_secondary_table[secondary_table_index as usize]; 600| 257k| let dist_symbol = (secondary_entry >> 4) as usize; 601| 257k| if dist_symbol >= 30 { 602| 0| return Err(DecompressionError::InvalidDistanceCode); 603| 257k| } 604| | 605| 257k| ( 606| 257k| DIST_SYM_TO_DIST_BASE[dist_symbol], 607| 257k| DIST_SYM_TO_DIST_EXTRA[dist_symbol], 608| 257k| (secondary_entry & 0xf) as u8, 609| 257k| ) 610| | }; 611| 44.1M| bits >>= dist_code_bits; 612| | 613| 44.1M| let dist = dist_base as usize + (bits & ((1 << dist_extra_bits) - 1)) as usize; 614| 44.1M| if dist > output_index { 615| 69| return Err(DecompressionError::DistanceTooFarBack); 616| 44.1M| } 617| | 618| 44.1M| self.consume_bits( 619| 44.1M| litlen_code_bits + length_extra_bits + dist_code_bits + dist_extra_bits, 620| | ); 621| 44.1M| self.fill_buffer(remaining_input); 622| 44.1M| litlen_entry = self.compression.litlen_table[(self.buffer & 0xfff) as usize]; 623| | 624| 44.1M| let copy_length = length.min(output.len() - output_index); 625| 44.1M| if dist == 1 { 626| 21.1M| let last = output[output_index - 1]; 627| 21.1M| output[output_index..][..copy_length].fill(last); 628| | 629| 21.1M| if copy_length < length { 630| 235k| self.queued_rle = Some((last, length - copy_length)); 631| 235k| output_index = output.len(); 632| 235k| break; 633| 20.9M| } 634| 22.9M| } else if output_index + length + 15 <= output.len() { 635| 22.3M| let start = output_index - dist; 636| 22.3M| output.copy_within(start..start + 16, output_index); 637| | 638| 22.3M| if length > 16 || dist < 16 { 639| 1.70G| for i in (0..length).step_by(dist.min(16)).skip(1) { 640| 1.70G| output.copy_within(start + i..start + i + 16, output_index + i); 641| 1.70G| } 642| 576k| } 643| | } else { 644| 655k| if dist < copy_length { 645| 89.4M| for i in 0..copy_length { 646| 89.4M| output[output_index + i] = output[output_index + i - dist]; 647| 89.4M| } 648| | } else { 649| 17.1k| output.copy_within( 650| 17.1k| output_index - dist..output_index + copy_length - dist, 651| 17.1k| output_index, 652| | ) 653| | } 654| | 655| 655k| if copy_length < length { 656| 615k| self.queued_backref = Some((dist, length - copy_length)); 657| 615k| output_index = output.len(); 658| 615k| break; 659| 40.4k| } 660| | } 661| 43.2M| output_index += copy_length; 662| | } 663| | 664| | // Careful decoding loop. 665| | // 666| | // This loop processes the remaining input when we're too close to the end of the input or 667| | // output to use the fast loop. 668| 987k| while let State::CompressedData = self.state { 669| 976k| self.fill_buffer(remaining_input); 670| 976k| if output_index == output.len() { 671| 855k| break; 672| 120k| } 673| | 674| 120k| let mut bits = self.buffer; 675| 120k| let litlen_entry = self.compression.litlen_table[(bits & 0xfff) as usize]; 676| 120k| let litlen_code_bits = litlen_entry as u8; 677| | 678| 120k| if litlen_entry & LITERAL_ENTRY != 0 { 679| | // Fast path: the next symbol is <= 12 bits and a literal, the table specifies the 680| | // output bytes and we can directly write them to the output buffer. 681| 26.9k| let advance_output_bytes = ((litlen_entry & 0xf00) >> 8) as usize; 682| | 683| 26.9k| if self.nbits < litlen_code_bits { 684| 1.55k| break; 685| 25.3k| } else if output_index + 1 < output.len() { 686| 24.7k| output[output_index] = (litlen_entry >> 16) as u8; 687| 24.7k| output[output_index + 1] = (litlen_entry >> 24) as u8; 688| 24.7k| output_index += advance_output_bytes; 689| 24.7k| self.consume_bits(litlen_code_bits); 690| 24.7k| continue; 691| 607| } else if output_index + advance_output_bytes == output.len() { 692| 278| debug_assert_eq!(advance_output_bytes, 1); 693| 278| output[output_index] = (litlen_entry >> 16) as u8; 694| 278| output_index += 1; 695| 278| self.consume_bits(litlen_code_bits); 696| 278| break; 697| | } else { 698| 329| debug_assert_eq!(advance_output_bytes, 2); 699| 329| output[output_index] = (litlen_entry >> 16) as u8; 700| 329| self.queued_rle = Some(((litlen_entry >> 24) as u8, 1)); 701| 329| output_index += 1; 702| 329| self.consume_bits(litlen_code_bits); 703| 329| break; 704| | } 705| 93.9k| } 706| | 707| 90.7k| let (length_base, length_extra_bits, litlen_code_bits) = 708| 93.9k| if litlen_entry & EXCEPTIONAL_ENTRY == 0 { 709| 90.4k| ( 710| 90.4k| litlen_entry >> 16, 711| 90.4k| (litlen_entry >> 8) as u8, 712| 90.4k| litlen_code_bits, 713| 90.4k| ) 714| 3.53k| } else if litlen_entry & SECONDARY_TABLE_ENTRY != 0 { 715| 557| let secondary_table_index = 716| 557| (litlen_entry >> 16) + ((bits >> 12) as u32 & (litlen_entry & 0xff)); 717| 557| let secondary_entry = 718| 557| self.compression.secondary_table[secondary_table_index as usize]; 719| 557| let litlen_symbol = secondary_entry >> 4; 720| 557| let litlen_code_bits = (secondary_entry & 0xf) as u8; 721| | 722| 557| if self.nbits < litlen_code_bits { 723| 8| break; 724| 549| } else if litlen_symbol < 256 { 725| 213| self.consume_bits(litlen_code_bits); 726| 213| output[output_index] = litlen_symbol as u8; 727| 213| output_index += 1; 728| 213| continue; 729| 336| } else if litlen_symbol == 256 { 730| 18| self.consume_bits(litlen_code_bits); 731| 18| self.state = match self.last_block { 732| 0| true => State::Checksum, 733| 18| false => State::BlockHeader, 734| | }; 735| 18| break; 736| 318| } 737| | 738| 318| ( 739| 318| LEN_SYM_TO_LEN_BASE[litlen_symbol as usize - 257] as u32, 740| 318| LEN_SYM_TO_LEN_EXTRA[litlen_symbol as usize - 257], 741| 318| litlen_code_bits, 742| 318| ) 743| 2.97k| } else if litlen_code_bits == 0 { 744| 0| return Err(DecompressionError::InvalidLiteralLengthCode); 745| | } else { 746| 2.97k| if self.nbits < litlen_code_bits { 747| 865| break; 748| 2.11k| } 749| 2.11k| self.consume_bits(litlen_code_bits); 750| 2.11k| self.state = match self.last_block { 751| 1.19k| true => State::Checksum, 752| 922| false => State::BlockHeader, 753| | }; 754| 2.11k| break; 755| | }; 756| 90.7k| bits >>= litlen_code_bits; 757| | 758| 90.7k| let length_extra_mask = (1 << length_extra_bits) - 1; 759| 90.7k| let length = length_base as usize + (bits & length_extra_mask) as usize; 760| 90.7k| bits >>= length_extra_bits; 761| | 762| 90.7k| let dist_entry = self.compression.dist_table[(bits & 0x1ff) as usize]; 763| 90.7k| let (dist_base, dist_extra_bits, dist_code_bits) = if dist_entry & LITERAL_ENTRY != 0 { 764| 90.1k| ( 765| 90.1k| (dist_entry >> 16) as u16, 766| 90.1k| (dist_entry >> 8) as u8 & 0xf, 767| 90.1k| dist_entry as u8, 768| 90.1k| ) 769| 642| } else if self.nbits > litlen_code_bits + length_extra_bits + 9 { 770| 438| if dist_entry >> 8 == 0 { 771| 19| return Err(DecompressionError::InvalidDistanceCode); 772| 419| } 773| | 774| 419| let secondary_table_index = 775| 419| (dist_entry >> 16) + ((bits >> 9) as u32 & (dist_entry & 0xff)); 776| 419| let secondary_entry = 777| 419| self.compression.dist_secondary_table[secondary_table_index as usize]; 778| 419| let dist_symbol = (secondary_entry >> 4) as usize; 779| 419| if dist_symbol >= 30 { 780| 0| return Err(DecompressionError::InvalidDistanceCode); 781| 419| } 782| | 783| 419| ( 784| 419| DIST_SYM_TO_DIST_BASE[dist_symbol], 785| 419| DIST_SYM_TO_DIST_EXTRA[dist_symbol], 786| 419| (secondary_entry & 0xf) as u8, 787| 419| ) 788| | } else { 789| 204| break; 790| | }; 791| 90.5k| bits >>= dist_code_bits; 792| | 793| 90.5k| let dist = dist_base as usize + (bits & ((1 << dist_extra_bits) - 1)) as usize; 794| 90.5k| let total_bits = 795| 90.5k| litlen_code_bits + length_extra_bits + dist_code_bits + dist_extra_bits; 796| | 797| 90.5k| if self.nbits < total_bits { 798| 1.33k| break; 799| 89.1k| } else if dist > output_index { 800| 93| return Err(DecompressionError::DistanceTooFarBack); 801| 89.1k| } 802| | 803| 89.1k| self.consume_bits(total_bits); 804| | 805| 89.1k| let copy_length = length.min(output.len() - output_index); 806| 89.1k| if dist == 1 { 807| 23.8k| let last = output[output_index - 1]; 808| 23.8k| output[output_index..][..copy_length].fill(last); 809| | 810| 23.8k| if copy_length < length { 811| 7.76k| self.queued_rle = Some((last, length - copy_length)); 812| 7.76k| output_index = output.len(); 813| 7.76k| break; 814| 16.0k| } 815| 65.2k| } else if output_index + length + 15 <= output.len() { 816| 42.8k| let start = output_index - dist; 817| 42.8k| output.copy_within(start..start + 16, output_index); 818| | 819| 42.8k| if length > 16 || dist < 16 { 820| 3.37M| for i in (0..length).step_by(dist.min(16)).skip(1) { 821| 3.37M| output.copy_within(start + i..start + i + 16, output_index + i); 822| 3.37M| } 823| 1.61k| } 824| | } else { 825| 22.4k| if dist < copy_length { 826| 329k| for i in 0..copy_length { 827| 329k| output[output_index + i] = output[output_index + i - dist]; 828| 329k| } 829| | } else { 830| 10.2k| output.copy_within( 831| 10.2k| output_index - dist..output_index + copy_length - dist, 832| 10.2k| output_index, 833| | ) 834| | } 835| | 836| 22.4k| if copy_length < length { 837| 21.3k| self.queued_backref = Some((dist, length - copy_length)); 838| 21.3k| output_index = output.len(); 839| 21.3k| break; 840| 1.02k| } 841| | } 842| 59.9k| output_index += copy_length; 843| | } 844| | 845| 902k| if self.state == State::CompressedData 846| 889k| && self.queued_backref.is_none() 847| 252k| && self.queued_rle.is_none() 848| 8.90k| && self.nbits >= 15 849| 5.20k| && self.peak_bits(15) as u16 & self.compression.eof_mask == self.compression.eof_code 850| | { 851| 733| self.consume_bits(self.compression.eof_bits); 852| 733| self.state = match self.last_block { 853| 654| true => State::Checksum, 854| 79| false => State::BlockHeader, 855| | }; 856| 901k| } 857| | 858| 902k| Ok(output_index) 859| 902k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor17read_block_header: 184| 21.2k| fn read_block_header(&mut self, remaining_input: &mut &[u8]) -> Result<(), DecompressionError> { 185| 21.2k| self.fill_buffer(remaining_input); 186| 21.2k| if self.nbits < 10 { 187| 429| return Ok(()); 188| 20.8k| } 189| | 190| 20.8k| let start = self.peak_bits(3); 191| 20.8k| self.last_block = start & 1 != 0; 192| 20.8k| match start >> 1 { 193| | 0b00 => { 194| 1.20k| let align_bits = (self.nbits - 3) % 8; 195| 1.20k| let header_bits = 3 + 32 + align_bits; 196| 1.20k| if self.nbits < header_bits { 197| 209| return Ok(()); 198| 998| } 199| | 200| 998| let len = (self.peak_bits(align_bits + 19) >> (align_bits + 3)) as u16; 201| 998| let nlen = (self.peak_bits(header_bits) >> (align_bits + 19)) as u16; 202| 998| if nlen != !len { 203| 69| return Err(DecompressionError::InvalidUncompressedBlockLength); 204| 929| } 205| | 206| 929| self.state = State::UncompressedData; 207| 929| self.uncompressed_bytes_left = len; 208| 929| self.consume_bits(header_bits); 209| 929| Ok(()) 210| | } 211| | 0b01 => { 212| 7.10k| self.consume_bits(3); 213| | 214| | // Check for an entirely empty blocks which can happen if there are "partial 215| | // flushes" in the deflate stream. With fixed huffman codes, the EOF symbol is 216| | // 7-bits of zeros so we peak ahead and see if the next 7-bits are all zero. 217| 7.10k| if self.peak_bits(7) == 0 { 218| 1.42k| self.consume_bits(7); 219| 1.42k| if self.last_block { 220| 19| self.state = State::Checksum; 221| 19| return Ok(()); 222| 1.40k| } 223| | 224| | // At this point we've consumed the entire block and need to read the next block 225| | // header. If tail call optimization were guaranteed, we could just recurse 226| | // here. But without it, a long sequence of empty fixed-blocks might cause a 227| | // stack overflow. Instead, we consume all empty blocks in a loop and then 228| | // recurse. This is the only recursive call this function, and thus is safe. 229| 2.17k| while self.nbits >= 10 && self.peak_bits(10) == 0b010 { 230| 770| self.consume_bits(10); 231| 770| self.fill_buffer(remaining_input); 232| 770| } 233| 1.40k| return self.read_block_header(remaining_input); 234| 5.68k| } 235| | 236| | // Build decoding tables if the previous block wasn't also a fixed block. 237| 5.68k| if !self.fixed_table { 238| 4.33k| self.fixed_table = true; 239| 34.6k| for chunk in self.compression.litlen_table.chunks_exact_mut(512) { 240| 34.6k| chunk.copy_from_slice(&FIXED_LITLEN_TABLE); 241| 34.6k| } 242| 69.2k| for chunk in self.compression.dist_table.chunks_exact_mut(32) { 243| 69.2k| chunk.copy_from_slice(&FIXED_DIST_TABLE); 244| 69.2k| } 245| 4.33k| self.compression.eof_bits = 7; 246| 4.33k| self.compression.eof_code = 0; 247| 4.33k| self.compression.eof_mask = 0x7f; 248| 1.35k| } 249| | 250| 5.68k| self.state = State::CompressedData; 251| 5.68k| Ok(()) 252| | } 253| | 0b10 => { 254| 12.4k| if self.nbits < 17 { 255| 84| return Ok(()); 256| 12.3k| } 257| | 258| 12.3k| self.header.hlit = (self.peak_bits(8) >> 3) as usize + 257; 259| 12.3k| self.header.hdist = (self.peak_bits(13) >> 8) as usize + 1; 260| 12.3k| self.header.hclen = (self.peak_bits(17) >> 13) as usize + 4; 261| 12.3k| if self.header.hlit > 286 { 262| 6| return Err(DecompressionError::InvalidHlit); 263| 12.3k| } 264| 12.3k| if self.header.hdist > 30 { 265| 5| return Err(DecompressionError::InvalidHdist); 266| 12.3k| } 267| | 268| 12.3k| self.consume_bits(17); 269| 12.3k| self.state = State::CodeLengthCodes; 270| 12.3k| self.fixed_table = false; 271| 12.3k| Ok(()) 272| | } 273| 30| 0b11 => Err(DecompressionError::InvalidBlockType), 274| 0| _ => unreachable!(), 275| | } 276| 21.2k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor17read_code_lengths: 317| 12.6k| fn read_code_lengths(&mut self, remaining_input: &mut &[u8]) -> Result<(), DecompressionError> { 318| 12.6k| let total_lengths = self.header.hlit + self.header.hdist; 319| 797k| while self.header.num_lengths_read < total_lengths { 320| 785k| self.fill_buffer(remaining_input); 321| 785k| if self.nbits < 7 { 322| 310| return Ok(()); 323| 784k| } 324| | 325| 784k| let code = self.peak_bits(7); 326| 784k| let entry = self.header.table[code as usize]; 327| 784k| let length = (entry & 0x7) as u8; 328| 784k| let symbol = (entry >> 16) as u8; 329| | 330| 784k| debug_assert!(length != 0); 331| 784k| match symbol { 332| 784k| 0..=15 => { 333| 681k| self.header.code_lengths[self.header.num_lengths_read] = symbol; 334| 681k| self.header.num_lengths_read += 1; 335| 681k| self.consume_bits(length); 336| 681k| } 337| 103k| 16..=18 => { 338| 103k| let (base_repeat, extra_bits) = match symbol { 339| 43.1k| 16 => (3, 2), 340| 28.2k| 17 => (3, 3), 341| 32.4k| 18 => (11, 7), 342| 0| _ => unreachable!(), 343| | }; 344| | 345| 103k| if self.nbits < length + extra_bits { 346| 283| return Ok(()); 347| 103k| } 348| | 349| 103k| let value = match symbol { 350| | 16 => { 351| 43.0k| self.header.code_lengths[self 352| 43.0k| .header 353| 43.0k| .num_lengths_read 354| 43.0k| .checked_sub(1) 355| 43.0k| .ok_or(DecompressionError::InvalidCodeLengthRepeat)?] 356| | // TODO: is this right? 357| | } 358| 28.2k| 17 => 0, 359| 32.2k| 18 => 0, 360| 0| _ => unreachable!(), 361| | }; 362| | 363| 103k| let repeat = 364| 103k| (self.peak_bits(length + extra_bits) >> length) as usize + base_repeat; 365| 103k| if self.header.num_lengths_read + repeat > total_lengths { 366| 26| return Err(DecompressionError::InvalidCodeLengthRepeat); 367| 103k| } 368| | 369| 2.80M| for i in 0..repeat { 370| 2.80M| self.header.code_lengths[self.header.num_lengths_read + i] = value; 371| 2.80M| } 372| 103k| self.header.num_lengths_read += repeat; 373| 103k| self.consume_bits(length + extra_bits); 374| | } 375| 0| _ => unreachable!(), 376| | } 377| | } 378| | 379| 12.0k| self.header 380| 12.0k| .code_lengths 381| 12.0k| .copy_within(self.header.hlit..total_lengths, 288); 382| 178k| for i in self.header.hlit..288 { 383| 178k| self.header.code_lengths[i] = 0; 384| 178k| } 385| 213k| for i in 288 + self.header.hdist..320 { 386| 213k| self.header.code_lengths[i] = 0; 387| 213k| } 388| | 389| 12.0k| Self::build_tables( 390| 12.0k| self.header.hlit, 391| 12.0k| &self.header.code_lengths, 392| 12.0k| &mut self.compression, 393| 201| )?; 394| 11.8k| self.state = State::CompressedData; 395| 11.8k| Ok(()) 396| 12.6k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor22read_code_length_codes: 278| 12.5k| fn read_code_length_codes( 279| 12.5k| &mut self, 280| 12.5k| remaining_input: &mut &[u8], 281| 12.5k| ) -> Result<(), DecompressionError> { 282| 12.5k| self.fill_buffer(remaining_input); 283| 12.5k| if self.nbits as usize + remaining_input.len() * 8 < 3 * self.header.hclen { 284| 234| return Ok(()); 285| 12.3k| } 286| | 287| 12.3k| let mut code_length_lengths = [0; 19]; 288| 216k| for i in 0..self.header.hclen { 289| 216k| code_length_lengths[CLCL_ORDER[i]] = self.peak_bits(3) as u8; 290| 216k| self.consume_bits(3); 291| | 292| | // We need to refill the buffer after reading 3 * 18 = 54 bits since the buffer holds 293| | // between 56 and 63 bits total. 294| 216k| if i == 17 { 295| 9.76k| self.fill_buffer(remaining_input); 296| 206k| } 297| | } 298| | 299| 12.3k| let mut codes = [0; 19]; 300| 12.3k| if !build_table( 301| 12.3k| &code_length_lengths, 302| 12.3k| &[], 303| 12.3k| &mut codes, 304| 12.3k| &mut self.header.table, 305| 12.3k| &mut Vec::new(), 306| 12.3k| false, 307| 12.3k| false, 308| 12.3k| ) { 309| 96| return Err(DecompressionError::BadCodeLengthHuffmanTree); 310| 12.2k| } 311| | 312| 12.2k| self.state = State::CodeLengths; 313| 12.2k| self.header.num_lengths_read = 0; 314| 12.2k| Ok(()) 315| 12.5k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor3new: 120| 12.3k| pub fn new() -> Self { 121| 12.3k| Self { 122| 12.3k| buffer: 0, 123| 12.3k| nbits: 0, 124| 12.3k| compression: CompressedBlock { 125| 12.3k| litlen_table: Box::new([0; 4096]), 126| 12.3k| dist_table: Box::new([0; 512]), 127| 12.3k| secondary_table: Vec::new(), 128| 12.3k| dist_secondary_table: Vec::new(), 129| 12.3k| eof_code: 0, 130| 12.3k| eof_mask: 0, 131| 12.3k| eof_bits: 0, 132| 12.3k| }, 133| 12.3k| header: BlockHeader { 134| 12.3k| hlit: 0, 135| 12.3k| hdist: 0, 136| 12.3k| hclen: 0, 137| 12.3k| table: [0; 128], 138| 12.3k| num_lengths_read: 0, 139| 12.3k| code_lengths: [0; 320], 140| 12.3k| }, 141| 12.3k| uncompressed_bytes_left: 0, 142| 12.3k| queued_rle: None, 143| 12.3k| queued_backref: None, 144| 12.3k| checksum: Adler32::new(), 145| 12.3k| state: State::ZlibHeader, 146| 12.3k| last_block: false, 147| 12.3k| ignore_adler32: false, 148| 12.3k| fixed_table: false, 149| 12.3k| } 150| 12.3k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor4read: 879| 896k| pub fn read( 880| 896k| &mut self, 881| 896k| input: &[u8], 882| 896k| output: &mut [u8], 883| 896k| output_position: usize, 884| 896k| end_of_input: bool, 885| 896k| ) -> Result<(usize, usize), DecompressionError> { 886| 896k| if let State::Done = self.state { 887| 0| return Ok((0, 0)); 888| 896k| } 889| | 890| 896k| assert!(output_position <= output.len()); 891| | 892| 896k| let mut remaining_input = input; 893| 896k| let mut output_index = output_position; 894| | 895| 896k| if let Some((data, len)) = self.queued_rle.take() { 896| 243k| let n = len.min(output.len() - output_index); 897| 243k| output[output_index..][..n].fill(data); 898| 243k| output_index += n; 899| 243k| if n < len { 900| 8| self.queued_rle = Some((data, len - n)); 901| 8| return Ok((0, n)); 902| 243k| } 903| 652k| } 904| 896k| if let Some((dist, len)) = self.queued_backref.take() { 905| 635k| let n = len.min(output.len() - output_index); 906| 81.6M| for i in 0..n { 907| 81.6M| output[output_index + i] = output[output_index + i - dist]; 908| 81.6M| } 909| 635k| output_index += n; 910| 635k| if n < len { 911| 17| self.queued_backref = Some((dist, len - n)); 912| 17| return Ok((0, n)); 913| 635k| } 914| 261k| } 915| | 916| | // Main decoding state machine. 917| 896k| let mut last_state = None; 918| 1.85M| while last_state != Some(self.state) { 919| 961k| last_state = Some(self.state); 920| 961k| match self.state { 921| | State::ZlibHeader => { 922| 9.73k| self.fill_buffer(&mut remaining_input); 923| 9.73k| if self.nbits < 16 { 924| 1.55k| break; 925| 8.18k| } 926| | 927| 8.18k| let input0 = self.peak_bits(8); 928| 8.18k| let input1 = self.peak_bits(16) >> 8 & 0xff; 929| 8.18k| if input0 & 0x0f != 0x08 930| 8.11k| || (input0 & 0xf0) > 0x70 931| 8.11k| || input1 & 0x20 != 0 932| 8.10k| || (input0 << 8 | input1) % 31 != 0 933| | { 934| 93| return Err(DecompressionError::BadZlibHeader); 935| 8.09k| } 936| | 937| 8.09k| self.consume_bits(16); 938| 8.09k| self.state = State::BlockHeader; 939| | } 940| | State::BlockHeader => { 941| 19.8k| self.read_block_header(&mut remaining_input)?; 942| | } 943| | State::CodeLengthCodes => { 944| 12.5k| self.read_code_length_codes(&mut remaining_input)?; 945| | } 946| | State::CodeLengths => { 947| 12.6k| self.read_code_lengths(&mut remaining_input)?; 948| | } 949| | State::CompressedData => { 950| | output_index = 951| 902k| self.read_compressed(&mut remaining_input, output, output_index)? 952| | } 953| | State::UncompressedData => { 954| | // Drain any bytes from our buffer. 955| 1.31k| debug_assert_eq!(self.nbits % 8, 0); 956| 3.01k| while self.nbits > 0 957| 1.77k| && self.uncompressed_bytes_left > 0 958| 1.69k| && output_index < output.len() 959| 1.69k| { 960| 1.69k| output[output_index] = self.peak_bits(8) as u8; 961| 1.69k| self.consume_bits(8); 962| 1.69k| output_index += 1; 963| 1.69k| self.uncompressed_bytes_left -= 1; 964| 1.69k| } 965| | // Buffer may contain one additional byte. Clear it to avoid confusion. 966| 1.31k| if self.nbits == 0 { 967| 1.23k| self.buffer = 0; 968| 1.23k| } 969| | 970| | // Copy subsequent bytes directly from the input. 971| 1.31k| let copy_bytes = (self.uncompressed_bytes_left as usize) 972| 1.31k| .min(remaining_input.len()) 973| 1.31k| .min(output.len() - output_index); 974| 1.31k| output[output_index..][..copy_bytes] 975| 1.31k| .copy_from_slice(&remaining_input[..copy_bytes]); 976| 1.31k| remaining_input = &remaining_input[copy_bytes..]; 977| 1.31k| output_index += copy_bytes; 978| 1.31k| self.uncompressed_bytes_left -= copy_bytes as u16; 979| | 980| 1.31k| if self.uncompressed_bytes_left == 0 { 981| 857| self.state = if self.last_block { 982| 3| State::Checksum 983| | } else { 984| 854| State::BlockHeader 985| | }; 986| 461| } 987| | } 988| | State::Checksum => { 989| 3.32k| self.fill_buffer(&mut remaining_input); 990| | 991| 3.32k| let align_bits = self.nbits % 8; 992| 3.32k| if self.nbits >= 32 + align_bits { 993| 3.05k| self.checksum.write(&output[output_position..output_index]); 994| 3.05k| if align_bits != 0 { 995| 2.71k| self.consume_bits(align_bits); 996| 2.71k| } 997| | #[cfg(not(fuzzing))] 998| | if !self.ignore_adler32 999| | && (self.peak_bits(32) as u32).swap_bytes() != self.checksum.finish() 1000| | { 1001| | return Err(DecompressionError::WrongChecksum); 1002| | } 1003| 3.05k| self.state = State::Done; 1004| 3.05k| self.consume_bits(32); 1005| 3.05k| break; 1006| 276| } 1007| | } 1008| 0| State::Done => unreachable!(), 1009| | } 1010| | } 1011| | 1012| 895k| if !self.ignore_adler32 && self.state != State::Done { 1013| 151k| self.checksum.write(&output[output_position..output_index]); 1014| 744k| } 1015| | 1016| 895k| if self.state == State::Done || !end_of_input || output_index == output.len() { 1017| 895k| let input_left = remaining_input.len(); 1018| 895k| Ok((input.len() - input_left, output_index - output_position)) 1019| | } else { 1020| 318| Err(DecompressionError::InsufficientInput) 1021| | } 1022| 896k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor7is_done: 1025| 1.64M| pub fn is_done(&self) -> bool { 1026| 1.64M| self.state == State::Done 1027| 1.64M| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor9peak_bits: 174| 1.19M| fn peak_bits(&mut self, nbits: u8) -> u64 { 175| 1.19M| debug_assert!(nbits <= 56 && nbits <= self.nbits); 176| 1.19M| self.buffer & ((1u64 << nbits) - 1) 177| 1.19M| } _RNvNtCsh5m7Dv6WxNY_8fdeflate10decompress25decompress_to_vec_bounded: 1063| 2.42k|pub fn decompress_to_vec_bounded( 1064| 2.42k| input: &[u8], 1065| 2.42k| maxlen: usize, 1066| 2.42k|) -> Result, BoundedDecompressionError> { 1067| 2.42k| let mut decoder = Decompressor::new(); 1068| 2.42k| let mut output = vec![0; 1024.min(maxlen)]; 1069| 2.42k| let mut input_index = 0; 1070| 2.42k| let mut output_index = 0; 1071| | loop { 1072| 153k| let (consumed, produced) = 1073| 153k| decoder.read(&input[input_index..], &mut output, output_index, true)?; 1074| 153k| input_index += consumed; 1075| 153k| output_index += produced; 1076| 153k| if decoder.is_done() || output_index == maxlen { 1077| 2.01k| break; 1078| 151k| } 1079| 151k| output.resize((output_index + 32 * 1024).min(maxlen), 0); 1080| | } 1081| 2.01k| output.resize(output_index, 0); 1082| | 1083| 2.01k| if decoder.is_done() { 1084| 2.01k| Ok(output) 1085| | } else { 1086| 0| Err(BoundedDecompressionError::OutputTooLarge { 1087| 0| partial_output: output, 1088| 0| }) 1089| | } 1090| 2.42k|} _RNvXs0_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB5_25BoundedDecompressionErrorINtNtCs6SNw0SRvItZ_4core7convert4FromNtB5_18DecompressionErrorE4from: 1056| 416| fn from(inner: DecompressionError) -> Self { 1057| 416| BoundedDecompressionError::DecompressionError { inner } 1058| 416| } _RNCNvNtCsh5m7Dv6WxNY_8fdeflate7huffman11build_table0B5_: 46| 8.79k| let symbol = lengths.iter().position(|&l| l == 1).unwrap(); _RNvNtCsh5m7Dv6WxNY_8fdeflate7huffman11build_table: 18| 35.4k|pub fn build_table( 19| 35.4k| lengths: &[u8], 20| 35.4k| entries: &[u32], 21| 35.4k| codes: &mut [u16], 22| 35.4k| primary_table: &mut [u32], 23| 35.4k| secondary_table: &mut Vec, 24| 35.4k| is_distance_table: bool, 25| 35.4k| double_literal: bool, 26| 35.4k|) -> bool { 27| | // Count the number of symbols with each code length. 28| 35.4k| let mut histogram = [0; 16]; 29| 3.91M| for &length in lengths { 30| 3.88M| histogram[length as usize] += 1; 31| 3.88M| } 32| | 33| | // Determine the maximum code length. 34| 35.4k| let mut max_length = 15; 35| 400k| while max_length > 1 && histogram[max_length] == 0 { 36| 365k| max_length -= 1; 37| 365k| } 38| | 39| | // Handle zero and one symbol huffman codes (which are only allowed for distance codes). 40| 35.4k| if is_distance_table { 41| 11.0k| if max_length == 0 { 42| 0| primary_table.fill(0); 43| 0| secondary_table.clear(); 44| 0| return true; 45| 11.0k| } else if max_length == 1 && histogram[1] == 1 { 46| 4.12k| let symbol = lengths.iter().position(|&l| l == 1).unwrap(); 47| 4.12k| codes[symbol] = 0; 48| 4.12k| let entry = entries 49| 4.12k| .get(symbol) 50| 4.12k| .cloned() 51| 4.12k| .unwrap_or((symbol as u32) << 16) 52| 4.12k| | 1; 53| 1.05M| for chunk in primary_table.chunks_mut(2) { 54| 1.05M| chunk[0] = entry; 55| 1.05M| chunk[1] = 0; 56| 1.05M| } 57| 4.12k| return true; 58| 6.89k| } 59| 24.3k| } 60| | 61| | // Sort symbols by code length. Given the histogram, we can determine the starting offset 62| | // for each code length. 63| 31.2k| let mut offsets = [0; 16]; 64| 31.2k| let mut codespace_used = 0; 65| 31.2k| offsets[1] = histogram[0]; 66| 130k| for i in 1..max_length { 67| 130k| offsets[i + 1] = offsets[i] + histogram[i]; 68| 130k| codespace_used = (codespace_used << 1) + histogram[i]; 69| 130k| } 70| 31.2k| codespace_used = (codespace_used << 1) + histogram[max_length]; 71| | 72| | // Check that the provided lengths form a valid Huffman tree. 73| 31.2k| if codespace_used != (1 << max_length) { 74| 287| return false; 75| 31.0k| } 76| | 77| | // Sort the symbols by code length. 78| 31.0k| let mut next_index = offsets; 79| 31.0k| let mut sorted_symbols = [0; 288]; 80| 3.72M| for symbol in 0..lengths.len() { 81| 3.72M| let length = lengths[symbol]; 82| 3.72M| sorted_symbols[next_index[length as usize]] = symbol; 83| 3.72M| next_index[length as usize] += 1; 84| 3.72M| } 85| | 86| 31.0k| let mut codeword = 0u16; 87| 31.0k| let mut i = histogram[0]; 88| | 89| | // Populate the primary decoding table 90| 31.0k| let primary_table_bits = primary_table.len().ilog2() as usize; 91| 31.0k| let primary_table_mask = (1 << primary_table_bits) - 1; 92| 290k| for length in 1..=primary_table_bits { 93| 290k| let current_table_end = 1 << length; 94| | 95| | // Loop over all symbols with the current code length and set their table entries. 96| 730k| for _ in 0..histogram[length] { 97| 730k| let symbol = sorted_symbols[i]; 98| 730k| i += 1; 99| 730k| 100| 730k| primary_table[codeword as usize] = entries 101| 730k| .get(symbol) 102| 730k| .cloned() 103| 730k| .unwrap_or((symbol as u32) << 16) 104| 730k| | length as u32; 105| 730k| 106| 730k| codes[symbol] = codeword; 107| 730k| codeword = next_codeword(codeword, current_table_end as u16); 108| 730k| } 109| | 110| 290k| if double_literal { 111| 659k| for len1 in 1..(length - 1) { 112| 659k| let len2 = length - len1; 113| 1.62M| for sym1_index in offsets[len1]..next_index[len1] { 114| 3.06M| for sym2_index in offsets[len2]..next_index[len2] { 115| 3.06M| let sym1 = sorted_symbols[sym1_index]; 116| 3.06M| let sym2 = sorted_symbols[sym2_index]; 117| 3.06M| if sym1 < 256 && sym2 < 256 { 118| 2.10M| let codeword1 = codes[sym1]; 119| 2.10M| let codeword2 = codes[sym2]; 120| 2.10M| let codeword = codeword1 | (codeword2 << len1); 121| 2.10M| let entry = (sym1 as u32) << 16 122| 2.10M| | (sym2 as u32) << 24 123| 2.10M| | LITERAL_ENTRY 124| 2.10M| | (2 << 8); 125| 2.10M| primary_table[codeword as usize] = entry | (length as u32); 126| 2.10M| } 127| | } 128| | } 129| | } 130| 146k| } 131| | 132| | // If we aren't at the maximum table size, double the size of the table. 133| 290k| if length < primary_table_bits { 134| 259k| primary_table.copy_within(0..current_table_end, current_table_end); 135| 259k| } 136| | } 137| | 138| | // Populate the secondary decoding table. 139| 31.0k| secondary_table.clear(); 140| 31.0k| if max_length > primary_table_bits { 141| 3.76k| let mut subtable_start = 0; 142| 3.76k| let mut subtable_prefix = !0; 143| 8.46k| for length in (primary_table_bits + 1)..=max_length { 144| 8.46k| let subtable_size = 1 << (length - primary_table_bits); 145| 8.46k| for _ in 0..histogram[length] { 146| | // If the codeword's prefix doesn't match the current subtable, create a new 147| | // subtable. 148| 148k| if codeword & primary_table_mask != subtable_prefix { 149| 47.1k| subtable_prefix = codeword & primary_table_mask; 150| 47.1k| subtable_start = secondary_table.len(); 151| 47.1k| primary_table[subtable_prefix as usize] = ((subtable_start as u32) << 16) 152| 47.1k| | EXCEPTIONAL_ENTRY 153| 47.1k| | SECONDARY_TABLE_ENTRY 154| 47.1k| | (subtable_size as u32 - 1); 155| 47.1k| secondary_table.resize(subtable_start + subtable_size, 0); 156| 101k| } 157| | 158| | // Lookup the symbol. 159| 148k| let symbol = sorted_symbols[i]; 160| 148k| i += 1; 161| | 162| | // Insert the symbol into the secondary table and advance to the next codeword. 163| 148k| codes[symbol] = codeword; 164| 148k| secondary_table[subtable_start + (codeword >> primary_table_bits) as usize] = 165| 148k| ((symbol as u16) << 4) | (length as u16); 166| 148k| codeword = next_codeword(codeword, 1 << length); 167| | } 168| | 169| | // If there are more codes with the same subtable prefix, extend the subtable. 170| 8.46k| if length < max_length && codeword & primary_table_mask == subtable_prefix { 171| 3.37k| secondary_table.extend_from_within(subtable_start..); 172| 3.37k| let subtable_size = secondary_table.len() - subtable_start; 173| 3.37k| primary_table[subtable_prefix as usize] = ((subtable_start as u32) << 16) 174| 3.37k| | EXCEPTIONAL_ENTRY 175| 3.37k| | SECONDARY_TABLE_ENTRY 176| 3.37k| | (subtable_size as u32 - 1); 177| 5.08k| } 178| | } 179| 27.2k| } 180| | 181| 31.0k| true 182| 35.4k|} _RNvNtCsh5m7Dv6WxNY_8fdeflate7huffman13next_codeword: 5| 878k|fn next_codeword(mut codeword: u16, table_size: u16) -> u16 { 6| 878k| if codeword == table_size - 1 { 7| 31.0k| return codeword; 8| 847k| } 9| | 10| 847k| let adv = (u16::BITS - 1) - (codeword ^ (table_size - 1)).leading_zeros(); 11| 847k| let bit = 1 << adv; 12| 847k| codeword &= bit - 1; 13| 847k| codeword |= bit; 14| 847k| codeword 15| 878k|} LLVMFuzzerInitialize: 252| 2| pub extern "C" fn LLVMFuzzerInitialize(_argc: *const isize, _argv: *const *const *const u8) -> isize { 253| 2| $crate::initialize(_argc, _argv); 254| | 255| | // Supplied init code 256| | $init; 257| 2| 0 258| 2| } _RNvNvCsjL4BTT8Uzs_17fuzzer_script_png1__19___libfuzzer_sys_run: 293| 9.65k| fn __libfuzzer_sys_run($bytes: &[u8]) -> $rty { 294| | $body 295| 9.65k| } rust_fuzzer_test_input: 261| 9.65k| pub extern "C" fn rust_fuzzer_test_input(bytes: &[u8]) -> i32 { 262| | // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug 263| | // formatting of the input to that file. This is only intended for 264| | // `cargo fuzz`'s use! 265| | 266| | // `RUST_LIBFUZZER_DEBUG_PATH` is set in initialization. 267| 9.65k| if let Some(path) = $crate::rust_libfuzzer_debug_path() { 268| | use std::io::Write; 269| 0| let mut file = std::fs::File::create(path) 270| 0| .expect("failed to create `RUST_LIBFUZZER_DEBUG_PATH` file"); 271| 0| writeln!(&mut file, "{:?}", bytes) 272| 0| .expect("failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file"); 273| 0| return 0; 274| 9.65k| } 275| | 276| 9.65k| let result = ::libfuzzer_sys::Corpus::from(__libfuzzer_sys_run(bytes)); 277| 9.65k| result.to_libfuzzer_code() 278| 9.65k| } LLVMFuzzerTestOneInput: 59| 9.65k|pub unsafe fn test_input_wrap(data: *const u8, size: usize) -> i32 { 60| 9.65k| let test_input = ::std::panic::catch_unwind(|| { 61| | let data_slice = ::std::slice::from_raw_parts(data, size); 62| | rust_fuzzer_test_input(data_slice) 63| | }); 64| | 65| 9.65k| match test_input { 66| 9.65k| Ok(i) => i, 67| | Err(_) => { 68| | // hopefully the custom panic hook will be called before and abort the 69| | // process before the stack frames are unwinded. 70| 0| ::std::process::abort(); 71| | } 72| | } 73| 9.65k|} _RNCNvCsjpvHGLbr0gV_13libfuzzer_sys15test_input_wrap0B3_: 60| 9.65k| let test_input = ::std::panic::catch_unwind(|| { 61| 9.65k| let data_slice = ::std::slice::from_raw_parts(data, size); 62| 9.65k| rust_fuzzer_test_input(data_slice) 63| 9.65k| }); _RNCNvCsjpvHGLbr0gV_13libfuzzer_sys25rust_libfuzzer_debug_path0B3_: 78| 1| RUST_LIBFUZZER_DEBUG_PATH.get_or_init(|| std::env::var("RUST_LIBFUZZER_DEBUG_PATH").ok()) _RNvCsjpvHGLbr0gV_13libfuzzer_sys10initialize: 82| 2|pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize { 83| | // Registers a panic hook that aborts the process before unwinding. 84| | // It is useful to abort before unwinding so that the fuzzer will then be 85| | // able to analyse the process stack frames to tell different bugs appart. 86| | // 87| | // HACK / FIXME: it would be better to use `-C panic=abort` but it's currently 88| | // impossible to build code using compiler plugins with this flag. 89| | // We will be able to remove this code when 90| | // https://github.com/rust-lang/cargo/issues/5423 is fixed. 91| 2| let default_hook = std::panic::take_hook(); 92| 2| std::panic::set_hook(Box::new(move |panic_info| { 93| | default_hook(panic_info); 94| | std::process::abort(); 95| | })); 96| 2| 0 97| 2|} _RNvCsjpvHGLbr0gV_13libfuzzer_sys25rust_libfuzzer_debug_path: 76| 9.65k|pub fn rust_libfuzzer_debug_path() -> &'static Option { 77| | static RUST_LIBFUZZER_DEBUG_PATH: OnceLock> = OnceLock::new(); 78| 9.65k| RUST_LIBFUZZER_DEBUG_PATH.get_or_init(|| std::env::var("RUST_LIBFUZZER_DEBUG_PATH").ok()) 79| 9.65k|} _RNvMs_CsjpvHGLbr0gV_13libfuzzer_sysNtB4_6Corpus17to_libfuzzer_code: 40| 9.65k| pub fn to_libfuzzer_code(self) -> i32 { 41| 9.65k| match self { 42| 9.65k| Corpus::Keep => 0, 43| 0| Corpus::Reject => -1, 44| | } 45| 9.65k| } _RNvXCsjpvHGLbr0gV_13libfuzzer_sysNtB2_6CorpusINtNtCs6SNw0SRvItZ_4core7convert4FromuE4from: 30| 9.65k| fn from(_: ()) -> Self { 31| 9.65k| Self::Keep 32| 9.65k| } _RNvMs_NtCs1jiJzeRTgBH_6moxcms3datNtB4_13ColorDateTime14new_from_slice: 81| 1.14k| pub fn new_from_slice(slice: &[u8]) -> Result { 82| 1.14k| if slice.len() != 12 { 83| 0| return Err(CmsError::InvalidProfile); 84| 1.14k| } 85| 1.14k| let year = u16::from_be_bytes([slice[0], slice[1]]); 86| 1.14k| let month = u16::from_be_bytes([slice[2], slice[3]]); 87| 1.14k| let day_of_the_month = u16::from_be_bytes([slice[4], slice[5]]); 88| 1.14k| let hours = u16::from_be_bytes([slice[6], slice[7]]); 89| 1.14k| let minutes = u16::from_be_bytes([slice[8], slice[9]]); 90| 1.14k| let seconds = u16::from_be_bytes([slice[10], slice[11]]); 91| 1.14k| Ok(ColorDateTime { 92| 1.14k| year, 93| 1.14k| month, 94| 1.14k| day_of_the_month, 95| 1.14k| hours, 96| 1.14k| minutes, 97| 1.14k| seconds, 98| 1.14k| }) 99| 1.14k| } _RNvMs_NtCs1jiJzeRTgBH_6moxcms3datNtB4_13ColorDateTime3now: 102| 1.08k| pub fn now() -> Self { 103| | #[cfg(not(target_arch = "wasm32"))] 104| 1.08k| let now = match SystemTime::now().duration_since(UNIX_EPOCH) { 105| 1.08k| Ok(v) => v, 106| 0| Err(_) => return Self::default(), 107| | }; 108| | #[cfg(target_arch = "wasm32")] 109| | use std::time::Duration; 110| | #[cfg(target_arch = "wasm32")] 111| | let now = Duration::new(365 * 60 * 60 * 24 * 30, 0); 112| 1.08k| let mut days = (now.as_secs() / 86_400) as i64; 113| 1.08k| let secs_of_day = (now.as_secs() % 86_400) as i64; 114| | 115| 1.08k| let mut year = 1970; 116| | loop { 117| 62.0k| let year_days = if is_leap(year) { 366 } else { 365 }; 118| 62.0k| if days >= year_days { 119| 60.9k| days -= year_days; 120| 60.9k| year += 1; 121| 60.9k| } else { 122| 1.08k| break; 123| | } 124| | } 125| | 126| 1.08k| let mut month = 1; 127| | loop { 128| 8.71k| let mdays = days_in_month(year, month); 129| 8.71k| if days >= mdays as i64 { 130| 7.62k| days -= mdays as i64; 131| 7.62k| month += 1; 132| 7.62k| } else { 133| 1.08k| break; 134| | } 135| | } 136| 1.08k| let day = days + 1; // days from zero based to 1 base 137| | 138| 1.08k| let hour = secs_of_day / 3600; 139| 1.08k| let min = (secs_of_day % 3600) / 60; 140| 1.08k| let sec = secs_of_day % 60; 141| 1.08k| Self { 142| 1.08k| year: year as u16, 143| 1.08k| month: month as u16, 144| 1.08k| day_of_the_month: day as u16, 145| 1.08k| hours: hour as u16, 146| 1.08k| minutes: min as u16, 147| 1.08k| seconds: sec as u16, 148| 1.08k| } 149| 1.08k| } _RNvNtCs1jiJzeRTgBH_6moxcms3dat13days_in_month: 49| 8.71k|fn days_in_month(year: i32, month: i32) -> i32 { 50| 8.71k| match month { 51| 1.08k| 1 => 31, 52| | 2 => { 53| 1.08k| if is_leap(year) { 54| 0| 29 55| | } else { 56| 1.08k| 28 57| | } 58| | } 59| 1.08k| 3 => 31, 60| 1.08k| 4 => 30, 61| 1.08k| 5 => 31, 62| 1.08k| 6 => 30, 63| 1.08k| 7 => 31, 64| 1.08k| 8 => 31, 65| 0| 9 => 30, 66| 0| 10 => 31, 67| 0| 11 => 30, 68| 0| 12 => 31, 69| 0| _ => unreachable!("Unknown month"), 70| | } 71| 8.71k|} _RNvNtCs1jiJzeRTgBH_6moxcms3dat7is_leap: 45| 63.1k|fn is_leap(year: i32) -> bool { 46| 63.1k| (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) 47| 63.1k|} _RNvXNtCs1jiJzeRTgBH_6moxcms3datNtB2_13ColorDateTimeNtNtCs6SNw0SRvItZ_4core7default7Default7default: 74| 1.08k| fn default() -> Self { 75| 1.08k| Self::now() 76| 1.08k| } _RNvMs19_NtCs1jiJzeRTgBH_6moxcms6matrixNtB6_3Xyz3newB8_: 1066| 1.10k| pub const fn new(x: $im_type, y: $im_type, z: $im_type) -> Self { 1067| 1.10k| Self { x, y, z } 1068| 1.10k| } _RNvMss_NtCs1jiJzeRTgBH_6moxcms6matrixNtB5_3Xyz7to_xyzd: 1244| 1.08k| pub fn to_xyzd(self) -> Xyzd { 1245| 1.08k| Xyzd { 1246| 1.08k| x: self.x as f64, 1247| 1.08k| y: self.y as f64, 1248| 1.08k| z: self.z as f64, 1249| 1.08k| } 1250| 1.08k| } _RNvMse_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_13ProfileHeader14new_from_slice: 686| 1.78k| pub(crate) fn new_from_slice(slice: &[u8]) -> Result { 687| 1.78k| if slice.len() < size_of::() { 688| 3| return Err(CmsError::InvalidProfile); 689| 1.78k| } 690| 1.78k| let mut cursor = std::io::Cursor::new(slice); 691| 1.78k| let mut buffer = [0u8; size_of::()]; 692| 1.78k| cursor 693| 1.78k| .read_exact(&mut buffer) 694| 1.78k| .map_err(|_| CmsError::InvalidProfile)?; 695| | 696| 1.10k| let header = Self { 697| 1.78k| size: u32::from_be_bytes(buffer[0..4].try_into().unwrap()), 698| 1.78k| cmm_type: u32::from_be_bytes(buffer[4..8].try_into().unwrap()), 699| 1.78k| version: ProfileVersion::try_from(u32::from_be_bytes( 700| 1.78k| buffer[8..12].try_into().unwrap(), 701| 57| ))?, 702| 1.72k| profile_class: ProfileClass::try_from(u32::from_be_bytes( 703| 1.72k| buffer[12..16].try_into().unwrap(), 704| 355| ))?, 705| 1.37k| data_color_space: DataColorSpace::try_from(u32::from_be_bytes( 706| 1.37k| buffer[16..20].try_into().unwrap(), 707| 125| ))?, 708| 1.24k| pcs: DataColorSpace::try_from(u32::from_be_bytes(buffer[20..24].try_into().unwrap()))?, 709| 1.14k| creation_date_time: ColorDateTime::new_from_slice(buffer[24..36].try_into().unwrap())?, 710| 1.14k| signature: ProfileSignature::try_from(u32::from_be_bytes( 711| 1.14k| buffer[36..40].try_into().unwrap(), 712| 36| ))?, 713| 1.10k| platform: u32::from_be_bytes(buffer[40..44].try_into().unwrap()), 714| 1.10k| flags: u32::from_be_bytes(buffer[44..48].try_into().unwrap()), 715| 1.10k| device_manufacturer: u32::from_be_bytes(buffer[48..52].try_into().unwrap()), 716| 1.10k| device_model: u32::from_be_bytes(buffer[52..56].try_into().unwrap()), 717| 1.10k| device_attributes: buffer[56..64].try_into().unwrap(), 718| 1.10k| rendering_intent: RenderingIntent::try_from(u32::from_be_bytes( 719| 1.10k| buffer[64..68].try_into().unwrap(), 720| 0| ))?, 721| 1.10k| illuminant: Xyz::new( 722| 1.10k| s15_fixed16_number_to_float(i32::from_be_bytes(buffer[68..72].try_into().unwrap())), 723| 1.10k| s15_fixed16_number_to_float(i32::from_be_bytes(buffer[72..76].try_into().unwrap())), 724| 1.10k| s15_fixed16_number_to_float(i32::from_be_bytes(buffer[76..80].try_into().unwrap())), 725| | ), 726| 1.10k| creator: u32::from_be_bytes(buffer[80..84].try_into().unwrap()), 727| 1.10k| profile_id: buffer[84..100].try_into().unwrap(), 728| 1.10k| reserved: buffer[100..128].try_into().unwrap(), 729| 1.10k| tag_count: u32::from_be_bytes(buffer[128..132].try_into().unwrap()), 730| | }; 731| 1.10k| Ok(header) 732| 1.78k| } _RNvMsn_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_12ColorProfile14new_from_slice: 978| 1.78k| pub fn new_from_slice(slice: &[u8]) -> Result { 979| 1.78k| Self::new_from_slice_with_options(slice, Default::default()) 980| 1.78k| } _RNvMsn_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_12ColorProfile27new_from_slice_with_options: 982| 1.78k| pub fn new_from_slice_with_options( 983| 1.78k| slice: &[u8], 984| 1.78k| options: ParsingOptions, 985| 1.78k| ) -> Result { 986| 1.78k| let header = ProfileHeader::new_from_slice(slice)?; 987| 1.10k| let tags_count = header.tag_count as usize; 988| 1.10k| if slice.len() >= options.max_profile_size { 989| 0| return Err(CmsError::InvalidProfile); 990| 1.10k| } 991| 1.10k| let tags_end = tags_count 992| 1.10k| .safe_mul(TAG_SIZE)? 993| 1.10k| .safe_add(size_of::())?; 994| 1.10k| if slice.len() < tags_end { 995| 17| return Err(CmsError::InvalidProfile); 996| 1.08k| } 997| 1.08k| let tags_slice = &slice[size_of::()..tags_end]; 998| 1.08k| let mut profile = ColorProfile { 999| 1.08k| rendering_intent: header.rendering_intent, 1000| 1.08k| pcs: header.pcs, 1001| 1.08k| profile_class: header.profile_class, 1002| 1.08k| color_space: header.data_color_space, 1003| 1.08k| white_point: header.illuminant.to_xyzd(), 1004| 1.08k| version_internal: header.version, 1005| 1.08k| creation_date_time: header.creation_date_time, 1006| 1.08k| ..Default::default() 1007| 1.08k| }; 1008| 1.08k| let color_space = profile.color_space; 1009| 26.5k| for tag in tags_slice.chunks_exact(TAG_SIZE) { 1010| 26.5k| let tag_value = u32::from_be_bytes([tag[0], tag[1], tag[2], tag[3]]); 1011| 26.5k| let tag_entry = u32::from_be_bytes([tag[4], tag[5], tag[6], tag[7]]); 1012| 26.5k| let tag_size = u32::from_be_bytes([tag[8], tag[9], tag[10], tag[11]]) as usize; 1013| | // Just ignore unknown tags 1014| 26.5k| if let Ok(tag) = Tag::try_from(tag_value) { 1015| 5.28k| match tag { 1016| | Tag::RedXyz => { 1017| 523| if color_space == DataColorSpace::Rgb { 1018| | profile.red_colorant = 1019| 523| Self::read_xyz_tag(slice, tag_entry as usize, tag_size)?; 1020| 0| } 1021| | } 1022| | Tag::GreenXyz => { 1023| 290| if color_space == DataColorSpace::Rgb { 1024| | profile.green_colorant = 1025| 290| Self::read_xyz_tag(slice, tag_entry as usize, tag_size)?; 1026| 0| } 1027| | } 1028| | Tag::BlueXyz => { 1029| 335| if color_space == DataColorSpace::Rgb { 1030| | profile.blue_colorant = 1031| 335| Self::read_xyz_tag(slice, tag_entry as usize, tag_size)?; 1032| 0| } 1033| | } 1034| | Tag::RedToneReproduction => { 1035| 123| if color_space == DataColorSpace::Rgb { 1036| 122| profile.red_trc = Self::read_trc_tag_s( 1037| 122| slice, 1038| 122| tag_entry as usize, 1039| 122| tag_size, 1040| 122| &options, 1041| 57| )?; 1042| 1| } 1043| | } 1044| | Tag::GreenToneReproduction => { 1045| 42| if color_space == DataColorSpace::Rgb { 1046| 41| profile.green_trc = Self::read_trc_tag_s( 1047| 41| slice, 1048| 41| tag_entry as usize, 1049| 41| tag_size, 1050| 41| &options, 1051| 1| )?; 1052| 1| } 1053| | } 1054| | Tag::BlueToneReproduction => { 1055| 18| if color_space == DataColorSpace::Rgb { 1056| 17| profile.blue_trc = Self::read_trc_tag_s( 1057| 17| slice, 1058| 17| tag_entry as usize, 1059| 17| tag_size, 1060| 17| &options, 1061| 1| )?; 1062| 1| } 1063| | } 1064| | Tag::GreyToneReproduction => { 1065| 91| if color_space == DataColorSpace::Gray { 1066| 79| profile.gray_trc = Self::read_trc_tag_s( 1067| 79| slice, 1068| 79| tag_entry as usize, 1069| 79| tag_size, 1070| 79| &options, 1071| 55| )?; 1072| 12| } 1073| | } 1074| | Tag::MediaWhitePoint => { 1075| | profile.media_white_point = 1076| 905| Self::read_xyz_tag(slice, tag_entry as usize, tag_size).map(Some)?; 1077| | } 1078| | Tag::Luminance => { 1079| | profile.luminance = 1080| 0| Self::read_xyz_tag(slice, tag_entry as usize, tag_size).map(Some)?; 1081| | } 1082| | Tag::Measurement => { 1083| | profile.measurement = 1084| 0| Self::read_meas_tag(slice, tag_entry as usize, tag_size)?; 1085| | } 1086| | Tag::CodeIndependentPoints => { 1087| | // This tag may be present when the data colour space in the profile header is RGB, YCbCr, or XYZ, and the 1088| | // profile class in the profile header is Input or Display. The tag shall not be present for other data colour spaces 1089| | // or profile classes indicated in the profile header. 1090| 28| if (profile.profile_class == ProfileClass::InputDevice 1091| 28| || profile.profile_class == ProfileClass::DisplayDevice) 1092| 28| && (profile.color_space == DataColorSpace::Rgb 1093| 0| || profile.color_space == DataColorSpace::YCbr 1094| 0| || profile.color_space == DataColorSpace::Xyz) 1095| | { 1096| | profile.cicp = 1097| 28| Self::read_cicp_tag(slice, tag_entry as usize, tag_size)?; 1098| 0| } 1099| | } 1100| | Tag::ChromaticAdaptation => { 1101| | profile.chromatic_adaptation = 1102| 0| Self::read_chad_tag(slice, tag_entry as usize, tag_size)?; 1103| | } 1104| | Tag::BlackPoint => { 1105| | profile.black_point = 1106| 619| Self::read_xyz_tag(slice, tag_entry as usize, tag_size).map(Some)? 1107| | } 1108| | Tag::DeviceToPcsLutPerceptual => { 1109| 0| profile.lut_a_to_b_perceptual = 1110| 0| Self::read_lut_tag(slice, tag_entry, tag_size, &options)?; 1111| | } 1112| | Tag::DeviceToPcsLutColorimetric => { 1113| 0| profile.lut_a_to_b_colorimetric = 1114| 0| Self::read_lut_tag(slice, tag_entry, tag_size, &options)?; 1115| | } 1116| | Tag::DeviceToPcsLutSaturation => { 1117| 0| profile.lut_a_to_b_saturation = 1118| 0| Self::read_lut_tag(slice, tag_entry, tag_size, &options)?; 1119| | } 1120| | Tag::PcsToDeviceLutPerceptual => { 1121| 0| profile.lut_b_to_a_perceptual = 1122| 0| Self::read_lut_tag(slice, tag_entry, tag_size, &options)?; 1123| | } 1124| | Tag::PcsToDeviceLutColorimetric => { 1125| 0| profile.lut_b_to_a_colorimetric = 1126| 0| Self::read_lut_tag(slice, tag_entry, tag_size, &options)?; 1127| | } 1128| | Tag::PcsToDeviceLutSaturation => { 1129| 0| profile.lut_b_to_a_saturation = 1130| 0| Self::read_lut_tag(slice, tag_entry, tag_size, &options)?; 1131| | } 1132| | Tag::Gamut => { 1133| 0| profile.gamut = Self::read_lut_tag(slice, tag_entry, tag_size, &options)?; 1134| | } 1135| | Tag::Copyright => { 1136| 991| profile.copyright = 1137| 1.04k| Self::read_string_tag(slice, tag_entry as usize, tag_size)?; 1138| | } 1139| | Tag::ProfileDescription => { 1140| 1.23k| profile.description = 1141| 1.26k| Self::read_string_tag(slice, tag_entry as usize, tag_size)?; 1142| | } 1143| | Tag::ViewingConditionsDescription => { 1144| 0| profile.viewing_conditions_description = 1145| 0| Self::read_string_tag(slice, tag_entry as usize, tag_size)?; 1146| | } 1147| | Tag::DeviceModel => { 1148| 0| profile.device_model = 1149| 1| Self::read_string_tag(slice, tag_entry as usize, tag_size)?; 1150| | } 1151| | Tag::DeviceManufacturer => { 1152| 0| profile.device_manufacturer = 1153| 0| Self::read_string_tag(slice, tag_entry as usize, tag_size)?; 1154| | } 1155| | Tag::CharTarget => { 1156| 0| profile.char_target = 1157| 1| Self::read_string_tag(slice, tag_entry as usize, tag_size)?; 1158| | } 1159| 3| Tag::Chromaticity => {} 1160| | Tag::ObserverConditions => { 1161| | profile.viewing_conditions = 1162| 0| Self::read_viewing_conditions(slice, tag_entry as usize, tag_size)?; 1163| | } 1164| | Tag::Technology => { 1165| | profile.technology = 1166| 0| Self::read_tech_tag(slice, tag_entry as usize, tag_size)?; 1167| | } 1168| | Tag::CalibrationDateTime => { 1169| | profile.calibration_date = 1170| 0| Self::read_date_time_tag(slice, tag_entry as usize, tag_size)?; 1171| | } 1172| | } 1173| 21.2k| } 1174| | } 1175| | 1176| 601| Ok(profile) 1177| 1.78k| } _RNvXNtCs1jiJzeRTgBH_6moxcms7profileNtB2_16ProfileSignatureINtNtCs6SNw0SRvItZ_4core7convert7TryFrommE8try_fromB4_: 54| 1.14k| fn try_from(value: u32) -> Result { 55| 1.14k| if value == u32::from_ne_bytes(*b"acsp").to_be() { 56| 1.10k| return Ok(ProfileSignature::Acsp); 57| 36| } 58| 36| Err(CmsError::InvalidProfile) 59| 1.14k| } _RNvXs0_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_14ProfileVersionINtNtCs6SNw0SRvItZ_4core7convert7TryFrommE8try_from: 90| 1.78k| fn try_from(value: u32) -> Result { 91| | // First try exact match for known versions 92| 1.78k| match value { 93| 1| 0x02000000 => return Ok(ProfileVersion::V2_0), 94| 1| 0x02100000 => return Ok(ProfileVersion::V2_1), 95| 295| 0x02200000 => return Ok(ProfileVersion::V2_2), 96| 1| 0x02300000 => return Ok(ProfileVersion::V2_3), 97| 731| 0x02400000 => return Ok(ProfileVersion::V2_4), 98| 1| 0x04000000 => return Ok(ProfileVersion::V4_0), 99| 0| 0x04100000 => return Ok(ProfileVersion::V4_1), 100| 2| 0x04200000 => return Ok(ProfileVersion::V4_2), 101| 0| 0x04300000 => return Ok(ProfileVersion::V4_3), 102| 1| 0x04400000 => return Ok(ProfileVersion::V4_4), 103| 750| _ => {} 104| | } 105| | 106| | // Extract major version (first byte) for range matching 107| | // ICC version format: major.minor.bugfix.zero in bytes [0][1][2][3] 108| 750| let major = (value >> 24) & 0xFF; 109| 750| let minor = (value >> 20) & 0x0F; 110| | 111| | // Accept profiles with patch versions (e.g., v2.0.2, v3.4, v4.2.9) 112| | // but reject invalid versions (v0.x) and unsupported versions (v5.x+ / ICC MAX) 113| 750| match major { 114| | 0 => { 115| | // Version 0.x is invalid - reject 116| 26| Err(CmsError::InvalidProfile) 117| | } 118| | 2 => { 119| | // v2.x - map to the appropriate v2 minor version or highest known 120| 486| match minor { 121| 43| 0 => Ok(ProfileVersion::V2_0), 122| 25| 1 => Ok(ProfileVersion::V2_1), 123| 267| 2 => Ok(ProfileVersion::V2_2), 124| 59| 3 => Ok(ProfileVersion::V2_3), 125| 92| _ => Ok(ProfileVersion::V2_4), // Higher minor versions -> v2.4 126| | } 127| | } 128| | 3 => { 129| | // v3.x (rare but exists) - treat as v2.4 (functionally similar) 130| 32| Ok(ProfileVersion::V2_4) 131| | } 132| | 4 => { 133| | // v4.x - map to the appropriate v4 minor version or highest known 134| 175| match minor { 135| 58| 0 => Ok(ProfileVersion::V4_0), 136| 33| 1 => Ok(ProfileVersion::V4_1), 137| 31| 2 => Ok(ProfileVersion::V4_2), 138| 34| 3 => Ok(ProfileVersion::V4_3), 139| 19| _ => Ok(ProfileVersion::V4_4), // Higher minor versions -> v4.4 140| | } 141| | } 142| | _ => { 143| | // v5.x+ (ICC MAX) and other unknown versions - reject 144| | // ICC MAX has different white point requirements and would produce wrong colors 145| 31| Err(CmsError::InvalidProfile) 146| | } 147| | } 148| 1.78k| } _RNvXs3_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_12ProfileClassINtNtCs6SNw0SRvItZ_4core7convert7TryFrommE8try_from: 269| 1.72k| fn try_from(value: u32) -> Result { 270| 1.72k| if value == u32::from_ne_bytes(*b"scnr").to_be() { 271| 355| return Ok(ProfileClass::InputDevice); 272| 1.37k| } else if value == u32::from_ne_bytes(*b"mntr").to_be() { 273| 789| return Ok(ProfileClass::DisplayDevice); 274| 582| } else if value == u32::from_ne_bytes(*b"prtr").to_be() { 275| 227| return Ok(ProfileClass::OutputDevice); 276| 355| } else if value == u32::from_ne_bytes(*b"link").to_be() { 277| 0| return Ok(ProfileClass::DeviceLink); 278| 355| } else if value == u32::from_ne_bytes(*b"spac").to_be() { 279| 0| return Ok(ProfileClass::ColorSpace); 280| 355| } else if value == u32::from_ne_bytes(*b"abst").to_be() { 281| 0| return Ok(ProfileClass::Abstract); 282| 355| } else if value == u32::from_ne_bytes(*b"nmcl").to_be() { 283| 0| return Ok(ProfileClass::Named); 284| 355| } 285| 355| Err(CmsError::InvalidProfile) 286| 1.72k| } _RNvXs7_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_14DataColorSpaceINtNtCs6SNw0SRvItZ_4core7convert7TryFrommE8try_from: 346| 2.61k| fn try_from(value: u32) -> Result { 347| 2.61k| if value == u32::from_ne_bytes(*b"XYZ ").to_be() { 348| 1.14k| return Ok(DataColorSpace::Xyz); 349| 1.47k| } else if value == u32::from_ne_bytes(*b"Lab ").to_be() { 350| 0| return Ok(DataColorSpace::Lab); 351| 1.47k| } else if value == u32::from_ne_bytes(*b"Luv ").to_be() { 352| 0| return Ok(DataColorSpace::Luv); 353| 1.47k| } else if value == u32::from_ne_bytes(*b"YCbr").to_be() { 354| 0| return Ok(DataColorSpace::YCbr); 355| 1.47k| } else if value == u32::from_ne_bytes(*b"Yxy ").to_be() { 356| 0| return Ok(DataColorSpace::Yxy); 357| 1.47k| } else if value == u32::from_ne_bytes(*b"RGB ").to_be() { 358| 767| return Ok(DataColorSpace::Rgb); 359| 709| } else if value == u32::from_ne_bytes(*b"GRAY").to_be() { 360| 480| return Ok(DataColorSpace::Gray); 361| 229| } else if value == u32::from_ne_bytes(*b"HSV ").to_be() { 362| 0| return Ok(DataColorSpace::Hsv); 363| 229| } else if value == u32::from_ne_bytes(*b"HLS ").to_be() { 364| 0| return Ok(DataColorSpace::Hls); 365| 229| } else if value == u32::from_ne_bytes(*b"CMYK").to_be() { 366| 0| return Ok(DataColorSpace::Cmyk); 367| 229| } else if value == u32::from_ne_bytes(*b"CMY ").to_be() { 368| 0| return Ok(DataColorSpace::Cmy); 369| 229| } else if value == u32::from_ne_bytes(*b"2CLR").to_be() { 370| 0| return Ok(DataColorSpace::Color2); 371| 229| } else if value == u32::from_ne_bytes(*b"3CLR").to_be() { 372| 0| return Ok(DataColorSpace::Color3); 373| 229| } else if value == u32::from_ne_bytes(*b"4CLR").to_be() { 374| 0| return Ok(DataColorSpace::Color4); 375| 229| } else if value == u32::from_ne_bytes(*b"5CLR").to_be() { 376| 0| return Ok(DataColorSpace::Color5); 377| 229| } else if value == u32::from_ne_bytes(*b"6CLR").to_be() { 378| 0| return Ok(DataColorSpace::Color6); 379| 229| } else if value == u32::from_ne_bytes(*b"7CLR").to_be() { 380| 0| return Ok(DataColorSpace::Color7); 381| 229| } else if value == u32::from_ne_bytes(*b"8CLR").to_be() { 382| 0| return Ok(DataColorSpace::Color8); 383| 229| } else if value == u32::from_ne_bytes(*b"9CLR").to_be() { 384| 0| return Ok(DataColorSpace::Color9); 385| 229| } else if value == u32::from_ne_bytes(*b"ACLR").to_be() { 386| 0| return Ok(DataColorSpace::Color10); 387| 229| } else if value == u32::from_ne_bytes(*b"BCLR").to_be() { 388| 0| return Ok(DataColorSpace::Color11); 389| 229| } else if value == u32::from_ne_bytes(*b"CCLR").to_be() { 390| 0| return Ok(DataColorSpace::Color12); 391| 229| } else if value == u32::from_ne_bytes(*b"DCLR").to_be() { 392| 0| return Ok(DataColorSpace::Color13); 393| 229| } else if value == u32::from_ne_bytes(*b"ECLR").to_be() { 394| 0| return Ok(DataColorSpace::Color14); 395| 229| } else if value == u32::from_ne_bytes(*b"FCLR").to_be() { 396| 0| return Ok(DataColorSpace::Color15); 397| 229| } 398| 229| Err(CmsError::InvalidProfile) 399| 2.61k| } _RNvXsc_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_15RenderingIntentINtNtCs6SNw0SRvItZ_4core7convert7TryFrommE8try_fromB7_: 605| 1.10k| fn try_from(value: u32) -> Result { 606| | // Rendering intent is a big-endian u32 at bytes 64-67 with valid 607| | // values 0-3. Non-conforming profiles (e.g. old Linotype "Lino" 608| | // v2.1 profiles with byte-swapped values) may have invalid values. 609| | // Default to Perceptual rather than rejecting the entire profile, 610| | // since this field is advisory — moxcms uses TransformOptions for 611| | // actual LUT selection. 612| 1.10k| match value { 613| 373| 0 => Ok(RenderingIntent::Perceptual), 614| 0| 1 => Ok(RenderingIntent::RelativeColorimetric), 615| 0| 2 => Ok(RenderingIntent::Saturation), 616| 636| 3 => Ok(RenderingIntent::AbsoluteColorimetric), 617| 97| _ => Ok(RenderingIntent::Perceptual), 618| | } 619| 1.10k| } _RNvXsm_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_14ParsingOptionsNtNtCs6SNw0SRvItZ_4core7default7Default7default: 963| 1.78k| fn default() -> Self { 964| 1.78k| Self { 965| 1.78k| max_profile_size: MAX_PROFILE_SIZE, 966| 1.78k| max_allowed_clut_size: 10_000_000, 967| 1.78k| max_allowed_trc_size: 40_000, 968| 1.78k| } 969| 1.78k| } _RNvMNtCs1jiJzeRTgBH_6moxcms6readerNtNtB4_7profile12ColorProfile12read_trc_tag: 713| 259| pub(crate) fn read_trc_tag( 714| 259| slice: &[u8], 715| 259| entry: usize, 716| 259| tag_size: usize, 717| 259| read_size: &mut usize, 718| 259| options: &ParsingOptions, 719| 259| ) -> Result, CmsError> { 720| 259| if slice.len() < entry.safe_add(4)? { 721| 126| return Ok(None); 722| 133| } 723| 133| let small_tag = &slice[entry..entry + 4]; 724| | // We require always recognize tone curves. 725| 133| let curve_type = TagTypeDefinition::from(u32::from_be_bytes([ 726| 133| small_tag[0], 727| 133| small_tag[1], 728| 133| small_tag[2], 729| 133| small_tag[3], 730| 133| ])); 731| 133| if tag_size != 0 && tag_size < TAG_SIZE { 732| 8| return Ok(None); 733| 125| } 734| 125| let last_tag_offset = if tag_size != 0 { 735| 115| tag_size + entry 736| | } else { 737| 10| slice.len() 738| | }; 739| 125| if last_tag_offset > slice.len() { 740| 68| return Err(CmsError::MalformedTrcCurve("Data exhausted".to_string())); 741| 57| } 742| 57| let tag = &slice[entry..last_tag_offset]; 743| 57| if tag.len() < TAG_SIZE { 744| 1| return Err(CmsError::MalformedTrcCurve("Data exhausted".to_string())); 745| 56| } 746| 56| if curve_type == TagTypeDefinition::LutToneCurve { 747| 18| let entry_count = u32::from_be_bytes([tag[8], tag[9], tag[10], tag[11]]) as usize; 748| 18| if entry_count == 0 { 749| 6| return Ok(Some(ToneReprCurve::Lut(vec![]))); 750| 12| } 751| 12| if entry_count > options.max_allowed_trc_size { 752| 6| return Err(CmsError::CurveLutIsTooLarge); 753| 6| } 754| 6| let curve_end = entry_count.safe_mul(size_of::())?.safe_add(12)?; 755| 6| if tag.len() < curve_end { 756| 1| return Err(CmsError::MalformedTrcCurve( 757| 1| "Curve end ends to early".to_string(), 758| 1| )); 759| 5| } 760| 5| let curve_sliced = &tag[12..curve_end]; 761| 5| let mut curve_values = try_vec![0u16; entry_count]; 762| 29| for (value, curve_value) in curve_sliced.chunks_exact(2).zip(curve_values.iter_mut()) { 763| 29| let gamma_s15 = u16::from_be_bytes([value[0], value[1]]); 764| 29| *curve_value = gamma_s15; 765| 29| } 766| 5| *read_size = curve_end; 767| 5| Ok(Some(ToneReprCurve::Lut(curve_values))) 768| 38| } else if curve_type == TagTypeDefinition::ParametricToneCurve { 769| 0| let entry_count = u16::from_be_bytes([tag[8], tag[9]]) as usize; 770| 0| if entry_count > 4 { 771| 0| return Err(CmsError::MalformedTrcCurve( 772| 0| "Parametric curve has unknown entries count".to_string(), 773| 0| )); 774| 0| } 775| | 776| | const COUNT_TO_LENGTH: [usize; 5] = [1, 3, 4, 5, 7]; //PARAMETRIC_CURVE_TYPE 777| | 778| 0| if tag.len() < 12 + COUNT_TO_LENGTH[entry_count] * size_of::() { 779| 0| return Err(CmsError::MalformedTrcCurve( 780| 0| "Parametric curve has unknown entries count exhaust data too early".to_string(), 781| 0| )); 782| 0| } 783| 0| let curve_sliced = &tag[12..12 + COUNT_TO_LENGTH[entry_count] * size_of::()]; 784| 0| let mut params = try_vec![0f32; COUNT_TO_LENGTH[entry_count]]; 785| 0| for (value, param_value) in curve_sliced.chunks_exact(4).zip(params.iter_mut()) { 786| 0| let parametric_value = i32::from_be_bytes([value[0], value[1], value[2], value[3]]); 787| 0| *param_value = s15_fixed16_number_to_float(parametric_value); 788| 0| } 789| 0| if entry_count == 1 || entry_count == 2 { 790| | // we have a type 1 or type 2 function that has a division by `a` 791| 0| let a: f32 = params[1]; 792| 0| if a == 0.0 { 793| 0| return Err(CmsError::ParametricCurveZeroDivision); 794| 0| } 795| 0| } 796| 0| *read_size = 12 + COUNT_TO_LENGTH[entry_count] * 4; 797| 0| Ok(Some(ToneReprCurve::Parametric(params))) 798| | } else { 799| 38| Err(CmsError::MalformedTrcCurve( 800| 38| "Unknown parametric curve tag".to_string(), 801| 38| )) 802| | } 803| 259| } _RNvMNtCs1jiJzeRTgBH_6moxcms6readerNtNtB4_7profile12ColorProfile12read_xyz_tagB4_: 935| 2.67k| pub(crate) fn read_xyz_tag( 936| 2.67k| slice: &[u8], 937| 2.67k| entry: usize, 938| 2.67k| tag_size: usize, 939| 2.67k| ) -> Result { 940| 2.67k| if tag_size < TAG_SIZE { 941| 104| return Ok(Xyzd::default()); 942| 2.56k| } 943| 2.56k| let last_tag_offset = tag_size.safe_add(entry)?; 944| 2.56k| if last_tag_offset > slice.len() { 945| 253| return Err(CmsError::InvalidProfile); 946| 2.31k| } 947| 2.31k| let tag = &slice[entry..entry + 12]; 948| 2.31k| let tag_type = u32::from_be_bytes([tag[0], tag[1], tag[2], tag[3]]); 949| 2.31k| let def = TagTypeDefinition::from(tag_type); 950| 2.31k| if def != TagTypeDefinition::Xyz { 951| 2.27k| return Ok(Xyzd::default()); 952| 43| } 953| | 954| 43| let tag = &slice[entry..last_tag_offset]; 955| 43| if tag.len() < 20 { 956| 7| return Err(CmsError::InvalidProfile); 957| 36| } 958| 36| let q15_16_x = i32::from_be_bytes([tag[8], tag[9], tag[10], tag[11]]); 959| 36| let q15_16_y = i32::from_be_bytes([tag[12], tag[13], tag[14], tag[15]]); 960| 36| let q15_16_z = i32::from_be_bytes([tag[16], tag[17], tag[18], tag[19]]); 961| 36| let x = s15_fixed16_number_to_double(q15_16_x); 962| 36| let y = s15_fixed16_number_to_double(q15_16_y); 963| 36| let z = s15_fixed16_number_to_double(q15_16_z); 964| 36| Ok(Xyzd { x, y, z }) 965| 2.67k| } _RNvMNtCs1jiJzeRTgBH_6moxcms6readerNtNtB4_7profile12ColorProfile13read_cicp_tag: 967| 28| pub(crate) fn read_cicp_tag( 968| 28| slice: &[u8], 969| 28| entry: usize, 970| 28| tag_size: usize, 971| 28| ) -> Result, CmsError> { 972| 28| if tag_size < TAG_SIZE { 973| 1| return Ok(None); 974| 27| } 975| 27| let last_tag_offset = tag_size.safe_add(entry)?; 976| 27| if last_tag_offset > slice.len() { 977| 25| return Err(CmsError::InvalidProfile); 978| 2| } 979| 2| let tag = &slice[entry..last_tag_offset]; 980| 2| if tag.len() < 12 { 981| 0| return Err(CmsError::InvalidProfile); 982| 2| } 983| 2| let tag_type = u32::from_be_bytes([tag[0], tag[1], tag[2], tag[3]]); 984| 2| let def = TagTypeDefinition::from(tag_type); 985| 2| if def != TagTypeDefinition::Cicp { 986| 2| return Ok(None); 987| 0| } 988| 0| let primaries = CicpColorPrimaries::try_from(tag[8])?; 989| 0| let transfer_characteristics = TransferCharacteristics::try_from(tag[9])?; 990| 0| let matrix_coefficients = MatrixCoefficients::try_from(tag[10])?; 991| 0| let full_range = tag[11] == 1; 992| 0| Ok(Some(CicpProfile { 993| 0| color_primaries: primaries, 994| 0| transfer_characteristics, 995| 0| matrix_coefficients, 996| 0| full_range, 997| 0| })) 998| 28| } _RNvMNtCs1jiJzeRTgBH_6moxcms6readerNtNtB4_7profile12ColorProfile14read_trc_tag_s: 703| 259| pub(crate) fn read_trc_tag_s( 704| 259| slice: &[u8], 705| 259| entry: usize, 706| 259| tag_size: usize, 707| 259| options: &ParsingOptions, 708| 259| ) -> Result, CmsError> { 709| 259| let mut _empty = 0usize; 710| 259| Self::read_trc_tag(slice, entry, tag_size, &mut _empty, options) 711| 259| } _RNvMNtCs1jiJzeRTgBH_6moxcms6readerNtNtB4_7profile12ColorProfile15read_string_tag: 176| 2.31k| pub(crate) fn read_string_tag( 177| 2.31k| slice: &[u8], 178| 2.31k| entry: usize, 179| 2.31k| tag_size: usize, 180| 2.31k| ) -> Result, CmsError> { 181| 2.31k| let tag_size = if tag_size == 0 { TAG_SIZE } else { tag_size }; 182| 2.31k| if tag_size < 4 { 183| 20| return Ok(None); 184| 2.29k| } 185| 2.29k| let last_tag_offset = tag_size.safe_add(entry)?; 186| 2.29k| if last_tag_offset > slice.len() { 187| 85| return Err(CmsError::InvalidProfile); 188| 2.20k| } 189| 2.20k| let tag = &slice[entry..last_tag_offset]; 190| 2.20k| if tag.len() < 8 { 191| 13| return Ok(None); 192| 2.19k| } 193| 2.19k| let tag_type = 194| 2.19k| TagTypeDefinition::from(u32::from_be_bytes([tag[0], tag[1], tag[2], tag[3]])); 195| | // Ignore unknown 196| 2.19k| if tag_type == TagTypeDefinition::Text { 197| 53| let sliced_from_to_end = &tag[8..tag.len()]; 198| 53| let str = String::from_utf8_lossy(sliced_from_to_end) 199| 53| .trim_end_matches('\0') 200| 53| .to_string(); 201| 53| return Ok(Some(ProfileText::PlainString(str))); 202| 2.13k| } else if tag_type == TagTypeDefinition::MultiLocalizedUnicode { 203| 0| if tag.len() < 28 { 204| 0| return Err(CmsError::InvalidProfile); 205| 0| } 206| | // let record_size = u32::from_be_bytes([tag[12], tag[13], tag[14], tag[15]]) as usize; 207| | // // Record size is reserved to be 12. 208| | // if record_size != 12 { 209| | // return Err(CmsError::InvalidIcc); 210| | // } 211| 0| let records_count = u32::from_be_bytes([tag[8], tag[9], tag[10], tag[11]]) as usize; 212| 0| let primary_language_code = String::from_utf8_lossy(&[tag[16], tag[17]]).to_string(); 213| 0| let primary_country_code = String::from_utf8_lossy(&[tag[18], tag[19]]).to_string(); 214| 0| let first_string_record_length = 215| 0| u32::from_be_bytes([tag[20], tag[21], tag[22], tag[23]]) as usize; 216| 0| let first_record_offset = 217| 0| u32::from_be_bytes([tag[24], tag[25], tag[26], tag[27]]) as usize; 218| | 219| 0| if tag.len() < first_record_offset.safe_add(first_string_record_length)? { 220| 0| return Ok(None); 221| 0| } 222| | 223| 0| let resliced = 224| 0| &tag[first_record_offset..first_record_offset + first_string_record_length]; 225| 0| let cvt = utf16be_to_utf16(resliced)?; 226| 0| let string_record = String::from_utf16_lossy(&cvt); 227| | 228| 0| let mut records = vec![LocalizableString { 229| 0| language: primary_language_code, 230| 0| country: primary_country_code, 231| 0| value: string_record, 232| 0| }]; 233| | 234| 0| for record in 1..records_count { 235| | // Localizable header must be at least 12 bytes 236| 0| let localizable_header_offset = if record == 1 { 237| 0| 28 238| | } else { 239| 0| 28 + 12 * (record - 1) 240| | }; 241| 0| if tag.len() < localizable_header_offset + 12 { 242| 0| return Err(CmsError::InvalidProfile); 243| 0| } 244| 0| let choked = &tag[localizable_header_offset..localizable_header_offset + 12]; 245| | 246| 0| let language_code = String::from_utf8_lossy(&[choked[0], choked[1]]).to_string(); 247| 0| let country_code = String::from_utf8_lossy(&[choked[2], choked[3]]).to_string(); 248| 0| let record_length = 249| 0| u32::from_be_bytes([choked[4], choked[5], choked[6], choked[7]]) as usize; 250| 0| let string_offset = 251| 0| u32::from_be_bytes([choked[8], choked[9], choked[10], choked[11]]) as usize; 252| | 253| 0| if tag.len() < string_offset.safe_add(record_length)? { 254| 0| return Ok(None); 255| 0| } 256| 0| let resliced = &tag[string_offset..string_offset + record_length]; 257| 0| let cvt = utf16be_to_utf16(resliced)?; 258| 0| let string_record = String::from_utf16_lossy(&cvt); 259| 0| records.push(LocalizableString { 260| 0| country: country_code, 261| 0| language: language_code, 262| 0| value: string_record, 263| 0| }); 264| | } 265| | 266| 0| return Ok(Some(ProfileText::Localizable(records))); 267| 2.13k| } else if tag_type == TagTypeDefinition::Description { 268| 471| if tag.len() < 12 { 269| 1| return Err(CmsError::InvalidProfile); 270| 470| } 271| 470| let ascii_length = u32::from_be_bytes([tag[8], tag[9], tag[10], tag[11]]) as usize; 272| 470| let ascii_end = 12usize.safe_add(ascii_length)?; 273| 470| if tag.len() < ascii_end { 274| 3| return Err(CmsError::InvalidProfile); 275| 467| } 276| 467| let sliced = &tag[12..ascii_end]; 277| 467| let ascii_string = String::from_utf8_lossy(sliced) 278| 467| .trim_end_matches('\0') 279| 467| .to_string(); 280| | 281| | // Tolerate truncated desc tags — the Unicode and ScriptCode 282| | // sections may be missing (common in non-conforming v4 profiles, 283| | // but also seen in some v2 profiles in the wild). 284| 467| let unicode_offset = ascii_end; 285| 467| let (unicode_code, unicode_string) = 286| 467| self::read_desc_unicode(tag, unicode_offset)?.unwrap_or((0, String::new())); 287| | 288| 467| return Ok(Some(ProfileText::Description(DescriptionString { 289| 467| ascii_string, 290| 467| unicode_language_code: unicode_code, 291| 467| unicode_string, 292| 467| mac_string: "".to_string(), 293| 467| script_code_code: -1, 294| 467| }))); 295| 1.66k| } 296| 1.66k| Ok(None) 297| 2.31k| } _RNvNtCs1jiJzeRTgBH_6moxcms6reader16utf16be_to_utf16: 74| 244|fn utf16be_to_utf16(slice: &[u8]) -> Result, CmsError> { 75| 244| let mut vec = try_vec![0u16; slice.len() / 2]; 76| 7.33k| for (dst, chunk) in vec.iter_mut().zip(slice.chunks_exact(2)) { 77| 7.33k| *dst = u16::from_be_bytes([chunk[0], chunk[1]]); 78| 7.33k| } 79| 244| Ok(vec) 80| 244|} _RNvNtCs1jiJzeRTgBH_6moxcms6reader17read_desc_unicode: 85| 467|fn read_desc_unicode(tag: &[u8], unicode_offset: usize) -> Result, CmsError> { 86| 467| if tag.len() < unicode_offset.safe_add(8)? { 87| 13| return Ok(None); 88| 454| } 89| 454| let header = &tag[unicode_offset..unicode_offset.safe_add(8)?]; 90| 454| let language_code = u32::from_be_bytes([header[0], header[1], header[2], header[3]]); 91| 454| let unicode_length = u32::from_be_bytes([header[4], header[5], header[6], header[7]]) as usize; 92| 454| if unicode_length == 0 { 93| 49| return Ok(Some((language_code, String::new()))); 94| 405| } 95| 405| let byte_length = unicode_length.safe_mul(2)?; 96| 405| let str_start = unicode_offset.safe_add(8)?; 97| 405| if tag.len() < str_start.safe_add(byte_length)? { 98| 161| return Ok(None); 99| 244| } 100| 244| let uc_data = &tag[str_start..str_start.safe_add(byte_length)?]; 101| 244| let wc = utf16be_to_utf16(uc_data)?; 102| 244| let s = String::from_utf16_lossy(&wc) 103| 244| .trim_end_matches('\0') 104| 244| .to_string(); 105| 244| Ok(Some((language_code, s))) 106| 467|} _RNvNtCs1jiJzeRTgBH_6moxcms6reader27s15_fixed16_number_to_floatB3_: 45| 3.31k|pub(crate) const fn s15_fixed16_number_to_float(a: i32) -> f32 { 46| 3.31k| a as f32 / 65536. 47| 3.31k|} _RNvNtCs1jiJzeRTgBH_6moxcms6reader28s15_fixed16_number_to_doubleB3_: 50| 108|pub(crate) const fn s15_fixed16_number_to_double(a: i32) -> f64 { 51| 108| a as f64 / 65536. 52| 108|} _RNvXs1_NtCs1jiJzeRTgBH_6moxcms9safe_mathjINtB5_7SafeAddjE8safe_add: 48| 8.70k| fn safe_add(&self, other: $type_name) -> Result<$type_name, CmsError> { 49| 8.70k| if let Some(result) = self.checked_add(other) { 50| 8.70k| return Ok(result); 51| 0| } 52| 0| Err(CmsError::OverflowingError) 53| 8.70k| } _RNvXs6_NtCs1jiJzeRTgBH_6moxcms9safe_mathjINtB5_7SafeMuljE8safe_mul: 68| 1.51k| fn safe_mul(&self, other: $type_name) -> Result<$type_name, CmsError> { 69| 1.51k| if let Some(result) = self.checked_mul(other) { 70| 1.51k| return Ok(result); 71| 0| } 72| 0| Err(CmsError::OverflowingError) 73| 1.51k| } _RNvXNtCs1jiJzeRTgBH_6moxcms3tagNtB2_3TagINtNtCs6SNw0SRvItZ_4core7convert7TryFrommE8try_from: 70| 26.5k| fn try_from(value: u32) -> Result { 71| 26.5k| if value == u32::from_ne_bytes(*b"rXYZ").to_be() { 72| 523| return Ok(Self::RedXyz); 73| 25.9k| } else if value == u32::from_ne_bytes(*b"gXYZ").to_be() { 74| 290| return Ok(Self::GreenXyz); 75| 25.6k| } else if value == u32::from_ne_bytes(*b"bXYZ").to_be() { 76| 335| return Ok(Self::BlueXyz); 77| 25.3k| } else if value == u32::from_ne_bytes(*b"rTRC").to_be() { 78| 123| return Ok(Self::RedToneReproduction); 79| 25.2k| } else if value == u32::from_ne_bytes(*b"gTRC").to_be() { 80| 42| return Ok(Self::GreenToneReproduction); 81| 25.1k| } else if value == u32::from_ne_bytes(*b"bTRC").to_be() { 82| 18| return Ok(Self::BlueToneReproduction); 83| 25.1k| } else if value == u32::from_ne_bytes(*b"kTRC").to_be() { 84| 91| return Ok(Self::GreyToneReproduction); 85| 25.0k| } else if value == u32::from_ne_bytes(*b"wtpt").to_be() { 86| 905| return Ok(Self::MediaWhitePoint); 87| 24.1k| } else if value == u32::from_ne_bytes(*b"cicp").to_be() { 88| 28| return Ok(Self::CodeIndependentPoints); 89| 24.1k| } else if value == u32::from_ne_bytes(*b"chad").to_be() { 90| 0| return Ok(Self::ChromaticAdaptation); 91| 24.1k| } else if value == u32::from_ne_bytes(*b"bkpt").to_be() { 92| 619| return Ok(Self::BlackPoint); 93| 23.5k| } else if value == u32::from_ne_bytes(*b"A2B0").to_be() { 94| 0| return Ok(Self::DeviceToPcsLutPerceptual); 95| 23.5k| } else if value == u32::from_ne_bytes(*b"A2B1").to_be() { 96| 0| return Ok(Self::DeviceToPcsLutColorimetric); 97| 23.5k| } else if value == u32::from_ne_bytes(*b"A2B2").to_be() { 98| 0| return Ok(Self::DeviceToPcsLutSaturation); 99| 23.5k| } else if value == u32::from_ne_bytes(*b"B2A0").to_be() { 100| 0| return Ok(Self::PcsToDeviceLutPerceptual); 101| 23.5k| } else if value == u32::from_ne_bytes(*b"B2A1").to_be() { 102| 0| return Ok(Self::PcsToDeviceLutColorimetric); 103| 23.5k| } else if value == u32::from_ne_bytes(*b"B2A2").to_be() { 104| 0| return Ok(Self::PcsToDeviceLutSaturation); 105| 23.5k| } else if value == u32::from_ne_bytes(*b"desc").to_be() { 106| 1.26k| return Ok(Self::ProfileDescription); 107| 22.2k| } else if value == u32::from_ne_bytes(*b"cprt").to_be() { 108| 1.04k| return Ok(Self::Copyright); 109| 21.2k| } else if value == u32::from_ne_bytes(*b"vued").to_be() { 110| 0| return Ok(Self::ViewingConditionsDescription); 111| 21.2k| } else if value == u32::from_ne_bytes(*b"dmnd").to_be() { 112| 0| return Ok(Self::DeviceManufacturer); 113| 21.2k| } else if value == u32::from_ne_bytes(*b"dmdd").to_be() { 114| 1| return Ok(Self::DeviceModel); 115| 21.2k| } else if value == u32::from_ne_bytes(*b"gamt").to_be() { 116| 0| return Ok(Self::Gamut); 117| 21.2k| } else if value == u32::from_ne_bytes(*b"lumi").to_be() { 118| 0| return Ok(Self::Luminance); 119| 21.2k| } else if value == u32::from_ne_bytes(*b"meas").to_be() { 120| 0| return Ok(Self::Measurement); 121| 21.2k| } else if value == u32::from_ne_bytes(*b"chrm").to_be() { 122| 3| return Ok(Self::Chromaticity); 123| 21.2k| } else if value == u32::from_ne_bytes(*b"view").to_be() { 124| 0| return Ok(Self::ObserverConditions); 125| 21.2k| } else if value == u32::from_ne_bytes(*b"targ").to_be() { 126| 1| return Ok(Self::CharTarget); 127| 21.2k| } else if value == u32::from_ne_bytes(*b"tech").to_be() { 128| 0| return Ok(Self::Technology); 129| 21.2k| } else if value == u32::from_ne_bytes(*b"calt").to_be() { 130| 0| return Ok(Self::CalibrationDateTime); 131| 21.2k| } 132| 21.2k| Err(CmsError::UnknownTag(value)) 133| 26.5k| } _RNvXs0_NtCs1jiJzeRTgBH_6moxcms3tagNtB5_17TagTypeDefinitionINtNtCs6SNw0SRvItZ_4core7convert4FrommE4from: 199| 4.64k| fn from(value: u32) -> Self { 200| 4.64k| if value == u32::from_ne_bytes(*b"mluc").to_be() { 201| 0| return TagTypeDefinition::MultiLocalizedUnicode; 202| 4.64k| } else if value == u32::from_ne_bytes(*b"desc").to_be() { 203| 478| return TagTypeDefinition::Description; 204| 4.16k| } else if value == u32::from_ne_bytes(*b"text").to_be() { 205| 56| return TagTypeDefinition::Text; 206| 4.10k| } else if value == u32::from_ne_bytes(*b"mAB ").to_be() { 207| 0| return TagTypeDefinition::MabLut; 208| 4.10k| } else if value == u32::from_ne_bytes(*b"mBA ").to_be() { 209| 0| return TagTypeDefinition::MbaLut; 210| 4.10k| } else if value == u32::from_ne_bytes(*b"para").to_be() { 211| 0| return TagTypeDefinition::ParametricToneCurve; 212| 4.10k| } else if value == u32::from_ne_bytes(*b"curv").to_be() { 213| 27| return TagTypeDefinition::LutToneCurve; 214| 4.08k| } else if value == u32::from_ne_bytes(*b"XYZ ").to_be() { 215| 45| return TagTypeDefinition::Xyz; 216| 4.03k| } else if value == u32::from_ne_bytes(*b"mpet").to_be() { 217| 0| return TagTypeDefinition::MultiProcessElement; 218| 4.03k| } else if value == u32::from_ne_bytes(*b"view").to_be() { 219| 0| return TagTypeDefinition::DefViewingConditions; 220| 4.03k| } else if value == u32::from_ne_bytes(*b"sig ").to_be() { 221| 1| return TagTypeDefinition::Signature; 222| 4.03k| } else if value == u32::from_ne_bytes(*b"cicp").to_be() { 223| 1| return TagTypeDefinition::Cicp; 224| 4.03k| } else if value == u32::from_ne_bytes(*b"dtim").to_be() { 225| 0| return TagTypeDefinition::DateTime; 226| 4.03k| } else if value == u32::from_ne_bytes(*b"meas").to_be() { 227| 0| return TagTypeDefinition::Measurement; 228| 4.03k| } else if value == u32::from_ne_bytes(*b"sf32").to_be() { 229| 0| return TagTypeDefinition::S15Fixed16Array; 230| 4.03k| } else if value == u32::from_ne_bytes(*b"uf32").to_be() { 231| 0| return TagTypeDefinition::U16Fixed16Array; 232| 4.03k| } else if value == u32::from_ne_bytes(*b"ui16").to_be() { 233| 0| return TagTypeDefinition::U16Array; 234| 4.03k| } else if value == u32::from_ne_bytes(*b"ui32").to_be() { 235| 0| return TagTypeDefinition::U32Array; 236| 4.03k| } else if value == u32::from_ne_bytes(*b"ui64").to_be() { 237| 0| return TagTypeDefinition::U64Array; 238| 4.03k| } else if value == u32::from_ne_bytes(*b"ui08").to_be() { 239| 0| return TagTypeDefinition::U8Array; 240| 4.03k| } 241| 4.03k| TagTypeDefinition::NotAllowed 242| 4.64k| } _RNvXs4_NtCs2ICmcE5qjLx_10num_traits10identitieshNtB5_4Zero4zeroCs3aXgM11XBGX_5image: 42| 4.47k| fn zero() -> $t { 43| | $v 44| 4.47k| } _RNvXs6_NtCs2ICmcE5qjLx_10num_traits10identitiestNtB5_4Zero4zeroCs3aXgM11XBGX_5image: 42| 1.53k| fn zero() -> $t { 43| | $v 44| 1.53k| } _RNCNvNtCshdzP3jLBsmJ_3png5adam718expand_adam7_bytes0B5_: 309| 1.57G| .map(move |i| (i * samp_mul + samp_off) * u64::from(bytes_pp)) _RNCNvNtCshdzP3jLBsmJ_3png5adam718expand_adam7_bytess_0B5_: 311| 1.57G| .map(move |i| i as usize + byte_start) _RNvMNtCshdzP3jLBsmJ_3png5adam7NtB2_9Adam7Info14pass_constants: 66| 25.9M| fn pass_constants(&self) -> PassConstants { 67| 25.9M| PassConstants::PASSES[self.pass as usize - 1] 68| 25.9M| } _RNvMs0_NtCshdzP3jLBsmJ_3png5adam7NtB5_13Adam7Iterator3new: 161| 2.47k| pub fn new(width: u32, height: u32) -> Adam7Iterator { 162| 2.47k| let mut this = Adam7Iterator { 163| 2.47k| line: 0, 164| 2.47k| lines: 0, 165| 2.47k| line_width: 0, 166| 2.47k| current_pass: 1, 167| 2.47k| width, 168| 2.47k| height, 169| 2.47k| }; 170| 2.47k| this.init_pass(); 171| 2.47k| this 172| 2.47k| } _RNvMs0_NtCshdzP3jLBsmJ_3png5adam7NtB5_13Adam7Iterator9init_pass: 175| 6.63k| fn init_pass(&mut self) { 176| 6.63k| let info = PassConstants::PASSES[self.current_pass as usize - 1]; 177| 6.63k| self.line_width = info.count_samples(self.width); 178| 6.63k| self.lines = info.count_lines(self.height); 179| 6.63k| self.line = 0; 180| 6.63k| } _RNvMs_NtCshdzP3jLBsmJ_3png5adam7NtB4_13PassConstants11count_lines: 107| 23.9k| pub fn count_lines(self, height: u32) -> u32 { 108| 23.9k| height 109| 23.9k| .saturating_sub(u32::from(self.y_offset)) 110| 23.9k| .div_ceil(u32::from(self.y_sampling)) 111| 23.9k| } _RNvMs_NtCshdzP3jLBsmJ_3png5adam7NtB4_13PassConstants13count_samples: 101| 23.9k| pub fn count_samples(self, width: u32) -> u32 { 102| 23.9k| width 103| 23.9k| .saturating_sub(u32::from(self.x_offset)) 104| 23.9k| .div_ceil(u32::from(self.x_sampling)) 105| 23.9k| } _RNvNtCshdzP3jLBsmJ_3png5adam711expand_pass: 348| 25.9M|pub fn expand_pass( 349| 25.9M| img: &mut [u8], 350| 25.9M| img_row_stride: usize, 351| 25.9M| interlaced_row: &[u8], 352| 25.9M| interlace_info: &Adam7Info, 353| 25.9M| bits_per_pixel: u8, 354| 25.9M|) { 355| 25.9M| match bits_per_pixel { 356| | // Note: for 1, 2, 4 multiple runs through the iteration will access the same byte in `img` 357| | // so we can not iterate over `&mut u8` values. A better strategy would write multiple bit 358| | // groups in one go. This would then also not be as bounds-check heavy? 359| | 1 => { 360| | const BIT_POS_1: [u8; 8] = [7, 6, 5, 4, 3, 2, 1, 0]; 361| 0| let bit_indices = expand_adam7_bits(img_row_stride, interlace_info, 1); 362| 0| for (pos, px) in bit_indices.zip(subbyte_values(interlaced_row, BIT_POS_1, 0b1)) { 363| 0| let shift = 8 - bits_per_pixel - pos.bit; 364| 0| img[pos.byte] |= px << shift; 365| 0| } 366| | } 367| | 2 => { 368| | const BIT_POS_2: [u8; 4] = [6, 4, 2, 0]; 369| 0| let bit_indices = expand_adam7_bits(img_row_stride, interlace_info, 2); 370| | 371| 0| for (pos, px) in bit_indices.zip(subbyte_values(interlaced_row, BIT_POS_2, 0b11)) { 372| 0| let shift = 8 - bits_per_pixel - pos.bit; 373| 0| img[pos.byte] |= px << shift; 374| 0| } 375| | } 376| | 4 => { 377| | const BIT_POS_4: [u8; 2] = [4, 0]; 378| 0| let bit_indices = expand_adam7_bits(img_row_stride, interlace_info, 4); 379| | 380| 0| for (pos, px) in bit_indices.zip(subbyte_values(interlaced_row, BIT_POS_4, 0b1111)) { 381| 0| let shift = 8 - bits_per_pixel - pos.bit; 382| 0| img[pos.byte] |= px << shift; 383| 0| } 384| | } 385| | // While caught by the below loop, we special case this for codegen. The effects are 386| | // massive when the compiler uses the constant chunk size in particular for this case where 387| | // no more copy_from_slice is being issued by everything happens in the register alone. 388| | 8 => { 389| 25.6M| let byte_indices = expand_adam7_bytes(img_row_stride, interlace_info, 1); 390| | 391| 610M| for (bytepos, &px) in byte_indices.zip(interlaced_row) { 392| 610M| img[bytepos] = px; 393| 610M| } 394| | } 395| | 16 => { 396| 79.1k| let byte_indices = expand_adam7_bytes(img_row_stride, interlace_info, 2); 397| | 398| 209M| for (bytepos, px) in byte_indices.zip(interlaced_row.chunks(2)) { 399| 209M| img[bytepos..][..2].copy_from_slice(px); 400| 209M| } 401| | } 402| | _ => { 403| 214k| debug_assert!(bits_per_pixel % 8 == 0); 404| 214k| let bytes_pp = bits_per_pixel / 8; 405| 214k| let byte_indices = expand_adam7_bytes(img_row_stride, interlace_info, bytes_pp); 406| | 407| 751M| for (bytepos, px) in byte_indices.zip(interlaced_row.chunks(bytes_pp.into())) { 408| 751M| img[bytepos..][..px.len()].copy_from_slice(px); 409| 751M| } 410| | } 411| | } 412| 25.9M|} _RNvNtCshdzP3jLBsmJ_3png5adam718expand_adam7_bytes: 288| 25.9M|fn expand_adam7_bytes( 289| 25.9M| row_stride_in_bytes: usize, 290| 25.9M| info: &Adam7Info, 291| 25.9M| bytes_pp: u8, 292| 25.9M|) -> impl Iterator { 293| 25.9M| let (line_mul, line_off, samp_mul, samp_off) = { 294| 25.9M| let constants = info.pass_constants(); 295| 25.9M| ( 296| 25.9M| // Convert each to their respectively required type from u8. 297| 25.9M| usize::from(constants.y_sampling), 298| 25.9M| usize::from(constants.y_offset), 299| 25.9M| u64::from(constants.x_sampling), 300| 25.9M| u64::from(constants.x_offset), 301| 25.9M| ) 302| 25.9M| }; 303| | 304| | // the equivalent line number in progressive scan 305| 25.9M| let prog_line = line_mul * info.line as usize + line_off; 306| 25.9M| let byte_start = prog_line * row_stride_in_bytes; 307| | 308| 25.9M| (0..u64::from(info.samples)) 309| 25.9M| .map(move |i| (i * samp_mul + samp_off) * u64::from(bytes_pp)) 310| | // Bounded by the allocated buffer size so must fit in `usize` 311| 25.9M| .map(move |i| i as usize + byte_start) 312| 25.9M|} _RNvXs1_NtCshdzP3jLBsmJ_3png5adam7NtB5_13Adam7IteratorNtNtNtNtCs6SNw0SRvItZ_4core4iter6traits8iterator8Iterator4next: 186| 25.9M| fn next(&mut self) -> Option { 187| 25.9M| if self.line < self.lines && self.line_width > 0 { 188| 25.9M| let this_line = self.line; 189| 25.9M| self.line += 1; 190| 25.9M| Some(Adam7Info { 191| 25.9M| pass: self.current_pass, 192| 25.9M| line: this_line, 193| 25.9M| width: self.width, 194| 25.9M| samples: self.line_width, 195| 25.9M| }) 196| 4.42k| } else if self.current_pass < 7 { 197| 4.16k| self.current_pass += 1; 198| 4.16k| self.init_pass(); 199| 4.16k| self.next() 200| | } else { 201| 259| None 202| | } 203| 25.9M| } _RNvNtCshdzP3jLBsmJ_3png5chunk11is_critical: 67| 30.4k|pub fn is_critical(ChunkType(type_): ChunkType) -> bool { 68| 30.4k| type_[0] & 32 == 0 69| 30.4k|} _RNvMNtCshdzP3jLBsmJ_3png6commonNtB2_9ColorType10samples_u8: 31| 103M| pub(crate) fn samples_u8(self) -> u8 { 32| | use self::ColorType::*; 33| 103M| match self { 34| 102M| Grayscale | Indexed => 1, 35| 635k| Rgb => 3, 36| 70.3k| GrayscaleAlpha => 2, 37| 98.3k| Rgba => 4, 38| | } 39| 103M| } _RNvMNtCshdzP3jLBsmJ_3png6commonNtB2_9ColorType15bytes_per_pixel: 87| 6.25k| pub(crate) fn bytes_per_pixel(&self, bit_depth: BitDepth) -> usize { 88| | // If adjusting this for expansion or other transformation passes, remember to keep the old 89| | // implementation for bpp_in_prediction, which is internal to the png specification. 90| 6.25k| self.samples() * ((bit_depth as usize + 7) >> 3) 91| 6.25k| } _RNvMNtCshdzP3jLBsmJ_3png6commonNtB2_9ColorType22checked_raw_row_length: 53| 25.9M| pub(crate) fn checked_raw_row_length(self, depth: BitDepth, width: u32) -> Option { 54| | // No overflow can occur in 64 bits, we multiply 32-bit with 5 more bits. 55| 25.9M| let bits = u64::from(width) * u64::from(self.samples_u8()) * u64::from(depth.into_u8()); 56| 25.9M| TryFrom::try_from(1 + bits.div_ceil(8)).ok() 57| 25.9M| } _RNvMNtCshdzP3jLBsmJ_3png6commonNtB2_9ColorType22is_combination_invalid: 73| 9.39k| pub(crate) fn is_combination_invalid(self, bit_depth: BitDepth) -> bool { 74| | // Section 11.2.2 of the PNG standard disallows several combinations 75| | // of bit depth and color type 76| 9.39k| ((bit_depth == BitDepth::One || bit_depth == BitDepth::Two || bit_depth == BitDepth::Four) 77| 4.20k| && (self == ColorType::Rgb 78| 4.20k| || self == ColorType::GrayscaleAlpha 79| 4.20k| || self == ColorType::Rgba)) 80| 9.39k| || (bit_depth == BitDepth::Sixteen && self == ColorType::Indexed) 81| 9.39k| } _RNvMNtCshdzP3jLBsmJ_3png6commonNtB2_9ColorType25raw_row_length_from_width: 59| 77.7M| pub(crate) fn raw_row_length_from_width(self, depth: BitDepth, width: u32) -> usize { 60| 77.7M| let samples = width as usize * self.samples(); 61| 77.7M| 1 + match depth { 62| 356k| BitDepth::Sixteen => samples * 2, 63| 76.9M| BitDepth::Eight => samples, 64| 483k| subbyte => { 65| 483k| let samples_per_byte = 8 / subbyte as usize; 66| 483k| let whole = samples / samples_per_byte; 67| 483k| let fract = usize::from(samples % samples_per_byte > 0); 68| 483k| whole + fract 69| | } 70| | } 71| 77.7M| } _RNvMNtCshdzP3jLBsmJ_3png6commonNtB2_9ColorType7from_u8: 42| 9.40k| pub fn from_u8(n: u8) -> Option { 43| 9.40k| match n { 44| 4.68k| 0 => Some(ColorType::Grayscale), 45| 1.36k| 2 => Some(ColorType::Rgb), 46| 1.64k| 3 => Some(ColorType::Indexed), 47| 446| 4 => Some(ColorType::GrayscaleAlpha), 48| 1.25k| 6 => Some(ColorType::Rgba), 49| 8| _ => None, 50| | } 51| 9.40k| } _RNvMNtCshdzP3jLBsmJ_3png6commonNtB2_9ColorType7samples: 27| 77.7M| pub fn samples(self) -> usize { 28| 77.7M| self.samples_u8().into() 29| 77.7M| } _RNvMs0_NtCshdzP3jLBsmJ_3png6commonNtB5_4Unit7from_u8: 160| 394| pub fn from_u8(n: u8) -> Option { 161| 394| match n { 162| 15| 0 => Some(Unit::Unspecified), 163| 40| 1 => Some(Unit::Meter), 164| 339| _ => None, 165| | } 166| 394| } _RNvMs1_NtCshdzP3jLBsmJ_3png6commonNtB5_9DisposeOp7from_u8: 183| 256| pub fn from_u8(n: u8) -> Option { 184| 256| match n { 185| 141| 0 => Some(DisposeOp::None), 186| 111| 1 => Some(DisposeOp::Background), 187| 1| 2 => Some(DisposeOp::Previous), 188| 3| _ => None, 189| | } 190| 256| } _RNvMs3_NtCshdzP3jLBsmJ_3png6commonNtB5_7BlendOp7from_u8: 216| 253| pub fn from_u8(n: u8) -> Option { 217| 253| match n { 218| 240| 0 => Some(BlendOp::Source), 219| 12| 1 => Some(BlendOp::Over), 220| 1| _ => None, 221| | } 222| 253| } _RNvMs_NtCshdzP3jLBsmJ_3png6commonNtB4_8BitDepth7from_u8: 123| 77.7M| pub fn from_u8(n: u8) -> Option { 124| 77.7M| match n { 125| 2.58k| 1 => Some(BitDepth::One), 126| 691| 2 => Some(BitDepth::Two), 127| 929| 4 => Some(BitDepth::Four), 128| 77.4M| 8 => Some(BitDepth::Eight), 129| 356k| 16 => Some(BitDepth::Sixteen), 130| 24| _ => None, 131| | } 132| 77.7M| } _RNvMs_NtCshdzP3jLBsmJ_3png6commonNtB4_8BitDepth7into_u8: 134| 25.9M| pub(crate) fn into_u8(self) -> u8 { 135| 25.9M| self as u8 136| 25.9M| } _RNvMsb_NtCshdzP3jLBsmJ_3png6commonNtB5_11ScaledFloat11from_scaled: 458| 358| pub fn from_scaled(val: u32) -> Self { 459| 358| Self(val) 460| 358| } _RNvMsd_NtCshdzP3jLBsmJ_3png6commonNtB5_19SrgbRenderingIntent8from_raw: 544| 275| pub(crate) fn from_raw(raw: u8) -> Option { 545| 275| match raw { 546| 36| 0 => Some(SrgbRenderingIntent::Perceptual), 547| 36| 1 => Some(SrgbRenderingIntent::RelativeColorimetric), 548| 0| 2 => Some(SrgbRenderingIntent::Saturation), 549| 0| 3 => Some(SrgbRenderingIntent::AbsoluteColorimetric), 550| 203| _ => None, 551| | } 552| 275| } _RNvMsf_NtCshdzP3jLBsmJ_3png6commonNtB5_4Info15bytes_per_pixel: 772| 6.25k| pub fn bytes_per_pixel(&self) -> usize { 773| | // If adjusting this for expansion or other transformation passes, remember to keep the old 774| | // implementation for bpp_in_prediction, which is internal to the png specification. 775| 6.25k| self.color_type.bytes_per_pixel(self.bit_depth) 776| 6.25k| } _RNvMsf_NtCshdzP3jLBsmJ_3png6commonNtB5_4Info17bpp_in_prediction: 785| 6.25k| pub(crate) fn bpp_in_prediction(&self) -> BytesPerPixel { 786| 6.25k| BytesPerPixel::from_usize(self.bytes_per_pixel()) 787| 6.25k| } _RNvMsf_NtCshdzP3jLBsmJ_3png6commonNtB5_4Info22checked_raw_row_length: 799| 28.1k| pub(crate) fn checked_raw_row_length(&self) -> Option { 800| 28.1k| self.color_type 801| 28.1k| .checked_raw_row_length(self.bit_depth, self.width) 802| 28.1k| } _RNvMsf_NtCshdzP3jLBsmJ_3png6commonNtB5_4Info25raw_row_length_from_width: 805| 25.9M| pub fn raw_row_length_from_width(&self, width: u32) -> usize { 806| 25.9M| self.color_type 807| 25.9M| .raw_row_length_from_width(self.bit_depth, width) 808| 25.9M| } _RNvMsf_NtCshdzP3jLBsmJ_3png6commonNtB5_4Info4size: 747| 33.6k| pub fn size(&self) -> (u32, u32) { 748| 33.6k| (self.width, self.height) 749| 33.6k| } _RNvMsg_NtCshdzP3jLBsmJ_3png6commonNtB5_13BytesPerPixel10from_usize: 841| 6.25k| pub(crate) fn from_usize(bpp: usize) -> Self { 842| 6.25k| match bpp { 843| 3.58k| 1 => BytesPerPixel::One, 844| 1.01k| 2 => BytesPerPixel::Two, 845| 638| 3 => BytesPerPixel::Three, 846| 376| 4 => BytesPerPixel::Four, 847| 401| 6 => BytesPerPixel::Six, // Only rgb×16bit 848| 249| 8 => BytesPerPixel::Eight, // Only rgba×16bit 849| 0| _ => unreachable!("Not a possible byte rounded pixel width"), 850| | } 851| 6.25k| } _RNvXse_NtCshdzP3jLBsmJ_3png6commonNtB5_4InfoNtNtCs6SNw0SRvItZ_4core7default7Default7default: 705| 9.37k| fn default() -> Info<'static> { 706| 9.37k| Info { 707| 9.37k| width: 0, 708| 9.37k| height: 0, 709| 9.37k| bit_depth: BitDepth::Eight, 710| 9.37k| color_type: ColorType::Grayscale, 711| 9.37k| interlaced: false, 712| 9.37k| palette: None, 713| 9.37k| sbit: None, 714| 9.37k| trns: None, 715| 9.37k| gama_chunk: None, 716| 9.37k| chrm_chunk: None, 717| 9.37k| bkgd: None, 718| 9.37k| pixel_dims: None, 719| 9.37k| frame_control: None, 720| 9.37k| animation_control: None, 721| 9.37k| source_gamma: None, 722| 9.37k| source_chromaticities: None, 723| 9.37k| srgb: None, 724| 9.37k| icc_profile: None, 725| 9.37k| coding_independent_code_points: None, 726| 9.37k| mastering_display_color_volume: None, 727| 9.37k| content_light_level: None, 728| 9.37k| exif_metadata: None, 729| 9.37k| uncompressed_latin1_text: Vec::new(), 730| 9.37k| compressed_latin1_text: Vec::new(), 731| 9.37k| utf8_text: Vec::new(), 732| 9.37k| } 733| 9.37k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder14interlace_infoNtB2_13InterlaceInfo11line_number: 38| 25.9M| pub(crate) fn line_number(&self) -> u32 { 39| 25.9M| match self { 40| 3.59k| InterlaceInfo::Null(NullInfo { line }) => *line, 41| 25.9M| InterlaceInfo::Adam7(Adam7Info { line, .. }) => *line, 42| | } 43| 25.9M| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder14interlace_infoNtB2_13InterlaceInfo14get_adam7_info: 45| 25.9M| pub(crate) fn get_adam7_info(&self) -> Option<&Adam7Info> { 46| 25.9M| match self { 47| 0| InterlaceInfo::Null(_) => None, 48| 25.9M| InterlaceInfo::Adam7(adam7info) => Some(adam7info), 49| | } 50| 25.9M| } _RNvMs_NtNtCshdzP3jLBsmJ_3png7decoder14interlace_infoNtB4_17InterlaceInfoIter3new: 60| 6.25k| pub fn new(width: u32, height: u32, interlaced: bool) -> Self { 61| 6.25k| if interlaced { 62| 2.47k| Self(IterImpl::Adam7(Adam7Iterator::new(width, height))) 63| | } else { 64| 3.78k| Self(IterImpl::None(0..height)) 65| | } 66| 6.25k| } _RNvMs_NtNtCshdzP3jLBsmJ_3png7decoder14interlace_infoNtB4_17InterlaceInfoIter5empty: 56| 9.37k| pub fn empty() -> Self { 57| 9.37k| Self(IterImpl::None(0..0)) 58| 9.37k| } _RNvXs0_NtNtCshdzP3jLBsmJ_3png7decoder14interlace_infoNtB5_17InterlaceInfoIterNtNtNtNtCs6SNw0SRvItZ_4core4iter6traits8iterator8Iterator4next: 72| 26.3M| fn next(&mut self) -> Option { 73| 26.3M| match self.0 { 74| 25.9M| IterImpl::Adam7(ref mut adam7) => Some(InterlaceInfo::Adam7(adam7.next()?)), 75| 416k| IterImpl::None(ref mut height) => Some(InterlaceInfo::Null(NullInfo { 76| 416k| line: height.next()?, 77| | })), 78| | } 79| 26.3M| } _RNCNCNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB9_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE19next_interlaced_row00Cs3aXgM11XBGX_5image: 533| 25.9M| option.map(move |interlace| { 534| 25.9M| let output_line_size = self.output_line_size_for_interlace_info(&interlace); 535| 25.9M| InterlacedRow { 536| 25.9M| data: &self.scratch_buffer[..output_line_size], 537| 25.9M| interlace, 538| 25.9M| } 539| 25.9M| }) _RNCNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB7_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE10next_frame0Cs3aXgM11XBGX_5image: 472| 3.59k| .map(|info| info.line_number()) _RNCNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB7_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE19next_interlaced_row0Cs3aXgM11XBGX_5image: 532| 25.9M| result.map(move |option| { 533| 25.9M| option.map(move |interlace| { 534| | let output_line_size = self.output_line_size_for_interlace_info(&interlace); 535| | InterlacedRow { 536| | data: &self.scratch_buffer[..output_line_size], 537| | interlace, 538| | } 539| | }) 540| 25.9M| }) _RNCNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB7_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE23next_raw_interlaced_row0Cs3aXgM11XBGX_5image: 712| 1.40M| .with_unfilled_buffer(|buffer| self.decoder.decode_image_data(Some(buffer))); _RNvMs3_NtCshdzP3jLBsmJ_3png7decoderINtB5_7DecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE10set_limitsCs3aXgM11XBGX_5image: 177| 9.65k| pub fn set_limits(&mut self, limits: Limits) { 178| 9.65k| self.read_decoder.set_limits(limits); 179| 9.65k| } _RNvMs3_NtCshdzP3jLBsmJ_3png7decoderINtB5_7DecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE15new_with_limitsCs3aXgM11XBGX_5image: 132| 9.65k| pub fn new_with_limits(r: R, limits: Limits) -> Decoder { 133| 9.65k| let mut read_decoder = ReadDecoder::new(r); 134| 9.65k| read_decoder.set_limits(limits); 135| | 136| 9.65k| Decoder { 137| 9.65k| read_decoder, 138| 9.65k| transform: Transformations::IDENTITY, 139| 9.65k| } 140| 9.65k| } _RNvMs3_NtCshdzP3jLBsmJ_3png7decoderINtB5_7DecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE16read_header_infoCs3aXgM11XBGX_5image: 187| 19.0k| pub fn read_header_info(&mut self) -> Result<&Info<'static>, DecodingError> { 188| 19.0k| self.read_decoder.read_header_info() 189| 19.0k| } _RNvMs3_NtCshdzP3jLBsmJ_3png7decoderINtB5_7DecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE19set_transformationsCs3aXgM11XBGX_5image: 250| 9.37k| pub fn set_transformations(&mut self, transform: Transformations) { 251| 9.37k| self.transform = transform; 252| 9.37k| } _RNvMs3_NtCshdzP3jLBsmJ_3png7decoderINtB5_7DecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE21set_ignore_text_chunkCs3aXgM11XBGX_5image: 265| 9.65k| pub fn set_ignore_text_chunk(&mut self, ignore_text_chunk: bool) { 266| 9.65k| self.read_decoder.set_ignore_text_chunk(ignore_text_chunk); 267| 9.65k| } _RNvMs3_NtCshdzP3jLBsmJ_3png7decoderINtB5_7DecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE9read_infoCs3aXgM11XBGX_5image: 192| 9.37k| pub fn read_info(mut self) -> Result, DecodingError> { 193| 9.37k| let info = self.read_header_info()?; 194| 9.37k| let unfiltering_buffer = UnfilteringBuffer::new(info); 195| | 196| 9.37k| let mut reader = Reader { 197| 9.37k| decoder: self.read_decoder, 198| 9.37k| bpp: BytesPerPixel::One, 199| 9.37k| subframe: SubframeInfo::not_yet_init(), 200| 9.37k| remaining_frames: 0, // Temporary value - fixed below after reading `acTL` and `fcTL`. 201| 9.37k| unfiltering_buffer, 202| 9.37k| transform: self.transform, 203| 9.37k| transform_fn: None, 204| 9.37k| scratch_buffer: Vec::new(), 205| 9.37k| finished: false, 206| 9.37k| }; 207| | 208| | // Check if the decoding buffer of a single raw line has a valid size. 209| | // 210| | // FIXME: this check and the next can be delayed until processing image data. This would 211| | // allow usage where only the metadata is processes, or where the image is processed 212| | // line-by-line even on targets that can not fit the whole image into their address space. 213| | // We should strive for a balance between implementation complexity (still ensure that the 214| | // no-overflow preconditions are met for internal calculation) and use possibilities. 215| 9.37k| if reader.info().checked_raw_row_length().is_none() { 216| 0| return Err(DecodingError::LimitsExceeded); 217| 9.37k| } 218| | 219| | // Check if the output buffer has a valid size. 220| | // 221| | // FIXME: see above and 222| | // 223| 9.37k| if reader.output_buffer_size().is_none() { 224| 47| return Err(DecodingError::LimitsExceeded); 225| 9.32k| } 226| | 227| 9.32k| reader.read_until_image_data()?; 228| | 229| 6.23k| reader.remaining_frames = match reader.info().animation_control.as_ref() { 230| 6.18k| None => 1, // No `acTL` => only expecting `IDAT` frame. 231| 43| Some(animation) => { 232| | // Note: limited to (2^32 - 1) frames by the APNG spec so addition does not 233| | // overflow on 32-bit targets nor 64-bit targets. 234| 43| let mut num_frames = animation.num_frames; 235| 43| if reader.info().frame_control.is_none() { 236| 41| // No `fcTL` before `IDAT` => `IDAT` is not part of the animation, but 237| 41| // represents an *extra*, default frame for non-APNG-aware decoders. 238| 41| num_frames += 1; 239| 41| } 240| 43| num_frames 241| | } 242| | }; 243| 6.23k| Ok(reader) 244| 9.37k| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE10next_frameCs3aXgM11XBGX_5image: 416| 6.00k| pub fn next_frame(&mut self, buf: &mut [u8]) -> Result { 417| 6.00k| if self.remaining_frames == 0 { 418| 0| return Err(DecodingError::Parameter( 419| 0| ParameterErrorKind::PolledAfterEndOfImage.into(), 420| 0| )); 421| 6.00k| } else if self.subframe.consumed_and_flushed { 422| | // Advance until the next `fdAT` 423| | // (along the way we should encounter the fcTL for this frame). 424| 0| self.read_until_image_data()?; 425| 6.00k| } 426| | 427| | // Note that we only check if the buffer size calculation holds in a call to decoding the 428| | // frame. Consequently, we can represent the `Info` and frameless decoding even when the 429| | // target architecture's address space is too small for a frame. However reading the actual 430| 6.00k| let required_len = self 431| 6.00k| .output_buffer_size() 432| 6.00k| .ok_or(DecodingError::LimitsExceeded)?; 433| | 434| 6.00k| if buf.len() < required_len { 435| 0| return Err(DecodingError::Parameter( 436| 0| ParameterErrorKind::ImageBufferSize { 437| 0| expected: required_len, 438| 0| actual: buf.len(), 439| 0| } 440| 0| .into(), 441| 0| )); 442| 6.00k| } 443| | 444| 6.00k| let (color_type, bit_depth) = self.output_color_type(); 445| 6.00k| let output_info = OutputInfo { 446| 6.00k| width: self.subframe.width, 447| 6.00k| height: self.subframe.height, 448| 6.00k| color_type, 449| 6.00k| bit_depth, 450| 6.00k| line_size: self.unguarded_output_line_size(self.subframe.width), 451| 6.00k| }; 452| | 453| 6.00k| if self.info().interlaced { 454| 2.40k| let stride = self.unguarded_output_line_size(self.info().width); 455| 2.40k| let samples = color_type.samples() as u8; 456| 2.40k| let bits_pp = samples * (bit_depth as u8); 457| 2.40k| let expand = crate::adam7::expand_pass; 458| | 459| | while let Some(InterlacedRow { 460| 25.9M| data: row, 461| 25.9M| interlace, 462| | .. 463| 25.9M| }) = self.next_interlaced_row()? 464| 25.9M| { 465| 25.9M| // `unwrap` won't panic, because we checked `self.info().interlaced` above. 466| 25.9M| let adam7info = interlace.get_adam7_info().unwrap(); 467| 25.9M| expand(buf, stride, row, adam7info, bits_pp); 468| 25.9M| } 469| | } else { 470| 3.59k| let current_interlace_info = self.subframe.current_interlace_info.as_ref(); 471| 3.59k| let already_done_rows = current_interlace_info 472| 3.59k| .map(|info| info.line_number()) 473| 3.59k| .unwrap_or(self.subframe.height); 474| | 475| 414k| for row in buf 476| 3.59k| .chunks_exact_mut(output_info.line_size) 477| 3.59k| .take(self.subframe.height as usize) 478| 3.59k| .skip(already_done_rows as usize) 479| | { 480| 414k| self.next_interlaced_row_impl(self.subframe.rowlen, row)?; 481| | } 482| | } 483| | 484| | // Advance over the rest of data for this (sub-)frame. 485| 2.11k| self.finish_decoding()?; 486| | 487| 1.98k| Ok(output_info) 488| 6.00k| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE15finish_decodingCs3aXgM11XBGX_5image: 499| 2.37k| fn finish_decoding(&mut self) -> Result<(), DecodingError> { 500| | // Double-check that all rows of this frame have been decoded (i.e. that the potential 501| | // `finish_decoding` call below won't be discarding any data). 502| 2.37k| assert!(self.subframe.current_interlace_info.is_none()); 503| | 504| | // Discard the remaining data in the current sequence of `IDAT` or `fdAT` chunks. 505| 2.37k| if !self.subframe.consumed_and_flushed { 506| 2.29k| self.decoder.finish_decoding_image_data()?; 507| 1.98k| self.mark_subframe_as_consumed_and_flushed(); 508| 76| } 509| | 510| 2.06k| Ok(()) 511| 2.37k| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE16output_line_sizeCs3aXgM11XBGX_5image: 692| 25.9M| pub fn output_line_size(&self, width: u32) -> Option { 693| 25.9M| let (color, depth) = self.output_color_type(); 694| 25.9M| let length = color.checked_raw_row_length(depth, width)?.checked_sub(1)?; 695| | // Ensure that it fits into address space not only `usize` to allocate. 696| 25.9M| (length <= isize::MAX as usize).then_some(length) 697| 25.9M| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE17output_color_typeCs3aXgM11XBGX_5image: 629| 77.7M| pub fn output_color_type(&self) -> (ColorType, BitDepth) { 630| | use crate::common::ColorType::*; 631| 77.7M| let t = self.transform; 632| 77.7M| let info = self.info(); 633| 77.7M| if t == Transformations::IDENTITY { 634| 0| (info.color_type, info.bit_depth) 635| | } else { 636| 77.7M| let bits = match info.bit_depth as u8 { 637| 354k| 16 if t.intersects(Transformations::STRIP_16) => 8, 638| 77.7M| n if n < 8 639| 1.44M| && (t.contains(Transformations::EXPAND) 640| 1.44M| || t.contains(Transformations::ALPHA)) => 641| | { 642| 1.44M| 8 643| | } 644| 76.3M| n => n, 645| | }; 646| 77.7M| let color_type = 647| 77.7M| if t.contains(Transformations::EXPAND) || t.contains(Transformations::ALPHA) { 648| 77.7M| let has_trns = info.trns.is_some() || t.contains(Transformations::ALPHA); 649| 77.0M| match info.color_type { 650| 20.7k| Grayscale if has_trns => GrayscaleAlpha, 651| 12.3k| Rgb if has_trns => Rgba, 652| 21.8k| Indexed if has_trns => Rgba, 653| 368k| Indexed => Rgb, 654| 77.3M| ct => ct, 655| | } 656| | } else { 657| 0| info.color_type 658| | }; 659| 77.7M| (color_type, BitDepth::from_u8(bits).unwrap()) 660| | } 661| 77.7M| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE18output_buffer_sizeCs3aXgM11XBGX_5image: 668| 15.3k| pub fn output_buffer_size(&self) -> Option { 669| 15.3k| let (width, height) = self.info().size(); 670| 15.3k| let (color, depth) = self.output_color_type(); 671| | // The subtraction should always work, but we do this for consistency. Also note that by 672| | // calling `checked_raw_row_length` the row buffer is guaranteed to work whereas if we 673| | // ran other function that didn't include the filter byte that could later fail on an image 674| | // that is `1xN`... 675| 15.3k| let linelen = color.checked_raw_row_length(depth, width)?.checked_sub(1)?; 676| 15.3k| let height = usize::try_from(height).ok()?; 677| 15.3k| let imglen = linelen.checked_mul(height)?; 678| | // Ensure that it fits into address space not only `usize` to allocate. 679| 15.3k| (imglen <= isize::MAX as usize).then_some(imglen) 680| 15.3k| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE19next_interlaced_rowCs3aXgM11XBGX_5image: 524| 25.9M| pub fn next_interlaced_row(&mut self) -> Result>, DecodingError> { 525| 25.9M| let mut output_buffer = mem::take(&mut self.scratch_buffer); 526| 25.9M| let max_line_size = self 527| 25.9M| .output_line_size(self.info().width) 528| 25.9M| .ok_or(DecodingError::LimitsExceeded)?; 529| 25.9M| output_buffer.resize(max_line_size, 0u8); 530| 25.9M| let result = self.read_row(&mut output_buffer); 531| 25.9M| self.scratch_buffer = output_buffer; 532| 25.9M| result.map(move |option| { 533| | option.map(move |interlace| { 534| | let output_line_size = self.output_line_size_for_interlace_info(&interlace); 535| | InterlacedRow { 536| | data: &self.scratch_buffer[..output_line_size], 537| | interlace, 538| | } 539| | }) 540| | }) 541| 25.9M| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE21read_until_image_dataCs3aXgM11XBGX_5image: 368| 9.32k| fn read_until_image_data(&mut self) -> Result<(), DecodingError> { 369| 9.32k| self.decoder.read_until_image_data()?; 370| | 371| 6.25k| self.subframe = SubframeInfo::new(self.info()); 372| 6.25k| self.bpp = self.info().bpp_in_prediction(); 373| | 374| 6.25k| let frame_bytes = if self.info().interlaced { 375| 2.47k| let mut bytes = 0u64; 376| 19.7k| for pass in crate::adam7::PassConstants::PASSES { 377| 17.2k| bytes += self 378| 17.2k| .info() 379| 17.2k| .raw_row_length_from_width(pass.count_samples(self.subframe.width)) 380| 17.2k| as u64 381| 17.2k| * pass.count_lines(self.subframe.height) as u64; 382| 17.2k| } 383| 2.47k| bytes 384| | } else { 385| 3.78k| (self.subframe.rowlen as u64) * self.subframe.height as u64 386| | }; 387| 6.25k| self.unfiltering_buffer.start_frame(frame_bytes); 388| | 389| | // Allocate output buffer. 390| 6.25k| let buflen = self.unguarded_output_line_size(self.subframe.width); 391| 6.25k| self.decoder.reserve_bytes(buflen)?; 392| | 393| 6.23k| Ok(()) 394| 9.32k| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE23next_raw_interlaced_rowCs3aXgM11XBGX_5image: 700| 26.3M| fn next_raw_interlaced_row(&mut self, rowlen: usize) -> Result<(), DecodingError> { 701| | // Read image data until we have at least one full row (but possibly more than one). 702| 27.0M| while self.unfiltering_buffer.mutable_len_of_curr_row() < rowlen { 703| 1.41M| if self.subframe.consumed_and_flushed { 704| 11| return Err(DecodingError::Format( 705| 11| FormatErrorInner::NoMoreImageData.into(), 706| 11| )); 707| 1.40M| } 708| | 709| 1.40M| assert!(self.unfiltering_buffer.remaining_bytes() > 0); 710| 1.40M| let completion_status = self 711| 1.40M| .unfiltering_buffer 712| 1.40M| .with_unfilled_buffer(|buffer| self.decoder.decode_image_data(Some(buffer))); 713| 753k| match completion_status { 714| 753k| Ok(ImageDataCompletionStatus::ExpectingMoreData) => (), 715| 12| Ok(ImageDataCompletionStatus::Done) => self.mark_subframe_as_consumed_and_flushed(), 716| 652k| Err(DecodingError::IoError(e)) 717| 655k| if e.kind() == std::io::ErrorKind::UnexpectedEof 718| 655k| && self.unfiltering_buffer.readable_len_of_curr_row() >= rowlen => 719| | { 720| 652k| return self 721| 652k| .unfiltering_buffer 722| 652k| .unfilter_curr_row_using_scratch_buffer(rowlen, self.bpp); 723| | } 724| 3.54k| Err(other_error) => return Err(other_error), 725| | } 726| | } 727| | 728| 25.6M| self.unfiltering_buffer 729| 25.6M| .unfilter_curr_row_in_place(rowlen, self.bpp) 730| 26.3M| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE24next_interlaced_row_implCs3aXgM11XBGX_5image: 605| 26.3M| fn next_interlaced_row_impl( 606| 26.3M| &mut self, 607| 26.3M| rowlen: usize, 608| 26.3M| output_buffer: &mut [u8], 609| 26.3M| ) -> Result<(), DecodingError> { 610| 26.3M| self.next_raw_interlaced_row(rowlen)?; 611| 26.3M| let row = self.unfiltering_buffer.prev_row(); 612| 26.3M| assert_eq!(row.len(), rowlen - 1); 613| | 614| | // Apply transformations and write resulting data to buffer. 615| 26.3M| let transform_fn = { 616| 26.3M| if self.transform_fn.is_none() { 617| 4.45k| self.transform_fn = Some(create_transform_fn(self.info(), self.transform)?); 618| 26.3M| } 619| 26.3M| self.transform_fn.as_deref().unwrap() 620| | }; 621| 26.3M| transform_fn(row, output_buffer, self.info()); 622| | 623| 26.3M| self.subframe.current_interlace_info = self.subframe.interlace_info_iter.next(); 624| 26.3M| Ok(()) 625| 26.3M| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE26unguarded_output_line_sizeCs3aXgM11XBGX_5image: 683| 51.8M| pub(crate) fn unguarded_output_line_size(&self, width: u32) -> usize { 684| 51.8M| let (color, depth) = self.output_color_type(); 685| 51.8M| color.raw_row_length_from_width(depth, width) - 1 686| 51.8M| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE35output_line_size_for_interlace_infoCs3aXgM11XBGX_5image: 580| 51.8M| fn output_line_size_for_interlace_info(&self, interlace: &InterlaceInfo) -> usize { 581| 51.8M| let width = match interlace { 582| 51.8M| InterlaceInfo::Adam7(Adam7Info { samples: width, .. }) => *width, 583| 0| InterlaceInfo::Null(_) => self.subframe.width, 584| | }; 585| 51.8M| self.unguarded_output_line_size(width) 586| 51.8M| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE37mark_subframe_as_consumed_and_flushedCs3aXgM11XBGX_5image: 490| 2.00k| fn mark_subframe_as_consumed_and_flushed(&mut self) { 491| 2.00k| assert!(self.remaining_frames > 0); 492| 2.00k| self.remaining_frames -= 1; 493| | 494| 2.00k| self.subframe.consumed_and_flushed = true; 495| 2.00k| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE4infoCs3aXgM11XBGX_5image: 399| 156M| pub fn info(&self) -> &Info<'static> { 400| 156M| self.decoder.info().unwrap() 401| 156M| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE8read_rowCs3aXgM11XBGX_5image: 551| 25.9M| pub fn read_row( 552| 25.9M| &mut self, 553| 25.9M| output_buffer: &mut [u8], 554| 25.9M| ) -> Result, DecodingError> { 555| 25.9M| let interlace = match self.subframe.current_interlace_info.as_ref() { 556| | None => { 557| 259| self.finish_decoding()?; 558| 75| return Ok(None); 559| | } 560| 25.9M| Some(interlace) => *interlace, 561| | }; 562| 25.9M| if interlace.line_number() == 0 { 563| 5.96k| self.unfiltering_buffer.reset_prev_row(); 564| 25.9M| } 565| 25.9M| let rowlen = match interlace { 566| 0| InterlaceInfo::Null(_) => self.subframe.rowlen, 567| 25.9M| InterlaceInfo::Adam7(Adam7Info { samples: width, .. }) => { 568| 25.9M| self.info().raw_row_length_from_width(width) 569| | } 570| | }; 571| | 572| 25.9M| let output_line_size = self.output_line_size_for_interlace_info(&interlace); 573| 25.9M| let output_buffer = &mut output_buffer[..output_line_size]; 574| | 575| 25.9M| self.next_interlaced_row_impl(rowlen, output_buffer)?; 576| | 577| 25.9M| Ok(Some(interlace)) 578| 25.9M| } _RNvMs5_NtCshdzP3jLBsmJ_3png7decoderNtB5_12SubframeInfo12not_yet_init: 734| 9.37k| fn not_yet_init() -> Self { 735| 9.37k| SubframeInfo { 736| 9.37k| width: 0, 737| 9.37k| height: 0, 738| 9.37k| rowlen: 0, 739| 9.37k| current_interlace_info: None, 740| 9.37k| interlace_info_iter: InterlaceInfoIter::empty(), 741| 9.37k| consumed_and_flushed: false, 742| 9.37k| } 743| 9.37k| } _RNvMs5_NtCshdzP3jLBsmJ_3png7decoderNtB5_12SubframeInfo3new: 745| 6.25k| fn new(info: &Info) -> Self { 746| | // The apng fctnl overrides width and height. 747| | // All other data is set by the main info struct. 748| 6.25k| let (width, height) = if let Some(fc) = info.frame_control { 749| 2| (fc.width, fc.height) 750| | } else { 751| 6.25k| (info.width, info.height) 752| | }; 753| | 754| 6.25k| let mut interlace_info_iter = InterlaceInfoIter::new(width, height, info.interlaced); 755| 6.25k| let current_interlace_info = interlace_info_iter.next(); 756| 6.25k| SubframeInfo { 757| 6.25k| width, 758| 6.25k| height, 759| 6.25k| rowlen: info.raw_row_length_from_width(width), 760| 6.25k| current_interlace_info, 761| 6.25k| interlace_info_iter, 762| 6.25k| consumed_and_flushed: false, 763| 6.25k| } 764| 6.25k| } _RNvMs_NtCshdzP3jLBsmJ_3png7decoderNtB4_6Limits13reserve_bytes: 71| 43.3k| pub(crate) fn reserve_bytes(&mut self, bytes: usize) -> Result<(), DecodingError> { 72| 43.3k| if self.bytes >= bytes { 73| 43.3k| self.bytes -= bytes; 74| 43.3k| Ok(()) 75| | } else { 76| 25| Err(DecodingError::LimitsExceeded) 77| | } 78| 43.3k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE10set_limitsCs3aXgM11XBGX_5image: 39| 19.3k| pub fn set_limits(&mut self, limits: Limits) { 40| 19.3k| self.decoder.limits = limits; 41| 19.3k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE11decode_nextCs3aXgM11XBGX_5image: 62| 1.56M| fn decode_next( 63| 1.56M| &mut self, 64| 1.56M| image_data: Option<&mut UnfilterBuf<'_>>, 65| 1.56M| ) -> Result { 66| 906k| let (consumed, result) = { 67| 1.56M| let buf = self.reader.fill_buf()?; 68| 1.56M| if buf.is_empty() { 69| 658k| return Err(DecodingError::IoError(ErrorKind::UnexpectedEof.into())); 70| 908k| } 71| 908k| self.decoder.update(buf, image_data)? 72| | }; 73| 906k| self.reader.consume(consumed); 74| 906k| Ok(result) 75| 1.56M| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE13reserve_bytesCs3aXgM11XBGX_5image: 43| 6.25k| pub fn reserve_bytes(&mut self, bytes: usize) -> Result<(), DecodingError> { 44| 6.25k| self.decoder.limits.reserve_bytes(bytes) 45| 6.25k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE16read_header_infoCs3aXgM11XBGX_5image: 80| 19.0k| pub fn read_header_info(&mut self) -> Result<&Info<'static>, DecodingError> { 81| 37.8k| while self.info().is_none() { 82| 19.1k| if let Decoded::ChunkComplete(chunk::IEND) = self.decode_next(None)? { 83| 0| unreachable!() 84| 18.8k| } 85| | } 86| 18.7k| Ok(self.info().unwrap()) 87| 19.0k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE17decode_image_dataCs3aXgM11XBGX_5image: 113| 1.41M| pub fn decode_image_data( 114| 1.41M| &mut self, 115| 1.41M| image_data: Option<&mut UnfilterBuf<'_>>, 116| 1.41M| ) -> Result { 117| 1.41M| match self.decode_next(image_data)? { 118| 743k| Decoded::ImageData => Ok(ImageDataCompletionStatus::ExpectingMoreData), 119| 2.00k| Decoded::ImageDataFlushed => Ok(ImageDataCompletionStatus::Done), 120| | // Ignore other events that may happen within an `IDAT` / `fdAT` chunks sequence. 121| 13.7k| _ => Ok(ImageDataCompletionStatus::ExpectingMoreData), 122| | } 123| 1.41M| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE21read_until_image_dataCs3aXgM11XBGX_5image: 92| 9.32k| pub fn read_until_image_data(&mut self) -> Result<(), DecodingError> { 93| | loop { 94| 131k| match self.decode_next(None)? { 95| 6.25k| Decoded::ChunkBegin(_, chunk::IDAT) | Decoded::ChunkBegin(_, chunk::fdAT) => break, 96| | Decoded::ChunkComplete(chunk::IEND) => { 97| 1| return Err(DecodingError::Format( 98| 1| FormatErrorInner::MissingImageData.into(), 99| 1| )) 100| | } 101| | // Ignore all other chunk events. Any other chunk may be between IDAT chunks, fdAT 102| | // chunks and their control chunks. 103| 122k| _ => {} 104| | } 105| | } 106| 6.25k| Ok(()) 107| 9.32k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE21set_ignore_text_chunkCs3aXgM11XBGX_5image: 47| 9.65k| pub fn set_ignore_text_chunk(&mut self, ignore_text_chunk: bool) { 48| 9.65k| self.decoder.set_ignore_text_chunk(ignore_text_chunk); 49| 9.65k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE26finish_decoding_image_dataCs3aXgM11XBGX_5image: 128| 2.29k| pub fn finish_decoding_image_data(&mut self) -> Result<(), DecodingError> { 129| | loop { 130| 6.16k| if let ImageDataCompletionStatus::Done = self.decode_image_data(None)? { 131| 1.98k| return Ok(()); 132| 3.87k| } 133| | } 134| 2.29k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE3newCs3aXgM11XBGX_5image: 25| 9.65k| pub fn new(r: R) -> Self { 26| 9.65k| Self { 27| 9.65k| reader: r, 28| 9.65k| decoder: StreamingDecoder::new(), 29| 9.65k| } 30| 9.65k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE4infoCs3aXgM11XBGX_5image: 144| 156M| pub fn info(&self) -> Option<&Info<'static>> { 145| 156M| self.decoder.info.as_ref() 146| 156M| } _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder10parse_itxt0Bb_: 1884| 79| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingCompressionFlag))?; _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder10parse_itxts0_0Bb_: 1892| 46.5k| .position(|&b| b == 0) _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder10parse_itxts1_0Bb_: 1893| 402| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))? _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder10parse_itxts2_0Bb_: 1900| 21.4k| .position(|&b| b == 0) _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder10parse_itxts3_0Bb_: 1901| 446| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))? _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder10parse_itxts_0Bb_: 1888| 68| .ok_or_else(|| DecodingError::from(TextDecodingError::InvalidCompressionMethod))?; _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder10parse_srgb0Bb_: 1522| 203| let rendering_intent = crate::SrgbRenderingIntent::from_raw(raw).ok_or_else(|| { 1523| 203| FormatError::from(FormatErrorInner::InvalidSrgbRenderingIntent(raw)) 1524| 203| })?; _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder10parse_ztxt0Bb_: 1864| 73| .ok_or_else(|| DecodingError::from(TextDecodingError::InvalidCompressionMethod))?; _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder11parse_chunk0Bb_: 1134| 18.9k| parse_result = parse_result.map_err(|e| { 1135| 7| match e { 1136| | // `parse_chunk` is invoked after gathering **all** bytes of a chunk, so 1137| | // `UnexpectedEof` from something like `read_be` is permanent and indicates an 1138| | // invalid PNG that should be represented as a `FormatError`, rather than as a 1139| | // (potentially recoverable) `IoError` / `UnexpectedEof`. 1140| 7| DecodingError::IoError(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => { 1141| 0| let fmt_err: FormatError = 1142| 0| FormatErrorInner::ChunkLengthWrong { kind: type_str }.into(); 1143| 0| fmt_err.into() 1144| | } 1145| 18.9k| e => e, 1146| | } 1147| 18.9k| }); _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder13split_keyword0Bb_: 1831| 243k| .position(|&b| b == 0) _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder13split_keywords_0Bb_: 1832| 1.86k| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))?; _RNvMNtNtCshdzP3jLBsmJ_3png7decoder6streamNtB2_5State7new_u32: 73| 269k| fn new_u32(kind: U32ValueKind) -> Self { 74| 269k| Self::U32 { 75| 269k| kind, 76| 269k| bytes: [0; 4], 77| 269k| accumulated_count: 0, 78| 269k| } 79| 269k| } _RNvMs8_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_13DecodeOptions21set_ignore_text_chunk: 511| 9.65k| pub fn set_ignore_text_chunk(&mut self, ignore_text_chunk: bool) { 512| 9.65k| self.ignore_text_chunk = ignore_text_chunk; 513| 9.65k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10next_state: 710| 1.09M| fn next_state( 711| 1.09M| &mut self, 712| 1.09M| buf: &[u8], 713| 1.09M| image_data: Option<&mut UnfilterBuf<'_>>, 714| 1.09M| ) -> Result<(usize, Decoded), DecodingError> { 715| | use self::State::*; 716| | 717| | // Driver should ensure that state is never None 718| 1.09M| let state = self.state.take().unwrap(); 719| | 720| 1.09M| match state { 721| | U32 { 722| 268k| kind, 723| 268k| mut bytes, 724| 268k| mut accumulated_count, 725| | } => { 726| 268k| debug_assert!(accumulated_count <= 4); 727| 268k| if accumulated_count == 0 && buf.len() >= 4 { 728| | // Handling these `accumulated_count` and `buf.len()` values in a separate `if` 729| | // branch is not strictly necessary - the `else` statement below is already 730| | // capable of handling these values. The main reason for special-casing these 731| | // values is that they occur fairly frequently and special-casing them results 732| | // in performance gains. 733| | const CONSUMED_BYTES: usize = 4; 734| 267k| self.parse_u32(kind, &buf[0..4], image_data, CONSUMED_BYTES) 735| | } else { 736| 446| let remaining_count = 4 - accumulated_count; 737| 446| let consumed_bytes = { 738| 446| let available_count = min(remaining_count, buf.len()); 739| 446| bytes[accumulated_count..accumulated_count + available_count] 740| 446| .copy_from_slice(&buf[0..available_count]); 741| 446| accumulated_count += available_count; 742| 446| available_count 743| | }; 744| | 745| 446| if accumulated_count < 4 { 746| 446| self.state = Some(U32 { 747| 446| kind, 748| 446| bytes, 749| 446| accumulated_count, 750| 446| }); 751| 446| Ok((consumed_bytes, Decoded::Nothing)) 752| | } else { 753| 0| debug_assert_eq!(accumulated_count, 4); 754| 0| self.parse_u32(kind, &bytes, image_data, consumed_bytes) 755| | } 756| | } 757| | } 758| 83.2k| ReadChunkData(type_str) => { 759| 83.2k| debug_assert!(type_str != IDAT && type_str != chunk::fdAT); 760| 83.2k| if self.current_chunk.remaining == 0 { 761| 5.88k| self.state = Some(State::new_u32(U32ValueKind::Crc(type_str))); 762| 5.88k| Ok((0, Decoded::Nothing)) 763| | } else { 764| | let ChunkState { 765| 77.3k| crc, 766| 77.3k| remaining, 767| 77.3k| raw_bytes, 768| | type_: _, 769| 77.3k| action, 770| 77.3k| } = &mut self.current_chunk; 771| | 772| 77.3k| let buf_avail = raw_bytes.capacity() - raw_bytes.len(); 773| 77.3k| let bytes_avail = min(buf.len(), buf_avail); 774| 77.3k| let n = min(*remaining, bytes_avail as u32); 775| 77.3k| let buf = &buf[..n as usize]; 776| | 777| 77.3k| if !self.decode_options.ignore_crc { 778| 77.3k| crc.update(buf); 779| 77.3k| } 780| | 781| 77.3k| if *action == ChunkAction::Process { 782| 65.6k| if raw_bytes.len() == raw_bytes.capacity() { 783| 5.80k| if self.limits.bytes == 0 { 784| 0| return Err(DecodingError::LimitsExceeded); 785| 5.80k| } 786| | 787| | // Double the size of the Vec, but not beyond the allocation limit. 788| 5.80k| debug_assert!(raw_bytes.capacity() > 0); 789| 5.80k| let reserve_size = raw_bytes.capacity().min(self.limits.bytes); 790| | 791| 5.80k| self.limits.reserve_bytes(reserve_size)?; 792| 5.80k| raw_bytes.reserve_exact(reserve_size); 793| 59.8k| } 794| 65.6k| raw_bytes.extend_from_slice(buf); 795| 11.7k| } 796| | 797| 77.3k| *remaining -= n; 798| 77.3k| if *remaining == 0 { 799| 64.0k| debug_assert!(type_str != IDAT && type_str != chunk::fdAT); 800| 64.0k| self.state = Some(State::new_u32(U32ValueKind::Crc(type_str))); 801| 13.2k| } else { 802| 13.2k| self.state = Some(ReadChunkData(type_str)); 803| 13.2k| } 804| 77.3k| Ok((n as usize, Decoded::Nothing)) 805| | } 806| | } 807| 744k| ImageData(type_str) => { 808| 744k| debug_assert!(type_str == IDAT || type_str == chunk::fdAT); 809| 744k| let len = std::cmp::min(buf.len(), self.current_chunk.remaining as usize); 810| 744k| let buf = &buf[..len]; 811| | 812| 744k| let consumed = if let Some(image_data) = image_data { 813| 743k| self.inflater.decompress(buf, image_data)? 814| | } else { 815| 1.38k| len 816| | }; 817| | 818| 743k| if !self.decode_options.ignore_crc { 819| 743k| self.current_chunk.crc.update(&buf[..consumed]); 820| 743k| } 821| | 822| 743k| self.current_chunk.remaining -= consumed as u32; 823| 743k| if self.current_chunk.remaining == 0 { 824| 7.98k| self.state = Some(State::new_u32(U32ValueKind::Crc(type_str))); 825| 735k| } else { 826| 735k| self.state = Some(ImageData(type_str)); 827| 735k| } 828| 743k| Ok((consumed, Decoded::ImageData)) 829| | } 830| | } 831| 1.09M| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_actl: 1236| 857| fn parse_actl(&mut self) -> Result<(), DecodingError> { 1237| 857| let info = self.info.as_mut().unwrap(); 1238| 857| if self.have_idat { 1239| 0| Err(DecodingError::Format( 1240| 0| FormatErrorInner::AfterIdat { kind: chunk::acTL }.into(), 1241| 0| )) 1242| 857| } else if info.animation_control.is_some() { 1243| 264| Err(DecodingError::Format( 1244| 264| FormatErrorInner::DuplicateChunk { kind: chunk::acTL }.into(), 1245| 264| )) 1246| | } else { 1247| 593| let mut buf = &self.current_chunk.raw_bytes[..]; 1248| 593| let actl = AnimationControl { 1249| 593| num_frames: buf.read_be()?, 1250| 593| num_plays: buf.read_be()?, 1251| | }; 1252| | // The spec says that "0 is not a valid value" for `num_frames`. 1253| | // So let's ignore such malformed `acTL` chunks. 1254| 593| if actl.num_frames == 0 { 1255| 66| return Ok(()); 1256| 527| } 1257| | 1258| | // The spec also says that the number of frames and number of plays should be limited 1259| | // to (2^31)-1. Same as the other condition we enforce it by ignoring the chunk. 1260| | // Another option may be saturation which would lose us some frames but encourage 1261| | // rather dubious handling. 1262| 527| if actl.num_frames > 0x7FFFFFFF || actl.num_plays > 0x7FFFFFFF { 1263| 467| return Ok(()); 1264| 60| } 1265| | 1266| 60| info.animation_control = Some(actl); 1267| 60| Ok(()) 1268| | } 1269| 857| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_bkgd: 1924| 1.70k| fn parse_bkgd(&mut self) -> Result<(), DecodingError> { 1925| 1.70k| let info = self.info.as_mut().unwrap(); 1926| 1.70k| if info.bkgd.is_some() { 1927| | // Only one bKGD chunk is allowed 1928| 465| return Err(DecodingError::Format( 1929| 465| FormatErrorInner::DuplicateChunk { kind: chunk::bKGD }.into(), 1930| 465| )); 1931| 1.23k| } else if self.have_idat { 1932| 0| return Err(DecodingError::Format( 1933| 0| FormatErrorInner::AfterIdat { kind: chunk::bKGD }.into(), 1934| 0| )); 1935| 1.23k| } 1936| | 1937| 1.23k| let expected = match info.color_type { 1938| | ColorType::Indexed => { 1939| 204| if info.palette.is_none() { 1940| 1| return Err(DecodingError::IoError( 1941| 1| std::io::ErrorKind::InvalidData.into(), 1942| 1| )); 1943| 203| }; 1944| 203| 1 1945| | } 1946| 633| ColorType::Grayscale | ColorType::GrayscaleAlpha => 2, 1947| 400| ColorType::Rgb | ColorType::Rgba => 6, 1948| | }; 1949| 1.23k| let vec = self.current_chunk.raw_bytes.clone(); 1950| 1.23k| if vec.len() != expected { 1951| 1.20k| return Err(DecodingError::Format( 1952| 1.20k| FormatErrorInner::ChunkLengthWrong { kind: chunk::bKGD }.into(), 1953| 1.20k| )); 1954| 28| } 1955| | 1956| 28| info.bkgd = Some(Cow::Owned(vec)); 1957| 28| Ok(()) 1958| 1.70k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_chrm: 1439| 394| fn parse_chrm(&mut self) -> Result<(), DecodingError> { 1440| 394| let info = self.info.as_mut().unwrap(); 1441| 394| if self.have_idat { 1442| 0| Err(DecodingError::Format( 1443| 0| FormatErrorInner::AfterIdat { kind: chunk::cHRM }.into(), 1444| 0| )) 1445| 394| } else if info.chrm_chunk.is_some() { 1446| 374| Err(DecodingError::Format( 1447| 374| FormatErrorInner::DuplicateChunk { kind: chunk::cHRM }.into(), 1448| 374| )) 1449| | } else { 1450| 20| let mut buf = &self.current_chunk.raw_bytes[..]; 1451| 20| let white_x: u32 = buf.read_be()?; 1452| 20| let white_y: u32 = buf.read_be()?; 1453| 20| let red_x: u32 = buf.read_be()?; 1454| 20| let red_y: u32 = buf.read_be()?; 1455| 20| let green_x: u32 = buf.read_be()?; 1456| 20| let green_y: u32 = buf.read_be()?; 1457| 20| let blue_x: u32 = buf.read_be()?; 1458| 20| let blue_y: u32 = buf.read_be()?; 1459| | 1460| 20| let source_chromaticities = SourceChromaticities { 1461| 20| white: ( 1462| 20| ScaledFloat::from_scaled(white_x), 1463| 20| ScaledFloat::from_scaled(white_y), 1464| 20| ), 1465| 20| red: ( 1466| 20| ScaledFloat::from_scaled(red_x), 1467| 20| ScaledFloat::from_scaled(red_y), 1468| 20| ), 1469| 20| green: ( 1470| 20| ScaledFloat::from_scaled(green_x), 1471| 20| ScaledFloat::from_scaled(green_y), 1472| 20| ), 1473| 20| blue: ( 1474| 20| ScaledFloat::from_scaled(blue_x), 1475| 20| ScaledFloat::from_scaled(blue_y), 1476| 20| ), 1477| 20| }; 1478| | 1479| 20| info.chrm_chunk = Some(source_chromaticities); 1480| 20| Ok(()) 1481| | } 1482| 394| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_cicp: 1532| 481| fn parse_cicp(&mut self) -> Result<(), DecodingError> { 1533| 481| let info = self.info.as_mut().unwrap(); 1534| | 1535| | // The spec requires that the cICP chunk MUST come before the PLTE and IDAT chunks. 1536| 481| if info.coding_independent_code_points.is_some() { 1537| 247| return Err(DecodingError::Format( 1538| 247| FormatErrorInner::DuplicateChunk { kind: chunk::cICP }.into(), 1539| 247| )); 1540| 234| } else if info.palette.is_some() { 1541| 215| return Err(DecodingError::Format( 1542| 215| FormatErrorInner::AfterPlte { kind: chunk::cICP }.into(), 1543| 215| )); 1544| 19| } else if self.have_idat { 1545| 0| return Err(DecodingError::Format( 1546| 0| FormatErrorInner::AfterIdat { kind: chunk::cICP }.into(), 1547| 0| )); 1548| 19| } 1549| | 1550| 19| let mut buf = &*self.current_chunk.raw_bytes; 1551| 19| let color_primaries: u8 = buf.read_be()?; 1552| 19| let transfer_function: u8 = buf.read_be()?; 1553| 19| let matrix_coefficients: u8 = buf.read_be()?; 1554| 15| let is_video_full_range_image = { 1555| 19| let flag: u8 = buf.read_be()?; 1556| 19| match flag { 1557| 15| 0 => false, 1558| 0| 1 => true, 1559| | _ => { 1560| 4| return Err(DecodingError::IoError( 1561| 4| std::io::ErrorKind::InvalidData.into(), 1562| 4| )); 1563| | } 1564| | } 1565| | }; 1566| | 1567| | // RGB is currently the only supported color model in PNG, and as 1568| | // such Matrix Coefficients shall be set to 0. 1569| 15| if matrix_coefficients != 0 { 1570| 2| return Err(DecodingError::IoError( 1571| 2| std::io::ErrorKind::InvalidData.into(), 1572| 2| )); 1573| 13| } 1574| | 1575| 13| if !buf.is_empty() { 1576| 0| return Err(DecodingError::IoError( 1577| 0| std::io::ErrorKind::InvalidData.into(), 1578| 0| )); 1579| 13| } 1580| | 1581| 13| info.coding_independent_code_points = Some(CodingIndependentCodePoints { 1582| 13| color_primaries, 1583| 13| transfer_function, 1584| 13| matrix_coefficients, 1585| 13| is_video_full_range_image, 1586| 13| }); 1587| | 1588| 13| Ok(()) 1589| 481| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_clli: 1649| 390| fn parse_clli(&mut self) -> Result<(), DecodingError> { 1650| 390| let info = self.info.as_mut().unwrap(); 1651| 390| if info.content_light_level.is_some() { 1652| 376| return Err(DecodingError::Format( 1653| 376| FormatErrorInner::DuplicateChunk { kind: chunk::cLLI }.into(), 1654| 376| )); 1655| 14| } 1656| | 1657| 14| let mut buf = &*self.current_chunk.raw_bytes; 1658| 14| let max_content_light_level: u32 = buf.read_be()?; 1659| 14| let max_frame_average_light_level: u32 = buf.read_be()?; 1660| 14| if !buf.is_empty() { 1661| 0| return Err(DecodingError::IoError( 1662| 0| std::io::ErrorKind::InvalidData.into(), 1663| 0| )); 1664| 14| } 1665| 14| info.content_light_level = Some(ContentLightLevelInfo { 1666| 14| max_content_light_level, 1667| 14| max_frame_average_light_level, 1668| 14| }); 1669| | 1670| 14| Ok(()) 1671| 390| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_exif: 1673| 674| fn parse_exif(&mut self) -> Result<(), DecodingError> { 1674| 674| let info = self.info.as_mut().unwrap(); 1675| 674| if info.exif_metadata.is_some() { 1676| 581| return Err(DecodingError::Format( 1677| 581| FormatErrorInner::DuplicateChunk { kind: chunk::eXIf }.into(), 1678| 581| )); 1679| 93| } 1680| | 1681| 93| info.exif_metadata = Some(self.current_chunk.raw_bytes.clone().into()); 1682| 93| Ok(()) 1683| 674| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_fctl: 1167| 344| fn parse_fctl(&mut self) -> Result<(), DecodingError> { 1168| 344| let mut buf = &self.current_chunk.raw_bytes[..]; 1169| 344| let next_seq_no = buf.read_be()?; 1170| | 1171| | // Assuming that fcTL is required before *every* fdAT-sequence 1172| 344| self.current_seq_no = Some(if let Some(seq_no) = self.current_seq_no { 1173| 48| if next_seq_no != seq_no + 1 { 1174| 47| return Err(DecodingError::Format( 1175| 47| FormatErrorInner::ApngOrder { 1176| 47| expected: seq_no + 1, 1177| 47| present: next_seq_no, 1178| 47| } 1179| 47| .into(), 1180| 47| )); 1181| 1| } 1182| 1| next_seq_no 1183| | } else { 1184| 296| if next_seq_no != 0 { 1185| 41| return Err(DecodingError::Format( 1186| 41| FormatErrorInner::ApngOrder { 1187| 41| expected: 0, 1188| 41| present: next_seq_no, 1189| 41| } 1190| 41| .into(), 1191| 41| )); 1192| 255| } 1193| 255| 0 1194| | }); 1195| 256| self.inflater.reset(); 1196| 256| self.ready_for_fdat_chunks = self.have_idat; 1197| 252| let fc = FrameControl { 1198| 256| sequence_number: next_seq_no, 1199| 256| width: buf.read_be()?, 1200| 256| height: buf.read_be()?, 1201| 256| x_offset: buf.read_be()?, 1202| 256| y_offset: buf.read_be()?, 1203| 256| delay_num: buf.read_be()?, 1204| 256| delay_den: buf.read_be()?, 1205| | dispose_op: { 1206| 256| let dispose_op = buf.read_be()?; 1207| 256| match DisposeOp::from_u8(dispose_op) { 1208| 253| Some(dispose_op) => dispose_op, 1209| | None => { 1210| 3| return Err(DecodingError::Format( 1211| 3| FormatErrorInner::InvalidDisposeOp(dispose_op).into(), 1212| 3| )) 1213| | } 1214| | } 1215| | }, 1216| | blend_op: { 1217| 253| let blend_op = buf.read_be()?; 1218| 253| match BlendOp::from_u8(blend_op) { 1219| 252| Some(blend_op) => blend_op, 1220| | None => { 1221| 1| return Err(DecodingError::Format( 1222| 1| FormatErrorInner::InvalidBlendOp(blend_op).into(), 1223| 1| )) 1224| | } 1225| | } 1226| | }, 1227| | }; 1228| 252| self.info.as_ref().unwrap().validate(&fc)?; 1229| 194| if !self.have_idat { 1230| 194| self.info.as_ref().unwrap().validate_default_image(&fc)?; 1231| 0| } 1232| 52| self.info.as_mut().unwrap().frame_control = Some(fc); 1233| 52| Ok(()) 1234| 344| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_gama: 1484| 365| fn parse_gama(&mut self) -> Result<(), DecodingError> { 1485| 365| let info = self.info.as_mut().unwrap(); 1486| 365| if self.have_idat { 1487| 0| Err(DecodingError::Format( 1488| 0| FormatErrorInner::AfterIdat { kind: chunk::gAMA }.into(), 1489| 0| )) 1490| 365| } else if info.gama_chunk.is_some() { 1491| 199| Err(DecodingError::Format( 1492| 199| FormatErrorInner::DuplicateChunk { kind: chunk::gAMA }.into(), 1493| 199| )) 1494| | } else { 1495| 166| let mut buf = &self.current_chunk.raw_bytes[..]; 1496| 166| let source_gamma: u32 = buf.read_be()?; 1497| 166| if source_gamma == 0 { 1498| 72| return Err(DecodingError::Format( 1499| 72| FormatErrorInner::BadGammaValue.into(), 1500| 72| )); 1501| 94| } 1502| | 1503| 94| let source_gamma = ScaledFloat::from_scaled(source_gamma); 1504| 94| info.gama_chunk = Some(source_gamma); 1505| 94| Ok(()) 1506| | } 1507| 365| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_iccp: 1685| 3.05k| fn parse_iccp(&mut self) -> Result<(), DecodingError> { 1686| 3.05k| if self.have_idat { 1687| 0| Err(DecodingError::Format( 1688| 0| FormatErrorInner::AfterIdat { kind: chunk::iCCP }.into(), 1689| 0| )) 1690| 3.05k| } else if self.have_iccp { 1691| 627| Err(DecodingError::Format( 1692| 627| FormatErrorInner::DuplicateChunk { kind: chunk::iCCP }.into(), 1693| 627| )) 1694| | } else { 1695| 2.42k| self.have_iccp = true; 1696| 2.42k| let _ = self.parse_iccp_raw(); 1697| 2.42k| Ok(()) 1698| | } 1699| 3.05k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_ihdr: 1744| 9.43k| fn parse_ihdr(&mut self) -> Result<(), DecodingError> { 1745| 9.43k| if self.info.is_some() { 1746| 2| return Err(DecodingError::Format( 1747| 2| FormatErrorInner::DuplicateChunk { kind: IHDR }.into(), 1748| 2| )); 1749| 9.42k| } 1750| 9.42k| let mut buf = &self.current_chunk.raw_bytes[..]; 1751| 9.42k| let width = buf.read_be()?; 1752| 9.42k| let height = buf.read_be()?; 1753| 9.42k| if width == 0 || height == 0 { 1754| 2| return Err(DecodingError::Format( 1755| 2| FormatErrorInner::InvalidDimensions.into(), 1756| 2| )); 1757| 9.42k| } 1758| 9.42k| let bit_depth = buf.read_be()?; 1759| 9.42k| let bit_depth = match BitDepth::from_u8(bit_depth) { 1760| 9.40k| Some(bits) => bits, 1761| | None => { 1762| 24| return Err(DecodingError::Format( 1763| 24| FormatErrorInner::InvalidBitDepth(bit_depth).into(), 1764| 24| )) 1765| | } 1766| | }; 1767| 9.40k| let color_type = buf.read_be()?; 1768| 9.40k| let color_type = match ColorType::from_u8(color_type) { 1769| 9.39k| Some(color_type) => { 1770| 9.39k| if color_type.is_combination_invalid(bit_depth) { 1771| 4| return Err(DecodingError::Format( 1772| 4| FormatErrorInner::InvalidColorBitDepth { 1773| 4| color_type, 1774| 4| bit_depth, 1775| 4| } 1776| 4| .into(), 1777| 4| )); 1778| | } else { 1779| 9.39k| color_type 1780| | } 1781| | } 1782| | None => { 1783| 8| return Err(DecodingError::Format( 1784| 8| FormatErrorInner::InvalidColorType(color_type).into(), 1785| 8| )) 1786| | } 1787| | }; 1788| 9.39k| match buf.read_be()? { 1789| | // compression method 1790| 9.38k| 0u8 => (), 1791| 8| n => { 1792| 8| return Err(DecodingError::Format( 1793| 8| FormatErrorInner::UnknownCompressionMethod(n).into(), 1794| 8| )) 1795| | } 1796| | } 1797| 9.38k| match buf.read_be()? { 1798| | // filter method 1799| 9.37k| 0u8 => (), 1800| 7| n => { 1801| 7| return Err(DecodingError::Format( 1802| 7| FormatErrorInner::UnknownFilterMethod(n).into(), 1803| 7| )) 1804| | } 1805| | } 1806| 9.37k| let interlaced = match buf.read_be()? { 1807| 6.32k| 0u8 => false, 1808| 3.04k| 1 => true, 1809| 6| n => { 1810| 6| return Err(DecodingError::Format( 1811| 6| FormatErrorInner::UnknownInterlaceMethod(n).into(), 1812| 6| )) 1813| | } 1814| | }; 1815| | 1816| 9.37k| self.info = Some(Info { 1817| 9.37k| width, 1818| 9.37k| height, 1819| 9.37k| bit_depth, 1820| 9.37k| color_type, 1821| 9.37k| interlaced, 1822| 9.37k| ..Default::default() 1823| 9.37k| }); 1824| | 1825| 9.37k| Ok(()) 1826| 9.43k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_itxt: 1876| 12.9k| fn parse_itxt(&mut self) -> Result<(), DecodingError> { 1877| 12.9k| let buf = &self.current_chunk.raw_bytes[..]; 1878| 12.9k| self.limits.reserve_bytes(buf.len())?; 1879| | 1880| 12.9k| let (keyword_slice, value_slice) = Self::split_keyword(buf)?; 1881| | 1882| 11.5k| let compression_flag = *value_slice 1883| 11.5k| .first() 1884| 11.5k| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingCompressionFlag))?; 1885| | 1886| 11.4k| let compression_method = *value_slice 1887| 11.4k| .get(1) 1888| 11.4k| .ok_or_else(|| DecodingError::from(TextDecodingError::InvalidCompressionMethod))?; 1889| | 1890| 11.4k| let second_null_byte_index = value_slice[2..] 1891| 11.4k| .iter() 1892| 11.4k| .position(|&b| b == 0) 1893| 11.4k| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))? 1894| | + 2; 1895| | 1896| 11.0k| let language_tag_slice = &value_slice[2..second_null_byte_index]; 1897| | 1898| 11.0k| let third_null_byte_index = value_slice[second_null_byte_index + 1..] 1899| 11.0k| .iter() 1900| 11.0k| .position(|&b| b == 0) 1901| 11.0k| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))? 1902| 10.5k| + (second_null_byte_index + 1); 1903| | 1904| 10.5k| let translated_keyword_slice = 1905| 10.5k| &value_slice[second_null_byte_index + 1..third_null_byte_index]; 1906| | 1907| 10.5k| let text_slice = &value_slice[third_null_byte_index + 1..]; 1908| | 1909| 10.5k| self.info.as_mut().unwrap().utf8_text.push( 1910| 10.5k| ITXtChunk::decode( 1911| 10.5k| keyword_slice, 1912| 10.5k| compression_flag, 1913| 10.5k| compression_method, 1914| 10.5k| language_tag_slice, 1915| 10.5k| translated_keyword_slice, 1916| 10.5k| text_slice, 1917| | ) 1918| 10.5k| .map_err(DecodingError::from)?, 1919| | ); 1920| | 1921| 8.59k| Ok(()) 1922| 12.9k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_mdcv: 1591| 454| fn parse_mdcv(&mut self) -> Result<(), DecodingError> { 1592| 454| let info = self.info.as_mut().unwrap(); 1593| | 1594| | // The spec requires that the mDCV chunk MUST come before the PLTE and IDAT chunks. 1595| 454| if info.mastering_display_color_volume.is_some() { 1596| 374| return Err(DecodingError::Format( 1597| 374| FormatErrorInner::DuplicateChunk { kind: chunk::mDCV }.into(), 1598| 374| )); 1599| 80| } else if info.palette.is_some() { 1600| 67| return Err(DecodingError::Format( 1601| 67| FormatErrorInner::AfterPlte { kind: chunk::mDCV }.into(), 1602| 67| )); 1603| 13| } else if self.have_idat { 1604| 0| return Err(DecodingError::Format( 1605| 0| FormatErrorInner::AfterIdat { kind: chunk::mDCV }.into(), 1606| 0| )); 1607| 13| } 1608| | 1609| 13| let mut buf = &*self.current_chunk.raw_bytes; 1610| 13| let red_x: u16 = buf.read_be()?; 1611| 13| let red_y: u16 = buf.read_be()?; 1612| 13| let green_x: u16 = buf.read_be()?; 1613| 13| let green_y: u16 = buf.read_be()?; 1614| 13| let blue_x: u16 = buf.read_be()?; 1615| 13| let blue_y: u16 = buf.read_be()?; 1616| 13| let white_x: u16 = buf.read_be()?; 1617| 13| let white_y: u16 = buf.read_be()?; 1618| | fn scale(chunk: u16) -> ScaledFloat { 1619| | // `ScaledFloat::SCALING` is hardcoded to 100_000, which works 1620| | // well for the `cHRM` chunk where the spec says that "a value 1621| | // of 0.3127 would be stored as the integer 31270". In the 1622| | // `mDCV` chunk the spec says that "0.708, 0.292)" is stored as 1623| | // "{ 35400, 14600 }", using a scaling factor of 50_000, so we 1624| | // multiply by 2 before converting. 1625| | ScaledFloat::from_scaled((chunk as u32) * 2) 1626| | } 1627| 13| let chromaticities = SourceChromaticities { 1628| 13| white: (scale(white_x), scale(white_y)), 1629| 13| red: (scale(red_x), scale(red_y)), 1630| 13| green: (scale(green_x), scale(green_y)), 1631| 13| blue: (scale(blue_x), scale(blue_y)), 1632| 13| }; 1633| 13| let max_luminance: u32 = buf.read_be()?; 1634| 13| let min_luminance: u32 = buf.read_be()?; 1635| 13| if !buf.is_empty() { 1636| 0| return Err(DecodingError::IoError( 1637| 0| std::io::ErrorKind::InvalidData.into(), 1638| 0| )); 1639| 13| } 1640| 13| info.mastering_display_color_volume = Some(MasteringDisplayColorVolume { 1641| 13| chromaticities, 1642| 13| max_luminance, 1643| 13| min_luminance, 1644| 13| }); 1645| | 1646| 13| Ok(()) 1647| 454| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_phys: 1410| 769| fn parse_phys(&mut self) -> Result<(), DecodingError> { 1411| 769| let info = self.info.as_mut().unwrap(); 1412| 769| if self.have_idat { 1413| 0| Err(DecodingError::Format( 1414| 0| FormatErrorInner::AfterIdat { kind: chunk::pHYs }.into(), 1415| 0| )) 1416| 769| } else if info.pixel_dims.is_some() { 1417| 375| Err(DecodingError::Format( 1418| 375| FormatErrorInner::DuplicateChunk { kind: chunk::pHYs }.into(), 1419| 375| )) 1420| | } else { 1421| 394| let mut buf = &self.current_chunk.raw_bytes[..]; 1422| 394| let xppu = buf.read_be()?; 1423| 394| let yppu = buf.read_be()?; 1424| 394| let unit = buf.read_be()?; 1425| 394| let unit = match Unit::from_u8(unit) { 1426| 55| Some(unit) => unit, 1427| | None => { 1428| 339| return Err(DecodingError::Format( 1429| 339| FormatErrorInner::InvalidUnit(unit).into(), 1430| 339| )) 1431| | } 1432| | }; 1433| 55| let pixel_dims = PixelDimensions { xppu, yppu, unit }; 1434| 55| info.pixel_dims = Some(pixel_dims); 1435| 55| Ok(()) 1436| | } 1437| 769| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_plte: 1271| 1.18k| fn parse_plte(&mut self) -> Result<(), DecodingError> { 1272| 1.18k| let info = self.info.as_mut().unwrap(); 1273| 1.18k| if info.palette.is_some() { 1274| | // Only one palette is allowed 1275| 4| Err(DecodingError::Format( 1276| 4| FormatErrorInner::DuplicateChunk { kind: chunk::PLTE }.into(), 1277| 4| )) 1278| | } else { 1279| 1.18k| info.palette = Some(Cow::Owned(self.current_chunk.raw_bytes.clone())); 1280| 1.18k| Ok(()) 1281| | } 1282| 1.18k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_sbit: 1284| 4.34k| fn parse_sbit(&mut self) -> Result<(), DecodingError> { 1285| 4.34k| let info = self.info.as_mut().unwrap(); 1286| 4.34k| if info.palette.is_some() { 1287| 196| return Err(DecodingError::Format( 1288| 196| FormatErrorInner::AfterPlte { kind: chunk::sBIT }.into(), 1289| 196| )); 1290| 4.14k| } 1291| | 1292| 4.14k| if self.have_idat { 1293| 0| return Err(DecodingError::Format( 1294| 0| FormatErrorInner::AfterIdat { kind: chunk::sBIT }.into(), 1295| 0| )); 1296| 4.14k| } 1297| | 1298| 4.14k| if info.sbit.is_some() { 1299| 198| return Err(DecodingError::Format( 1300| 198| FormatErrorInner::DuplicateChunk { kind: chunk::sBIT }.into(), 1301| 198| )); 1302| 3.95k| } 1303| | 1304| 3.95k| let (color_type, bit_depth) = { (info.color_type, info.bit_depth) }; 1305| | // The sample depth for color type 3 is fixed at eight bits. 1306| 3.95k| let sample_depth = if color_type == ColorType::Indexed { 1307| 3.09k| BitDepth::Eight 1308| | } else { 1309| 858| bit_depth 1310| | }; 1311| 3.95k| let vec = self.current_chunk.raw_bytes.clone(); 1312| 3.95k| let len = vec.len(); 1313| | 1314| | // expected lenth of the chunk 1315| 3.95k| let expected = match color_type { 1316| 798| ColorType::Grayscale => 1, 1317| 3.14k| ColorType::Rgb | ColorType::Indexed => 3, 1318| 3| ColorType::GrayscaleAlpha => 2, 1319| 4| ColorType::Rgba => 4, 1320| | }; 1321| | 1322| | // Check if the sbit chunk size is valid. 1323| 3.95k| if expected != len { 1324| 343| return Err(DecodingError::Format( 1325| 343| FormatErrorInner::InvalidSbitChunkSize { 1326| 343| color_type, 1327| 343| expected, 1328| 343| len, 1329| 343| } 1330| 343| .into(), 1331| 343| )); 1332| 3.60k| } 1333| | 1334| 8.32k| for sbit in &vec { 1335| 8.30k| if *sbit < 1 || *sbit > sample_depth as u8 { 1336| 3.58k| return Err(DecodingError::Format( 1337| 3.58k| FormatErrorInner::InvalidSbit { 1338| 3.58k| sample_depth, 1339| 3.58k| sbit: *sbit, 1340| 3.58k| } 1341| 3.58k| .into(), 1342| 3.58k| )); 1343| 4.71k| } 1344| | } 1345| 19| info.sbit = Some(Cow::Owned(vec)); 1346| 19| Ok(()) 1347| 4.34k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_srgb: 1509| 474| fn parse_srgb(&mut self) -> Result<(), DecodingError> { 1510| 474| let info = self.info.as_mut().unwrap(); 1511| 474| if self.have_idat { 1512| 0| Err(DecodingError::Format( 1513| 0| FormatErrorInner::AfterIdat { kind: chunk::sRGB }.into(), 1514| 0| )) 1515| 474| } else if info.srgb.is_some() { 1516| 199| Err(DecodingError::Format( 1517| 199| FormatErrorInner::DuplicateChunk { kind: chunk::sRGB }.into(), 1518| 199| )) 1519| | } else { 1520| 275| let mut buf = &self.current_chunk.raw_bytes[..]; 1521| 275| let raw: u8 = buf.read_be()?; // BE is is nonsense for single bytes, but this way the size is checked. 1522| 275| let rendering_intent = crate::SrgbRenderingIntent::from_raw(raw).ok_or_else(|| { 1523| | FormatError::from(FormatErrorInner::InvalidSrgbRenderingIntent(raw)) 1524| 203| })?; 1525| | 1526| | // Set srgb and override source gamma and chromaticities. 1527| 72| info.srgb = Some(rendering_intent); 1528| 72| Ok(()) 1529| | } 1530| 474| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_text: 1841| 8.63k| fn parse_text(&mut self) -> Result<(), DecodingError> { 1842| 8.63k| let buf = &self.current_chunk.raw_bytes[..]; 1843| 8.63k| self.limits.reserve_bytes(buf.len())?; 1844| | 1845| 8.63k| let (keyword_slice, value_slice) = Self::split_keyword(buf)?; 1846| | 1847| 7.45k| self.info 1848| 7.45k| .as_mut() 1849| 7.45k| .unwrap() 1850| 7.45k| .uncompressed_latin1_text 1851| 7.45k| .push(TEXtChunk::decode(keyword_slice, value_slice).map_err(DecodingError::from)?); 1852| | 1853| 7.45k| Ok(()) 1854| 8.63k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_trns: 1349| 1.68k| fn parse_trns(&mut self) -> Result<(), DecodingError> { 1350| 1.68k| let info = self.info.as_mut().unwrap(); 1351| 1.68k| if info.trns.is_some() { 1352| 502| return Err(DecodingError::Format( 1353| 502| FormatErrorInner::DuplicateChunk { kind: chunk::PLTE }.into(), 1354| 502| )); 1355| 1.18k| } 1356| 1.18k| let (color_type, bit_depth) = { (info.color_type, info.bit_depth as u8) }; 1357| 1.18k| let mut vec = self.current_chunk.raw_bytes.clone(); 1358| 1.18k| let len = vec.len(); 1359| 1.18k| match color_type { 1360| | ColorType::Grayscale => { 1361| 463| if len < 2 { 1362| 237| return Err(DecodingError::Format( 1363| 237| FormatErrorInner::ShortPalette { expected: 2, len }.into(), 1364| 237| )); 1365| 226| } 1366| 226| if bit_depth < 16 { 1367| 140| vec[0] = vec[1]; 1368| 140| vec.truncate(1); 1369| 140| } 1370| 226| info.trns = Some(Cow::Owned(vec)); 1371| 226| Ok(()) 1372| | } 1373| | ColorType::Rgb => { 1374| 226| if len < 6 { 1375| 195| return Err(DecodingError::Format( 1376| 195| FormatErrorInner::ShortPalette { expected: 6, len }.into(), 1377| 195| )); 1378| 31| } 1379| 31| if bit_depth < 16 { 1380| 27| vec[0] = vec[1]; 1381| 27| vec[1] = vec[3]; 1382| 27| vec[2] = vec[5]; 1383| 27| vec.truncate(3); 1384| 27| } 1385| 31| info.trns = Some(Cow::Owned(vec)); 1386| 31| Ok(()) 1387| | } 1388| | ColorType::Indexed => { 1389| | // The transparency chunk must be after the palette chunk and 1390| | // before the data chunk. 1391| 295| if info.palette.is_none() { 1392| 196| return Err(DecodingError::Format( 1393| 196| FormatErrorInner::BeforePlte { kind: chunk::tRNS }.into(), 1394| 196| )); 1395| 99| } else if self.have_idat { 1396| 0| return Err(DecodingError::Format( 1397| 0| FormatErrorInner::OutsidePlteIdat { kind: chunk::tRNS }.into(), 1398| 0| )); 1399| 99| } 1400| | 1401| 99| info.trns = Some(Cow::Owned(vec)); 1402| 99| Ok(()) 1403| | } 1404| 201| c => Err(DecodingError::Format( 1405| 201| FormatErrorInner::ColorWithBadTrns(c).into(), 1406| 201| )), 1407| | } 1408| 1.68k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_ztxt: 1856| 7.78k| fn parse_ztxt(&mut self) -> Result<(), DecodingError> { 1857| 7.78k| let buf = &self.current_chunk.raw_bytes[..]; 1858| 7.78k| self.limits.reserve_bytes(buf.len())?; 1859| | 1860| 7.78k| let (keyword_slice, value_slice) = Self::split_keyword(buf)?; 1861| | 1862| 6.95k| let compression_method = *value_slice 1863| 6.95k| .first() 1864| 6.95k| .ok_or_else(|| DecodingError::from(TextDecodingError::InvalidCompressionMethod))?; 1865| | 1866| 6.88k| let text_slice = &value_slice[1..]; 1867| | 1868| 6.88k| self.info.as_mut().unwrap().compressed_latin1_text.push( 1869| 6.88k| ZTXtChunk::decode(keyword_slice, compression_method, text_slice) 1870| 6.88k| .map_err(DecodingError::from)?, 1871| | ); 1872| | 1873| 6.51k| Ok(()) 1874| 7.78k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder11parse_chunk: 1096| 63.8k| fn parse_chunk(&mut self, type_str: ChunkType) -> Result { 1097| 63.8k| let mut parse_result = match type_str { 1098| | // Critical non-data chunks. 1099| 9.43k| IHDR => self.parse_ihdr(), 1100| 1.18k| chunk::PLTE => self.parse_plte(), 1101| 1| chunk::IEND => Ok(()), // TODO: Check chunk size. 1102| | 1103| | // Data chunks handled separately. 1104| 7.92k| chunk::IDAT => Ok(()), 1105| 0| chunk::fdAT => Ok(()), 1106| | 1107| | // Recognized bounded-size ancillary chunks. 1108| 4.34k| chunk::sBIT => self.parse_sbit(), 1109| 1.68k| chunk::tRNS => self.parse_trns(), 1110| 769| chunk::pHYs => self.parse_phys(), 1111| 365| chunk::gAMA => self.parse_gama(), 1112| 857| chunk::acTL => self.parse_actl(), 1113| 344| chunk::fcTL => self.parse_fctl(), 1114| 394| chunk::cHRM => self.parse_chrm(), 1115| 474| chunk::sRGB => self.parse_srgb(), 1116| 481| chunk::cICP => self.parse_cicp(), 1117| 454| chunk::mDCV => self.parse_mdcv(), 1118| 390| chunk::cLLI => self.parse_clli(), 1119| 1.70k| chunk::bKGD => self.parse_bkgd(), 1120| | 1121| | // Ancillary chunks with unbounded size. 1122| 674| chunk::eXIf => self.parse_exif(), 1123| 3.05k| chunk::iCCP => self.parse_iccp(), 1124| 8.63k| chunk::tEXt => self.parse_text(), 1125| 7.78k| chunk::zTXt => self.parse_ztxt(), 1126| 12.9k| chunk::iTXt => self.parse_itxt(), 1127| | 1128| | // Unrecognized chunks. 1129| 0| _ => unreachable!( 1130| | "Unrecognized chunk {type_str:?} should have been caught in start_chunk" 1131| | ), 1132| | }; 1133| | 1134| 63.8k| parse_result = parse_result.map_err(|e| { 1135| | match e { 1136| | // `parse_chunk` is invoked after gathering **all** bytes of a chunk, so 1137| | // `UnexpectedEof` from something like `read_be` is permanent and indicates an 1138| | // invalid PNG that should be represented as a `FormatError`, rather than as a 1139| | // (potentially recoverable) `IoError` / `UnexpectedEof`. 1140| | DecodingError::IoError(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => { 1141| | let fmt_err: FormatError = 1142| | FormatErrorInner::ChunkLengthWrong { kind: type_str }.into(); 1143| | fmt_err.into() 1144| | } 1145| | e => e, 1146| | } 1147| | }); 1148| | 1149| 18.9k| match parse_result { 1150| 44.8k| Ok(()) => Ok(Decoded::ChunkComplete(type_str)), 1151| | Err(DecodingError::Format(_)) 1152| 18.9k| if type_str != chunk::fcTL && !chunk::is_critical(type_str) => 1153| | { 1154| | // Ignore benign errors in most auxiliary chunks. `LimitsExceeded`, `Parameter` and 1155| | // other error kinds are *not* treated as benign. We don't ignore errors in `fcTL` 1156| | // chunks because the fallback to the static/non-animated image has to be 1157| | // implemented *on top* of the `StreamingDecoder` API. 1158| | // 1159| | // TODO: Consider supporting a strict mode where even benign errors are reported up. 1160| | // See https://github.com/image-rs/image-png/pull/569#issuecomment-2642062285 1161| 18.6k| Ok(Decoded::BadAncillaryChunk(type_str)) 1162| | } 1163| 364| Err(e) => Err(e), 1164| | } 1165| 63.8k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder11start_chunk: 1038| 71.2k| fn start_chunk(&mut self, type_str: ChunkType, length: u32) -> Result { 1039| 59.3k| let target_length = match type_str { 1040| 9.49k| IHDR => 13..=13, 1041| 1.19k| chunk::PLTE => 3..=768, 1042| 3| chunk::IEND => 0..=0, 1043| 4.58k| chunk::sBIT => 1..=4, 1044| 2.05k| chunk::tRNS => 1..=256, 1045| 1.75k| chunk::pHYs => 9..=9, 1046| 593| chunk::gAMA => 4..=4, 1047| 982| chunk::acTL => 8..=8, 1048| 346| chunk::fcTL => 26..=26, 1049| 590| chunk::cHRM => 32..=32, 1050| 1.37k| chunk::sRGB => 1..=1, 1051| 560| chunk::cICP => 4..=4, 1052| 535| chunk::mDCV => 24..=24, 1053| 458| chunk::cLLI => 8..=8, 1054| 1.73k| chunk::bKGD => 1..=6, 1055| | 1056| | // Unbounded size chunks 1057| 689| chunk::eXIf => 0..=u32::MAX >> 1, // TODO: allow skipping. 1058| 3.07k| chunk::iCCP if !self.decode_options.ignore_iccp_chunk => 0..=u32::MAX >> 1, 1059| 8.64k| chunk::tEXt if !self.decode_options.ignore_text_chunk => 0..=u32::MAX >> 1, 1060| 7.79k| chunk::zTXt if !self.decode_options.ignore_text_chunk => 0..=u32::MAX >> 1, 1061| 12.9k| chunk::iTXt if !self.decode_options.ignore_text_chunk => 0..=u32::MAX >> 1, 1062| | 1063| 0| chunk::IDAT | chunk::fdAT => unreachable!(), 1064| | 1065| 11.8k| _ if is_critical(type_str) => { 1066| 321| return Err(DecodingError::Format( 1067| 321| FormatErrorInner::UnrecognizedCriticalChunk { type_str }.into(), 1068| 321| )); 1069| | } 1070| | _ => { 1071| 11.4k| self.current_chunk.action = ChunkAction::Skip; 1072| 11.4k| return Ok(State::ReadChunkData(type_str)); 1073| | } 1074| | }; 1075| | 1076| 59.3k| if !target_length.contains(&length) { 1077| | // Uncomment to detect unexpected chunk lengths during testing. 1078| | // panic!("chunk type_str={type_str:?} has length={length}, target_length={target_length:?}"); 1079| 3.34k| match type_str { 1080| | IHDR | chunk::PLTE | chunk::IEND | chunk::fcTL => { 1081| 49| return Err(DecodingError::Format( 1082| 49| FormatErrorInner::ChunkLengthWrong { kind: type_str }.into(), 1083| 49| )); 1084| | } 1085| 3.29k| _ => { 1086| 3.29k| self.current_chunk.action = ChunkAction::Reject; 1087| 3.29k| } 1088| | } 1089| 56.0k| } else { 1090| 56.0k| self.current_chunk.action = ChunkAction::Process; 1091| 56.0k| } 1092| | 1093| 59.3k| Ok(State::ReadChunkData(type_str)) 1094| 71.2k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder13split_keyword: 1828| 29.3k| fn split_keyword(buf: &[u8]) -> Result<(&[u8], &[u8]), DecodingError> { 1829| 29.3k| let null_byte_index = buf 1830| 29.3k| .iter() 1831| 29.3k| .position(|&b| b == 0) 1832| 29.3k| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))?; 1833| | 1834| 27.4k| if null_byte_index == 0 || null_byte_index > 79 { 1835| 1.49k| return Err(DecodingError::from(TextDecodingError::InvalidKeywordSize)); 1836| 25.9k| } 1837| | 1838| 25.9k| Ok((&buf[..null_byte_index], &buf[null_byte_index + 1..])) 1839| 29.3k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder14parse_iccp_raw: 1701| 2.42k| fn parse_iccp_raw(&mut self) -> Result<(), DecodingError> { 1702| 2.42k| let info = self.info.as_mut().unwrap(); 1703| 2.42k| let mut buf = &self.current_chunk.raw_bytes[..]; 1704| | 1705| | // read profile name 1706| 28.2k| for len in 0..=80 { 1707| 28.2k| let raw: u8 = buf.read_be()?; 1708| 28.1k| if (raw == 0 && len == 0) || (raw != 0 && len == 80) { 1709| 2| return Err(DecodingError::from(TextDecodingError::InvalidKeywordSize)); 1710| 28.1k| } 1711| 28.1k| if raw == 0 { 1712| 2.39k| break; 1713| 25.7k| } 1714| | } 1715| | 1716| 2.39k| match buf.read_be()? { 1717| | // compression method 1718| 2.38k| 0u8 => (), 1719| 8| n => { 1720| 8| return Err(DecodingError::Format( 1721| 8| FormatErrorInner::UnknownCompressionMethod(n).into(), 1722| 8| )) 1723| | } 1724| | } 1725| | 1726| 2.38k| match fdeflate::decompress_to_vec_bounded(buf, self.limits.bytes) { 1727| 1.99k| Ok(profile) => { 1728| 1.99k| self.limits.reserve_bytes(profile.len())?; 1729| 1.99k| info.icc_profile = Some(Cow::Owned(profile)); 1730| | } 1731| 384| Err(fdeflate::BoundedDecompressionError::DecompressionError { inner: err }) => { 1732| 384| return Err(DecodingError::Format( 1733| 384| FormatErrorInner::CorruptFlateStream { err }.into(), 1734| 384| )) 1735| | } 1736| | Err(fdeflate::BoundedDecompressionError::OutputTooLarge { .. }) => { 1737| 0| return Err(DecodingError::LimitsExceeded); 1738| | } 1739| | } 1740| | 1741| 1.99k| Ok(()) 1742| 2.42k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder16new_with_options: 593| 9.65k| pub fn new_with_options(decode_options: DecodeOptions) -> StreamingDecoder { 594| 9.65k| let mut inflater = ZlibStream::new(); 595| 9.65k| inflater.set_ignore_adler32(decode_options.ignore_adler32); 596| | 597| 9.65k| StreamingDecoder { 598| 9.65k| state: Some(State::new_u32(U32ValueKind::Signature1stU32)), 599| 9.65k| current_chunk: ChunkState { 600| 9.65k| type_: ChunkType([0; 4]), 601| 9.65k| crc: Crc32::new(), 602| 9.65k| remaining: 0, 603| 9.65k| raw_bytes: Vec::with_capacity(CHUNK_BUFFER_SIZE), 604| 9.65k| action: ChunkAction::Process, 605| 9.65k| }, 606| 9.65k| inflater, 607| 9.65k| info: None, 608| 9.65k| current_seq_no: None, 609| 9.65k| have_idat: false, 610| 9.65k| have_iccp: false, 611| 9.65k| ready_for_idat_chunks: true, 612| 9.65k| ready_for_fdat_chunks: false, 613| 9.65k| decode_options, 614| 9.65k| limits: Limits { bytes: usize::MAX }, 615| 9.65k| } 616| 9.65k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder21set_ignore_text_chunk: 635| 9.65k| pub fn set_ignore_text_chunk(&mut self, ignore_text_chunk: bool) { 636| 9.65k| self.decode_options.set_ignore_text_chunk(ignore_text_chunk); 637| 9.65k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder3new: 589| 9.65k| pub fn new() -> StreamingDecoder { 590| 9.65k| StreamingDecoder::new_with_options(DecodeOptions::default()) 591| 9.65k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder6update: 680| 908k| pub fn update( 681| 908k| &mut self, 682| 908k| mut buf: &[u8], 683| 908k| mut image_data: Option<&mut UnfilterBuf<'_>>, 684| 908k| ) -> Result<(usize, Decoded), DecodingError> { 685| 908k| if self.state.is_none() { 686| 0| return Err(DecodingError::Parameter( 687| 0| ParameterErrorKind::PolledAfterFatalError.into(), 688| 0| )); 689| 908k| } 690| | 691| 908k| let len = buf.len(); 692| 1.09M| while !buf.is_empty() { 693| 1.09M| let image_data = image_data.as_deref_mut(); 694| | 695| 1.09M| match self.next_state(buf, image_data) { 696| 188k| Ok((bytes, Decoded::Nothing)) => buf = &buf[bytes..], 697| 906k| Ok((bytes, result)) => { 698| 906k| buf = &buf[bytes..]; 699| 906k| return Ok((len - buf.len(), result)); 700| | } 701| 1.66k| Err(err) => { 702| 1.66k| debug_assert!(self.state.is_none()); 703| 1.66k| return Err(err); 704| | } 705| | } 706| | } 707| 778| Ok((len - buf.len(), Decoded::Nothing)) 708| 908k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder9parse_u32: 833| 267k| fn parse_u32( 834| 267k| &mut self, 835| 267k| kind: U32ValueKind, 836| 267k| u32_be_bytes: &[u8], 837| 267k| image_data: Option<&mut UnfilterBuf<'_>>, 838| 267k| consumed_bytes: usize, 839| 267k| ) -> Result<(usize, Decoded), DecodingError> { 840| 267k| debug_assert_eq!(u32_be_bytes.len(), 4); 841| 267k| let bytes = u32_be_bytes.try_into().unwrap(); 842| 267k| let val = u32::from_be_bytes(bytes); 843| | 844| 267k| match kind { 845| | U32ValueKind::Signature1stU32 => { 846| 9.63k| if bytes == [137, 80, 78, 71] { 847| 9.58k| self.state = Some(State::new_u32(U32ValueKind::Signature2ndU32)); 848| 9.58k| Ok((consumed_bytes, Decoded::Nothing)) 849| | } else { 850| 49| Err(DecodingError::Format( 851| 49| FormatErrorInner::InvalidSignature.into(), 852| 49| )) 853| | } 854| | } 855| | U32ValueKind::Signature2ndU32 => { 856| 9.58k| if bytes == [13, 10, 26, 10] { 857| 9.53k| self.state = Some(State::new_u32(U32ValueKind::Length)); 858| 9.53k| Ok((consumed_bytes, Decoded::Nothing)) 859| | } else { 860| 45| Err(DecodingError::Format( 861| 45| FormatErrorInner::InvalidSignature.into(), 862| 45| )) 863| | } 864| | } 865| | U32ValueKind::Length => { 866| 85.5k| self.state = Some(State::new_u32(U32ValueKind::Type { length: val })); 867| 85.5k| Ok((consumed_bytes, Decoded::Nothing)) 868| | } 869| 85.4k| U32ValueKind::Type { length } => { 870| 85.4k| let type_str = ChunkType(bytes); 871| 85.4k| if self.info.is_none() && type_str != IHDR { 872| 48| return Err(DecodingError::Format( 873| 48| FormatErrorInner::ChunkBeforeIhdr { kind: type_str }.into(), 874| 48| )); 875| 85.4k| } 876| 85.4k| if type_str != self.current_chunk.type_ 877| 35.6k| && (self.current_chunk.type_ == IDAT || self.current_chunk.type_ == chunk::fdAT) 878| | { 879| 2.21k| let finished = match image_data { 880| 229| Some(image_data) => self.inflater.finish(image_data)?, 881| 1.98k| None => true, 882| | }; 883| | 884| | // We ended up handling IDAT/fdAT data rather than the chunk 885| | // type header atually received. Thus rewind `self.state` to 886| | // what it was before this function was called. 887| 2.04k| self.state = Some(State::U32 { 888| 2.04k| kind, 889| 2.04k| bytes, 890| 2.04k| accumulated_count: 4 - consumed_bytes, 891| 2.04k| }); 892| | 893| 2.04k| if finished { 894| | // We've processed all the image data necessary. Update 895| | // `current_chunk.type_`so this codepath isn't taken 896| | // again next time. 897| 2.00k| self.current_chunk.type_ = type_str; 898| 2.00k| self.ready_for_idat_chunks = false; 899| 2.00k| self.ready_for_fdat_chunks = false; 900| 2.00k| return Ok((0, Decoded::ImageDataFlushed)); 901| | } else { 902| | // Report that we processed some image data without 903| | // consuming any input. This gives the caller a chance 904| | // to grow the output buffer and call us again. 905| 47| return Ok((0, Decoded::ImageData)); 906| | } 907| 83.1k| } 908| | 909| 83.1k| self.current_chunk.type_ = type_str; 910| 83.1k| if !self.decode_options.ignore_crc { 911| 83.1k| self.current_chunk.crc.reset(); 912| 83.1k| self.current_chunk.crc.update(&type_str.0); 913| 83.1k| } 914| 83.1k| self.current_chunk.remaining = length; 915| 83.1k| self.current_chunk.raw_bytes.clear(); 916| | 917| 83.1k| self.state = match type_str { 918| | chunk::fdAT => { 919| 1| if !self.ready_for_fdat_chunks { 920| 1| return Err(DecodingError::Format( 921| 1| FormatErrorInner::UnexpectedRestartOfDataChunkSequence { 922| 1| kind: chunk::fdAT, 923| 1| } 924| 1| .into(), 925| 1| )); 926| 0| } 927| 0| if length < 4 { 928| 0| return Err(DecodingError::Format( 929| 0| FormatErrorInner::FdatShorterThanFourBytes.into(), 930| 0| )); 931| 0| } 932| 0| self.current_chunk.action = ChunkAction::Process; 933| 0| Some(State::new_u32(U32ValueKind::ApngSequenceNumber)) 934| | } 935| | IDAT => { 936| 11.9k| if !self.ready_for_idat_chunks { 937| 0| return Err(DecodingError::Format( 938| 0| FormatErrorInner::UnexpectedRestartOfDataChunkSequence { 939| 0| kind: IDAT, 940| 0| } 941| 0| .into(), 942| 0| )); 943| 11.9k| } 944| 11.9k| self.have_idat = true; 945| 11.9k| self.current_chunk.action = ChunkAction::Process; 946| 11.9k| Some(State::ImageData(type_str)) 947| | } 948| 71.2k| _ => Some(self.start_chunk(type_str, length)?), 949| | }; 950| 82.8k| Ok((consumed_bytes, Decoded::ChunkBegin(length, type_str))) 951| | } 952| 77.8k| U32ValueKind::Crc(type_str) => { 953| | // If ignore_crc is set, do not calculate CRC. We set 954| | // sum=val so that it short-circuits to true in the next 955| | // if-statement block 956| 77.8k| let sum = if self.decode_options.ignore_crc { 957| 0| val 958| | } else { 959| 77.8k| self.current_chunk.crc.clone().finalize() 960| | }; 961| | 962| 77.8k| if val == sum || CHECKSUM_DISABLED { 963| 77.8k| match self.current_chunk.action { 964| | ChunkAction::Process => { 965| | // A fatal error in chunk parsing leaves the decoder in state 'None' to enforce 966| | // that parsing can't continue after an error. 967| 63.8k| debug_assert!(self.state.is_none()); 968| 63.8k| let decoded = self.parse_chunk(type_str)?; 969| | 970| 63.5k| if type_str != IEND { 971| 63.5k| self.state = Some(State::new_u32(U32ValueKind::Length)); 972| 63.5k| } 973| 63.5k| Ok((consumed_bytes, decoded)) 974| | } 975| | ChunkAction::Skip => { 976| 10.7k| self.state = Some(State::new_u32(U32ValueKind::Length)); 977| 10.7k| Ok(( 978| 10.7k| consumed_bytes, 979| 10.7k| Decoded::SkippedAncillaryChunk(self.current_chunk.type_), 980| 10.7k| )) 981| | } 982| | ChunkAction::Reject => { 983| 3.21k| self.state = Some(State::new_u32(U32ValueKind::Length)); 984| 3.21k| Ok((consumed_bytes, Decoded::BadAncillaryChunk(type_str))) 985| | } 986| | } 987| 0| } else if self.decode_options.skip_ancillary_crc_failures 988| 0| && !chunk::is_critical(type_str) 989| | { 990| | // Ignore ancillary chunk with invalid CRC 991| 0| self.state = Some(State::new_u32(U32ValueKind::Length)); 992| 0| Ok((consumed_bytes, Decoded::BadAncillaryChunk(type_str))) 993| | } else { 994| 0| Err(DecodingError::Format( 995| 0| FormatErrorInner::CrcMismatch { 996| 0| crc_val: val, 997| 0| crc_sum: sum, 998| 0| chunk: type_str, 999| 0| } 1000| 0| .into(), 1001| 0| )) 1002| | } 1003| | } 1004| | U32ValueKind::ApngSequenceNumber => { 1005| 0| debug_assert_eq!(self.current_chunk.type_, chunk::fdAT); 1006| 0| let next_seq_no = val; 1007| | 1008| | // Should be verified by the FdatShorterThanFourBytes check earlier. 1009| 0| debug_assert!(self.current_chunk.remaining >= 4); 1010| 0| self.current_chunk.remaining -= 4; 1011| | 1012| 0| if let Some(seq_no) = self.current_seq_no { 1013| 0| if next_seq_no != seq_no + 1 { 1014| 0| return Err(DecodingError::Format( 1015| 0| FormatErrorInner::ApngOrder { 1016| 0| present: next_seq_no, 1017| 0| expected: seq_no + 1, 1018| 0| } 1019| 0| .into(), 1020| 0| )); 1021| 0| } 1022| 0| self.current_seq_no = Some(next_seq_no); 1023| | } else { 1024| 0| return Err(DecodingError::Format(FormatErrorInner::MissingFctl.into())); 1025| | } 1026| | 1027| 0| if !self.decode_options.ignore_crc { 1028| 0| let data = next_seq_no.to_be_bytes(); 1029| 0| self.current_chunk.crc.update(&data); 1030| 0| } 1031| | 1032| 0| self.state = Some(State::ImageData(chunk::fdAT)); 1033| 0| Ok((consumed_bytes, Decoded::Nothing)) 1034| | } 1035| | } 1036| 267k| } _RNvNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder10parse_mdcv5scale: 1618| 104| fn scale(chunk: u16) -> ScaledFloat { 1619| | // `ScaledFloat::SCALING` is hardcoded to 100_000, which works 1620| | // well for the `cHRM` chunk where the spec says that "a value 1621| | // of 0.3127 would be stored as the integer 31270". In the 1622| | // `mDCV` chunk the spec says that "0.708, 0.292)" is stored as 1623| | // "{ 35400, 14600 }", using a scaling factor of 50_000, so we 1624| | // multiply by 2 before converting. 1625| 104| ScaledFloat::from_scaled((chunk as u32) * 2) 1626| 104| } _RNvXs2_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_13DecodingErrorINtNtCs6SNw0SRvItZ_4core7convert4FromNtNtNtCsjS9ICikYiHq_3std2io5error5ErrorE4from: 430| 34| fn from(err: io::Error) -> DecodingError { 431| 34| DecodingError::IoError(err) 432| 34| } _RNvXs3_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_13DecodingErrorINtNtCs6SNw0SRvItZ_4core7convert4FromNtB5_11FormatErrorE4from: 436| 203| fn from(err: FormatError) -> DecodingError { 437| 203| DecodingError::Format(err) 438| 203| } _RNvXs4_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_11FormatErrorINtNtCs6SNw0SRvItZ_4core7convert4FromNtB5_16FormatErrorInnerE4from: 442| 26.3M| fn from(inner: FormatErrorInner) -> Self { 443| 26.3M| FormatError { inner } 444| 26.3M| } _RNvXs6_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_13DecodingErrorINtNtCs6SNw0SRvItZ_4core7convert4FromNtNtB9_13text_metadata17TextDecodingErrorE4from: 457| 6.81k| fn from(tbe: TextDecodingError) -> Self { 458| 6.81k| DecodingError::Format(FormatError { 459| 6.81k| inner: FormatErrorInner::BadTextEncoding(tbe), 460| 6.81k| }) 461| 6.81k| } _RNvXs7_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_13DecodeOptionsNtNtCs6SNw0SRvItZ_4core7default7Default7default: 475| 9.65k| fn default() -> Self { 476| 9.65k| Self { 477| 9.65k| ignore_adler32: true, 478| 9.65k| ignore_crc: false, 479| 9.65k| ignore_text_chunk: false, 480| 9.65k| ignore_iccp_chunk: false, 481| 9.65k| skip_ancillary_crc_failures: true, 482| 9.65k| } 483| 9.65k| } _RNvMsa_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtNtB9_6common4Info22validate_default_image: 1962| 194| fn validate_default_image(&self, fc: &FrameControl) -> Result<(), DecodingError> { 1963| | // https://www.w3.org/TR/png-3/#fcTL-chunk says that: 1964| | // 1965| | // > The fcTL chunk corresponding to the default image, if it exists, has these 1966| | // > restrictions: 1967| | // > 1968| | // > * The x_offset and y_offset fields must be 0. 1969| | // > * The width and height fields must equal 1970| | // > the corresponding fields from the IHDR chunk. 1971| 194| if fc.x_offset != 0 1972| 155| || fc.y_offset != 0 1973| 119| || fc.width != self.width 1974| 87| || fc.height != self.height 1975| | { 1976| 142| return Err(DecodingError::Format( 1977| 142| FormatErrorInner::BadSubFrameBounds {}.into(), 1978| 142| )); 1979| 52| } 1980| 52| Ok(()) 1981| 194| } _RNvMsa_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtNtB9_6common4Info8validate: 1983| 252| fn validate(&self, fc: &FrameControl) -> Result<(), DecodingError> { 1984| 252| if fc.width == 0 || fc.height == 0 { 1985| 2| return Err(DecodingError::Format( 1986| 2| FormatErrorInner::InvalidDimensions.into(), 1987| 2| )); 1988| 250| } 1989| | 1990| | // Validate mathematically: fc.width + fc.x_offset <= self.width 1991| 250| let in_x_bounds = Some(fc.width) <= self.width.checked_sub(fc.x_offset); 1992| | // Validate mathematically: fc.height + fc.y_offset <= self.height 1993| 250| let in_y_bounds = Some(fc.height) <= self.height.checked_sub(fc.y_offset); 1994| | 1995| 250| if !in_x_bounds || !in_y_bounds { 1996| 56| return Err(DecodingError::Format( 1997| 56| // TODO: do we want to display the bad bounds? 1998| 56| FormatErrorInner::BadSubFrameBounds {}.into(), 1999| 56| )); 2000| 194| } 2001| | 2002| 194| Ok(()) 2003| 252| } _RINvNtNtCshdzP3jLBsmJ_3png7decoder9transform11unpack_bitsNCNvB2_14expand_gray_u80EB6_: 90| 476k|fn unpack_bits(input: &[u8], output: &mut [u8], channels: usize, bit_depth: u8, func: F) 91| 476k|where 92| 476k| F: Fn(u8, &mut [u8]), 93| |{ 94| | // Only [1, 2, 4, 8] are valid bit depths 95| 476k| assert!(matches!(bit_depth, 1 | 2 | 4 | 8)); 96| | // Check that `input` is capable of producing a buffer as long as `output`: 97| | // number of shift lookups per bit depth * channels * input length 98| 476k| assert!((8 / bit_depth as usize * channels).saturating_mul(input.len()) >= output.len()); 99| | 100| 476k| let mut buf_chunks = output.chunks_exact_mut(channels); 101| 476k| let mut iter = input.iter(); 102| | 103| | // `shift` iterates through the corresponding bit depth sequence: 104| | // 1 => &[7, 6, 5, 4, 3, 2, 1, 0], 105| | // 2 => &[6, 4, 2, 0], 106| | // 4 => &[4, 0], 107| | // 8 => &[0], 108| | // 109| | // `(0..8).step_by(bit_depth.into()).rev()` doesn't always optimize well so 110| | // shifts are calculated instead. (2023-08, Rust 1.71) 111| | 112| 476k| if bit_depth == 8 { 113| 0| for (&curr, chunk) in iter.zip(&mut buf_chunks) { 114| 0| func(curr, chunk); 115| 0| } 116| | } else { 117| 476k| let mask = ((1u16 << bit_depth) - 1) as u8; 118| | 119| | // These variables are initialized in the loop 120| 476k| let mut shift = -1; 121| 476k| let mut curr = 0; 122| | 123| 689M| for chunk in buf_chunks { 124| 689M| if shift < 0 { 125| 141M| shift = 8 - bit_depth as i32; 126| 141M| curr = *iter.next().expect("input for unpack bits is not empty"); 127| 547M| } 128| | 129| 689M| let pixel = (curr >> shift) & mask; 130| 689M| func(pixel, chunk); 131| | 132| 689M| shift -= bit_depth as i32; 133| | } 134| | } 135| 476k|} _RINvNtNtCshdzP3jLBsmJ_3png7decoder9transform11unpack_bitsNCNvB2_24expand_gray_u8_with_trns0EB6_: 90| 2.24k|fn unpack_bits(input: &[u8], output: &mut [u8], channels: usize, bit_depth: u8, func: F) 91| 2.24k|where 92| 2.24k| F: Fn(u8, &mut [u8]), 93| |{ 94| | // Only [1, 2, 4, 8] are valid bit depths 95| 2.24k| assert!(matches!(bit_depth, 1 | 2 | 4 | 8)); 96| | // Check that `input` is capable of producing a buffer as long as `output`: 97| | // number of shift lookups per bit depth * channels * input length 98| 2.24k| assert!((8 / bit_depth as usize * channels).saturating_mul(input.len()) >= output.len()); 99| | 100| 2.24k| let mut buf_chunks = output.chunks_exact_mut(channels); 101| 2.24k| let mut iter = input.iter(); 102| | 103| | // `shift` iterates through the corresponding bit depth sequence: 104| | // 1 => &[7, 6, 5, 4, 3, 2, 1, 0], 105| | // 2 => &[6, 4, 2, 0], 106| | // 4 => &[4, 0], 107| | // 8 => &[0], 108| | // 109| | // `(0..8).step_by(bit_depth.into()).rev()` doesn't always optimize well so 110| | // shifts are calculated instead. (2023-08, Rust 1.71) 111| | 112| 2.24k| if bit_depth == 8 { 113| 0| for (&curr, chunk) in iter.zip(&mut buf_chunks) { 114| 0| func(curr, chunk); 115| 0| } 116| | } else { 117| 2.24k| let mask = ((1u16 << bit_depth) - 1) as u8; 118| | 119| | // These variables are initialized in the loop 120| 2.24k| let mut shift = -1; 121| 2.24k| let mut curr = 0; 122| | 123| 114M| for chunk in buf_chunks { 124| 114M| if shift < 0 { 125| 15.5M| shift = 8 - bit_depth as i32; 126| 15.5M| curr = *iter.next().expect("input for unpack bits is not empty"); 127| 99.4M| } 128| | 129| 114M| let pixel = (curr >> shift) & mask; 130| 114M| func(pixel, chunk); 131| | 132| 114M| shift -= bit_depth as i32; 133| | } 134| | } 135| 2.24k|} _RNCNvNtNtCshdzP3jLBsmJ_3png7decoder9transform14expand_gray_u80B7_: 183| 689M| unpack_bits(row, buffer, 1, info.bit_depth as u8, |val, chunk| { 184| 689M| chunk[0] = val * scaling_factor 185| 689M| }); _RNCNvNtNtCshdzP3jLBsmJ_3png7decoder9transform24expand_gray_u8_with_trns0B7_: 191| 114M| unpack_bits(row, buffer, 2, info.bit_depth as u8, |pixel, chunk| { 192| 114M| chunk[1] = if let Some(trns) = trns { 193| 114M| if pixel == trns[0] { 194| 15.9M| 0 195| | } else { 196| 98.9M| 0xFF 197| | } 198| | } else { 199| 0| 0xFF 200| | }; 201| 114M| chunk[0] = pixel * scaling_factor 202| 114M| }); _RNvNtNtCshdzP3jLBsmJ_3png7decoder9transform14expand_gray_u8: 181| 476k|fn expand_gray_u8(row: &[u8], buffer: &mut [u8], info: &Info) { 182| 476k| let scaling_factor = (255) / ((1u16 << info.bit_depth as u8) - 1) as u8; 183| 476k| unpack_bits(row, buffer, 1, info.bit_depth as u8, |val, chunk| { 184| | chunk[0] = val * scaling_factor 185| | }); 186| 476k|} _RNvNtNtCshdzP3jLBsmJ_3png7decoder9transform16expand_trns_line: 137| 2.42k|fn expand_trns_line(input: &[u8], output: &mut [u8], info: &Info) { 138| 2.42k| let channels = info.color_type.samples(); 139| 2.42k| let trns = info.trns.as_deref(); 140| 51.3M| for (input, output) in input 141| 2.42k| .chunks_exact(channels) 142| 2.42k| .zip(output.chunks_exact_mut(channels + 1)) 143| | { 144| 51.3M| output[..channels].copy_from_slice(input); 145| 51.3M| output[channels] = if Some(input) == trns { 0 } else { 0xFF }; 146| | } 147| 2.42k|} _RNvNtNtCshdzP3jLBsmJ_3png7decoder9transform18expand_trns_line16: 149| 6.34k|fn expand_trns_line16(input: &[u8], output: &mut [u8], info: &Info) { 150| 6.34k| let channels = info.color_type.samples(); 151| 6.34k| let trns = info.trns.as_deref(); 152| 8.91M| for (input, output) in input 153| 6.34k| .chunks_exact(channels * 2) 154| 6.34k| .zip(output.chunks_exact_mut(channels * 2 + 2)) 155| | { 156| 8.91M| output[..channels * 2].copy_from_slice(input); 157| 8.91M| if Some(input) == trns { 158| 5.61k| output[channels * 2] = 0; 159| 5.61k| output[channels * 2 + 1] = 0 160| | } else { 161| 8.90M| output[channels * 2] = 0xFF; 162| 8.90M| output[channels * 2 + 1] = 0xFF 163| | }; 164| | } 165| 6.34k|} _RNvNtNtCshdzP3jLBsmJ_3png7decoder9transform19create_transform_fn: 20| 4.45k|pub fn create_transform_fn( 21| 4.45k| info: &Info, 22| 4.45k| transform: Transformations, 23| 4.45k|) -> Result { 24| 4.45k| let color_type = info.color_type; 25| 4.45k| let bit_depth = info.bit_depth as u8; 26| 4.45k| let trns = info.trns.is_some() || transform.contains(Transformations::ALPHA); 27| 4.45k| let expand = 28| 4.45k| transform.contains(Transformations::EXPAND) || transform.contains(Transformations::ALPHA); 29| 4.45k| let strip16 = bit_depth == 16 && transform.contains(Transformations::STRIP_16); 30| 756| match color_type { 31| 1.01k| ColorType::Indexed if expand => { 32| 1.01k| if info.palette.is_none() { 33| 18| Err(DecodingError::Format( 34| 18| FormatErrorInner::PaletteRequired.into(), 35| 18| )) 36| 998| } else if let BitDepth::Sixteen = info.bit_depth { 37| | // This should have been caught earlier but let's check again. Can't hurt. 38| 0| Err(DecodingError::Format( 39| 0| FormatErrorInner::InvalidColorBitDepth { 40| 0| color_type: ColorType::Indexed, 41| 0| bit_depth: BitDepth::Sixteen, 42| 0| } 43| 0| .into(), 44| 0| )) 45| | } else { 46| 998| Ok(if trns { 47| 89| palette::create_expansion_into_rgba8(info) 48| | } else { 49| 909| palette::create_expansion_into_rgb8(info) 50| | }) 51| | } 52| | } 53| 2.27k| ColorType::Grayscale | ColorType::GrayscaleAlpha if bit_depth < 8 && expand => { 54| 1.41k| Ok(Box::new(if trns { 55| 86| expand_gray_u8_with_trns 56| 1.32k| } else { 57| 1.32k| expand_gray_u8 58| 1.32k| })) 59| | } 60| 868| ColorType::Grayscale | ColorType::Rgb if expand && trns => { 61| 135| Ok(Box::new(if bit_depth == 8 { 62| 53| expand_trns_line 63| 82| } else if strip16 { 64| 0| expand_trns_and_strip_line16 65| 0| } else { 66| 82| assert_eq!(bit_depth, 16); 67| 82| expand_trns_line16 68| | })) 69| | } 70| | ColorType::Grayscale | ColorType::GrayscaleAlpha | ColorType::Rgb | ColorType::Rgba 71| 0| if strip16 => 72| | { 73| 0| Ok(Box::new(transform_row_strip16)) 74| | } 75| 1.89k| _ => Ok(Box::new(copy_row)), 76| | } 77| 4.45k|} _RNvNtNtCshdzP3jLBsmJ_3png7decoder9transform24expand_gray_u8_with_trns: 188| 2.24k|fn expand_gray_u8_with_trns(row: &[u8], buffer: &mut [u8], info: &Info) { 189| 2.24k| let scaling_factor = (255) / ((1u16 << info.bit_depth as u8) - 1) as u8; 190| 2.24k| let trns = info.trns.as_deref(); 191| 2.24k| unpack_bits(row, buffer, 2, info.bit_depth as u8, |pixel, chunk| { 192| | chunk[1] = if let Some(trns) = trns { 193| | if pixel == trns[0] { 194| | 0 195| | } else { 196| | 0xFF 197| | } 198| | } else { 199| | 0xFF 200| | }; 201| | chunk[0] = pixel * scaling_factor 202| | }); 203| 2.24k|} _RNvNtNtCshdzP3jLBsmJ_3png7decoder9transform8copy_row: 79| 25.6M|fn copy_row(row: &[u8], output_buffer: &mut [u8], _: &Info) { 80| 25.6M| output_buffer.copy_from_slice(row); 81| 25.6M|} _RINvNtNtCshdzP3jLBsmJ_3png7decoder9transform11unpack_bitsNCNvNtB2_7palette16expand_into_rgb80EB6_: 90| 162k|fn unpack_bits(input: &[u8], output: &mut [u8], channels: usize, bit_depth: u8, func: F) 91| 162k|where 92| 162k| F: Fn(u8, &mut [u8]), 93| |{ 94| | // Only [1, 2, 4, 8] are valid bit depths 95| 162k| assert!(matches!(bit_depth, 1 | 2 | 4 | 8)); 96| | // Check that `input` is capable of producing a buffer as long as `output`: 97| | // number of shift lookups per bit depth * channels * input length 98| 162k| assert!((8 / bit_depth as usize * channels).saturating_mul(input.len()) >= output.len()); 99| | 100| 162k| let mut buf_chunks = output.chunks_exact_mut(channels); 101| 162k| let mut iter = input.iter(); 102| | 103| | // `shift` iterates through the corresponding bit depth sequence: 104| | // 1 => &[7, 6, 5, 4, 3, 2, 1, 0], 105| | // 2 => &[6, 4, 2, 0], 106| | // 4 => &[4, 0], 107| | // 8 => &[0], 108| | // 109| | // `(0..8).step_by(bit_depth.into()).rev()` doesn't always optimize well so 110| | // shifts are calculated instead. (2023-08, Rust 1.71) 111| | 112| 162k| if bit_depth == 8 { 113| 0| for (&curr, chunk) in iter.zip(&mut buf_chunks) { 114| 0| func(curr, chunk); 115| 0| } 116| | } else { 117| 162k| let mask = ((1u16 << bit_depth) - 1) as u8; 118| | 119| | // These variables are initialized in the loop 120| 162k| let mut shift = -1; 121| 162k| let mut curr = 0; 122| | 123| 120M| for chunk in buf_chunks { 124| 120M| if shift < 0 { 125| 15.1M| shift = 8 - bit_depth as i32; 126| 15.1M| curr = *iter.next().expect("input for unpack bits is not empty"); 127| 105M| } 128| | 129| 120M| let pixel = (curr >> shift) & mask; 130| 120M| func(pixel, chunk); 131| | 132| 120M| shift -= bit_depth as i32; 133| | } 134| | } 135| 162k|} _RINvNtNtCshdzP3jLBsmJ_3png7decoder9transform11unpack_bitsNCNvNtB2_7palette26expand_paletted_into_rgba80EB6_: 90| 7.38k|fn unpack_bits(input: &[u8], output: &mut [u8], channels: usize, bit_depth: u8, func: F) 91| 7.38k|where 92| 7.38k| F: Fn(u8, &mut [u8]), 93| |{ 94| | // Only [1, 2, 4, 8] are valid bit depths 95| 7.38k| assert!(matches!(bit_depth, 1 | 2 | 4 | 8)); 96| | // Check that `input` is capable of producing a buffer as long as `output`: 97| | // number of shift lookups per bit depth * channels * input length 98| 7.38k| assert!((8 / bit_depth as usize * channels).saturating_mul(input.len()) >= output.len()); 99| | 100| 7.38k| let mut buf_chunks = output.chunks_exact_mut(channels); 101| 7.38k| let mut iter = input.iter(); 102| | 103| | // `shift` iterates through the corresponding bit depth sequence: 104| | // 1 => &[7, 6, 5, 4, 3, 2, 1, 0], 105| | // 2 => &[6, 4, 2, 0], 106| | // 4 => &[4, 0], 107| | // 8 => &[0], 108| | // 109| | // `(0..8).step_by(bit_depth.into()).rev()` doesn't always optimize well so 110| | // shifts are calculated instead. (2023-08, Rust 1.71) 111| | 112| 7.38k| if bit_depth == 8 { 113| 45.2k| for (&curr, chunk) in iter.zip(&mut buf_chunks) { 114| 45.2k| func(curr, chunk); 115| 45.2k| } 116| | } else { 117| 2.40k| let mask = ((1u16 << bit_depth) - 1) as u8; 118| | 119| | // These variables are initialized in the loop 120| 2.40k| let mut shift = -1; 121| 2.40k| let mut curr = 0; 122| | 123| 1.24M| for chunk in buf_chunks { 124| 1.24M| if shift < 0 { 125| 166k| shift = 8 - bit_depth as i32; 126| 166k| curr = *iter.next().expect("input for unpack bits is not empty"); 127| 1.07M| } 128| | 129| 1.24M| let pixel = (curr >> shift) & mask; 130| 1.24M| func(pixel, chunk); 131| | 132| 1.24M| shift -= bit_depth as i32; 133| | } 134| | } 135| 7.38k|} _RNCNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette16expand_into_rgb80B9_: 109| 120M| unpack_bits(row, buffer, 3, info.bit_depth as u8, |i, chunk| { 110| 120M| let rgba = &rgba_palette[i as usize]; 111| 120M| chunk[0] = rgba[0]; 112| 120M| chunk[1] = rgba[1]; 113| 120M| chunk[2] = rgba[2]; 114| 120M| }) _RNCNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette26create_expansion_into_rgb80B9_: 26| 4.03k| Box::new(move |input, output, _info| expand_8bit_into_rgb8(input, output, &rgba_palette)) _RNCNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette26create_expansion_into_rgb8s_0B9_: 28| 162k| Box::new(move |input, output, info| expand_into_rgb8(input, output, info, &rgba_palette)) _RNCNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette26expand_paletted_into_rgba80B9_: 123| 1.28M| unpack_bits(row, buffer, 4, info.bit_depth as u8, |i, chunk| { 124| 1.28M| chunk.copy_from_slice(&rgba_palette[i as usize]); 125| 1.28M| }); _RNCNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette27create_expansion_into_rgba80B9_: 34| 7.38k| Box::new(move |input, output, info| { 35| 7.38k| expand_paletted_into_rgba8(input, output, info, &rgba_palette) 36| 7.38k| }) _RNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette16expand_into_rgb8: 108| 162k|fn expand_into_rgb8(row: &[u8], buffer: &mut [u8], info: &Info, rgba_palette: &[[u8; 4]; 256]) { 109| 162k| unpack_bits(row, buffer, 3, info.bit_depth as u8, |i, chunk| { 110| | let rgba = &rgba_palette[i as usize]; 111| | chunk[0] = rgba[0]; 112| | chunk[1] = rgba[1]; 113| | chunk[2] = rgba[2]; 114| | }) 115| 162k|} _RNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette19create_rgba_palette: 39| 998|fn create_rgba_palette(info: &Info) -> [[u8; 4]; 256] { 40| 998| let palette = info.palette.as_deref().expect("Caller should verify"); 41| 998| let trns = info.trns.as_deref().unwrap_or(&[]); 42| | 43| | // > The tRNS chunk shall not contain more alpha values than there are palette 44| | // entries, but a tRNS chunk may contain fewer values than there are palette 45| | // entries. In this case, the alpha value for all remaining palette entries is 46| | // assumed to be 255. 47| | // 48| | // It seems, accepted reading is to fully *ignore* an invalid tRNS as if it were 49| | // completely empty / all pixels are non-transparent. 50| 998| let trns = if trns.len() <= palette.len() / 3 { 51| 963| trns 52| | } else { 53| 35| &[] 54| | }; 55| | 56| | // Default to black, opaque entries. 57| 998| let mut rgba_palette = [[0, 0, 0, 0xFF]; 256]; 58| | 59| | // Copy `palette` (RGB) entries into `rgba_palette`. This may clobber alpha 60| | // values in `rgba_palette` - we need to fix this later. 61| | { 62| 998| let mut palette_iter = palette; 63| 998| let mut rgba_iter = &mut rgba_palette[..]; 64| 3.18k| while palette_iter.len() >= 4 { 65| 2.18k| // Copying 4 bytes at a time is more efficient than copying 3. 66| 2.18k| // OTOH, this clobbers the alpha value in `rgba_iter[0][3]` - we 67| 2.18k| // need to fix this later. 68| 2.18k| rgba_iter[0].copy_from_slice(&palette_iter[0..4]); 69| 2.18k| 70| 2.18k| palette_iter = &palette_iter[3..]; 71| 2.18k| rgba_iter = &mut rgba_iter[1..]; 72| 2.18k| } 73| 998| if !palette_iter.is_empty() { 74| 998| rgba_iter[0][0..3].copy_from_slice(&palette_iter[0..3]); 75| 998| } 76| | } 77| | 78| | // Copy `trns` (alpha) entries into `rgba_palette`. `trns.len()` may be 79| | // smaller than `palette.len()` and therefore this is not sufficient to fix 80| | // all the clobbered alpha values. 81| 998| for (alpha, rgba) in trns.iter().copied().zip(rgba_palette.iter_mut()) { 82| 337| rgba[3] = alpha; 83| 337| } 84| | 85| | // Unclobber the remaining alpha values. 86| 2.84k| for rgba in rgba_palette[trns.len()..(palette.len() / 3)].iter_mut() { 87| 2.84k| rgba[3] = 0xFF; 88| 2.84k| } 89| | 90| 998| rgba_palette 91| 998|} _RNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette21expand_8bit_into_rgb8: 93| 4.03k|fn expand_8bit_into_rgb8(mut input: &[u8], mut output: &mut [u8], rgba_palette: &[[u8; 4]; 256]) { 94| 261k| while output.len() >= 4 { 95| 257k| // Copying 4 bytes at a time is more efficient than 3. 96| 257k| let rgba = &rgba_palette[input[0] as usize]; 97| 257k| output[0..4].copy_from_slice(rgba); 98| 257k| 99| 257k| input = &input[1..]; 100| 257k| output = &mut output[3..]; 101| 257k| } 102| 4.03k| if !output.is_empty() { 103| 4.03k| let rgba = &rgba_palette[input[0] as usize]; 104| 4.03k| output[0..3].copy_from_slice(&rgba[0..3]); 105| 4.03k| } 106| 4.03k|} _RNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette26create_expansion_into_rgb8: 22| 909|pub fn create_expansion_into_rgb8(info: &Info) -> TransformFn { 23| 909| let rgba_palette = create_rgba_palette(info); 24| | 25| 909| if info.bit_depth == BitDepth::Eight { 26| 53| Box::new(move |input, output, _info| expand_8bit_into_rgb8(input, output, &rgba_palette)) 27| | } else { 28| 856| Box::new(move |input, output, info| expand_into_rgb8(input, output, info, &rgba_palette)) 29| | } 30| 909|} _RNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette26expand_paletted_into_rgba8: 117| 7.38k|fn expand_paletted_into_rgba8( 118| 7.38k| row: &[u8], 119| 7.38k| buffer: &mut [u8], 120| 7.38k| info: &Info, 121| 7.38k| rgba_palette: &[[u8; 4]; 256], 122| 7.38k|) { 123| 7.38k| unpack_bits(row, buffer, 4, info.bit_depth as u8, |i, chunk| { 124| | chunk.copy_from_slice(&rgba_palette[i as usize]); 125| | }); 126| 7.38k|} _RNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette27create_expansion_into_rgba8: 32| 89|pub fn create_expansion_into_rgba8(info: &Info) -> TransformFn { 33| 89| let rgba_palette = create_rgba_palette(info); 34| 89| Box::new(move |input, output, info| { 35| | expand_paletted_into_rgba8(input, output, info, &rgba_palette) 36| | }) 37| 89|} _RINvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB3_17UnfilteringBuffer20with_unfilled_bufferNCNvMs4_B5_INtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE23next_raw_interlaced_row0INtNtCs6SNw0SRvItZ_4core6result6ResultNtNtB5_12read_decoder25ImageDataCompletionStatusNtNtB5_6stream13DecodingErrorEECs3aXgM11XBGX_5image: 166| 1.40M| pub fn with_unfilled_buffer(&mut self, f: F) -> T 167| 1.40M| where 168| 1.40M| F: FnOnce(&mut UnfilterBuf<'_>) -> T, 169| | { 170| | // Potentially shift the buffer left to avoid unbounded growth. 171| 1.40M| let discard_size = self.available.min(match &self.prev_row { 172| 1.09M| PrevRow::None | PrevRow::Scratch(_) => self.current_start, 173| 316k| PrevRow::InPlace(prev_start) => *prev_start, 174| | }); 175| 1.40M| if discard_size >= self.shift_back_limit 176| | // Avoid the shift back if the buffer is still very empty. Consider how we got here: a 177| | // previous decompression filled the buffer, then we unfiltered, we're now refilling 178| | // the buffer again. The condition implies, the previous decompression filled at most 179| | // half the buffer. Likely the same will happen again so the following decompression 180| | // attempt will not yet be limited by the buffer length. 181| 1.78k| && self.filled >= self.data_stream.len() / 2 182| 1.78k| { 183| 1.78k| self.shift_buffer_left(discard_size); 184| 1.40M| } 185| | 186| 1.40M| if self.filled + Self::GROWTH_BYTES > self.data_stream.len() { 187| 689k| self.data_stream.resize(self.filled + Self::GROWTH_BYTES, 0); 188| 720k| } 189| | 190| 1.40M| if self.remaining_bytes < usize::MAX as u64 191| 1.40M| && self.filled.saturating_add(self.remaining_bytes as usize) < self.data_stream.len() 192| 48.2k| { 193| 48.2k| self.data_stream 194| 48.2k| .resize(self.filled + self.remaining_bytes as usize, 0); 195| 1.36M| } 196| | 197| 1.40M| let old_filled = self.filled; 198| 1.40M| let ret = f(&mut UnfilterBuf { 199| 1.40M| buffer: &mut self.data_stream, 200| 1.40M| filled: &mut self.filled, 201| 1.40M| available: &mut self.available, 202| 1.40M| }); 203| 1.40M| assert!(self.filled >= old_filled); 204| 1.40M| self.remaining_bytes -= (self.filled - old_filled) as u64; 205| | 206| 1.40M| if self.remaining_bytes == 0 { 207| 2.30k| self.available = self.filled; 208| 1.40M| } 209| | 210| 1.40M| self.debug_assert_invariants(); 211| 1.40M| ret 212| 1.40M| } _RNCNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB4_17UnfilteringBuffer3new0B8_: 63| 9.37k| .and_then(|v| v.checked_mul(info.height.min(128) as usize)) _RNCNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB4_17UnfilteringBuffer3news0_0B8_: 81| 9.37k| .and_then(|v| v.checked_mul(4)) _RNCNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB4_17UnfilteringBuffer3news1_0B8_: 86| 9.37k| .and_then(|v| checked_next_multiple_of(v, 64)) _RNCNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB4_17UnfilteringBuffer3news_0B8_: 66| 9.37k| .and_then(|v| checked_next_multiple_of(v, 256)) _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer11start_frame: 120| 6.25k| pub fn start_frame(&mut self, frame_bytes: u64) { 121| 6.25k| self.data_stream.clear(); 122| 6.25k| self.prev_row = PrevRow::None; 123| 6.25k| self.current_start = 0; 124| 6.25k| self.filled = 0; 125| 6.25k| self.available = 0; 126| 6.25k| self.remaining_bytes = frame_bytes; 127| 6.25k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer14reset_prev_row: 109| 26.3M| pub fn reset_prev_row(&mut self) { 110| | // Stash a previously allocated buffer (for potential reuse later) 111| | // rather than throwing it away when resetting `self.prev_row`. 112| 26.3M| if let PrevRow::Scratch(buf) = &mut self.prev_row { 113| 651k| self.scratch_buffer = std::mem::take(buf); 114| 25.6M| } 115| | 116| 26.3M| self.prev_row = PrevRow::None; 117| 26.3M| self.debug_assert_invariants(); 118| 26.3M| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer15curr_row_filter: 244| 26.3M| fn curr_row_filter(&self) -> Result { 245| 26.3M| let filter = self.data_stream[self.current_start]; 246| 26.3M| RowFilter::from_u8(filter).ok_or(DecodingError::Format( 247| 26.3M| FormatErrorInner::UnknownFilterMethod(filter).into(), 248| 26.3M| )) 249| 26.3M| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer15remaining_bytes: 129| 1.40M| pub fn remaining_bytes(&self) -> u64 { 130| 1.40M| self.remaining_bytes 131| 1.40M| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer17shift_buffer_left: 216| 1.78k| fn shift_buffer_left(&mut self, discard_size: usize) { 217| | // Violating this assertion will clobber the immutable "lookback" 218| | // window that needs to be maintained for decompressor. 219| 1.78k| assert!(discard_size <= self.available); 220| | 221| | // We have to relocate the data to the start of the buffer. Benchmarking suggests that 222| | // the codegen for an unbounded range is better / different than the one for a bounded 223| | // range. We prefer the former if the data overhead is not too high. `16` was 224| | // determined experimentally and might be system (memory) dependent. There's also the 225| | // question if we could be a little smarter and avoid crossing page boundaries when 226| | // that is not required. Alas, microbenchmarking TBD. 227| 1.78k| if let Some(16..) = self.data_stream.len().checked_sub(self.filled) { 228| 1.00k| self.data_stream.copy_within(discard_size..self.filled, 0); 229| 1.00k| } else { 230| 777| self.data_stream.copy_within(discard_size.., 0); 231| 777| } 232| | 233| | // The data kept its relative position to `filled` which now lands exactly at 234| | // the distance between prev_start and filled. 235| 1.78k| self.current_start -= discard_size; 236| 1.78k| self.available -= discard_size; 237| 1.78k| self.filled -= discard_size; 238| 1.78k| match &mut self.prev_row { 239| 68| PrevRow::None | PrevRow::Scratch(_) => (), 240| 1.71k| PrevRow::InPlace(prev_start) => *prev_start -= discard_size, 241| | } 242| 1.78k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer23debug_assert_invariants: 37| 54.0M| fn debug_assert_invariants(&self) {} _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer23mutable_len_of_curr_row: 146| 27.0M| pub fn mutable_len_of_curr_row(&self) -> usize { 147| 27.0M| self.available.saturating_sub(self.current_start) 148| 27.0M| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer24readable_len_of_curr_row: 155| 655k| pub fn readable_len_of_curr_row(&self) -> usize { 156| 655k| self.filled - self.current_start 157| 655k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer26unfilter_curr_row_in_place: 257| 25.6M| pub fn unfilter_curr_row_in_place( 258| 25.6M| &mut self, 259| 25.6M| rowlen: usize, 260| 25.6M| bpp: BytesPerPixel, 261| 25.6M| ) -> Result<(), DecodingError> { 262| 25.6M| debug_assert!(rowlen >= 2); // 1 byte for `RowFilter` and at least 1 byte of pixel data. 263| | 264| | // Violating the assertion below would clobber the bytes in the 265| | // "lookback" window. 266| 25.6M| debug_assert!(self.mutable_len_of_curr_row() >= rowlen); 267| | 268| 25.6M| let filter = self.curr_row_filter()?; 269| 25.6M| let (prev, row) = self.data_stream.split_at_mut(self.current_start); 270| 25.6M| let prev: &[u8] = self.prev_row.as_slice(prev); 271| 25.6M| let row = &mut row[1..rowlen]; // Skip the `RowFilter` byte. 272| 25.6M| debug_assert!(prev.is_empty() || prev.len() == row.len()); 273| | 274| 25.6M| unfilter(filter, bpp, prev, row); 275| | 276| 25.6M| self.reset_prev_row(); 277| 25.6M| self.prev_row = PrevRow::InPlace(self.current_start + 1); 278| 25.6M| self.current_start += rowlen; 279| 25.6M| self.debug_assert_invariants(); 280| | 281| 25.6M| Ok(()) 282| 25.6M| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer38unfilter_curr_row_using_scratch_buffer: 291| 652k| pub fn unfilter_curr_row_using_scratch_buffer( 292| 652k| &mut self, 293| 652k| rowlen: usize, 294| 652k| bpp: BytesPerPixel, 295| 652k| ) -> Result<(), DecodingError> { 296| 652k| debug_assert!(rowlen >= 2); // 1 byte for `RowFilter` and at least 1 byte of pixel data. 297| 652k| debug_assert!(self.readable_len_of_curr_row() >= rowlen); 298| | 299| | // If `mutable_len_of_curr_row >= rowlen`, then `unfilter_curr_row_in_place` 300| | // should have been called instead (to avoid the cost of `copy_from_slice` below). 301| 652k| debug_assert!(self.mutable_len_of_curr_row() < rowlen); 302| | 303| 652k| let filter = self.curr_row_filter()?; 304| | 305| 652k| let mut row = std::mem::take(&mut self.scratch_buffer); 306| 652k| row.resize(rowlen - 1, 0); 307| 652k| row.as_mut_slice() 308| 652k| .copy_from_slice(&self.data_stream[self.current_start + 1..][..rowlen - 1]); 309| | 310| 652k| let prev = self.prev_row(); 311| 652k| debug_assert!(prev.is_empty() || prev.len() == (rowlen - 1)); 312| | 313| 652k| unfilter(filter, bpp, prev, &mut row); 314| | 315| 652k| self.reset_prev_row(); 316| 652k| self.prev_row = PrevRow::Scratch(row); 317| 652k| self.current_start += rowlen; 318| | 319| 652k| self.debug_assert_invariants(); 320| | 321| 652k| Ok(()) 322| 652k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer3new: 49| 9.37k| pub fn new(info: &Info<'_>) -> Self { 50| | // We don't need all of `info` here so if that becomes a structural problem then these 51| | // derived constants can be extracted into a parameter struct. For instance they may be 52| | // adjusted according to platform hardware such as cache sizes. 53| 9.37k| let data_stream_capacity = { 54| 9.37k| let max_data = info 55| 9.37k| .checked_raw_row_length() 56| | // In the current state this is really dependent on IDAT sizes and the compression 57| | // settings. We aim to avoid overallocation here, but that occurs in part due to 58| | // the algorithm for draining the buffer, which at the time of writing is at each 59| | // individual IDAT chunk boundary. So this is set for a quadratic image roughly 60| | // fitting into a single 4k chunk at compression.. A very arbitrary choice made 61| | // from (probably overfitting) a benchmark of that image size. With a different 62| | // algorithm we may come to different buffer uses and have to re-evaluate. 63| 9.37k| .and_then(|v| v.checked_mul(info.height.min(128) as usize)) 64| | // In the worst case this is additional room for use of unmasked SIMD moves. But 65| | // the other idea here is that the allocator generally aligns the buffer. 66| 9.37k| .and_then(|v| checked_next_multiple_of(v, 256)) 67| 9.37k| .unwrap_or(usize::MAX); 68| | // We do not want to pre-allocate too much in case of a faulty image (no DOS by 69| | // pretending to be very very large) and also we want to avoid allocating more data 70| | // than we need for the image itself. 71| 9.37k| max_data.min(128 * 1024) 72| | }; 73| | 74| 9.37k| let shift_back_limit = { 75| | // Prefer shifting by powers of two and only after having done some number of 76| | // lines that then become free at the end of the buffer. 77| 9.37k| let rowlen_pot = info 78| 9.37k| .checked_raw_row_length() 79| | // Ensure some number of rows are actually present before shifting back, i.e. next 80| | // time around we want to be able to decode them without reallocating the buffer. 81| 9.37k| .and_then(|v| v.checked_mul(4)) 82| | // And also, we should be able to use aligned memcopy on the whole thing. Well at 83| | // least that is the idea but the parameter is just benchmarking. Higher numbers 84| | // did not result in performance gains but lowers also, so this is fickle. Maybe 85| | // our shift back behavior can not be tuned very well. 86| 9.37k| .and_then(|v| checked_next_multiple_of(v, 64)) 87| 9.37k| .unwrap_or(isize::MAX as usize); 88| | // But never shift back before we have a number of pages freed. 89| 9.37k| rowlen_pot.max(128 * 1024) 90| | }; 91| | 92| 9.37k| let result = Self { 93| 9.37k| data_stream: Vec::with_capacity(data_stream_capacity), 94| 9.37k| prev_row: PrevRow::None, 95| 9.37k| current_start: 0, 96| 9.37k| filled: 0, 97| 9.37k| available: 0, 98| 9.37k| shift_back_limit, 99| 9.37k| remaining_bytes: u64::MAX, 100| 9.37k| scratch_buffer: Vec::new(), 101| 9.37k| }; 102| | 103| 9.37k| result.debug_assert_invariants(); 104| 9.37k| result 105| 9.37k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer8prev_row: 134| 26.9M| pub fn prev_row(&self) -> &[u8] { 135| 26.9M| self.prev_row 136| 26.9M| .as_slice(&self.data_stream[..self.current_start]) 137| 26.9M| } _RNvMs_NtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB4_7PrevRow8as_slice: 355| 52.6M| fn as_slice<'a>(&'a self, buf: &'a [u8]) -> &'a [u8] { 356| 52.6M| match self { 357| 7.69k| PrevRow::None => &[], 358| 51.3M| PrevRow::InPlace(prev_start) => &buf[*prev_start..], 359| 1.30M| PrevRow::Scratch(scratch) => scratch.as_slice(), 360| | } 361| 52.6M| } _RNvNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_buffer24checked_next_multiple_of: 364| 18.7k|fn checked_next_multiple_of(val: usize, factor: usize) -> Option { 365| 18.7k| if factor == 0 { 366| 0| return None; 367| 18.7k| } 368| | 369| 18.7k| let remainder = val % factor; 370| | 371| 18.7k| if remainder > 0 { 372| 17.1k| val.checked_add(factor - remainder) 373| | } else { 374| 1.56k| Some(val) 375| | } 376| 18.7k|} _RNCNvMNtNtCshdzP3jLBsmJ_3png7decoder4zlibNtB4_10ZlibStream6finish0B8_: 162| 1| .map_err(|err| { 163| 1| DecodingError::Format(FormatErrorInner::CorruptFlateStream { err }.into()) 164| 1| })?; _RNCNvMs0_NtNtCshdzP3jLBsmJ_3png7decoder4zlibNtB7_11UnfilterBuf10decompress0Bb_: 233| 619| .map_err(|err| { 234| 619| DecodingError::Format(FormatErrorInner::CorruptFlateStream { err }.into()) 235| 619| })?; _RNvMNtNtCshdzP3jLBsmJ_3png7decoder4zlibNtB2_10ZlibStream10decompress: 109| 743k| pub(crate) fn decompress( 110| 743k| &mut self, 111| 743k| data: &[u8], 112| 743k| image_data: &mut UnfilterBuf<'_>, 113| 743k| ) -> Result { 114| | // There may be more data past the adler32 checksum at the end of the deflate stream. We 115| | // match libpng's default behavior and ignore any trailing data. In the future we may want 116| | // to add a flag to control this behavior. 117| 743k| if self.state.is_done() { 118| 406| return Ok(data.len()); 119| 742k| } 120| | 121| 742k| if !self.started && self.ignore_adler32 { 122| 5.89k| self.state.ignore_adler32(); 123| 736k| } 124| | 125| 742k| let in_consumed = image_data.decompress(&mut self.state, data)?; 126| 742k| self.started = true; 127| | 128| 742k| Ok(in_consumed) 129| 743k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder4zlibNtB2_10ZlibStream18set_ignore_adler32: 93| 9.65k| pub(crate) fn set_ignore_adler32(&mut self, flag: bool) -> bool { 94| 9.65k| if !self.started { 95| 9.65k| self.ignore_adler32 = flag; 96| 9.65k| true 97| | } else { 98| 0| false 99| | } 100| 9.65k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder4zlibNtB2_10ZlibStream3new: 73| 9.65k| pub(crate) fn new() -> Self { 74| 9.65k| ZlibStream { 75| 9.65k| state: Box::new(Decompressor::new()), 76| 9.65k| started: false, 77| 9.65k| ignore_adler32: true, 78| 9.65k| } 79| 9.65k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder4zlibNtB2_10ZlibStream5reset: 81| 256| pub(crate) fn reset(&mut self) { 82| 256| self.started = false; 83| 256| *self.state = Decompressor::new(); 84| 256| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder4zlibNtB2_10ZlibStream6finish: 138| 229| pub(crate) fn finish( 139| 229| &mut self, 140| 229| image_data: &mut UnfilterBuf<'_>, 141| 229| ) -> Result { 142| 229| if !self.started || self.state.is_done() { 143| 10| return Ok(true); 144| 219| } 145| | 146| | // If the zlib stream isn't done but we've already output all the pixel 147| | // data needed, then either there's too much compressed data or the 148| | // checksum is missing. Those aren't allowed by the spec, but libpng 149| | // generally doesn't treat them as fatal. 150| 219| if *image_data.filled == image_data.buffer.len() { 151| 0| return Ok(true); 152| 219| } 153| | 154| 219| let (_, out_consumed) = self 155| 219| .state 156| 219| .read( 157| 219| &[], 158| 219| &mut image_data.buffer[*image_data.available..], 159| 219| *image_data.filled - *image_data.available, 160| | false, 161| | ) 162| 219| .map_err(|err| { 163| | DecodingError::Format(FormatErrorInner::CorruptFlateStream { err }.into()) 164| 1| })?; 165| 218| *image_data.filled += out_consumed; 166| | 167| 218| if self.state.is_done() { 168| 2| *image_data.available = *image_data.filled; 169| 2| return Ok(true); 170| 216| } 171| | 172| | // More output is only possible if zlib stream hasn't finished and the 173| | // output buffer *is* full. (Empty space in the output buffer tells us 174| | // there wasn't more data to write into it.) 175| 216| if *image_data.filled == image_data.buffer.len() { 176| 47| *image_data.available = 177| 47| (*image_data.available).max(image_data.filled.saturating_sub(LOOKBACK_SIZE)); 178| 47| return Ok(false); 179| 169| } 180| | 181| | // The zlib stream was truncated before the end of the pixel data. This 182| | // would ordinarily be caught within fdeflate if we'd passed 183| | // end_of_input=true. But we intentionally don't pass that flag so that 184| | // we're able to drain all available pixel data first. 185| 169| Err(DecodingError::Format( 186| 169| FormatErrorInner::CorruptFlateStream { 187| 169| err: fdeflate::DecompressionError::InsufficientInput, 188| 169| } 189| 169| .into(), 190| 169| )) 191| 229| } _RNvMs0_NtNtCshdzP3jLBsmJ_3png7decoder4zlibNtB5_11UnfilterBuf10decompressB9_: 220| 742k| fn decompress( 221| 742k| &mut self, 222| 742k| decompressor: &mut fdeflate::Decompressor, 223| 742k| input: &[u8], 224| 742k| ) -> Result { 225| 742k| let output_limit = (*self.filled + UnfilteringBuffer::GROWTH_BYTES).min(self.buffer.len()); 226| 742k| let (in_consumed, out_consumed) = decompressor 227| 742k| .read( 228| 742k| input, 229| 742k| &mut self.buffer[*self.available..output_limit], 230| 742k| *self.filled - *self.available, 231| | false, 232| | ) 233| 742k| .map_err(|err| { 234| | DecodingError::Format(FormatErrorInner::CorruptFlateStream { err }.into()) 235| 619| })?; 236| | 237| 742k| *self.filled += out_consumed; 238| 742k| if decompressor.is_done() { 239| 1.03k| *self.available = *self.filled; 240| 741k| } else if let Some(new_available) = self.filled.checked_sub(LOOKBACK_SIZE) { 241| | // The decompressed data may have started in the middle of the buffer, 242| | // so ensure that `self.available` never goes backward. This is needed 243| | // to avoid miscommunicating the size of the "look-back" window when calling 244| | // `fdeflate::Decompressor::read` a bit earlier and passing 245| | // `&mut self.buffer[*self.available..output_limit]`. 246| 730k| if new_available > *self.available { 247| 728k| *self.available = new_available; 248| 728k| } 249| 10.8k| } 250| | 251| 742k| Ok(in_consumed) 252| 742k| } _RNCNvNtCshdzP3jLBsmJ_3png6filter8unfilter0B5_: 123| 302M| current.iter_mut().reduce(|&mut prev, curr| { 124| 302M| *curr = curr.wrapping_add(prev); 125| 302M| curr 126| 302M| }); _RNCNvNtCshdzP3jLBsmJ_3png6filter8unfilters_0B5_: 204| 46.5M| current.iter_mut().reduce(|&mut prev, curr| { 205| 46.5M| *curr = curr.wrapping_add(prev / 2); 206| 46.5M| curr 207| 46.5M| }); _RNvMs2_NtCshdzP3jLBsmJ_3png6filterNtB5_9RowFilter7from_u8: 79| 26.3M| pub fn from_u8(n: u8) -> Option { 80| 26.3M| match n { 81| 25.9M| 0 => Some(Self::NoFilter), 82| 117k| 1 => Some(Self::Sub), 83| 78.4k| 2 => Some(Self::Up), 84| 143k| 3 => Some(Self::Avg), 85| 29.4k| 4 => Some(Self::Paeth), 86| 136| _ => None, 87| | } 88| 26.3M| } _RNvNtCshdzP3jLBsmJ_3png6filter8unfilter: 102| 26.3M|pub(crate) fn unfilter( 103| 26.3M| mut filter: RowFilter, 104| 26.3M| tbpp: BytesPerPixel, 105| 26.3M| previous: &[u8], 106| 26.3M| current: &mut [u8], 107| 26.3M|) { 108| | use self::RowFilter::*; 109| | 110| | // If the previous row is empty, then treat it as if it were filled with zeros. 111| 26.3M| if previous.is_empty() { 112| 7.69k| if filter == Paeth { 113| 773| filter = Sub; 114| 6.92k| } else if filter == Up { 115| 554| filter = NoFilter; 116| 6.37k| } 117| 26.3M| } 118| | 119| 143k| match filter { 120| 25.9M| NoFilter => {} 121| 118k| Sub => match tbpp { 122| | BytesPerPixel::One => { 123| 42.9k| current.iter_mut().reduce(|&mut prev, curr| { 124| | *curr = curr.wrapping_add(prev); 125| | curr 126| | }); 127| | } 128| | BytesPerPixel::Two => { 129| 21.6k| let mut prev = [0; 2]; 130| 225M| for chunk in current.chunks_exact_mut(2) { 131| 225M| let new_chunk = [ 132| 225M| chunk[0].wrapping_add(prev[0]), 133| 225M| chunk[1].wrapping_add(prev[1]), 134| 225M| ]; 135| 225M| *TryInto::<&mut [u8; 2]>::try_into(chunk).unwrap() = new_chunk; 136| 225M| prev = new_chunk; 137| 225M| } 138| | } 139| | BytesPerPixel::Three => { 140| 37.4k| let mut prev = [0; 3]; 141| 187M| for chunk in current.chunks_exact_mut(3) { 142| 187M| let new_chunk = [ 143| 187M| chunk[0].wrapping_add(prev[0]), 144| 187M| chunk[1].wrapping_add(prev[1]), 145| 187M| chunk[2].wrapping_add(prev[2]), 146| 187M| ]; 147| 187M| *TryInto::<&mut [u8; 3]>::try_into(chunk).unwrap() = new_chunk; 148| 187M| prev = new_chunk; 149| 187M| } 150| | } 151| | BytesPerPixel::Four => { 152| 11.7k| let mut prev = [0; 4]; 153| 133M| for chunk in current.chunks_exact_mut(4) { 154| 133M| let new_chunk = [ 155| 133M| chunk[0].wrapping_add(prev[0]), 156| 133M| chunk[1].wrapping_add(prev[1]), 157| 133M| chunk[2].wrapping_add(prev[2]), 158| 133M| chunk[3].wrapping_add(prev[3]), 159| 133M| ]; 160| 133M| *TryInto::<&mut [u8; 4]>::try_into(chunk).unwrap() = new_chunk; 161| 133M| prev = new_chunk; 162| 133M| } 163| | } 164| | BytesPerPixel::Six => { 165| 3.36k| let mut prev = [0; 6]; 166| 13.3M| for chunk in current.chunks_exact_mut(6) { 167| 13.3M| let new_chunk = [ 168| 13.3M| chunk[0].wrapping_add(prev[0]), 169| 13.3M| chunk[1].wrapping_add(prev[1]), 170| 13.3M| chunk[2].wrapping_add(prev[2]), 171| 13.3M| chunk[3].wrapping_add(prev[3]), 172| 13.3M| chunk[4].wrapping_add(prev[4]), 173| 13.3M| chunk[5].wrapping_add(prev[5]), 174| 13.3M| ]; 175| 13.3M| *TryInto::<&mut [u8; 6]>::try_into(chunk).unwrap() = new_chunk; 176| 13.3M| prev = new_chunk; 177| 13.3M| } 178| | } 179| | BytesPerPixel::Eight => { 180| 1.27k| let mut prev = [0; 8]; 181| 5.91M| for chunk in current.chunks_exact_mut(8) { 182| 5.91M| let new_chunk = [ 183| 5.91M| chunk[0].wrapping_add(prev[0]), 184| 5.91M| chunk[1].wrapping_add(prev[1]), 185| 5.91M| chunk[2].wrapping_add(prev[2]), 186| 5.91M| chunk[3].wrapping_add(prev[3]), 187| 5.91M| chunk[4].wrapping_add(prev[4]), 188| 5.91M| chunk[5].wrapping_add(prev[5]), 189| 5.91M| chunk[6].wrapping_add(prev[6]), 190| 5.91M| chunk[7].wrapping_add(prev[7]), 191| 5.91M| ]; 192| 5.91M| *TryInto::<&mut [u8; 8]>::try_into(chunk).unwrap() = new_chunk; 193| 5.91M| prev = new_chunk; 194| 5.91M| } 195| | } 196| | }, 197| | Up => { 198| 270M| for (curr, &above) in current.iter_mut().zip(previous) { 199| 270M| *curr = curr.wrapping_add(above); 200| 270M| } 201| | } 202| 143k| Avg if previous.is_empty() => match tbpp { 203| | BytesPerPixel::One => { 204| 397| current.iter_mut().reduce(|&mut prev, curr| { 205| | *curr = curr.wrapping_add(prev / 2); 206| | curr 207| | }); 208| | } 209| | BytesPerPixel::Two => { 210| 252| let mut prev = [0; 2]; 211| 48.6M| for chunk in current.chunks_exact_mut(2) { 212| 48.6M| let new_chunk = [ 213| 48.6M| chunk[0].wrapping_add(prev[0] / 2), 214| 48.6M| chunk[1].wrapping_add(prev[1] / 2), 215| 48.6M| ]; 216| 48.6M| *TryInto::<&mut [u8; 2]>::try_into(chunk).unwrap() = new_chunk; 217| 48.6M| prev = new_chunk; 218| 48.6M| } 219| | } 220| | BytesPerPixel::Three => { 221| 149| let mut prev = [0; 3]; 222| 58.3M| for chunk in current.chunks_exact_mut(3) { 223| 58.3M| let new_chunk = [ 224| 58.3M| chunk[0].wrapping_add(prev[0] / 2), 225| 58.3M| chunk[1].wrapping_add(prev[1] / 2), 226| 58.3M| chunk[2].wrapping_add(prev[2] / 2), 227| 58.3M| ]; 228| 58.3M| *TryInto::<&mut [u8; 3]>::try_into(chunk).unwrap() = new_chunk; 229| 58.3M| prev = new_chunk; 230| 58.3M| } 231| | } 232| | BytesPerPixel::Four => { 233| 192| let mut prev = [0; 4]; 234| 41.7M| for chunk in current.chunks_exact_mut(4) { 235| 41.7M| let new_chunk = [ 236| 41.7M| chunk[0].wrapping_add(prev[0] / 2), 237| 41.7M| chunk[1].wrapping_add(prev[1] / 2), 238| 41.7M| chunk[2].wrapping_add(prev[2] / 2), 239| 41.7M| chunk[3].wrapping_add(prev[3] / 2), 240| 41.7M| ]; 241| 41.7M| *TryInto::<&mut [u8; 4]>::try_into(chunk).unwrap() = new_chunk; 242| 41.7M| prev = new_chunk; 243| 41.7M| } 244| | } 245| | BytesPerPixel::Six => { 246| 110| let mut prev = [0; 6]; 247| 1.05M| for chunk in current.chunks_exact_mut(6) { 248| 1.05M| let new_chunk = [ 249| 1.05M| chunk[0].wrapping_add(prev[0] / 2), 250| 1.05M| chunk[1].wrapping_add(prev[1] / 2), 251| 1.05M| chunk[2].wrapping_add(prev[2] / 2), 252| 1.05M| chunk[3].wrapping_add(prev[3] / 2), 253| 1.05M| chunk[4].wrapping_add(prev[4] / 2), 254| 1.05M| chunk[5].wrapping_add(prev[5] / 2), 255| 1.05M| ]; 256| 1.05M| *TryInto::<&mut [u8; 6]>::try_into(chunk).unwrap() = new_chunk; 257| 1.05M| prev = new_chunk; 258| 1.05M| } 259| | } 260| | BytesPerPixel::Eight => { 261| 161| let mut prev = [0; 8]; 262| 2.47M| for chunk in current.chunks_exact_mut(8) { 263| 2.47M| let new_chunk = [ 264| 2.47M| chunk[0].wrapping_add(prev[0] / 2), 265| 2.47M| chunk[1].wrapping_add(prev[1] / 2), 266| 2.47M| chunk[2].wrapping_add(prev[2] / 2), 267| 2.47M| chunk[3].wrapping_add(prev[3] / 2), 268| 2.47M| chunk[4].wrapping_add(prev[4] / 2), 269| 2.47M| chunk[5].wrapping_add(prev[5] / 2), 270| 2.47M| chunk[6].wrapping_add(prev[6] / 2), 271| 2.47M| chunk[7].wrapping_add(prev[7] / 2), 272| 2.47M| ]; 273| 2.47M| *TryInto::<&mut [u8; 8]>::try_into(chunk).unwrap() = new_chunk; 274| 2.47M| prev = new_chunk; 275| 2.47M| } 276| | } 277| | }, 278| 142k| Avg => match tbpp { 279| | BytesPerPixel::One => { 280| 55.2k| let mut lprev = [0; 1]; 281| 43.1M| for (chunk, above) in current.chunks_exact_mut(1).zip(previous.chunks_exact(1)) { 282| 43.1M| let new_chunk = 283| 43.1M| [chunk[0].wrapping_add(((above[0] as u16 + lprev[0] as u16) / 2) as u8)]; 284| 43.1M| *TryInto::<&mut [u8; 1]>::try_into(chunk).unwrap() = new_chunk; 285| 43.1M| lprev = new_chunk; 286| 43.1M| } 287| | } 288| | BytesPerPixel::Two => { 289| 9.63k| let mut lprev = [0; 2]; 290| 1.20M| for (chunk, above) in current.chunks_exact_mut(2).zip(previous.chunks_exact(2)) { 291| 1.20M| let new_chunk = [ 292| 1.20M| chunk[0].wrapping_add(((above[0] as u16 + lprev[0] as u16) / 2) as u8), 293| 1.20M| chunk[1].wrapping_add(((above[1] as u16 + lprev[1] as u16) / 2) as u8), 294| 1.20M| ]; 295| 1.20M| *TryInto::<&mut [u8; 2]>::try_into(chunk).unwrap() = new_chunk; 296| 1.20M| lprev = new_chunk; 297| 1.20M| } 298| | } 299| | BytesPerPixel::Three => { 300| 1.89k| let mut lprev = [0; 3]; 301| 41.7M| for (chunk, above) in current.chunks_exact_mut(3).zip(previous.chunks_exact(3)) { 302| 41.7M| let new_chunk = [ 303| 41.7M| chunk[0].wrapping_add(((above[0] as u16 + lprev[0] as u16) / 2) as u8), 304| 41.7M| chunk[1].wrapping_add(((above[1] as u16 + lprev[1] as u16) / 2) as u8), 305| 41.7M| chunk[2].wrapping_add(((above[2] as u16 + lprev[2] as u16) / 2) as u8), 306| 41.7M| ]; 307| 41.7M| *TryInto::<&mut [u8; 3]>::try_into(chunk).unwrap() = new_chunk; 308| 41.7M| lprev = new_chunk; 309| 41.7M| } 310| | } 311| | BytesPerPixel::Four => { 312| 67.1k| let mut lprev = [0; 4]; 313| 43.1M| for (chunk, above) in current.chunks_exact_mut(4).zip(previous.chunks_exact(4)) { 314| 43.1M| let new_chunk = [ 315| 43.1M| chunk[0].wrapping_add(((above[0] as u16 + lprev[0] as u16) / 2) as u8), 316| 43.1M| chunk[1].wrapping_add(((above[1] as u16 + lprev[1] as u16) / 2) as u8), 317| 43.1M| chunk[2].wrapping_add(((above[2] as u16 + lprev[2] as u16) / 2) as u8), 318| 43.1M| chunk[3].wrapping_add(((above[3] as u16 + lprev[3] as u16) / 2) as u8), 319| 43.1M| ]; 320| 43.1M| *TryInto::<&mut [u8; 4]>::try_into(chunk).unwrap() = new_chunk; 321| 43.1M| lprev = new_chunk; 322| 43.1M| } 323| | } 324| | BytesPerPixel::Six => { 325| 1.74k| let mut lprev = [0; 6]; 326| 18.9M| for (chunk, above) in current.chunks_exact_mut(6).zip(previous.chunks_exact(6)) { 327| 18.9M| let new_chunk = [ 328| 18.9M| chunk[0].wrapping_add(((above[0] as u16 + lprev[0] as u16) / 2) as u8), 329| 18.9M| chunk[1].wrapping_add(((above[1] as u16 + lprev[1] as u16) / 2) as u8), 330| 18.9M| chunk[2].wrapping_add(((above[2] as u16 + lprev[2] as u16) / 2) as u8), 331| 18.9M| chunk[3].wrapping_add(((above[3] as u16 + lprev[3] as u16) / 2) as u8), 332| 18.9M| chunk[4].wrapping_add(((above[4] as u16 + lprev[4] as u16) / 2) as u8), 333| 18.9M| chunk[5].wrapping_add(((above[5] as u16 + lprev[5] as u16) / 2) as u8), 334| 18.9M| ]; 335| 18.9M| *TryInto::<&mut [u8; 6]>::try_into(chunk).unwrap() = new_chunk; 336| 18.9M| lprev = new_chunk; 337| 18.9M| } 338| | } 339| | BytesPerPixel::Eight => { 340| 6.92k| let mut lprev = [0; 8]; 341| 11.1M| for (chunk, above) in current.chunks_exact_mut(8).zip(previous.chunks_exact(8)) { 342| 11.1M| let new_chunk = [ 343| 11.1M| chunk[0].wrapping_add(((above[0] as u16 + lprev[0] as u16) / 2) as u8), 344| 11.1M| chunk[1].wrapping_add(((above[1] as u16 + lprev[1] as u16) / 2) as u8), 345| 11.1M| chunk[2].wrapping_add(((above[2] as u16 + lprev[2] as u16) / 2) as u8), 346| 11.1M| chunk[3].wrapping_add(((above[3] as u16 + lprev[3] as u16) / 2) as u8), 347| 11.1M| chunk[4].wrapping_add(((above[4] as u16 + lprev[4] as u16) / 2) as u8), 348| 11.1M| chunk[5].wrapping_add(((above[5] as u16 + lprev[5] as u16) / 2) as u8), 349| 11.1M| chunk[6].wrapping_add(((above[6] as u16 + lprev[6] as u16) / 2) as u8), 350| 11.1M| chunk[7].wrapping_add(((above[7] as u16 + lprev[7] as u16) / 2) as u8), 351| 11.1M| ]; 352| 11.1M| *TryInto::<&mut [u8; 8]>::try_into(chunk).unwrap() = new_chunk; 353| 11.1M| lprev = new_chunk; 354| 11.1M| } 355| | } 356| | }, 357| 28.6k| Paeth => paeth::unfilter(tbpp, previous, current), 358| | } 359| 26.3M|} _RNvNtNtCshdzP3jLBsmJ_3png6filter5paeth17filter_paeth_stbi: 28| 466M|pub(super) fn filter_paeth_stbi(a: i16, b: i16, c: i16) -> u8 { 29| | // Decoding optimizes better with this algorithm than with `filter_paeth` 30| | // 31| | // This formulation looks very different from the reference in the PNG spec, but is 32| | // actually equivalent and has favorable data dependencies and admits straightforward 33| | // generation of branch-free code, which helps performance significantly. 34| | // 35| | // Adapted from public domain PNG implementation: 36| | // https://github.com/nothings/stb/blob/5c205738c191bcb0abc65c4febfa9bd25ff35234/stb_image.h#L4657-L4668 37| 466M| let thresh = c * 3 - (a + b); 38| 466M| let lo = a.min(b); 39| 466M| let hi = a.max(b); 40| 466M| let t0 = if hi <= thresh { lo } else { c }; 41| 466M| let t1 = if thresh <= lo { hi } else { t0 }; 42| 466M| t1 as u8 43| 466M|} _RNvNtNtCshdzP3jLBsmJ_3png6filter5paeth8unfilter: 221| 28.6k|pub(super) fn unfilter(tbpp: BytesPerPixel, previous: &[u8], current: &mut [u8]) { 222| | // Paeth filter pixels: 223| | // C B D 224| | // A X 225| 28.6k| match tbpp { 226| | BytesPerPixel::One => { 227| | const BPP: usize = 1; 228| 8.18k| let mut a_bpp = [0; BPP]; 229| 8.18k| let mut c_bpp = [0; BPP]; 230| | 231| 34.0M| for (c, p) in current 232| 8.18k| .chunks_exact_mut(BPP) 233| 8.18k| .zip(previous.chunks_exact(BPP)) 234| | { 235| 68.1M| for i in 0..BPP { 236| 34.0M| c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i])); 237| 34.0M| } 238| | 239| 34.0M| a_bpp = [c[0] as i16]; 240| 34.0M| c_bpp = [p[0] as i16]; 241| | } 242| | } 243| | BytesPerPixel::Two => { 244| | const BPP: usize = 2; 245| 10.9k| let mut a_bpp = [0; BPP]; 246| 10.9k| let mut c_bpp = [0; BPP]; 247| | 248| 40.2M| for (c, p) in current 249| 10.9k| .chunks_exact_mut(BPP) 250| 10.9k| .zip(previous.chunks_exact(BPP)) 251| | { 252| 120M| for i in 0..BPP { 253| 80.4M| c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i])); 254| 80.4M| } 255| | 256| 40.2M| a_bpp = [c[0] as i16, c[1] as i16]; 257| 40.2M| c_bpp = [p[0] as i16, p[1] as i16]; 258| | } 259| | } 260| | BytesPerPixel::Three => { 261| | #[cfg(feature = "unstable")] 262| | { 263| | // Results in PR: https://github.com/image-rs/image-png/pull/632 264| | // 23% better on an Epyc 7B13, 10% on a Zen 3 part. 265| | // ~30% when targeting x86-64-v2. 266| | super::simd::paeth_unfilter_3bpp(current, previous); 267| | return; 268| | } 269| | const BPP: usize = 3; 270| 2.31k| let mut a_bpp = [0; BPP]; 271| 2.31k| let mut c_bpp = [0; BPP]; 272| | 273| 29.0M| for (c, p) in current 274| 2.31k| .chunks_exact_mut(BPP) 275| 2.31k| .zip(previous.chunks_exact(BPP)) 276| | { 277| 116M| for i in 0..BPP { 278| 87.0M| c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i])); 279| 87.0M| } 280| | 281| 29.0M| a_bpp = [c[0] as i16, c[1] as i16, c[2] as i16]; 282| 29.0M| c_bpp = [p[0] as i16, p[1] as i16, p[2] as i16]; 283| | } 284| | } 285| | BytesPerPixel::Four => { 286| | #[cfg(feature = "unstable")] 287| | { 288| | // Results in PR: https://github.com/image-rs/image-png/pull/633 289| | // May be slightly faster on AMD EPYC 7B13. 290| | super::simd::paeth_unfilter_4bpp(current, previous); 291| | return; 292| | } 293| | const BPP: usize = 4; 294| 2.46k| let mut a_bpp = [0; BPP]; 295| 2.46k| let mut c_bpp = [0; BPP]; 296| | 297| 29.8M| for (c, p) in current 298| 2.46k| .chunks_exact_mut(BPP) 299| 2.46k| .zip(previous.chunks_exact(BPP)) 300| | { 301| 149M| for i in 0..BPP { 302| 119M| c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i])); 303| 119M| } 304| | 305| 29.8M| a_bpp = [c[0] as i16, c[1] as i16, c[2] as i16, c[3] as i16]; 306| 29.8M| c_bpp = [p[0] as i16, p[1] as i16, p[2] as i16, p[3] as i16]; 307| | } 308| | } 309| | BytesPerPixel::Six => { 310| | const BPP: usize = 6; 311| 4.43k| let mut a_bpp = [0; BPP]; 312| 4.43k| let mut c_bpp = [0; BPP]; 313| | 314| 22.3M| for (c, p) in current 315| 4.43k| .chunks_exact_mut(BPP) 316| 4.43k| .zip(previous.chunks_exact(BPP)) 317| | { 318| 156M| for i in 0..BPP { 319| 133M| c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i])); 320| 133M| } 321| | 322| 22.3M| a_bpp = [ 323| 22.3M| c[0] as i16, 324| 22.3M| c[1] as i16, 325| 22.3M| c[2] as i16, 326| 22.3M| c[3] as i16, 327| 22.3M| c[4] as i16, 328| 22.3M| c[5] as i16, 329| 22.3M| ]; 330| 22.3M| c_bpp = [ 331| 22.3M| p[0] as i16, 332| 22.3M| p[1] as i16, 333| 22.3M| p[2] as i16, 334| 22.3M| p[3] as i16, 335| 22.3M| p[4] as i16, 336| 22.3M| p[5] as i16, 337| 22.3M| ]; 338| | } 339| | } 340| | BytesPerPixel::Eight => { 341| | const BPP: usize = 8; 342| 315| let mut a_bpp = [0; BPP]; 343| 315| let mut c_bpp = [0; BPP]; 344| | 345| 1.50M| for (c, p) in current 346| 315| .chunks_exact_mut(BPP) 347| 315| .zip(previous.chunks_exact(BPP)) 348| | { 349| 13.5M| for i in 0..BPP { 350| 12.0M| c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i])); 351| 12.0M| } 352| | 353| 1.50M| a_bpp = [ 354| 1.50M| c[0] as i16, 355| 1.50M| c[1] as i16, 356| 1.50M| c[2] as i16, 357| 1.50M| c[3] as i16, 358| 1.50M| c[4] as i16, 359| 1.50M| c[5] as i16, 360| 1.50M| c[6] as i16, 361| 1.50M| c[7] as i16, 362| 1.50M| ]; 363| 1.50M| c_bpp = [ 364| 1.50M| p[0] as i16, 365| 1.50M| p[1] as i16, 366| 1.50M| p[2] as i16, 367| 1.50M| p[3] as i16, 368| 1.50M| p[4] as i16, 369| 1.50M| p[5] as i16, 370| 1.50M| p[6] as i16, 371| 1.50M| p[7] as i16, 372| 1.50M| ]; 373| | } 374| | } 375| | } 376| 28.6k|} _RNCNvNtCshdzP3jLBsmJ_3png13text_metadata17decode_iso_8859_10B5_: 158| 1.12M| text.iter().map(|&b| b as char).collect() _RNvMNtCshdzP3jLBsmJ_3png13text_metadataNtB2_9TEXtChunk6decode: 199| 7.45k| pub(crate) fn decode( 200| 7.45k| keyword_slice: &[u8], 201| 7.45k| text_slice: &[u8], 202| 7.45k| ) -> Result { 203| 7.45k| if keyword_slice.is_empty() || keyword_slice.len() > 79 { 204| 0| return Err(TextDecodingError::InvalidKeywordSize); 205| 7.45k| } 206| | 207| 7.45k| Ok(Self { 208| 7.45k| keyword: decode_iso_8859_1(keyword_slice), 209| 7.45k| text: decode_iso_8859_1(text_slice), 210| 7.45k| }) 211| 7.45k| } _RNvMs0_NtCshdzP3jLBsmJ_3png13text_metadataNtB5_9ZTXtChunk26decompress_text_with_limit: 283| 44| pub fn decompress_text_with_limit(&mut self, limit: usize) -> Result<(), DecodingError> { 284| 44| match &self.text { 285| 44| OptCompressed::Compressed(v) => { 286| 44| let uncompressed_raw = match fdeflate::decompress_to_vec_bounded(&v[..], limit) { 287| 17| Ok(s) => s, 288| | Err(BoundedDecompressionError::OutputTooLarge { .. }) => { 289| 0| return Err(DecodingError::from( 290| 0| TextDecodingError::OutOfDecompressionSpace, 291| 0| )); 292| | } 293| | Err(_) => { 294| 27| return Err(DecodingError::from(TextDecodingError::InflationError)); 295| | } 296| | }; 297| 17| self.text = OptCompressed::Uncompressed(decode_iso_8859_1(&uncompressed_raw)); 298| | } 299| 0| OptCompressed::Uncompressed(_) => {} 300| | }; 301| 17| Ok(()) 302| 44| } _RNvMs0_NtCshdzP3jLBsmJ_3png13text_metadataNtB5_9ZTXtChunk6decode: 258| 6.88k| pub(crate) fn decode( 259| 6.88k| keyword_slice: &[u8], 260| 6.88k| compression_method: u8, 261| 6.88k| text_slice: &[u8], 262| 6.88k| ) -> Result { 263| 6.88k| if keyword_slice.is_empty() || keyword_slice.len() > 79 { 264| 0| return Err(TextDecodingError::InvalidKeywordSize); 265| 6.88k| } 266| | 267| 6.88k| if compression_method != 0 { 268| 368| return Err(TextDecodingError::InvalidCompressionMethod); 269| 6.51k| } 270| | 271| 6.51k| Ok(Self { 272| 6.51k| keyword: decode_iso_8859_1(keyword_slice), 273| 6.51k| text: OptCompressed::Compressed(text_slice.to_vec()), 274| 6.51k| }) 275| 6.88k| } _RNvMs0_NtCshdzP3jLBsmJ_3png13text_metadataNtB5_9ZTXtChunk8get_text: 306| 17| pub fn get_text(&self) -> Result { 307| 17| match &self.text { 308| 0| OptCompressed::Compressed(v) => { 309| 0| let uncompressed_raw = fdeflate::decompress_to_vec(v) 310| 0| .map_err(|_| DecodingError::from(TextDecodingError::InflationError))?; 311| 0| Ok(decode_iso_8859_1(&uncompressed_raw)) 312| | } 313| 17| OptCompressed::Uncompressed(s) => Ok(s.clone()), 314| | } 315| 17| } _RNvMs2_NtCshdzP3jLBsmJ_3png13text_metadataNtB5_9ITXtChunk26decompress_text_with_limit: 453| 14| pub fn decompress_text_with_limit(&mut self, limit: usize) -> Result<(), DecodingError> { 454| 14| match &self.text { 455| 5| OptCompressed::Compressed(v) => { 456| 5| let uncompressed_raw = match fdeflate::decompress_to_vec_bounded(v, limit) { 457| 0| Ok(s) => s, 458| | Err(BoundedDecompressionError::OutputTooLarge { .. }) => { 459| 0| return Err(DecodingError::from( 460| 0| TextDecodingError::OutOfDecompressionSpace, 461| 0| )); 462| | } 463| | Err(_) => { 464| 5| return Err(DecodingError::from(TextDecodingError::InflationError)); 465| | } 466| | }; 467| 0| self.text = OptCompressed::Uncompressed( 468| 0| String::from_utf8(uncompressed_raw) 469| 0| .map_err(|_| TextDecodingError::Unrepresentable)?, 470| | ); 471| | } 472| 9| OptCompressed::Uncompressed(_) => {} 473| | }; 474| 9| Ok(()) 475| 14| } _RNvMs2_NtCshdzP3jLBsmJ_3png13text_metadataNtB5_9ITXtChunk6decode: 401| 10.5k| pub(crate) fn decode( 402| 10.5k| keyword_slice: &[u8], 403| 10.5k| compression_flag: u8, 404| 10.5k| compression_method: u8, 405| 10.5k| language_tag_slice: &[u8], 406| 10.5k| translated_keyword_slice: &[u8], 407| 10.5k| text_slice: &[u8], 408| 10.5k| ) -> Result { 409| 10.5k| if keyword_slice.is_empty() || keyword_slice.len() > 79 { 410| 0| return Err(TextDecodingError::InvalidKeywordSize); 411| 10.5k| } 412| 10.5k| let keyword = decode_iso_8859_1(keyword_slice); 413| | 414| 10.5k| let compressed = match compression_flag { 415| 8.17k| 0 => false, 416| 2.18k| 1 => true, 417| 217| _ => return Err(TextDecodingError::InvalidCompressionFlag), 418| | }; 419| | 420| 10.3k| if compressed && compression_method != 0 { 421| 211| return Err(TextDecodingError::InvalidCompressionMethod); 422| 10.1k| } 423| | 424| 10.1k| let language_tag = decode_ascii(language_tag_slice)?.to_owned(); 425| | 426| 9.33k| let translated_keyword = std::str::from_utf8(translated_keyword_slice) 427| 9.33k| .map_err(|_| TextDecodingError::Unrepresentable)? 428| 9.24k| .to_string(); 429| 9.24k| let text = if compressed { 430| 1.76k| OptCompressed::Compressed(text_slice.to_vec()) 431| | } else { 432| | OptCompressed::Uncompressed( 433| 7.48k| String::from_utf8(text_slice.to_vec()) 434| 7.48k| .map_err(|_| TextDecodingError::Unrepresentable)?, 435| | ) 436| | }; 437| | 438| 8.59k| Ok(Self { 439| 8.59k| keyword, 440| 8.59k| compressed, 441| 8.59k| language_tag, 442| 8.59k| translated_keyword, 443| 8.59k| text, 444| 8.59k| }) 445| 10.5k| } _RNvMs2_NtCshdzP3jLBsmJ_3png13text_metadataNtB5_9ITXtChunk8get_text: 479| 9| pub fn get_text(&self) -> Result { 480| 9| match &self.text { 481| 0| OptCompressed::Compressed(v) => { 482| 0| let uncompressed_raw = fdeflate::decompress_to_vec(v) 483| 0| .map_err(|_| DecodingError::from(TextDecodingError::InflationError))?; 484| 0| String::from_utf8(uncompressed_raw) 485| 0| .map_err(|_| TextDecodingError::Unrepresentable.into()) 486| | } 487| 9| OptCompressed::Uncompressed(s) => Ok(s.clone()), 488| | } 489| 9| } _RNvNtCshdzP3jLBsmJ_3png13text_metadata12decode_ascii: 177| 10.1k|fn decode_ascii(text: &[u8]) -> Result<&str, TextDecodingError> { 178| 10.1k| if text.is_ascii() { 179| | // `from_utf8` cannot panic because we're already checked that `text` is ASCII-7. 180| | // And this is the only safe way to get ASCII-7 string from `&[u8]`. 181| 9.33k| Ok(std::str::from_utf8(text).expect("unreachable")) 182| | } else { 183| 811| Err(TextDecodingError::Unrepresentable) 184| | } 185| 10.1k|} _RNvNtCshdzP3jLBsmJ_3png13text_metadata17decode_iso_8859_1: 157| 32.0k|fn decode_iso_8859_1(text: &[u8]) -> String { 158| 32.0k| text.iter().map(|&b| b as char).collect() 159| 32.0k|} _RNvXNtCshdzP3jLBsmJ_3png6traitsRShINtB2_12ReadBytesExthE7read_beB4_: 7| 78.8k| fn read_be(&mut self) -> io::Result<$output_type> { 8| 78.8k| let mut bytes = [0u8; std::mem::size_of::<$output_type>()]; 9| 78.8k| self.read_exact(&mut bytes)?; 10| 78.8k| Ok(<$output_type>::from_be_bytes(bytes)) 11| 78.8k| } _RNvXs0_NtCshdzP3jLBsmJ_3png6traitsRShINtB5_12ReadBytesExtmE7read_beB7_: 7| 22.5k| fn read_be(&mut self) -> io::Result<$output_type> { 8| 22.5k| let mut bytes = [0u8; std::mem::size_of::<$output_type>()]; 9| 22.5k| self.read_exact(&mut bytes)?; 10| 22.5k| Ok(<$output_type>::from_be_bytes(bytes)) 11| 22.5k| } _RNvXs_NtCshdzP3jLBsmJ_3png6traitsRShINtB4_12ReadBytesExttE7read_beB6_: 7| 616| fn read_be(&mut self) -> io::Result<$output_type> { 8| 616| let mut bytes = [0u8; std::mem::size_of::<$output_type>()]; 9| 616| self.read_exact(&mut bytes)?; 10| 616| Ok(<$output_type>::from_be_bytes(bytes)) 11| 616| } _RNvNtNtCs2divbjE383Z_12simd_adler323imp4avx213get_imp_innerB5_: 10| 12.3k|fn get_imp_inner() -> Option { 11| 12.3k| if std::is_x86_feature_detected!("avx2") { 12| 12.3k| Some(imp::update) 13| | } else { 14| 0| None 15| | } 16| 12.3k|} _RNvNtNtCs2divbjE383Z_12simd_adler323imp4avx27get_imp: 4| 12.3k|pub fn get_imp() -> Option { 5| 12.3k| get_imp_inner() 6| 12.3k|} _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp10reduce_add: 143| 1.81M| unsafe fn reduce_add(v: __m256i) -> u32 { 144| 1.81M| let sum = _mm_add_epi32(_mm256_castsi256_si128(v), _mm256_extracti128_si256(v, 1)); 145| 1.81M| let hi = _mm_unpackhi_epi64(sum, sum); 146| | 147| 1.81M| let sum = _mm_add_epi32(hi, sum); 148| 1.81M| let hi = _mm_shuffle_epi32(sum, crate::imp::_MM_SHUFFLE(2, 3, 0, 1)); 149| | 150| 1.81M| let sum = _mm_add_epi32(sum, hi); 151| | 152| 1.81M| _mm_cvtsi128_si32(sum) as _ 153| 1.81M| } _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp10update_impB7_: 57| 154k| unsafe fn update_imp(a: u16, b: u16, data: &[u8]) -> (u16, u16) { 58| 154k| let mut a = a as u32; 59| 154k| let mut b = b as u32; 60| | 61| 154k| let chunks = data.chunks_exact(CHUNK_SIZE); 62| 154k| let remainder = chunks.remainder(); 63| 906k| for chunk in chunks { 64| 752k| update_chunk_block(&mut a, &mut b, chunk); 65| 752k| } 66| | 67| 154k| update_block(&mut a, &mut b, remainder); 68| | 69| 154k| (a as u16, b as u16) 70| 154k| } _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp11get_weights: 156| 906k| unsafe fn get_weights() -> __m256i { 157| 906k| _mm256_set_epi8( 158| | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 159| | 24, 25, 26, 27, 28, 29, 30, 31, 32, 160| | ) 161| 906k| } _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp12update_blockB7_: 89| 154k| unsafe fn update_block(a: &mut u32, b: &mut u32, chunk: &[u8]) { 90| 154k| debug_assert!( 91| 0| chunk.len() <= CHUNK_SIZE, 92| 0| "Unexpected chunk size (expected <= {}, got {})", 93| | CHUNK_SIZE, 94| 0| chunk.len() 95| | ); 96| | 97| 154k| for byte in reduce_add_blocks(a, b, chunk) { 98| 52.4k| *a += *byte as u32; 99| 52.4k| *b += *a; 100| 52.4k| } 101| | 102| 154k| *a %= MOD; 103| 154k| *b %= MOD; 104| 154k| } _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp17reduce_add_blocks: 107| 906k| unsafe fn reduce_add_blocks<'a>(a: &mut u32, b: &mut u32, chunk: &'a [u8]) -> &'a [u8] { 108| 906k| if chunk.len() < BLOCK_SIZE { 109| 211| return chunk; 110| 906k| } 111| | 112| 906k| let blocks = chunk.chunks_exact(BLOCK_SIZE); 113| 906k| let blocks_remainder = blocks.remainder(); 114| | 115| 906k| let one_v = _mm256_set1_epi16(1); 116| 906k| let zero_v = _mm256_setzero_si256(); 117| 906k| let weights = get_weights(); 118| | 119| 906k| let mut p_v = _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, (*a * blocks.len() as u32) as _); 120| 906k| let mut a_v = _mm256_setzero_si256(); 121| 906k| let mut b_v = _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, *b as _); 122| | 123| 155M| for block in blocks { 124| 154M| let block_ptr = block.as_ptr() as *const _; 125| 154M| let block = _mm256_loadu_si256(block_ptr); 126| 154M| 127| 154M| p_v = _mm256_add_epi32(p_v, a_v); 128| 154M| 129| 154M| a_v = _mm256_add_epi32(a_v, _mm256_sad_epu8(block, zero_v)); 130| 154M| let mad = _mm256_maddubs_epi16(block, weights); 131| 154M| b_v = _mm256_add_epi32(b_v, _mm256_madd_epi16(mad, one_v)); 132| 154M| } 133| | 134| 906k| b_v = _mm256_add_epi32(b_v, _mm256_slli_epi32(p_v, 5)); 135| | 136| 906k| *a += reduce_add(a_v); 137| 906k| *b = reduce_add(b_v); 138| | 139| 906k| blocks_remainder 140| 906k| } _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp18update_chunk_blockB7_: 73| 752k| unsafe fn update_chunk_block(a: &mut u32, b: &mut u32, chunk: &[u8]) { 74| 752k| debug_assert_eq!( 75| 0| chunk.len(), 76| | CHUNK_SIZE, 77| 0| "Unexpected chunk size (expected {}, got {})", 78| | CHUNK_SIZE, 79| 0| chunk.len() 80| | ); 81| | 82| 752k| reduce_add_blocks(a, b, chunk); 83| | 84| 752k| *a %= MOD; 85| 752k| *b %= MOD; 86| 752k| } _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp6update: 51| 154k| pub fn update(a: u16, b: u16, data: &[u8]) -> (u16, u16) { 52| 154k| unsafe { update_imp(a, b, data) } 53| 154k| } _RNvNtNtCs2divbjE383Z_12simd_adler323imp6avx51213get_imp_innerB5_: 44| 12.3k|fn get_imp_inner() -> Option { 45| 12.3k| None 46| 12.3k|} _RNvNtNtCs2divbjE383Z_12simd_adler323imp6avx5127get_imp: 4| 12.3k|pub fn get_imp() -> Option { 5| 12.3k| get_imp_inner() 6| 12.3k|} _RNvNtCs2divbjE383Z_12simd_adler323imp7get_imp: 17| 12.3k|pub fn get_imp() -> Adler32Imp { 18| 12.3k| avx512::get_imp() 19| 12.3k| .or_else(neon::get_imp) 20| 12.3k| .or_else(avx2::get_imp) 21| 12.3k| .or_else(ssse3::get_imp) 22| 12.3k| .or_else(sse2::get_imp) 23| 12.3k| .or_else(wasm::get_imp) 24| 12.3k| .unwrap_or(scalar::update) 25| 12.3k|} _RNvNtNtCs2divbjE383Z_12simd_adler323imp4neon7get_imp: 9| 12.3k|pub fn get_imp() -> Option { 10| 12.3k| None 11| 12.3k|} _RNvMCs2divbjE383Z_12simd_adler32NtB2_7Adler323new: 125| 12.3k| pub fn new() -> Self { 126| 12.3k| Default::default() 127| 12.3k| } _RNvMCs2divbjE383Z_12simd_adler32NtB2_7Adler325write: 149| 154k| pub fn write(&mut self, data: &[u8]) { 150| 154k| let (a, b) = (self.update)(self.a, self.b, data); 151| | 152| 154k| self.a = a; 153| 154k| self.b = b; 154| 154k| } _RNvXs_Cs2divbjE383Z_12simd_adler32NtB4_7Adler32NtNtCs6SNw0SRvItZ_4core7default7Default7default: 195| 12.3k| fn default() -> Self { 196| 12.3k| Self { 197| 12.3k| a: 1, 198| 12.3k| b: 0, 199| 12.3k| update: get_imp(), 200| 12.3k| } 201| 12.3k| } _RNvMs4_NtNtCs3aXgM11XBGX_5image6codecs3pngNtNtB9_5error10ImageError8from_png: 959| 7.46k| fn from_png(err: png::DecodingError) -> ImageError { 960| | use png::DecodingError::*; 961| 7.46k| match err { 962| 5.53k| IoError(err) => ImageError::IoError(err), 963| | // The input image was not a valid PNG. 964| 1.85k| err @ Format(_) => { 965| 1.85k| ImageError::Decoding(DecodingError::new(ImageFormat::Png.into(), err)) 966| | } 967| | // Other is used when: 968| | // - The decoder is polled for more animation frames despite being done (or not being animated 969| | // in the first place). 970| | // - The output buffer does not have the required size. 971| 0| err @ Parameter(_) => ImageError::Parameter(ParameterError::from_kind( 972| 0| ParameterErrorKind::Generic(err.to_string()), 973| 0| )), 974| | LimitsExceeded => { 975| 72| ImageError::Limits(LimitError::from_kind(LimitErrorKind::InsufficientMemory)) 976| | } 977| | } 978| 7.46k| } _RNCNCNvXs_NtNtCs3aXgM11XBGX_5image6codecs3pngINtB8_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBc_2io7decoder12ImageDecoder13iptc_metadata00Bc_: 348| 2.00k| .find(|chunk| IPTC_KEYS.iter().any(|key| chunk.keyword.contains(key))) _RNCNCNvXs_NtNtCs3aXgM11XBGX_5image6codecs3pngINtB8_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBc_2io7decoder12ImageDecoder13iptc_metadatas0_00Bc_: 364| 828| .find(|chunk| IPTC_KEYS.iter().any(|key| chunk.keyword.contains(key))) _RNCNvNtNtCs3aXgM11XBGX_5image6codecs3png27big_endian_to_native_endian0B7_: 271| 54.6M| 2 => buf.as_chunks_mut::<2>().0.iter_mut().for_each(|c| { 272| 54.6M| *c = u16::from_be_bytes(*c).to_ne_bytes(); 273| 54.6M| }), _RNCNvXs_NtNtCs3aXgM11XBGX_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder11icc_profile0Ba_: 309| 1.82k| Ok(reader.info().icc_profile.as_ref().map(|x| x.to_vec())) _RNCNvXs_NtNtCs3aXgM11XBGX_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder12xmp_metadata0Ba_: 325| 696| .find(|chunk| chunk.keyword == XMP_KEY) _RNCNvXs_NtNtCs3aXgM11XBGX_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder12xmp_metadatas_0Ba_: 333| 9| .map(|text| Some(text.into_bytes())) _RNCNvXs_NtNtCs3aXgM11XBGX_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder13exif_metadata0Ba_: 314| 56| Ok(reader.info().exif_metadata.as_ref().map(|x| x.to_vec())) _RNCNvXs_NtNtCs3aXgM11XBGX_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder13iptc_metadata0Ba_: 348| 1.01k| .find(|chunk| IPTC_KEYS.iter().any(|key| chunk.keyword.contains(key))) _RNCNvXs_NtNtCs3aXgM11XBGX_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder13iptc_metadatas0_0Ba_: 364| 417| .find(|chunk| IPTC_KEYS.iter().any(|key| chunk.keyword.contains(key))) _RNCNvXs_NtNtCs3aXgM11XBGX_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder13iptc_metadatas_0Ba_: 356| 17| .map(|text| Some(text.into_bytes())) _RNvMNtNtCs3aXgM11XBGX_5image6codecs3pngINtB2_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE11with_limitsB6_: 53| 9.65k| pub fn with_limits(r: R, limits: Limits) -> PngDecoder { 54| 9.65k| let max_bytes = usize::try_from(limits.max_alloc.unwrap_or(u64::MAX)).unwrap_or(usize::MAX); 55| 9.65k| let mut decoder = png::Decoder::new_with_limits(r, png::Limits { bytes: max_bytes }); 56| 9.65k| decoder.set_ignore_text_chunk(false); 57| | 58| 9.65k| PngDecoder { 59| 9.65k| decoder: Some(decoder), 60| 9.65k| // We'll replace this once we have a reader. 61| 9.65k| color_type: ColorType::L8, 62| 9.65k| reader: None, 63| 9.65k| limits, 64| 9.65k| } 65| 9.65k| } _RNvMNtNtCs3aXgM11XBGX_5image6codecs3pngINtB2_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE15color_type_infoB6_: 189| 6.00k| fn color_type_info(info: &png::Info<'_>) -> ExtendedColorType { 190| 6.00k| match (info.color_type, info.bit_depth) { 191| 1.08k| (png::ColorType::Grayscale, png::BitDepth::One) => ExtendedColorType::L1, 192| 212| (png::ColorType::Grayscale, png::BitDepth::Two) => ExtendedColorType::L2, 193| 578| (png::ColorType::Grayscale, png::BitDepth::Four) => ExtendedColorType::L4, 194| 480| (png::ColorType::Grayscale, png::BitDepth::Eight) => ExtendedColorType::L8, 195| 764| (png::ColorType::Grayscale, png::BitDepth::Sixteen) => ExtendedColorType::L16, 196| 0| (png::ColorType::GrayscaleAlpha, png::BitDepth::One) => ExtendedColorType::La1, 197| 0| (png::ColorType::GrayscaleAlpha, png::BitDepth::Two) => ExtendedColorType::La2, 198| 0| (png::ColorType::GrayscaleAlpha, png::BitDepth::Four) => ExtendedColorType::La4, 199| 214| (png::ColorType::GrayscaleAlpha, png::BitDepth::Eight) => ExtendedColorType::La8, 200| 131| (png::ColorType::GrayscaleAlpha, png::BitDepth::Sixteen) => ExtendedColorType::La16, 201| 0| (png::ColorType::Rgb, png::BitDepth::One) => ExtendedColorType::Rgb1, 202| 0| (png::ColorType::Rgb, png::BitDepth::Two) => ExtendedColorType::Rgb2, 203| 0| (png::ColorType::Rgb, png::BitDepth::Four) => ExtendedColorType::Rgb4, 204| 612| (png::ColorType::Rgb, png::BitDepth::Eight) => ExtendedColorType::Rgb8, 205| 392| (png::ColorType::Rgb, png::BitDepth::Sixteen) => ExtendedColorType::Rgb16, 206| 0| (png::ColorType::Rgba, png::BitDepth::One) => ExtendedColorType::Rgba1, 207| 0| (png::ColorType::Rgba, png::BitDepth::Two) => ExtendedColorType::Rgba2, 208| 0| (png::ColorType::Rgba, png::BitDepth::Four) => ExtendedColorType::Rgba4, 209| 234| (png::ColorType::Rgba, png::BitDepth::Eight) => ExtendedColorType::Rgba8, 210| 243| (png::ColorType::Rgba, png::BitDepth::Sixteen) => ExtendedColorType::Rgba16, 211| 879| (png::ColorType::Indexed, png::BitDepth::One) => ExtendedColorType::Unknown(1), 212| 44| (png::ColorType::Indexed, png::BitDepth::Two) => ExtendedColorType::Unknown(2), 213| 34| (png::ColorType::Indexed, png::BitDepth::Four) => ExtendedColorType::Unknown(4), 214| 100| (png::ColorType::Indexed, png::BitDepth::Eight) => ExtendedColorType::Unknown(8), 215| 0| (png::ColorType::Indexed, png::BitDepth::Sixteen) => ExtendedColorType::Unknown(16), 216| | } 217| 6.00k| } _RNvMNtNtCs3aXgM11XBGX_5image6codecs3pngINtB2_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE21text_decompress_limitB6_: 221| 12.4k| fn text_decompress_limit(&mut self) -> usize { 222| 12.4k| let max = png::text_metadata::DECOMPRESSION_LIMIT as u64; 223| 12.4k| self.limits.max_alloc.unwrap_or(max).min(max) as usize 224| 12.4k| } _RNvMNtNtCs3aXgM11XBGX_5image6codecs3pngINtB2_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE24ensure_reader_and_headerB6_: 67| 52.5k| fn ensure_reader_and_header(&mut self) -> ImageResult<&mut png::Reader> { 68| 52.5k| if self.reader.is_some() { 69| | // We do this for borrow-checking issues, do not borrow self outside the conditional 70| | // branch. So the None/Err case here is not reachable. 71| 42.9k| return self.reader.as_mut().ok_or_else(|| unreachable!()); 72| 9.65k| } 73| | 74| 9.65k| let Some(mut decoder) = self.decoder.take() else { 75| 0| return Err(reader_finished_already()); 76| | }; 77| | 78| 9.65k| self.limits.check_support(&crate::LimitSupport::default())?; 79| | 80| 9.65k| let info = decoder.read_header_info().map_err(ImageError::from_png)?; 81| 9.37k| self.limits.check_dimensions(info.width, info.height)?; 82| | 83| | // By default the PNG decoder will scale 16 bpc to 8 bpc, so custom 84| | // transformations must be set. EXPAND preserves the default behavior 85| | // expanding bpc < 8 to 8 bpc. 86| 9.37k| decoder.set_transformations(png::Transformations::EXPAND); 87| 9.37k| let reader = decoder.read_info().map_err(ImageError::from_png)?; 88| 6.23k| let (color_type, bits) = reader.output_color_type(); 89| | 90| 6.23k| let color_type = match (color_type, bits) { 91| 2.29k| (png::ColorType::Grayscale, png::BitDepth::Eight) => ColorType::L8, 92| 699| (png::ColorType::Grayscale, png::BitDepth::Sixteen) => ColorType::L16, 93| 346| (png::ColorType::GrayscaleAlpha, png::BitDepth::Eight) => ColorType::La8, 94| 215| (png::ColorType::GrayscaleAlpha, png::BitDepth::Sixteen) => ColorType::La16, 95| 1.66k| (png::ColorType::Rgb, png::BitDepth::Eight) => ColorType::Rgb8, 96| 397| (png::ColorType::Rgb, png::BitDepth::Sixteen) => ColorType::Rgb16, 97| 356| (png::ColorType::Rgba, png::BitDepth::Eight) => ColorType::Rgba8, 98| 251| (png::ColorType::Rgba, png::BitDepth::Sixteen) => ColorType::Rgba16, 99| | 100| | (png::ColorType::Grayscale, png::BitDepth::One) => { 101| 0| return Err(unsupported_color(ExtendedColorType::L1)) 102| | } 103| | (png::ColorType::GrayscaleAlpha, png::BitDepth::One) => { 104| 0| return Err(unsupported_color(ExtendedColorType::La1)) 105| | } 106| | (png::ColorType::Rgb, png::BitDepth::One) => { 107| 0| return Err(unsupported_color(ExtendedColorType::Rgb1)) 108| | } 109| | (png::ColorType::Rgba, png::BitDepth::One) => { 110| 0| return Err(unsupported_color(ExtendedColorType::Rgba1)) 111| | } 112| | 113| | (png::ColorType::Grayscale, png::BitDepth::Two) => { 114| 0| return Err(unsupported_color(ExtendedColorType::L2)) 115| | } 116| | (png::ColorType::GrayscaleAlpha, png::BitDepth::Two) => { 117| 0| return Err(unsupported_color(ExtendedColorType::La2)) 118| | } 119| | (png::ColorType::Rgb, png::BitDepth::Two) => { 120| 0| return Err(unsupported_color(ExtendedColorType::Rgb2)) 121| | } 122| | (png::ColorType::Rgba, png::BitDepth::Two) => { 123| 0| return Err(unsupported_color(ExtendedColorType::Rgba2)) 124| | } 125| | 126| | (png::ColorType::Grayscale, png::BitDepth::Four) => { 127| 0| return Err(unsupported_color(ExtendedColorType::L4)) 128| | } 129| | (png::ColorType::GrayscaleAlpha, png::BitDepth::Four) => { 130| 0| return Err(unsupported_color(ExtendedColorType::La4)) 131| | } 132| | (png::ColorType::Rgb, png::BitDepth::Four) => { 133| 0| return Err(unsupported_color(ExtendedColorType::Rgb4)) 134| | } 135| | (png::ColorType::Rgba, png::BitDepth::Four) => { 136| 0| return Err(unsupported_color(ExtendedColorType::Rgba4)) 137| | } 138| | 139| 0| (png::ColorType::Indexed, bits) => { 140| 0| return Err(unsupported_color(ExtendedColorType::Unknown(bits as u8))) 141| | } 142| | }; 143| | 144| 6.23k| self.color_type = color_type; 145| 6.23k| Ok(self.reader.insert(reader)) 146| 52.5k| } _RNvMNtNtCs3aXgM11XBGX_5image6codecs3pngINtB2_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE3newB6_: 48| 9.65k| pub fn new(r: R) -> PngDecoder { 49| 9.65k| Self::with_limits(r, Limits::no_limits()) 50| 9.65k| } _RNvXs_NtNtCs3aXgM11XBGX_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder10read_imageB8_: 372| 6.00k| fn read_image(&mut self, buf: &mut [u8]) -> ImageResult { 373| 6.00k| let layout = self.prepare_image()?; 374| 6.00k| assert_eq!(u64::try_from(buf.len()), Ok(layout.total_bytes())); 375| | 376| 6.00k| let reader = self.ensure_reader_and_header()?; 377| 6.00k| let original_color_type = Self::color_type_info(reader.info()); 378| 6.00k| reader.next_frame(buf).map_err(ImageError::from_png)?; 379| | 380| 1.98k| big_endian_to_native_endian(buf, layout.layout.color); 381| | 382| 1.98k| Ok(DecodedImageAttributes { 383| 1.98k| original_color_type: Some(original_color_type), 384| 1.98k| ..DecodedImageAttributes::default() 385| 1.98k| }) 386| 6.00k| } _RNvXs_NtNtCs3aXgM11XBGX_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder10set_limitsB8_: 388| 9.65k| fn set_limits(&mut self, limits: Limits) -> ImageResult<()> { 389| 9.65k| limits.check_support(&crate::LimitSupport::default())?; 390| | 391| 9.65k| if let Some(decoder) = &mut self.decoder { 392| 9.65k| decoder.set_limits(png::Limits { 393| 9.65k| bytes: match limits.max_alloc { 394| 0| None => usize::MAX, 395| 9.65k| Some(limit) => limit.try_into().unwrap_or(usize::MAX), 396| | }, 397| | }); 398| | 399| 9.65k| self.limits = limits; 400| 9.65k| Ok(()) 401| | } else { 402| 0| Err(decoding_started_already()) 403| | } 404| 9.65k| } _RNvXs_NtNtCs3aXgM11XBGX_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder11icc_profileB8_: 307| 6.23k| fn icc_profile(&mut self) -> ImageResult>> { 308| 6.23k| let reader = self.ensure_reader_and_header()?; 309| 6.23k| Ok(reader.info().icc_profile.as_ref().map(|x| x.to_vec())) 310| 6.23k| } _RNvXs_NtNtCs3aXgM11XBGX_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder12xmp_metadataB8_: 317| 6.23k| fn xmp_metadata(&mut self) -> ImageResult>> { 318| 6.23k| let decompression_limit = self.text_decompress_limit(); 319| 6.23k| let reader = self.ensure_reader_and_header()?; 320| | 321| 6.23k| if let Some(mut itx_chunk) = reader 322| 6.23k| .info() 323| 6.23k| .utf8_text 324| 6.23k| .iter() 325| 6.23k| .find(|chunk| chunk.keyword == XMP_KEY) 326| 6.23k| .cloned() 327| | { 328| 14| itx_chunk 329| 14| .decompress_text_with_limit(decompression_limit) 330| 14| .map_err(ImageError::from_png)?; 331| 9| return itx_chunk 332| 9| .get_text() 333| 9| .map(|text| Some(text.into_bytes())) 334| 9| .map_err(ImageError::from_png); 335| 6.21k| } 336| | 337| 6.21k| Ok(None) 338| 6.23k| } _RNvXs_NtNtCs3aXgM11XBGX_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder13exif_metadataB8_: 312| 6.23k| fn exif_metadata(&mut self) -> ImageResult>> { 313| 6.23k| let reader = self.ensure_reader_and_header()?; 314| 6.23k| Ok(reader.info().exif_metadata.as_ref().map(|x| x.to_vec())) 315| 6.23k| } _RNvXs_NtNtCs3aXgM11XBGX_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder13iptc_metadataB8_: 340| 6.23k| fn iptc_metadata(&mut self) -> ImageResult>> { 341| 6.23k| let decompression_limit = self.text_decompress_limit(); 342| 6.23k| let reader = self.ensure_reader_and_header()?; 343| | 344| 6.23k| if let Some(mut text_chunk) = reader 345| 6.23k| .info() 346| 6.23k| .compressed_latin1_text 347| 6.23k| .iter() 348| 6.23k| .find(|chunk| IPTC_KEYS.iter().any(|key| chunk.keyword.contains(key))) 349| 6.23k| .cloned() 350| | { 351| 44| text_chunk 352| 44| .decompress_text_with_limit(decompression_limit) 353| 44| .map_err(ImageError::from_png)?; 354| 17| return text_chunk 355| 17| .get_text() 356| 17| .map(|text| Some(text.into_bytes())) 357| 17| .map_err(ImageError::from_png); 358| 6.18k| } 359| | 360| 6.18k| if let Some(text_chunk) = reader 361| 6.18k| .info() 362| 6.18k| .uncompressed_latin1_text 363| 6.18k| .iter() 364| 6.18k| .find(|chunk| IPTC_KEYS.iter().any(|key| chunk.keyword.contains(key))) 365| 6.18k| .cloned() 366| | { 367| 12| return Ok(Some(text_chunk.text.into_bytes())); 368| 6.17k| } 369| 6.17k| Ok(None) 370| 6.23k| } _RNvXs_NtNtCs3aXgM11XBGX_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder13prepare_imageB8_: 280| 21.6k| fn prepare_image(&mut self) -> ImageResult { 281| 21.6k| let reader = self.ensure_reader_and_header()?; 282| 18.2k| let (width, height) = reader.info().size(); 283| 18.2k| Ok(DecoderPreparedImage::new(width, height, self.color_type)) 284| 21.6k| } _RNvXs_NtNtCs3aXgM11XBGX_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder17format_attributesB8_: 286| 10.2k| fn format_attributes(&self) -> FormatAttributes { 287| 10.2k| FormatAttributes { 288| 10.2k| // is any sort of iTXT chunk. 289| 10.2k| // FIXME: we do not collect these in advance. 290| 10.2k| xmp: DecodedMetadataHint::InHeader, 291| 10.2k| // is any sort of iTXT chunk. 292| 10.2k| // FIXME: we do not collect these in advance. 293| 10.2k| iptc: DecodedMetadataHint::InHeader, 294| 10.2k| // see iCCP chunk order. 295| 10.2k| icc: DecodedMetadataHint::InHeader, 296| 10.2k| // see eXIf chunk order. 297| 10.2k| exif: DecodedMetadataHint::InHeader, 298| 10.2k| ..FormatAttributes::default() 299| 10.2k| } 300| 10.2k| } _RNvNtNtCs3aXgM11XBGX_5image6codecs3png27big_endian_to_native_endian: 266| 1.98k|fn big_endian_to_native_endian(buf: &mut [u8], color: ColorType) { 267| 1.98k| let bytes_per_channel = color.bytes_per_pixel() / color.channel_count(); 268| | 269| 1.98k| match bytes_per_channel { 270| 1.67k| 1 => (), // No reodering necessary for u8 271| 316| 2 => buf.as_chunks_mut::<2>().0.iter_mut().for_each(|c| { 272| | *c = u16::from_be_bytes(*c).to_ne_bytes(); 273| | }), 274| | // not emitted by png crate 275| 0| _ => unreachable!(), 276| | } 277| 1.98k|} _RNvMNtCs3aXgM11XBGX_5image5colorNtB2_9ColorType13channel_count: 89| 1.98k| pub fn channel_count(self) -> u8 { 90| 1.98k| let e: ExtendedColorType = self.into(); 91| 1.98k| e.channel_count() 92| 1.98k| } _RNvMNtCs3aXgM11XBGX_5image5colorNtB2_9ColorType15bytes_per_pixel: 47| 20.2k| pub fn bytes_per_pixel(self) -> u8 { 48| 20.2k| match self { 49| 7.55k| ColorType::L8 => 1, 50| 3.39k| ColorType::L16 | ColorType::La8 => 2, 51| 5.57k| ColorType::Rgb8 => 3, 52| 1.74k| ColorType::Rgba8 | ColorType::La16 | ColorType::L32F => 4, 53| 1.19k| ColorType::Rgb16 => 6, 54| 755| ColorType::Rgba16 | ColorType::La32F => 8, 55| 0| ColorType::Rgb32F => 3 * 4, 56| 0| ColorType::Rgba32F => 4 * 4, 57| | } 58| 20.2k| } _RNvMs_NtCs3aXgM11XBGX_5image5colorNtB4_17ExtendedColorType13channel_count: 186| 1.98k| pub fn channel_count(self) -> u8 { 187| 1.98k| match self { 188| | ExtendedColorType::A8 189| | | ExtendedColorType::L1 190| | | ExtendedColorType::L2 191| | | ExtendedColorType::L4 192| | | ExtendedColorType::L8 193| | | ExtendedColorType::L16 194| | | ExtendedColorType::L32F 195| 1.08k| | ExtendedColorType::Unknown(_) => 1, 196| | ExtendedColorType::La1 197| | | ExtendedColorType::La2 198| | | ExtendedColorType::La4 199| | | ExtendedColorType::La8 200| | | ExtendedColorType::La16 201| 26| | ExtendedColorType::La32F => 2, 202| | ExtendedColorType::Rgb1 203| | | ExtendedColorType::Rgb2 204| | | ExtendedColorType::Rgb4 205| | | ExtendedColorType::Rgb5x1 206| | | ExtendedColorType::Rgb8 207| | | ExtendedColorType::Rgb16 208| | | ExtendedColorType::Rgb32F 209| | | ExtendedColorType::YCbCr8 210| 814| | ExtendedColorType::Bgr8 => 3, 211| | ExtendedColorType::Rgba1 212| | | ExtendedColorType::Rgba2 213| | | ExtendedColorType::Rgba4 214| | | ExtendedColorType::Rgba8 215| | | ExtendedColorType::Rgba16 216| | | ExtendedColorType::Rgba32F 217| | | ExtendedColorType::Bgra8 218| | | ExtendedColorType::Cmyk8 219| 62| | ExtendedColorType::Cmyk16 => 4, 220| | } 221| 1.98k| } _RNvXs0_NtCs3aXgM11XBGX_5image5colorNtB5_17ExtendedColorTypeINtNtCs6SNw0SRvItZ_4core7convert4FromNtB5_9ColorTypeE4from: 316| 1.98k| fn from(c: ColorType) -> Self { 317| 1.98k| match c { 318| 807| ColorType::L8 => ExtendedColorType::L8, 319| 18| ColorType::La8 => ExtendedColorType::La8, 320| 798| ColorType::Rgb8 => ExtendedColorType::Rgb8, 321| 50| ColorType::Rgba8 => ExtendedColorType::Rgba8, 322| 280| ColorType::L16 => ExtendedColorType::L16, 323| 8| ColorType::La16 => ExtendedColorType::La16, 324| 16| ColorType::Rgb16 => ExtendedColorType::Rgb16, 325| 12| ColorType::Rgba16 => ExtendedColorType::Rgba16, 326| 0| ColorType::L32F => ExtendedColorType::L32F, 327| 0| ColorType::La32F => ExtendedColorType::La32F, 328| 0| ColorType::Rgb32F => ExtendedColorType::Rgb32F, 329| 0| ColorType::Rgba32F => ExtendedColorType::Rgba32F, 330| | } 331| 1.98k| } _RINvMs_NtCs3aXgM11XBGX_5image5errorNtB5_13DecodingError3newNtNtNtCshdzP3jLBsmJ_3png7decoder6stream13DecodingErrorEB7_: 226| 1.85k| pub fn new(format: ImageFormatHint, err: impl Into>) -> Self { 227| 1.85k| DecodingError { 228| 1.85k| format, 229| 1.85k| underlying: Some(err.into()), 230| 1.85k| } 231| 1.85k| } _RNvMs2_NtCs3aXgM11XBGX_5image5errorNtB5_10LimitError9from_kind: 298| 303| pub fn from_kind(kind: LimitErrorKind) -> Self { 299| 303| LimitError { kind } 300| 303| } _RNvXs6_NtCs3aXgM11XBGX_5image5errorNtB5_15ImageFormatHintINtNtCs6SNw0SRvItZ_4core7convert4FromNtNtNtB7_2io6format11ImageFormatE4from: 328| 1.85k| fn from(format: ImageFormat) -> Self { 329| 1.85k| ImageFormatHint::Exact(format) 330| 1.85k| } _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16check_image_fits0Bb_: 635| 798| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_len0Bb_: 640| 798| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_lens_0Bb_: 641| 798| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color3RgbtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16check_image_fits0Bb_: 635| 16| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color3RgbtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_len0Bb_: 640| 16| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color3RgbtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_lens_0Bb_: 641| 16| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4LumahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16check_image_fits0Bb_: 635| 807| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4LumahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_len0Bb_: 640| 807| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4LumahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_lens_0Bb_: 641| 807| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4LumatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16check_image_fits0Bb_: 635| 280| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4LumatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_len0Bb_: 640| 280| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4LumatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_lens_0Bb_: 641| 280| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16check_image_fits0Bb_: 635| 50| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_len0Bb_: 640| 50| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_lens_0Bb_: 641| 50| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4RgbatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16check_image_fits0Bb_: 635| 12| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4RgbatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_len0Bb_: 640| 12| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4RgbatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_lens_0Bb_: 641| 12| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color5LumaAhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16check_image_fits0Bb_: 635| 18| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color5LumaAhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_len0Bb_: 640| 18| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color5LumaAhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_lens_0Bb_: 641| 18| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16check_image_fits0Bb_: 635| 8| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_len0Bb_: 640| 8| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_lens_0Bb_: 641| 8| .and_then(|size| size.checked_mul(height as usize)) _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16check_image_fitsB9_: 633| 798| fn check_image_fits(width: u32, height: u32, len: usize) -> bool { 634| 798| let checked_len = Self::image_buffer_len(width, height); 635| 798| checked_len.is_some_and(|min_len| min_len <= len) 636| 798| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_lenB9_: 638| 798| fn image_buffer_len(width: u32, height: u32) -> Option { 639| 798| Some(

::CHANNEL_COUNT as usize) 640| 798| .and_then(|size| size.checked_mul(width as usize)) 641| 798| .and_then(|size| size.checked_mul(height as usize)) 642| 798| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE8from_rawB9_: 511| 798| pub fn from_raw(width: u32, height: u32, buf: Container) -> Option> { 512| 798| if Self::check_image_fits(width, height, buf.len()) { 513| 798| Some(ImageBuffer { 514| 798| data: buf, 515| 798| width, 516| 798| height, 517| 798| color: Cicp::SRGB.into_rgb(), 518| 798| _phantom: PhantomData, 519| 798| }) 520| | } else { 521| 0| None 522| | } 523| 798| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16check_image_fitsB9_: 633| 16| fn check_image_fits(width: u32, height: u32, len: usize) -> bool { 634| 16| let checked_len = Self::image_buffer_len(width, height); 635| 16| checked_len.is_some_and(|min_len| min_len <= len) 636| 16| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_lenB9_: 638| 16| fn image_buffer_len(width: u32, height: u32) -> Option { 639| 16| Some(

::CHANNEL_COUNT as usize) 640| 16| .and_then(|size| size.checked_mul(width as usize)) 641| 16| .and_then(|size| size.checked_mul(height as usize)) 642| 16| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE8from_rawB9_: 511| 16| pub fn from_raw(width: u32, height: u32, buf: Container) -> Option> { 512| 16| if Self::check_image_fits(width, height, buf.len()) { 513| 16| Some(ImageBuffer { 514| 16| data: buf, 515| 16| width, 516| 16| height, 517| 16| color: Cicp::SRGB.into_rgb(), 518| 16| _phantom: PhantomData, 519| 16| }) 520| | } else { 521| 0| None 522| | } 523| 16| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4LumahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16check_image_fitsB9_: 633| 807| fn check_image_fits(width: u32, height: u32, len: usize) -> bool { 634| 807| let checked_len = Self::image_buffer_len(width, height); 635| 807| checked_len.is_some_and(|min_len| min_len <= len) 636| 807| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4LumahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_lenB9_: 638| 807| fn image_buffer_len(width: u32, height: u32) -> Option { 639| 807| Some(

::CHANNEL_COUNT as usize) 640| 807| .and_then(|size| size.checked_mul(width as usize)) 641| 807| .and_then(|size| size.checked_mul(height as usize)) 642| 807| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4LumahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE8from_rawB9_: 511| 807| pub fn from_raw(width: u32, height: u32, buf: Container) -> Option> { 512| 807| if Self::check_image_fits(width, height, buf.len()) { 513| 807| Some(ImageBuffer { 514| 807| data: buf, 515| 807| width, 516| 807| height, 517| 807| color: Cicp::SRGB.into_rgb(), 518| 807| _phantom: PhantomData, 519| 807| }) 520| | } else { 521| 0| None 522| | } 523| 807| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4LumatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16check_image_fitsB9_: 633| 280| fn check_image_fits(width: u32, height: u32, len: usize) -> bool { 634| 280| let checked_len = Self::image_buffer_len(width, height); 635| 280| checked_len.is_some_and(|min_len| min_len <= len) 636| 280| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4LumatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_lenB9_: 638| 280| fn image_buffer_len(width: u32, height: u32) -> Option { 639| 280| Some(

::CHANNEL_COUNT as usize) 640| 280| .and_then(|size| size.checked_mul(width as usize)) 641| 280| .and_then(|size| size.checked_mul(height as usize)) 642| 280| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4LumatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE8from_rawB9_: 511| 280| pub fn from_raw(width: u32, height: u32, buf: Container) -> Option> { 512| 280| if Self::check_image_fits(width, height, buf.len()) { 513| 280| Some(ImageBuffer { 514| 280| data: buf, 515| 280| width, 516| 280| height, 517| 280| color: Cicp::SRGB.into_rgb(), 518| 280| _phantom: PhantomData, 519| 280| }) 520| | } else { 521| 0| None 522| | } 523| 280| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16check_image_fitsB9_: 633| 50| fn check_image_fits(width: u32, height: u32, len: usize) -> bool { 634| 50| let checked_len = Self::image_buffer_len(width, height); 635| 50| checked_len.is_some_and(|min_len| min_len <= len) 636| 50| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_lenB9_: 638| 50| fn image_buffer_len(width: u32, height: u32) -> Option { 639| 50| Some(

::CHANNEL_COUNT as usize) 640| 50| .and_then(|size| size.checked_mul(width as usize)) 641| 50| .and_then(|size| size.checked_mul(height as usize)) 642| 50| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE8from_rawB9_: 511| 50| pub fn from_raw(width: u32, height: u32, buf: Container) -> Option> { 512| 50| if Self::check_image_fits(width, height, buf.len()) { 513| 50| Some(ImageBuffer { 514| 50| data: buf, 515| 50| width, 516| 50| height, 517| 50| color: Cicp::SRGB.into_rgb(), 518| 50| _phantom: PhantomData, 519| 50| }) 520| | } else { 521| 0| None 522| | } 523| 50| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16check_image_fitsB9_: 633| 12| fn check_image_fits(width: u32, height: u32, len: usize) -> bool { 634| 12| let checked_len = Self::image_buffer_len(width, height); 635| 12| checked_len.is_some_and(|min_len| min_len <= len) 636| 12| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_lenB9_: 638| 12| fn image_buffer_len(width: u32, height: u32) -> Option { 639| 12| Some(

::CHANNEL_COUNT as usize) 640| 12| .and_then(|size| size.checked_mul(width as usize)) 641| 12| .and_then(|size| size.checked_mul(height as usize)) 642| 12| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE8from_rawB9_: 511| 12| pub fn from_raw(width: u32, height: u32, buf: Container) -> Option> { 512| 12| if Self::check_image_fits(width, height, buf.len()) { 513| 12| Some(ImageBuffer { 514| 12| data: buf, 515| 12| width, 516| 12| height, 517| 12| color: Cicp::SRGB.into_rgb(), 518| 12| _phantom: PhantomData, 519| 12| }) 520| | } else { 521| 0| None 522| | } 523| 12| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16check_image_fitsB9_: 633| 18| fn check_image_fits(width: u32, height: u32, len: usize) -> bool { 634| 18| let checked_len = Self::image_buffer_len(width, height); 635| 18| checked_len.is_some_and(|min_len| min_len <= len) 636| 18| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_lenB9_: 638| 18| fn image_buffer_len(width: u32, height: u32) -> Option { 639| 18| Some(

::CHANNEL_COUNT as usize) 640| 18| .and_then(|size| size.checked_mul(width as usize)) 641| 18| .and_then(|size| size.checked_mul(height as usize)) 642| 18| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE8from_rawB9_: 511| 18| pub fn from_raw(width: u32, height: u32, buf: Container) -> Option> { 512| 18| if Self::check_image_fits(width, height, buf.len()) { 513| 18| Some(ImageBuffer { 514| 18| data: buf, 515| 18| width, 516| 18| height, 517| 18| color: Cicp::SRGB.into_rgb(), 518| 18| _phantom: PhantomData, 519| 18| }) 520| | } else { 521| 0| None 522| | } 523| 18| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16check_image_fitsB9_: 633| 8| fn check_image_fits(width: u32, height: u32, len: usize) -> bool { 634| 8| let checked_len = Self::image_buffer_len(width, height); 635| 8| checked_len.is_some_and(|min_len| min_len <= len) 636| 8| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_lenB9_: 638| 8| fn image_buffer_len(width: u32, height: u32) -> Option { 639| 8| Some(

::CHANNEL_COUNT as usize) 640| 8| .and_then(|size| size.checked_mul(width as usize)) 641| 8| .and_then(|size| size.checked_mul(height as usize)) 642| 8| } _RNvMsn_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE8from_rawB9_: 511| 8| pub fn from_raw(width: u32, height: u32, buf: Container) -> Option> { 512| 8| if Self::check_image_fits(width, height, buf.len()) { 513| 8| Some(ImageBuffer { 514| 8| data: buf, 515| 8| width, 516| 8| height, 517| 8| color: Cicp::SRGB.into_rgb(), 518| 8| _phantom: PhantomData, 519| 8| }) 520| | } else { 521| 0| None 522| | } 523| 8| } _RNvMsr_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE17set_rgb_primariesB9_: 1076| 798| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 798| self.color.primaries = color; 1078| 798| } _RNvMsr_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE21set_transfer_functionB9_: 1088| 798| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 798| self.color.transfer = tf; 1090| 798| } _RNvMsr_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE17set_rgb_primariesB9_: 1076| 16| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 16| self.color.primaries = color; 1078| 16| } _RNvMsr_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE21set_transfer_functionB9_: 1088| 16| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 16| self.color.transfer = tf; 1090| 16| } _RNvMsr_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4LumahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE17set_rgb_primariesB9_: 1076| 807| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 807| self.color.primaries = color; 1078| 807| } _RNvMsr_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4LumahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE21set_transfer_functionB9_: 1088| 807| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 807| self.color.transfer = tf; 1090| 807| } _RNvMsr_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4LumatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE17set_rgb_primariesB9_: 1076| 280| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 280| self.color.primaries = color; 1078| 280| } _RNvMsr_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4LumatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE21set_transfer_functionB9_: 1088| 280| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 280| self.color.transfer = tf; 1090| 280| } _RNvMsr_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE17set_rgb_primariesB9_: 1076| 50| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 50| self.color.primaries = color; 1078| 50| } _RNvMsr_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE21set_transfer_functionB9_: 1088| 50| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 50| self.color.transfer = tf; 1090| 50| } _RNvMsr_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE17set_rgb_primariesB9_: 1076| 12| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 12| self.color.primaries = color; 1078| 12| } _RNvMsr_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE21set_transfer_functionB9_: 1088| 12| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 12| self.color.transfer = tf; 1090| 12| } _RNvMsr_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE17set_rgb_primariesB9_: 1076| 18| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 18| self.color.primaries = color; 1078| 18| } _RNvMsr_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE21set_transfer_functionB9_: 1088| 18| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 18| self.color.transfer = tf; 1090| 18| } _RNvMsr_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE17set_rgb_primariesB9_: 1076| 8| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 8| self.color.primaries = color; 1078| 8| } _RNvMsr_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE21set_transfer_functionB9_: 1088| 8| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 8| self.color.transfer = tf; 1090| 8| } _RNvXst_NtNtCs3aXgM11XBGX_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEENtNtCs6SNw0SRvItZ_4core7default7Default7defaultB9_: 1189| 9.65k| fn default() -> Self { 1190| 9.65k| Self { 1191| 9.65k| width: 0, 1192| 9.65k| height: 0, 1193| 9.65k| _phantom: PhantomData, 1194| 9.65k| color: Cicp::SRGB.into_rgb(), 1195| 9.65k| data: Default::default(), 1196| 9.65k| } 1197| 9.65k| } _RNvNtNtCs3aXgM11XBGX_5image6images8dynimage28load_from_memory_with_format: 1959| 9.65k|pub fn load_from_memory_with_format(buf: &[u8], format: ImageFormat) -> ImageResult { 1960| | // Note: this function (and `load_from_memory`) were supposed to be generic over `AsRef<[u8]>` 1961| | // so that we do not monomorphize copies of all our decoders unless some downsteam crate 1962| | // actually calls one of these functions. See https://github.com/image-rs/image/pull/2470. 1963| | // 1964| | // However the type inference break of this is apparently quite large in the ecosystem so for 1965| | // now they are unfortunately not. See https://github.com/image-rs/image/issues/2585. 1966| 9.65k| let b = io::Cursor::new(buf); 1967| 9.65k| free_functions::load(b, format) 1968| 9.65k|} _RNvMs_NtNtCs3aXgM11XBGX_5image6images8dynimageNtB4_12DynamicImage10decode_raw: 280| 6.00k| pub(crate) fn decode_raw( 281| 6.00k| &mut self, 282| 6.00k| decoder: &mut dyn ImageDecoder, 283| 6.00k| layout: DecoderPreparedImage, 284| 6.00k| ) -> ImageResult { 285| 6.00k| decoder_to_image(self, decoder, layout) 286| 6.00k| } _RNvMs_NtNtCs3aXgM11XBGX_5image6images8dynimageNtB4_12DynamicImage17set_rgb_primaries: 929| 1.98k| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 930| 1.98k| dynamic_map!(self, ref mut p, p.set_rgb_primaries(color)); 931| 1.98k| } _RNvMs_NtNtCs3aXgM11XBGX_5image6images8dynimageNtB4_12DynamicImage21set_transfer_function: 939| 1.98k| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 940| 1.98k| dynamic_map!(self, ref mut p, p.set_transfer_function(tf)); 941| 1.98k| } _RNvNtNtCs3aXgM11XBGX_5image6images8dynimage16decoder_to_image: 1793| 6.00k|pub(crate) fn decoder_to_image( 1794| 6.00k| image: &mut DynamicImage, 1795| 6.00k| decoder: &mut dyn ImageDecoder, 1796| 6.00k| layout: DecoderPreparedImage, 1797| 6.00k|) -> ImageResult { 1798| | let crate::ImageLayout { 1799| 6.00k| width: w, 1800| 6.00k| height: h, 1801| 6.00k| color: color_type, 1802| | .. 1803| 6.00k| } = layout.layout; 1804| | 1805| | let attr; 1806| | 1807| 6.00k| *image = match color_type { 1808| | ColorType::Rgb8 => { 1809| | let buf; 1810| 1.55k| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1811| 798| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgb8) 1812| | } 1813| | 1814| | ColorType::Rgba8 => { 1815| | let buf; 1816| 347| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1817| 50| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgba8) 1818| | } 1819| | 1820| | ColorType::L8 => { 1821| | let buf; 1822| 2.22k| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1823| 807| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLuma8) 1824| | } 1825| | 1826| | ColorType::La8 => { 1827| | let buf; 1828| 341| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1829| 18| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLumaA8) 1830| | } 1831| | 1832| | ColorType::Rgb16 => { 1833| | let buf; 1834| 389| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1835| 16| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgb16) 1836| | } 1837| | 1838| | ColorType::Rgba16 => { 1839| | let buf; 1840| 246| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1841| 12| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgba16) 1842| | } 1843| | 1844| | ColorType::Rgb32F => { 1845| | let buf; 1846| 0| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1847| 0| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgb32F) 1848| | } 1849| | 1850| | ColorType::Rgba32F => { 1851| | let buf; 1852| 0| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1853| 0| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgba32F) 1854| | } 1855| | 1856| | ColorType::L16 => { 1857| | let buf; 1858| 684| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1859| 280| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLuma16) 1860| | } 1861| | 1862| | ColorType::La16 => { 1863| | let buf; 1864| 211| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1865| 8| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLumaA16) 1866| | } 1867| | 1868| | ColorType::L32F => { 1869| | let buf; 1870| 0| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1871| 0| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLuma32F) 1872| | } 1873| | 1874| | ColorType::La32F => { 1875| | let buf; 1876| 0| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1877| 0| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLumaA32F) 1878| | } 1879| | } 1880| 1.98k| .ok_or_else(|| { 1881| | ImageError::Parameter(ParameterError::from_kind( 1882| | ParameterErrorKind::DimensionMismatch, 1883| | )) 1884| 0| })?; 1885| | 1886| | // Presume SRGB for now. This is the one we convert into in some decoders and the one that is 1887| | // most widely used in the wild. FIXME: add an API to decoder to indicate the color space as a 1888| | // CICP directly or through interpreting the ICC information. 1889| 1.98k| image.set_rgb_primaries(Cicp::SRGB.primaries); 1890| 1.98k| image.set_transfer_function(Cicp::SRGB.transfer); 1891| | 1892| 1.98k| Ok(attr) 1893| 6.00k|} _RNvXse_NtNtCs3aXgM11XBGX_5image6images8dynimageNtB5_12DynamicImageNtNtCs6SNw0SRvItZ_4core7default7Default7default: 1785| 9.65k| fn default() -> Self { 1786| 9.65k| Self::ImageRgba8(Default::default()) 1787| 9.65k| } _RNvMs1_NtCs3aXgM11XBGX_5image2ioNtB5_20DecoderPreparedImage11total_bytes: 146| 18.2k| pub fn total_bytes(&self) -> u64 { 147| 18.2k| self.layout.total_bytes() 148| 18.2k| } _RNvMs1_NtCs3aXgM11XBGX_5image2ioNtB5_20DecoderPreparedImage3new: 132| 18.2k| pub fn new(w: u32, h: u32, color: crate::ColorType) -> DecoderPreparedImage { 133| 18.2k| DecoderPreparedImage { 134| 18.2k| layout: ImageLayout::new(w, h, color), 135| 18.2k| } 136| 18.2k| } _RNvMs_NtCs3aXgM11XBGX_5image2ioNtB4_11ImageLayout11total_bytes: 91| 18.2k| pub fn total_bytes(&self) -> u64 { 92| 18.2k| let ImageLayout { width, height, .. } = *self; 93| 18.2k| let total_pixels = u64::from(width) * u64::from(height); 94| 18.2k| let bytes_per_pixel = u64::from(self.color.bytes_per_pixel()); 95| 18.2k| total_pixels.saturating_mul(bytes_per_pixel) 96| 18.2k| } _RNvMs_NtCs3aXgM11XBGX_5image2ioNtB4_11ImageLayout3new: 60| 18.2k| pub fn new(w: u32, h: u32, color: crate::ColorType) -> ImageLayout { 61| 18.2k| ImageLayout { 62| 18.2k| color, 63| 18.2k| width: w, 64| 18.2k| height: h, 65| 18.2k| } 66| 18.2k| } _RNvXs_NtNtCs3aXgM11XBGX_5image2io7decoderINtNtCshDtJu3Ru83O_5alloc5boxed3BoxDNtB4_12ImageDecoderEL_EB1d_10set_limitsB8_: 318| 9.65k| fn set_limits(&mut self, limits: crate::Limits) -> ImageResult<()> { 319| 9.65k| (**self).set_limits(limits) 320| 9.65k| } _RNvXs_NtNtCs3aXgM11XBGX_5image2io7decoderINtNtCshDtJu3Ru83O_5alloc5boxed3BoxDNtB4_12ImageDecoderEL_EB1d_13prepare_imageB8_: 297| 9.65k| fn prepare_image(&mut self) -> ImageResult { 298| 9.65k| (**self).prepare_image() 299| 9.65k| } _RNvXs_NtNtCs3aXgM11XBGX_5image2io7decoderINtNtCshDtJu3Ru83O_5alloc5boxed3BoxDNtB4_12ImageDecoderEL_EB1d_17format_attributesB8_: 294| 6.23k| fn format_attributes(&self) -> FormatAttributes { 295| 6.23k| (**self).format_attributes() 296| 6.23k| } _RINvNtNtCs3aXgM11XBGX_5image2io14free_functions4loadINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEECsjL4BTT8Uzs_17fuzzer_script_png: 22| 9.65k|pub fn load(r: R, format: ImageFormat) -> ImageResult { 23| 9.65k| let mut reader = ImageReaderOptions::new(r); 24| 9.65k| reader.set_format(format); 25| 9.65k| reader.decode() 26| 9.65k|} _RINvNtNtCs3aXgM11XBGX_5image2io14free_functions14decoder_to_vechDNtNtB4_7decoder12ImageDecoderEL_EB6_: 170| 4.47k|pub(crate) fn decoder_to_vec( 171| 4.47k| decoder: &mut (impl ImageDecoder + ?Sized), 172| 4.47k|) -> ImageResult<(Vec, DecodedImageAttributes)> 173| 4.47k|where 174| 4.47k| T: crate::traits::Primitive + bytemuck::Pod, 175| |{ 176| 4.47k| let total_bytes = usize::try_from(decoder.prepare_image()?.total_bytes()); 177| 4.47k| if total_bytes.is_err() || total_bytes.unwrap() > isize::MAX as usize { 178| 0| return Err(ImageError::Limits(LimitError::from_kind( 179| 0| LimitErrorKind::InsufficientMemory, 180| 0| ))); 181| 4.47k| } 182| | 183| 4.47k| let mut buf = vec![num_traits::Zero::zero(); total_bytes.unwrap() / size_of::()]; 184| 4.47k| let attr = decoder.read_image(bytemuck::cast_slice_mut(buf.as_mut_slice()))?; 185| 1.67k| Ok((buf, attr)) 186| 4.47k|} _RINvNtNtCs3aXgM11XBGX_5image2io14free_functions14decoder_to_vectDNtNtB4_7decoder12ImageDecoderEL_EB6_: 170| 1.53k|pub(crate) fn decoder_to_vec( 171| 1.53k| decoder: &mut (impl ImageDecoder + ?Sized), 172| 1.53k|) -> ImageResult<(Vec, DecodedImageAttributes)> 173| 1.53k|where 174| 1.53k| T: crate::traits::Primitive + bytemuck::Pod, 175| |{ 176| 1.53k| let total_bytes = usize::try_from(decoder.prepare_image()?.total_bytes()); 177| 1.53k| if total_bytes.is_err() || total_bytes.unwrap() > isize::MAX as usize { 178| 0| return Err(ImageError::Limits(LimitError::from_kind( 179| 0| LimitErrorKind::InsufficientMemory, 180| 0| ))); 181| 1.53k| } 182| | 183| 1.53k| let mut buf = vec![num_traits::Zero::zero(); total_bytes.unwrap() / size_of::()]; 184| 1.53k| let attr = decoder.read_image(bytemuck::cast_slice_mut(buf.as_mut_slice()))?; 185| 316| Ok((buf, attr)) 186| 1.53k|} _RNvMNtNtCs3aXgM11XBGX_5image2io17image_reader_typeINtB2_18ImageReaderOptionsINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE10set_formatCsjL4BTT8Uzs_17fuzzer_script_png: 139| 9.65k| pub fn set_format(&mut self, format: ImageFormat) { 140| 9.65k| self.format = Some(Format::BuiltIn(format)); 141| 9.65k| } _RNCNvMs3_NtNtCs3aXgM11XBGX_5image2io17image_reader_typeNtB7_20DecodedImageMetadata13apply_metdata0Bb_: 937| 44| orientation = exif.and_then(|chunk| Orientation::from_exif_chunk(&chunk)); _RNvMNtNtCs3aXgM11XBGX_5image2io17image_reader_typeINtB2_18ImageReaderOptionsINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE11into_readerB6_: 257| 9.65k| pub fn into_reader(mut self) -> ImageResult> { 258| 9.65k| let format = self.require_format()?; 259| 9.65k| let decoder = Self::make_decoder(format, self.inner, self.spec_compliance)?; 260| 9.65k| let mut reader = ImageReader::from_decoder(decoder); 261| 9.65k| reader.set_limits(self.limits)?; 262| 9.65k| Ok(reader) 263| 9.65k| } _RNvMNtNtCs3aXgM11XBGX_5image2io17image_reader_typeINtB2_18ImageReaderOptionsINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE12make_decoderB6_: 176| 9.65k| fn make_decoder( 177| 9.65k| format: Format, 178| 9.65k| reader: R, 179| 9.65k| spec_compliance: SpecCompliance, 180| 9.65k| ) -> ImageResult> { 181| | #[allow(unused)] 182| | use crate::codecs::*; 183| | 184| 9.65k| let format = match format { 185| 9.65k| Format::BuiltIn(format) => format, 186| 0| Format::Extension(ext) => { 187| 0| if let Some(hook) = hooks::get_decoding_hook(&ext) { 188| 0| return hook(hooks::GenericReader::new(reader)); 189| 0| } 190| | 191| 0| ImageFormat::from_extension(&ext).ok_or(ImageError::Unsupported( 192| 0| ImageFormatHint::PathExtension(ext.into()).into(), 193| 0| ))? 194| | } 195| | }; 196| | 197| | #[allow(unreachable_patterns)] 198| | // Default is unreachable if all features are supported. 199| 9.65k| Ok(match format { 200| | #[cfg(feature = "avif-native")] 201| | ImageFormat::Avif => Box::new(avif::AvifDecoder::new(reader)?), 202| | #[cfg(feature = "png")] 203| 9.65k| ImageFormat::Png => Box::new(png::PngDecoder::new(reader)), 204| | #[cfg(feature = "gif")] 205| 0| ImageFormat::Gif => Box::new(gif::GifDecoder::new(reader)?), 206| | #[cfg(feature = "jpeg")] 207| 0| ImageFormat::Jpeg => Box::new(jpeg::JpegDecoder::with_spec_compliance( 208| 0| reader, 209| 0| spec_compliance, 210| 0| )), 211| | #[cfg(feature = "webp")] 212| 0| ImageFormat::WebP => Box::new(webp::WebPDecoder::new(reader)?), 213| | #[cfg(feature = "tiff")] 214| 0| ImageFormat::Tiff => Box::new(tiff::TiffDecoder::new(reader)?), 215| | #[cfg(feature = "tga")] 216| 0| ImageFormat::Tga => Box::new(tga::TgaDecoder::new(reader)?), 217| | #[cfg(feature = "bmp")] 218| 0| ImageFormat::Bmp => Box::new(bmp::BmpDecoder::with_spec_compliance( 219| 0| reader, 220| 0| spec_compliance, 221| 0| )?), 222| | #[cfg(feature = "ico")] 223| 0| ImageFormat::Ico => Box::new(ico::IcoDecoder::with_spec_compliance( 224| 0| reader, 225| 0| spec_compliance, 226| 0| )?), 227| | #[cfg(feature = "hdr")] 228| 0| ImageFormat::Hdr => Box::new(hdr::HdrDecoder::with_spec_compliance( 229| 0| reader, 230| 0| spec_compliance, 231| 0| )?), 232| | #[cfg(feature = "exr")] 233| 0| ImageFormat::OpenExr => Box::new(openexr::OpenExrDecoder::new(reader)?), 234| | #[cfg(feature = "pnm")] 235| 0| ImageFormat::Pnm => Box::new(pnm::PnmDecoder::new(reader)?), 236| | #[cfg(feature = "ff")] 237| 0| ImageFormat::Farbfeld => Box::new(farbfeld::FarbfeldDecoder::new(reader)?), 238| | #[cfg(feature = "qoi")] 239| 0| ImageFormat::Qoi => Box::new(qoi::QoiDecoder::new(reader)?), 240| 0| format => { 241| 0| return Err(ImageError::Unsupported( 242| 0| ImageFormatHint::Exact(format).into(), 243| 0| )); 244| | } 245| | }) 246| 9.65k| } _RNvMNtNtCs3aXgM11XBGX_5image2io17image_reader_typeINtB2_18ImageReaderOptionsINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE14require_formatB6_: 344| 9.65k| fn require_format(&mut self) -> ImageResult { 345| 9.65k| self.format.clone().ok_or_else(|| { 346| | ImageError::Unsupported(UnsupportedError::from_format_and_kind( 347| | ImageFormatHint::Unknown, 348| | UnsupportedErrorKind::Format(ImageFormatHint::Unknown), 349| | )) 350| | }) 351| 9.65k| } _RNvMNtNtCs3aXgM11XBGX_5image2io17image_reader_typeINtB2_18ImageReaderOptionsINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE3newB6_: 107| 9.65k| pub fn new(buffered_reader: R) -> Self { 108| 9.65k| ImageReaderOptions { 109| 9.65k| inner: buffered_reader, 110| 9.65k| format: None, 111| 9.65k| limits: Limits::default(), 112| 9.65k| spec_compliance: SpecCompliance::default(), 113| 9.65k| } 114| 9.65k| } _RNvMNtNtCs3aXgM11XBGX_5image2io17image_reader_typeINtB2_18ImageReaderOptionsINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE6decodeB6_: 339| 9.65k| pub fn decode(self) -> ImageResult { 340| 9.65k| let (image, _meta) = self.into_reader()?.decode()?; 341| 1.98k| Ok(image) 342| 9.65k| } _RNvMs0_NtNtCs3aXgM11XBGX_5image2io17image_reader_typeNtB5_13MetadataBlock11is_not_none: 433| 24.9k| fn is_not_none(&self) -> bool { 434| 24.9k| !matches!(self, MetadataBlock::None) 435| 24.9k| } _RNvMs0_NtNtCs3aXgM11XBGX_5image2io17image_reader_typeNtB5_13MetadataBlock3get: 437| 3.97k| fn get(&mut self) -> ImageResult>> { 438| 3.97k| match self { 439| 2.14k| MetadataBlock::None => Ok(None), 440| 1.83k| MetadataBlock::Ok(data) => Ok(Some(data.clone())), 441| 0| MetadataBlock::Err(err) => { 442| | // Doing a little dance to change the variant to ErrorTaken in-place. 443| 0| let replacement_err = ImageError::Parameter(ParameterError::from_kind( 444| 0| ParameterErrorKind::FailedAlready, 445| 0| )); 446| | 447| 0| let err = core::mem::replace(err, replacement_err); 448| | 449| 0| *self = if let ImageError::Unsupported(e) = &err { 450| 0| MetadataBlock::Unsupported(e.format_hint()) 451| | } else { 452| 0| MetadataBlock::ErrorTaken 453| | }; 454| | 455| 0| Err(err) 456| | } 457| 0| MetadataBlock::ErrorTaken => Err(ImageError::Parameter(ParameterError::from_kind( 458| 0| ParameterErrorKind::FailedAlready, 459| 0| ))), 460| 0| MetadataBlock::Unsupported(hint) => Err(ImageError::Unsupported( 461| 0| UnsupportedError::from_format_and_kind( 462| 0| hint.clone(), 463| 0| UnsupportedErrorKind::GenericFeature("metadata".to_string()), 464| 0| ), 465| 0| )), 466| | } 467| 3.97k| } _RNvMs2_NtNtCs3aXgM11XBGX_5image2io17image_reader_typeNtB5_11ImageReader10set_limits: 801| 9.65k| pub fn set_limits(&mut self, mut limits: Limits) -> ImageResult<()> { 802| 9.65k| if let Some(max_alloc) = &mut limits.max_alloc { 803| 9.65k| // We'll take half for ourselves, half to the decoder. 804| 9.65k| *max_alloc /= 2; 805| 9.65k| } 806| | 807| 9.65k| self.inner.set_limits(limits.clone())?; 808| 9.65k| self.limits = limits; 809| 9.65k| Ok(()) 810| 9.65k| } _RNvMs2_NtNtCs3aXgM11XBGX_5image2io17image_reader_typeNtB5_11ImageReader12from_decoder: 790| 9.65k| pub fn from_decoder(boxed: Box) -> Self { 791| 9.65k| ImageReader { 792| 9.65k| inner: boxed, 793| 9.65k| settings: ImageReaderSettings::default(), 794| 9.65k| limits: Limits::default(), 795| 9.65k| last_attributes: Default::default(), 796| 9.65k| metadata_buffers: MetadataBuffers::default(), 797| 9.65k| } 798| 9.65k| } _RNvMs2_NtNtCs3aXgM11XBGX_5image2io17image_reader_typeNtB5_11ImageReader18decode_to_dynimage: 541| 9.65k| pub(crate) fn decode_to_dynimage( 542| 9.65k| &mut self, 543| 9.65k| image: &mut DynamicImage, 544| 9.65k| ) -> ImageResult> { 545| 9.65k| let layout = self.inner.prepare_image()?; 546| 6.23k| self.fill_header_metadata_if_any(); 547| | 548| | // This is technically redundant but it's also cheap. 549| 6.23k| self.limits.check_layout_dimensions(&layout)?; 550| | // Check that we do not allocate a bigger buffer than we are allowed to 551| | // FIXME: should this rather go in `DynamicImage::from_decoder` somehow? 552| 6.23k| self.limits.reserve(layout.total_bytes())?; 553| | 554| | // Retrieve the raw image data as indicated by the layout. 555| 6.00k| self.last_attributes = image.decode_raw(self.inner.as_mut(), layout)?; 556| | 557| 1.98k| let mut meta = DecodedImageMetadata { 558| 1.98k| inner: self.inner.as_mut(), 559| 1.98k| attributes: &mut self.last_attributes, 560| 1.98k| metadata_buffers: &mut self.metadata_buffers, 561| 1.98k| }; 562| | 563| 1.98k| meta.apply_metdata(&self.settings, image)?; 564| | 565| 1.98k| Ok(meta) 566| 9.65k| } _RNvMs2_NtNtCs3aXgM11XBGX_5image2io17image_reader_typeNtB5_11ImageReader27fill_header_metadata_if_any: 658| 6.23k| fn fill_header_metadata_if_any(&mut self) { 659| | type MetadataFn<'a> = 660| | fn(&mut (dyn ImageDecoder + 'a)) -> Result>, ImageError>; 661| | 662| | // We retrieve `InHeader` metadata only once, before reading any our images. 663| 6.23k| let first_meta_retrieved = self.metadata_buffers.first_meta_retrieved; 664| 6.23k| let format_attrs = self.inner.format_attributes(); 665| | 666| 6.23k| let attributes = [ 667| 6.23k| ( 668| 6.23k| format_attrs.exif, 669| 6.23k| &mut self.metadata_buffers.exif, 670| 6.23k| ::exif_metadata as MetadataFn, 671| 6.23k| ), 672| 6.23k| ( 673| 6.23k| format_attrs.icc, 674| 6.23k| &mut self.metadata_buffers.icc, 675| 6.23k| ::icc_profile as MetadataFn, 676| 6.23k| ), 677| 6.23k| ( 678| 6.23k| format_attrs.xmp, 679| 6.23k| &mut self.metadata_buffers.xmp, 680| 6.23k| ::xmp_metadata as MetadataFn, 681| 6.23k| ), 682| 6.23k| ( 683| 6.23k| format_attrs.iptc, 684| 6.23k| &mut self.metadata_buffers.iptc, 685| 6.23k| ::iptc_metadata as MetadataFn, 686| 6.23k| ), 687| 6.23k| ]; 688| | 689| 31.1k| for (hint, buffer, getter) in attributes { 690| 24.9k| let should_buffer_now = match hint { 691| 24.9k| DecodedMetadataHint::InHeader => !first_meta_retrieved, 692| 0| DecodedMetadataHint::PerImage => true, 693| 0| DecodedMetadataHint::Unsupported | DecodedMetadataHint::None => false, 694| | }; 695| | 696| 24.9k| if !should_buffer_now { 697| 0| continue; 698| 24.9k| } 699| | 700| | // We might have already tried this and succeeded. Expect the same result as last time 701| | // but avoids the allocation associated with that. A repeated `None` should be cheap, 702| | // most probably. This holds for variants that retrieve it once. 703| 24.9k| if matches!(hint, DecodedMetadataHint::InHeader) && buffer.is_not_none() { 704| 0| continue; 705| 24.9k| } 706| | 707| 24.9k| match getter(self.inner.as_mut()) { 708| 22.9k| Ok(None) => *buffer = MetadataBlock::None, 709| 1.91k| Ok(Some(metadata)) => *buffer = MetadataBlock::Ok(metadata), 710| 32| Err(err) => { 711| 32| *buffer = MetadataBlock::Err(err); 712| 32| } 713| | } 714| | } 715| | 716| | // Note: on error we do not set this flag. You can try again. 717| 6.23k| self.metadata_buffers.first_meta_retrieved = true; 718| 6.23k| } _RNvMs2_NtNtCs3aXgM11XBGX_5image2io17image_reader_typeNtB5_11ImageReader6decode: 511| 9.65k| pub fn decode(&mut self) -> ImageResult<(DynamicImage, DecodedImageMetadata<'_>)> { 512| 9.65k| let mut empty = DynamicImage::default(); 513| 9.65k| let meta = self.decode_to_dynimage(&mut empty)?; 514| 1.98k| Ok((empty, meta)) 515| 9.65k| } _RNvMs3_NtNtCs3aXgM11XBGX_5image2io17image_reader_typeNtB5_20DecodedImageMetadata11icc_profile: 875| 1.98k| pub fn icc_profile(&mut self) -> ImageResult>> { 876| 1.98k| Self::access_block_with( 877| 1.98k| &mut self.metadata_buffers.icc, 878| 1.98k| self.inner.format_attributes().icc, 879| 1.98k| self.inner, 880| 1.98k| ::icc_profile, 881| | ) 882| 1.98k| } _RNvMs3_NtNtCs3aXgM11XBGX_5image2io17image_reader_typeNtB5_20DecodedImageMetadata13apply_metdata: 904| 1.98k| fn apply_metdata( 905| 1.98k| &mut self, 906| 1.98k| settings: &ImageReaderSettings, 907| 1.98k| image: &mut DynamicImage, 908| 1.98k| ) -> Result<(), ImageError> { 909| | // Run all the metadata extraction which we may need. 910| 1.98k| let icc = self.icc_profile()?; 911| 1.98k| let exif = self.exif_metadata()?; 912| | 913| | // Apply the profile. If the profile itself is not valid or not present you get the default 914| | // presumption: `sRGB`. Otherwise we will try to make sense of the profile and if it is not 915| | // RGB we'll treat it as unspecified so that downstream will know that our handling of this 916| | // _existing_ profile was not / could not be done with full fidelity. 917| 1.98k| if let Some(icc) = icc { 918| 1.78k| if let Some(cicp) = crate::metadata::cms_provider().parse_icc(&icc) { 919| | // We largely ignore the error itself here, you just get the image with no color 920| | // space attached to it. 921| 0| if let Ok(rgb) = cicp.try_into_rgb() { 922| 0| image.set_rgb_primaries(rgb.primaries); 923| 0| image.set_transfer_function(rgb.transfer); 924| 0| } else { 925| 0| image.set_rgb_primaries(crate::metadata::CicpColorPrimaries::Unspecified); 926| 0| image.set_transfer_function( 927| 0| crate::metadata::CicpTransferCharacteristics::Unspecified, 928| 0| ); 929| 0| } 930| 1.78k| } 931| 203| } 932| | 933| 1.98k| let mut orientation = self.attributes.orientation; 934| | 935| | // Determine which orientation to use. 936| 1.98k| if orientation.is_none() { 937| 1.98k| orientation = exif.and_then(|chunk| Orientation::from_exif_chunk(&chunk)); 938| 0| } 939| | 940| 1.98k| self.attributes.orientation = orientation; 941| | 942| 1.98k| if settings.apply_orientation { 943| 1.98k| if let Some(orient) = orientation { 944| 0| image.apply_orientation(orient); 945| 1.98k| } 946| 0| } 947| | 948| 1.98k| Ok(()) 949| 1.98k| } _RNvMs3_NtNtCs3aXgM11XBGX_5image2io17image_reader_typeNtB5_20DecodedImageMetadata13exif_metadata: 865| 1.98k| pub fn exif_metadata(&mut self) -> ImageResult>> { 866| 1.98k| Self::access_block_with( 867| 1.98k| &mut self.metadata_buffers.exif, 868| 1.98k| self.inner.format_attributes().exif, 869| 1.98k| self.inner, 870| 1.98k| ::exif_metadata, 871| | ) 872| 1.98k| } _RNvMs3_NtNtCs3aXgM11XBGX_5image2io17image_reader_typeNtB5_20DecodedImageMetadata17access_block_with: 951| 3.97k| fn access_block_with<'l>( 952| 3.97k| block: &mut MetadataBlock, 953| 3.97k| meta: DecodedMetadataHint, 954| 3.97k| decoder: &mut (dyn ImageDecoder + 'l), 955| 3.97k| access: fn(&'_ mut (dyn ImageDecoder + 'l)) -> ImageResult>>, 956| 3.97k| ) -> ImageResult>> { 957| 3.97k| match meta { 958| | DecodedMetadataHint::InHeader => { 959| 3.97k| if matches!(block, MetadataBlock::ErrorTaken) { 960| | // We can retry this, prefer rechecking from the source. 961| 0| access(decoder) 962| | } else { 963| 3.97k| block.get() 964| | } 965| | } 966| | DecodedMetadataHint::PerImage => { 967| | // This error is sensitive to the timing (after read_image it may or may not refer 968| | // to the next image until we access the decoder with `peek_layout` again. We don't 969| | // want to guess, any call after the first may substitute the error. 970| 0| block.get() 971| | } 972| 0| DecodedMetadataHint::Unsupported | DecodedMetadataHint::None => Ok(None), 973| | } 974| 3.97k| } _RNvXs1_NtNtCs3aXgM11XBGX_5image2io17image_reader_typeNtB5_19ImageReaderSettingsNtNtCs6SNw0SRvItZ_4core7default7Default7default: 476| 9.65k| fn default() -> Self { 477| 9.65k| ImageReaderSettings { 478| 9.65k| apply_orientation: true, 479| 9.65k| } 480| 9.65k| } _RNvMs_NtNtCs3aXgM11XBGX_5image2io6limitsNtB4_6Limits13check_support: 70| 19.3k| pub fn check_support(&self, _supported: &LimitSupport) -> ImageResult<()> { 71| 19.3k| Ok(()) 72| 19.3k| } _RNvMs_NtNtCs3aXgM11XBGX_5image2io6limitsNtB4_6Limits16check_dimensions: 83| 15.6k| pub fn check_dimensions(&self, width: u32, height: u32) -> ImageResult<()> { 84| 15.6k| if let Some(max_width) = self.max_image_width { 85| 0| if width > max_width { 86| 0| return Err(ImageError::Limits(error::LimitError::from_kind( 87| 0| error::LimitErrorKind::DimensionError, 88| 0| ))); 89| 0| } 90| 15.6k| } 91| | 92| 15.6k| if let Some(max_height) = self.max_image_height { 93| 0| if height > max_height { 94| 0| return Err(ImageError::Limits(error::LimitError::from_kind( 95| 0| error::LimitErrorKind::DimensionError, 96| 0| ))); 97| 0| } 98| 15.6k| } 99| | 100| 15.6k| Ok(()) 101| 15.6k| } _RNvMs_NtNtCs3aXgM11XBGX_5image2io6limitsNtB4_6Limits23check_layout_dimensions: 74| 6.23k| pub(crate) fn check_layout_dimensions( 75| 6.23k| &self, 76| 6.23k| layout: &crate::io::DecoderPreparedImage, 77| 6.23k| ) -> ImageResult<()> { 78| 6.23k| self.check_dimensions(layout.layout.width, layout.layout.height) 79| 6.23k| } _RNvMs_NtNtCs3aXgM11XBGX_5image2io6limitsNtB4_6Limits7reserve: 105| 6.23k| pub fn reserve(&mut self, amount: u64) -> ImageResult<()> { 106| 6.23k| if let Some(max_alloc) = self.max_alloc.as_mut() { 107| 6.23k| if *max_alloc < amount { 108| 231| return Err(ImageError::Limits(error::LimitError::from_kind( 109| 231| error::LimitErrorKind::InsufficientMemory, 110| 231| ))); 111| 6.00k| } 112| | 113| 6.00k| *max_alloc -= amount; 114| 0| } 115| | 116| 6.00k| Ok(()) 117| 6.23k| } _RNvMs_NtNtCs3aXgM11XBGX_5image2io6limitsNtB4_6Limits9no_limits: 61| 9.65k| pub fn no_limits() -> Limits { 62| 9.65k| Limits { 63| 9.65k| max_image_width: None, 64| 9.65k| max_image_height: None, 65| 9.65k| max_alloc: None, 66| 9.65k| } 67| 9.65k| } _RNvXNtNtCs3aXgM11XBGX_5image2io6limitsNtB2_6LimitsNtNtCs6SNw0SRvItZ_4core7default7Default7default: 49| 19.3k| fn default() -> Limits { 50| 19.3k| Limits { 51| 19.3k| max_image_width: None, 52| 19.3k| max_image_height: None, 53| 19.3k| max_alloc: Some(512 * 1024 * 1024), 54| 19.3k| } 55| 19.3k| } _RNvMNtCs3aXgM11XBGX_5image8metadataNtB2_11Orientation15from_exif_chunk: 95| 44| pub fn from_exif_chunk(chunk: &[u8]) -> Option { 96| 44| Self::from_exif_chunk_inner(chunk).map(|res| res.0) 97| 44| } _RNvMNtCs3aXgM11XBGX_5image8metadataNtB2_11Orientation21from_exif_chunk_inner: 126| 44| fn from_exif_chunk_inner(chunk: &[u8]) -> Option<(Self, u64, ExifEndian)> { 127| 44| let mut reader = Cursor::new(chunk); 128| | 129| 44| let mut magic = [0; 4]; 130| 44| reader.read_exact(&mut magic).ok()?; 131| | 132| 43| match magic { 133| | [0x49, 0x49, 42, 0] => { 134| 29| return Self::locate_orientation_entry::(&mut reader) 135| 29| .map(|(orient, offset)| (orient, offset, ExifEndian::Little)); 136| | } 137| | [0x4d, 0x4d, 0, 42] => { 138| 0| return Self::locate_orientation_entry::(&mut reader) 139| 0| .map(|(orient, offset)| (orient, offset, ExifEndian::Big)); 140| | } 141| 14| _ => {} 142| | } 143| 14| None 144| 44| } _RNvNtCs3aXgM11XBGX_5image8metadata12cms_provider: 22| 1.78k|pub(crate) fn cms_provider() -> &'static dyn CmsProvider { 23| 1.78k| &moxcms::Moxcms 24| 1.78k|} _RINvMNtCs3aXgM11XBGX_5image8metadataNtB3_11Orientation24locate_orientation_entryNtCs7zV65YDL4Pm_14byteorder_lite12LittleEndianEB5_: 147| 29| fn locate_orientation_entry(reader: &mut Cursor<&[u8]>) -> Option<(Self, u64)> 148| 29| where 149| 29| B: byteorder_lite::ByteOrder, 150| | { 151| 29| let ifd_offset = reader.read_u32::().ok()?; 152| 29| reader.set_position(u64::from(ifd_offset)); 153| 29| let entries = reader.read_u16::().ok()?; 154| 28| for _ in 0..entries { 155| 332| let tag = reader.read_u16::().ok()?; 156| 317| let format = reader.read_u16::().ok()?; 157| 313| let count = reader.read_u32::().ok()?; 158| 311| let value = reader.read_u16::().ok()?; 159| 310| let _padding = reader.read_u16::().ok()?; 160| 307| if tag == 0x112 && format == 3 && count == 1 { 161| 0| let offset = reader.position() - 4; // we've read 4 bytes (2 * u16) past the start of the value 162| 0| let orientation = Self::from_exif(value.min(255) as u8); 163| 0| return orientation.map(|orient| (orient, offset)); 164| 307| } 165| | } 166| | // If we reached this point without returning early, there was no orientation 167| 3| None 168| 29| } _RNvMs7_NtNtCs3aXgM11XBGX_5image8metadata4cicpNtB5_4Cicp8into_rgb: 1201| 11.6k| pub(crate) const fn into_rgb(self) -> CicpRgb { 1202| 11.6k| CicpRgb { 1203| 11.6k| primaries: self.primaries, 1204| 11.6k| transfer: self.transfer, 1205| 11.6k| // NOTE: if we add support for constant luminance (through the CMS having support for 1206| 11.6k| // the Luma->YCbCr->Rgb expansion natively or otherwise) then consider if we should 1207| 11.6k| // track here whether the matrix was `Identity` or `ChromaticityDerivedNonConstant` so 1208| 11.6k| // that the `ImageBuffer::color_space()` function roundtrips the value. It may be 1209| 11.6k| // important to know whether the non-constant chromaticity was an invention by `image` 1210| 11.6k| // or part of the file. The colorimetry is the same either way. 1211| 11.6k| luminance: DerivedLuminance::NonConstant, 1212| 11.6k| } 1213| 11.6k| } _RNvXNtNtCs3aXgM11XBGX_5image8metadata6moxcmsNtB2_6MoxcmsNtB4_11CmsProvider9parse_icc: 85| 1.78k| fn parse_icc(&self, icc: &[u8]) -> Option { 86| 1.78k| let profile = moxcms::ColorProfile::new_from_slice(icc).ok()?; 87| 601| let cicp = profile.cicp?; 88| | 89| | use moxcms::CicpColorPrimaries as Mcp; 90| | use moxcms::MatrixCoefficients as Mmc; 91| | use moxcms::TransferCharacteristics as Mtc; 92| | 93| | Some(Cicp { 94| 0| primaries: match cicp.color_primaries { 95| 0| Mcp::Bt709 => CicpColorPrimaries::SRgb, 96| 0| Mcp::Unspecified | Mcp::Reserved => CicpColorPrimaries::Unspecified, 97| 0| Mcp::Bt470M => CicpColorPrimaries::RgbM, 98| 0| Mcp::Bt470Bg => CicpColorPrimaries::RgbB, 99| 0| Mcp::Bt601 => CicpColorPrimaries::Bt601, 100| 0| Mcp::Smpte240 => CicpColorPrimaries::Rgb240m, 101| 0| Mcp::GenericFilm => CicpColorPrimaries::GenericFilm, 102| 0| Mcp::Bt2020 => CicpColorPrimaries::Rgb2020, 103| 0| Mcp::Xyz => CicpColorPrimaries::Xyz, 104| 0| Mcp::Smpte431 => CicpColorPrimaries::SmpteRp431, 105| 0| Mcp::Smpte432 => CicpColorPrimaries::SmpteRp432, 106| 0| Mcp::Ebu3213 => CicpColorPrimaries::Industry22, 107| | }, 108| 0| transfer: match cicp.transfer_characteristics { 109| 0| Mtc::Bt709 => CicpTransferCharacteristics::Bt709, 110| 0| Mtc::Unspecified | Mtc::Reserved => CicpTransferCharacteristics::Unspecified, 111| 0| Mtc::Bt470M => CicpTransferCharacteristics::Bt470M, 112| 0| Mtc::Bt470Bg => CicpTransferCharacteristics::Bt470BG, 113| 0| Mtc::Bt601 => CicpTransferCharacteristics::Bt601, 114| 0| Mtc::Smpte240 => CicpTransferCharacteristics::Smpte240m, 115| 0| Mtc::Linear => CicpTransferCharacteristics::Linear, 116| 0| Mtc::Log100 => CicpTransferCharacteristics::Log100, 117| 0| Mtc::Log100sqrt10 => CicpTransferCharacteristics::LogSqrt, 118| 0| Mtc::Iec61966 => CicpTransferCharacteristics::Iec61966_2_4, 119| 0| Mtc::Bt1361 => CicpTransferCharacteristics::Bt1361, 120| 0| Mtc::Srgb => CicpTransferCharacteristics::SRgb, 121| 0| Mtc::Bt202010bit => CicpTransferCharacteristics::Bt2020_10bit, 122| 0| Mtc::Bt202012bit => CicpTransferCharacteristics::Bt2020_12bit, 123| 0| Mtc::Smpte2084 => CicpTransferCharacteristics::Smpte2084, 124| 0| Mtc::Smpte428 => CicpTransferCharacteristics::Smpte428, 125| 0| Mtc::Hlg => CicpTransferCharacteristics::Bt2100Hlg, 126| | }, 127| 0| matrix: match cicp.matrix_coefficients { 128| 0| Mmc::Identity => CicpMatrixCoefficients::Identity, 129| 0| Mmc::Unspecified | Mmc::Reserved => CicpMatrixCoefficients::Unspecified, 130| 0| Mmc::Bt709 => CicpMatrixCoefficients::Bt709, 131| 0| Mmc::Fcc => CicpMatrixCoefficients::UsFCC, 132| 0| Mmc::Bt470Bg => CicpMatrixCoefficients::Bt470BG, 133| 0| Mmc::Smpte170m => CicpMatrixCoefficients::Smpte170m, 134| 0| Mmc::Smpte240m => CicpMatrixCoefficients::Smpte240m, 135| 0| Mmc::YCgCo => CicpMatrixCoefficients::YCgCo, 136| 0| Mmc::Bt2020Ncl => CicpMatrixCoefficients::Bt2020NonConstant, 137| 0| Mmc::Bt2020Cl => CicpMatrixCoefficients::Bt2020Constant, 138| 0| Mmc::Smpte2085 => CicpMatrixCoefficients::Smpte2085, 139| | Mmc::ChromaticityDerivedNCL => { 140| 0| CicpMatrixCoefficients::ChromaticityDerivedNonConstant 141| | } 142| 0| Mmc::ChromaticityDerivedCL => CicpMatrixCoefficients::ChromaticityDerivedConstant, 143| 0| Mmc::ICtCp => CicpMatrixCoefficients::Bt2100, 144| | }, 145| 0| full_range: match cicp.full_range { 146| 0| false => CicpVideoFullRangeFlag::NarrowRange, 147| 0| true => CicpVideoFullRangeFlag::FullRange, 148| | }, 149| | }) 150| 1.78k| }