_RNvMsg_NvNtCshdzP3jLBsmJ_3png6common1__NtB5_16InternalBitFlags10intersectsCs4rpmEmvDwFM_5image: 237| 892k| fn intersects(&self, other) { 238| 892k| self.0 & other.0 != <$T as $crate::Bits>::EMPTY _RNvMsg_NvNtCshdzP3jLBsmJ_3png6common1__NtB5_16InternalBitFlags8containsCs4rpmEmvDwFM_5image: 241| 139M| fn contains(&self, other) { 242| 139M| self.0 & other.0 == other.0 _RNvMsy_NvNtCshdzP3jLBsmJ_3png6common1__NtB7_15Transformations10intersectsCs4rpmEmvDwFM_5image: 78| 892k| fn intersects(&self, other) { 79| 892k| self.0.intersects(other.0) _RNvMsy_NvNtCshdzP3jLBsmJ_3png6common1__NtB7_15Transformations8containsCs4rpmEmvDwFM_5image: 82| 139M| fn contains(&self, other) { 83| 139M| self.0.contains(other.0) _RNvMsg_NvNtCshdzP3jLBsmJ_3png6common1__NtB5_16InternalBitFlags8containsB9_: 241| 9.17k| fn contains(&self, other) { 242| 9.17k| self.0 & other.0 == other.0 _RNvMsy_NvNtCshdzP3jLBsmJ_3png6common1__NtB7_15Transformations8containsB9_: 82| 9.17k| fn contains(&self, other) { 83| 9.17k| self.0.contains(other.0) _RINvNtCskQtIeRyuLP6_8bytemuck8internal14cast_slice_muthhECs4rpmEmvDwFM_5image: 268| 4.27k|pub(crate) unsafe fn cast_slice_mut(a: &mut [A]) -> &mut [B] { 269| 4.27k| match try_cast_slice_mut(a) { 270| 4.27k| Ok(b) => b, 271| 0| Err(e) => something_went_wrong("cast_slice_mut", e), 272| | } 273| 4.27k|} _RINvNtCskQtIeRyuLP6_8bytemuck8internal14cast_slice_mutthECs4rpmEmvDwFM_5image: 268| 1.50k|pub(crate) unsafe fn cast_slice_mut(a: &mut [A]) -> &mut [B] { 269| 1.50k| match try_cast_slice_mut(a) { 270| 1.50k| Ok(b) => b, 271| 0| Err(e) => something_went_wrong("cast_slice_mut", e), 272| | } 273| 1.50k|} _RINvNtCskQtIeRyuLP6_8bytemuck8internal18try_cast_slice_muthhECs4rpmEmvDwFM_5image: 381| 4.27k|pub(crate) unsafe fn try_cast_slice_mut( 382| 4.27k| a: &mut [A], 383| 4.27k|) -> Result<&mut [B], PodCastError> { 384| 4.27k| 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.27k| 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.27k| } else if size_of::() == size_of::() { 392| 4.27k| Ok(unsafe { 393| 4.27k| core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, a.len()) 394| 4.27k| }) 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.27k|} _RINvNtCskQtIeRyuLP6_8bytemuck8internal18try_cast_slice_mutthECs4rpmEmvDwFM_5image: 381| 1.50k|pub(crate) unsafe fn try_cast_slice_mut( 382| 1.50k| a: &mut [A], 383| 1.50k|) -> Result<&mut [B], PodCastError> { 384| 1.50k| 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.50k| 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.50k| } 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.50k| } else if (size_of::() != 0 && input_bytes % size_of::() == 0) 396| 0| || (size_of::() == 0 && input_bytes == 0) 397| | { 398| 1.50k| let new_len = 399| 1.50k| if size_of::() != 0 { input_bytes / size_of::() } else { 0 }; 400| 1.50k| Ok(unsafe { 401| 1.50k| core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, new_len) 402| 1.50k| }) 403| | } else { 404| 0| Err(PodCastError::OutputSliceWouldHaveSlop) 405| | } 406| 1.50k|} _RINvCskQtIeRyuLP6_8bytemuck14cast_slice_muthhECs4rpmEmvDwFM_5image: 423| 4.27k|pub fn cast_slice_mut< 424| 4.27k| A: NoUninit + AnyBitPattern, 425| 4.27k| B: NoUninit + AnyBitPattern, 426| 4.27k|>( 427| 4.27k| a: &mut [A], 428| 4.27k|) -> &mut [B] { 429| 4.27k| unsafe { internal::cast_slice_mut(a) } 430| 4.27k|} _RINvCskQtIeRyuLP6_8bytemuck14cast_slice_mutthECs4rpmEmvDwFM_5image: 423| 1.50k|pub fn cast_slice_mut< 424| 1.50k| A: NoUninit + AnyBitPattern, 425| 1.50k| B: NoUninit + AnyBitPattern, 426| 1.50k|>( 427| 1.50k| a: &mut [A], 428| 1.50k|) -> &mut [B] { 429| 1.50k| unsafe { internal::cast_slice_mut(a) } 430| 1.50k|} _RINvYINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShENtNtCs7zV65YDL4Pm_14byteorder_lite2io12ReadBytesExt8read_u16NtBR_12LittleEndianECs4rpmEmvDwFM_5image: 109| 1.45k| fn read_u16(&mut self) -> Result { 110| 1.45k| let mut buf = [0; 2]; 111| 1.45k| self.read_exact(&mut buf)?; 112| 1.43k| Ok(T::read_u16(&buf)) 113| 1.45k| } _RINvYINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShENtNtCs7zV65YDL4Pm_14byteorder_lite2io12ReadBytesExt8read_u32NtBR_12LittleEndianECs4rpmEmvDwFM_5image: 214| 380| fn read_u32(&mut self) -> Result { 215| 380| let mut buf = [0; 4]; 216| 380| self.read_exact(&mut buf)?; 217| 379| Ok(T::read_u32(&buf)) 218| 380| } _RNvXs1_Cs7zV65YDL4Pm_14byteorder_liteNtB5_12LittleEndianNtB5_9ByteOrder8read_u16Cs4rpmEmvDwFM_5image: 2059| 1.43k| fn read_u16(buf: &[u8]) -> u16 { 2060| 1.43k| u16::from_le_bytes(buf[..2].try_into().unwrap()) 2061| 1.43k| } _RNvXs1_Cs7zV65YDL4Pm_14byteorder_liteNtB5_12LittleEndianNtB5_9ByteOrder8read_u32Cs4rpmEmvDwFM_5image: 2064| 379| fn read_u32(buf: &[u8]) -> u32 { 2065| 379| u32::from_le_bytes(buf[..4].try_into().unwrap()) 2066| 379| } _RNvNtCs9CIo2vbsQYK_9crc32fast8baseline11update_slow: 61| 832k|pub(crate) fn update_slow(prev: u32, buf: &[u8]) -> u32 { 62| 832k| let mut crc = !prev; 63| | 64| 7.06M| for &byte in buf.iter() { 65| 7.06M| crc = CRC32_TABLE[0][((crc as u8) ^ byte) as usize] ^ (crc >> 8); 66| 7.06M| } 67| | 68| 832k| !crc 69| 832k|} _RNvNtCs9CIo2vbsQYK_9crc32fast8baseline14update_fast_16: 30| 832k|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| 832k| let mut crc = !prev; 35| | 36| 836k| while buf.len() >= BYTES_AT_ONCE { 37| 21.8k| for _ in 0..UNROLL { 38| 17.4k| crc = CRC32_TABLE[0x0][buf[0xf] as usize] 39| 17.4k| ^ CRC32_TABLE[0x1][buf[0xe] as usize] 40| 17.4k| ^ CRC32_TABLE[0x2][buf[0xd] as usize] 41| 17.4k| ^ CRC32_TABLE[0x3][buf[0xc] as usize] 42| 17.4k| ^ CRC32_TABLE[0x4][buf[0xb] as usize] 43| 17.4k| ^ CRC32_TABLE[0x5][buf[0xa] as usize] 44| 17.4k| ^ CRC32_TABLE[0x6][buf[0x9] as usize] 45| 17.4k| ^ CRC32_TABLE[0x7][buf[0x8] as usize] 46| 17.4k| ^ CRC32_TABLE[0x8][buf[0x7] as usize] 47| 17.4k| ^ CRC32_TABLE[0x9][buf[0x6] as usize] 48| 17.4k| ^ CRC32_TABLE[0xa][buf[0x5] as usize] 49| 17.4k| ^ CRC32_TABLE[0xb][buf[0x4] as usize] 50| 17.4k| ^ CRC32_TABLE[0xc][buf[0x3] as usize ^ ((crc >> 0x18) & 0xFF) as usize] 51| 17.4k| ^ CRC32_TABLE[0xd][buf[0x2] as usize ^ ((crc >> 0x10) & 0xFF) as usize] 52| 17.4k| ^ CRC32_TABLE[0xe][buf[0x1] as usize ^ ((crc >> 0x08) & 0xFF) as usize] 53| 17.4k| ^ CRC32_TABLE[0xf][buf[0x0] as usize ^ (crc & 0xFF) as usize]; 54| 17.4k| buf = &buf[16..]; 55| 17.4k| } 56| | } 57| | 58| 832k| update_slow(!crc, buf) 59| 832k|} _RNvMCs9CIo2vbsQYK_9crc32fastNtB2_6Hasher16new_with_initial: 84| 9.46k| pub fn new_with_initial(init: u32) -> Self { 85| 9.46k| Self::new_with_initial_len(init, 0) 86| 9.46k| } _RNvMCs9CIo2vbsQYK_9crc32fastNtB2_6Hasher20new_with_initial_len: 93| 9.46k| pub fn new_with_initial_len(init: u32, amount: u64) -> Self { 94| 9.46k| Self::internal_new_specialized(init, amount) 95| 9.46k| .unwrap_or_else(|| Self::internal_new_baseline(init, amount)) 96| 9.46k| } _RNvMCs9CIo2vbsQYK_9crc32fastNtB2_6Hasher24internal_new_specialized: 109| 9.46k| pub fn internal_new_specialized(init: u32, amount: u64) -> Option { 110| | { 111| 9.46k| if let Some(state) = specialized::State::new(init) { 112| 9.46k| return Some(Hasher { 113| 9.46k| amount, 114| 9.46k| state: State::Specialized(state), 115| 9.46k| }); 116| 0| } 117| | } 118| 0| None 119| 9.46k| } _RNvMCs9CIo2vbsQYK_9crc32fastNtB2_6Hasher3new: 76| 9.46k| pub fn new() -> Self { 77| 9.46k| Self::new_with_initial(DEFAULT_INIT_STATE) 78| 9.46k| } _RNvMCs9CIo2vbsQYK_9crc32fastNtB2_6Hasher5reset: 139| 83.5k| pub fn reset(&mut self) { 140| 83.5k| self.amount = 0; 141| 83.5k| match self.state { 142| 0| State::Baseline(ref mut state) => state.reset(), 143| 83.5k| State::Specialized(ref mut state) => state.reset(), 144| | } 145| 83.5k| } _RNvMCs9CIo2vbsQYK_9crc32fastNtB2_6Hasher6update: 122| 839k| pub fn update(&mut self, buf: &[u8]) { 123| 839k| self.amount += buf.len() as u64; 124| 839k| match self.state { 125| 0| State::Baseline(ref mut state) => state.update(buf), 126| 839k| State::Specialized(ref mut state) => state.update(buf), 127| | } 128| 839k| } _RNvMCs9CIo2vbsQYK_9crc32fastNtB2_6Hasher8finalize: 131| 78.1k| pub fn finalize(self) -> u32 { 132| 78.1k| match self.state { 133| 0| State::Baseline(state) => state.finalize(), 134| 78.1k| State::Specialized(state) => state.finalize(), 135| | } 136| 78.1k| } _RNvMNtNtCs9CIo2vbsQYK_9crc32fast11specialized9pclmulqdqNtB2_5State3new: 36| 9.46k| pub fn new(state: u32) -> Option { 37| 9.46k| if is_x86_feature_detected!("pclmulqdq") 38| 9.46k| && is_x86_feature_detected!("sse2") 39| 9.46k| && 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.46k| Some(Self { state }) 44| | } else { 45| 0| None 46| | } 47| 9.46k| } _RNvMNtNtCs9CIo2vbsQYK_9crc32fast11specialized9pclmulqdqNtB2_5State5reset: 59| 83.5k| pub fn reset(&mut self) { 60| 83.5k| self.state = 0; 61| 83.5k| } _RNvMNtNtCs9CIo2vbsQYK_9crc32fast11specialized9pclmulqdqNtB2_5State6update: 49| 839k| 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| 839k| self.state = unsafe { calculate(self.state, buf) } 53| 839k| } _RNvMNtNtCs9CIo2vbsQYK_9crc32fast11specialized9pclmulqdqNtB2_5State8finalize: 55| 78.1k| pub fn finalize(self) -> u32 { 56| 78.1k| self.state 57| 78.1k| } _RNvNtNtCs9CIo2vbsQYK_9crc32fast11specialized9pclmulqdq3get: 180| 2.49M|unsafe fn get(a: &mut &[u8]) -> arch::__m128i { 181| 2.49M| debug_assert!(a.len() >= 16); 182| 2.49M| let r = arch::_mm_loadu_si128(a.as_ptr() as *const arch::__m128i); 183| 2.49M| *a = &a[16..]; 184| 2.49M| r 185| 2.49M|} _RNvNtNtCs9CIo2vbsQYK_9crc32fast11specialized9pclmulqdq9calculate: 78| 839k|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| 839k| if data.len() < 128 { 83| 825k| return crate::baseline::update_fast_16(crc, data); 84| 14.2k| } 85| | 86| | // Step 1: fold by 4 loop 87| 14.2k| let mut x3 = get(&mut data); 88| 14.2k| let mut x2 = get(&mut data); 89| 14.2k| let mut x1 = get(&mut data); 90| 14.2k| let mut x0 = get(&mut data); 91| | 92| | // fold in our initial value, part of the incremental crc checksum 93| 14.2k| x3 = arch::_mm_xor_si128(x3, arch::_mm_cvtsi32_si128(!crc as i32)); 94| | 95| 14.2k| let k1k2 = arch::_mm_set_epi64x(K2, K1); 96| 621k| while data.len() >= 64 { 97| 606k| x3 = reduce128(x3, get(&mut data), k1k2); 98| 606k| x2 = reduce128(x2, get(&mut data), k1k2); 99| 606k| x1 = reduce128(x1, get(&mut data), k1k2); 100| 606k| x0 = reduce128(x0, get(&mut data), k1k2); 101| 606k| } 102| | 103| 14.2k| let k3k4 = arch::_mm_set_epi64x(K4, K3); 104| 14.2k| let mut x = reduce128(x3, x2, k3k4); 105| 14.2k| x = reduce128(x, x1, k3k4); 106| 14.2k| x = reduce128(x, x0, k3k4); 107| | 108| | // Step 2: fold by 1 loop 109| 26.4k| while data.len() >= 16 { 110| 12.1k| x = reduce128(x, get(&mut data), k3k4); 111| 12.1k| } 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| 14.2k| let x = arch::_mm_xor_si128( 132| 14.2k| arch::_mm_clmulepi64_si128(x, k3k4, 0x10), 133| 14.2k| arch::_mm_srli_si128(x, 8), 134| | ); 135| 14.2k| let x = arch::_mm_xor_si128( 136| 14.2k| arch::_mm_clmulepi64_si128( 137| 14.2k| arch::_mm_and_si128(x, arch::_mm_set_epi32(0, 0, 0, !0)), 138| 14.2k| arch::_mm_set_epi64x(0, K5), 139| | 0x00, 140| | ), 141| 14.2k| 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| 14.2k| let pu = arch::_mm_set_epi64x(U_PRIME, P_X); 148| | 149| | // T1(x) = ⌊(R(x) % x^32)⌋ • μ 150| 14.2k| let t1 = arch::_mm_clmulepi64_si128( 151| 14.2k| arch::_mm_and_si128(x, arch::_mm_set_epi32(0, 0, 0, !0)), 152| 14.2k| pu, 153| | 0x10, 154| | ); 155| | // T2(x) = ⌊(T1(x) % x^32)⌋ • P(x) 156| 14.2k| let t2 = arch::_mm_clmulepi64_si128( 157| 14.2k| arch::_mm_and_si128(t1, arch::_mm_set_epi32(0, 0, 0, !0)), 158| 14.2k| 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| 14.2k| let c = arch::_mm_extract_epi32(arch::_mm_xor_si128(x, t2), 1) as u32; 166| | 167| 14.2k| if !data.is_empty() { 168| 7.02k| crate::baseline::update_fast_16(!c, data) 169| | } else { 170| 7.26k| !c 171| | } 172| 839k|} _RNvNtNtCs9CIo2vbsQYK_9crc32fast11specialized9pclmulqdq9reduce128: 174| 2.48M|unsafe fn reduce128(a: arch::__m128i, b: arch::__m128i, keys: arch::__m128i) -> arch::__m128i { 175| 2.48M| let t1 = arch::_mm_clmulepi64_si128(a, keys, 0x00); 176| 2.48M| let t2 = arch::_mm_clmulepi64_si128(a, keys, 0x11); 177| 2.48M| arch::_mm_xor_si128(arch::_mm_xor_si128(b, t1), t2) 178| 2.48M|} _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor11fill_buffer: 157| 47.4M| fn fill_buffer(&mut self, input: &mut &[u8]) { 158| 47.4M| if input.len() >= 8 { 159| 47.3M| self.buffer |= u64::from_le_bytes(input[..8].try_into().unwrap()) << self.nbits; 160| 47.3M| *input = &input[(63 - self.nbits as usize) / 8..]; 161| 47.3M| self.nbits |= 56; 162| 47.3M| } else { 163| 117k| let nbytes = input.len().min((63 - self.nbits as usize) / 8); 164| 117k| let mut input_data = [0; 8]; 165| 117k| input_data[..nbytes].copy_from_slice(&input[..nbytes]); 166| 117k| self.buffer |= u64::from_le_bytes(input_data) 167| 117k| .checked_shl(self.nbits as u32) 168| 117k| .unwrap_or(0); 169| 117k| self.nbits += nbytes as u8 * 8; 170| 117k| *input = &input[nbytes..]; 171| 117k| } 172| 47.4M| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor12build_tables: 398| 11.9k| fn build_tables( 399| 11.9k| hlit: usize, 400| 11.9k| code_lengths: &[u8], 401| 11.9k| compression: &mut CompressedBlock, 402| 11.9k| ) -> Result<(), DecompressionError> { 403| | // If there is no code assigned for the EOF symbol then the bitstream is invalid. 404| 11.9k| if code_lengths[256] == 0 { 405| | // TODO: Return a dedicated error in this case. 406| 11| return Err(DecompressionError::BadLiteralLengthHuffmanTree); 407| 11.9k| } 408| | 409| 11.9k| let mut codes = [0; 288]; 410| 11.9k| compression.secondary_table.clear(); 411| 11.9k| if !huffman::build_table( 412| 11.9k| &code_lengths[..hlit], 413| 11.9k| &LITLEN_TABLE_ENTRIES, 414| 11.9k| &mut codes[..hlit], 415| 11.9k| &mut *compression.litlen_table, 416| 11.9k| &mut compression.secondary_table, 417| 11.9k| false, 418| 11.9k| true, 419| 11.9k| ) { 420| 70| return Err(DecompressionError::BadCodeLengthHuffmanTree); 421| 11.8k| } 422| | 423| 11.8k| compression.eof_code = codes[256]; 424| 11.8k| compression.eof_mask = (1 << code_lengths[256]) - 1; 425| 11.8k| compression.eof_bits = code_lengths[256]; 426| | 427| | // Build the distance code table. 428| 11.8k| let lengths = &code_lengths[288..320]; 429| 11.8k| if lengths == [0; 32] { 430| 751| compression.dist_table.fill(0); 431| 751| } else { 432| 11.1k| let mut dist_codes = [0; 32]; 433| 11.1k| if !huffman::build_table( 434| 11.1k| lengths, 435| 11.1k| &tables::DISTANCE_TABLE_ENTRIES, 436| 11.1k| &mut dist_codes, 437| 11.1k| &mut *compression.dist_table, 438| 11.1k| &mut compression.dist_secondary_table, 439| 11.1k| true, 440| 11.1k| false, 441| 11.1k| ) { 442| 115| return Err(DecompressionError::BadDistanceHuffmanTree); 443| 11.0k| } 444| | } 445| | 446| 11.7k| Ok(()) 447| 11.9k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor12consume_bits: 178| 46.5M| fn consume_bits(&mut self, nbits: u8) { 179| 46.5M| debug_assert!(self.nbits >= nbits); 180| 46.5M| self.buffer >>= nbits; 181| 46.5M| self.nbits -= nbits; 182| 46.5M| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor14ignore_adler32: 153| 5.66k| pub fn ignore_adler32(&mut self) { 154| 5.66k| self.ignore_adler32 = true; 155| 5.66k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor15read_compressed: 449| 846k| fn read_compressed( 450| 846k| &mut self, 451| 846k| remaining_input: &mut &[u8], 452| 846k| output: &mut [u8], 453| 846k| mut output_index: usize, 454| 846k| ) -> 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| 846k| self.fill_buffer(remaining_input); 468| 846k| let mut litlen_entry = self.compression.litlen_table[(self.buffer & 0xfff) as usize]; 469| 44.7M| while self.state == State::CompressedData 470| 44.7M| && output_index + 8 <= output.len() 471| 44.6M| && 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| 44.6M| let mut litlen_code_bits = litlen_entry as u8; 477| 44.6M| if litlen_entry & LITERAL_ENTRY != 0 { 478| 2.29M| let litlen_entry2 = self.compression.litlen_table 479| 2.29M| [(self.buffer >> litlen_code_bits & 0xfff) as usize]; 480| 2.29M| let litlen_code_bits2 = litlen_entry2 as u8; 481| 2.29M| let litlen_entry3 = self.compression.litlen_table 482| 2.29M| [(self.buffer >> (litlen_code_bits + litlen_code_bits2) & 0xfff) as usize]; 483| 2.29M| let litlen_code_bits3 = litlen_entry3 as u8; 484| 2.29M| let litlen_entry4 = self.compression.litlen_table[(self.buffer 485| 2.29M| >> (litlen_code_bits + litlen_code_bits2 + litlen_code_bits3) 486| 2.29M| & 0xfff) 487| 2.29M| as usize]; 488| | 489| 2.29M| let advance_output_bytes = ((litlen_entry & 0xf00) >> 8) as usize; 490| 2.29M| output[output_index] = (litlen_entry >> 16) as u8; 491| 2.29M| output[output_index + 1] = (litlen_entry >> 24) as u8; 492| 2.29M| output_index += advance_output_bytes; 493| | 494| 2.29M| if litlen_entry2 & LITERAL_ENTRY != 0 { 495| 1.73M| let advance_output_bytes2 = ((litlen_entry2 & 0xf00) >> 8) as usize; 496| 1.73M| output[output_index] = (litlen_entry2 >> 16) as u8; 497| 1.73M| output[output_index + 1] = (litlen_entry2 >> 24) as u8; 498| 1.73M| output_index += advance_output_bytes2; 499| | 500| 1.73M| if litlen_entry3 & LITERAL_ENTRY != 0 { 501| 1.64M| let advance_output_bytes3 = ((litlen_entry3 & 0xf00) >> 8) as usize; 502| 1.64M| output[output_index] = (litlen_entry3 >> 16) as u8; 503| 1.64M| output[output_index + 1] = (litlen_entry3 >> 24) as u8; 504| 1.64M| output_index += advance_output_bytes3; 505| | 506| 1.64M| litlen_entry = litlen_entry4; 507| 1.64M| self.consume_bits(litlen_code_bits + litlen_code_bits2 + litlen_code_bits3); 508| 1.64M| self.fill_buffer(remaining_input); 509| 1.64M| continue; 510| 96.6k| } else { 511| 96.6k| self.consume_bits(litlen_code_bits + litlen_code_bits2); 512| 96.6k| litlen_entry = litlen_entry3; 513| 96.6k| litlen_code_bits = litlen_code_bits3; 514| 96.6k| self.fill_buffer(remaining_input); 515| 96.6k| bits = self.buffer; 516| 96.6k| } 517| | } else { 518| 557k| self.consume_bits(litlen_code_bits); 519| 557k| bits = self.buffer; 520| 557k| litlen_entry = litlen_entry2; 521| 557k| litlen_code_bits = litlen_code_bits2; 522| 557k| if self.nbits < 48 { 523| 42.0k| self.fill_buffer(remaining_input); 524| 514k| } 525| | } 526| 42.3M| } else { 527| 42.3M| bits = self.buffer; 528| 42.3M| } 529| | 530| | // The next symbol is either a 13+ bit literal, back-reference, or an EOF symbol. 531| 42.9M| let (length_base, length_extra_bits, litlen_code_bits) = 532| 43.0M| if litlen_entry & EXCEPTIONAL_ENTRY == 0 { 533| 42.7M| ( 534| 42.7M| litlen_entry >> 16, 535| 42.7M| (litlen_entry >> 8) as u8, 536| 42.7M| litlen_code_bits, 537| 42.7M| ) 538| 319k| } else if litlen_entry & SECONDARY_TABLE_ENTRY != 0 { 539| 310k| let secondary_table_index = 540| 310k| (litlen_entry >> 16) + ((bits >> 12) as u32 & (litlen_entry & 0xff)); 541| 310k| let secondary_entry = 542| 310k| self.compression.secondary_table[secondary_table_index as usize]; 543| 310k| let litlen_symbol = secondary_entry >> 4; 544| 310k| let litlen_code_bits = (secondary_entry & 0xf) as u8; 545| | 546| 310k| match litlen_symbol { 547| 310k| 0..=255 => { 548| 36.1k| self.consume_bits(litlen_code_bits); 549| 36.1k| litlen_entry = 550| 36.1k| self.compression.litlen_table[(self.buffer & 0xfff) as usize]; 551| 36.1k| self.fill_buffer(remaining_input); 552| 36.1k| output[output_index] = litlen_symbol as u8; 553| 36.1k| output_index += 1; 554| 36.1k| continue; 555| | } 556| | 256 => { 557| 1.89k| self.consume_bits(litlen_code_bits); 558| 1.89k| self.state = match self.last_block { 559| 0| true => State::Checksum, 560| 1.89k| false => State::BlockHeader, 561| | }; 562| 1.89k| break; 563| | } 564| 272k| _ => ( 565| 272k| LEN_SYM_TO_LEN_BASE[litlen_symbol as usize - 257] as u32, 566| 272k| LEN_SYM_TO_LEN_EXTRA[litlen_symbol as usize - 257], 567| 272k| litlen_code_bits, 568| 272k| ), 569| | } 570| 9.68k| } else if litlen_code_bits == 0 { 571| 0| return Err(DecompressionError::InvalidLiteralLengthCode); 572| | } else { 573| 9.68k| self.consume_bits(litlen_code_bits); 574| 9.68k| self.state = match self.last_block { 575| 998| true => State::Checksum, 576| 8.68k| false => State::BlockHeader, 577| | }; 578| 9.68k| break; 579| | }; 580| 42.9M| bits >>= litlen_code_bits; 581| | 582| 42.9M| let length_extra_mask = (1 << length_extra_bits) - 1; 583| 42.9M| let length = length_base as usize + (bits & length_extra_mask) as usize; 584| 42.9M| bits >>= length_extra_bits; 585| | 586| 42.9M| let dist_entry = self.compression.dist_table[(bits & 0x1ff) as usize]; 587| 42.9M| let (dist_base, dist_extra_bits, dist_code_bits) = if dist_entry & LITERAL_ENTRY != 0 { 588| 42.7M| ( 589| 42.7M| (dist_entry >> 16) as u16, 590| 42.7M| (dist_entry >> 8) as u8 & 0xf, 591| 42.7M| dist_entry as u8, 592| 42.7M| ) 593| 254k| } else if dist_entry >> 8 == 0 { 594| 9| return Err(DecompressionError::InvalidDistanceCode); 595| | } else { 596| 254k| let secondary_table_index = 597| 254k| (dist_entry >> 16) + ((bits >> 9) as u32 & (dist_entry & 0xff)); 598| 254k| let secondary_entry = 599| 254k| self.compression.dist_secondary_table[secondary_table_index as usize]; 600| 254k| let dist_symbol = (secondary_entry >> 4) as usize; 601| 254k| if dist_symbol >= 30 { 602| 0| return Err(DecompressionError::InvalidDistanceCode); 603| 254k| } 604| | 605| 254k| ( 606| 254k| DIST_SYM_TO_DIST_BASE[dist_symbol], 607| 254k| DIST_SYM_TO_DIST_EXTRA[dist_symbol], 608| 254k| (secondary_entry & 0xf) as u8, 609| 254k| ) 610| | }; 611| 42.9M| bits >>= dist_code_bits; 612| | 613| 42.9M| let dist = dist_base as usize + (bits & ((1 << dist_extra_bits) - 1)) as usize; 614| 42.9M| if dist > output_index { 615| 68| return Err(DecompressionError::DistanceTooFarBack); 616| 42.9M| } 617| | 618| 42.9M| self.consume_bits( 619| 42.9M| litlen_code_bits + length_extra_bits + dist_code_bits + dist_extra_bits, 620| | ); 621| 42.9M| self.fill_buffer(remaining_input); 622| 42.9M| litlen_entry = self.compression.litlen_table[(self.buffer & 0xfff) as usize]; 623| | 624| 42.9M| let copy_length = length.min(output.len() - output_index); 625| 42.9M| if dist == 1 { 626| 21.2M| let last = output[output_index - 1]; 627| 21.2M| output[output_index..][..copy_length].fill(last); 628| | 629| 21.2M| if copy_length < length { 630| 228k| self.queued_rle = Some((last, length - copy_length)); 631| 228k| output_index = output.len(); 632| 228k| break; 633| 21.0M| } 634| 21.7M| } else if output_index + length + 15 <= output.len() { 635| 21.1M| let start = output_index - dist; 636| 21.1M| output.copy_within(start..start + 16, output_index); 637| | 638| 21.1M| if length > 16 || dist < 16 { 639| 1.59G| for i in (0..length).step_by(dist.min(16)).skip(1) { 640| 1.59G| output.copy_within(start + i..start + i + 16, output_index + i); 641| 1.59G| } 642| 615k| } 643| | } else { 644| 605k| if dist < copy_length { 645| 82.6M| for i in 0..copy_length { 646| 82.6M| output[output_index + i] = output[output_index + i - dist]; 647| 82.6M| } 648| | } else { 649| 16.9k| output.copy_within( 650| 16.9k| output_index - dist..output_index + copy_length - dist, 651| 16.9k| output_index, 652| | ) 653| | } 654| | 655| 605k| if copy_length < length { 656| 568k| self.queued_backref = Some((dist, length - copy_length)); 657| 568k| output_index = output.len(); 658| 568k| break; 659| 37.6k| } 660| | } 661| 42.1M| 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| 927k| while let State::CompressedData = self.state { 669| 915k| self.fill_buffer(remaining_input); 670| 915k| if output_index == output.len() { 671| 801k| break; 672| 114k| } 673| | 674| 114k| let mut bits = self.buffer; 675| 114k| let litlen_entry = self.compression.litlen_table[(bits & 0xfff) as usize]; 676| 114k| let litlen_code_bits = litlen_entry as u8; 677| | 678| 114k| 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| 24.3k| let advance_output_bytes = ((litlen_entry & 0xf00) >> 8) as usize; 682| | 683| 24.3k| if self.nbits < litlen_code_bits { 684| 1.32k| break; 685| 23.0k| } else if output_index + 1 < output.len() { 686| 22.4k| output[output_index] = (litlen_entry >> 16) as u8; 687| 22.4k| output[output_index + 1] = (litlen_entry >> 24) as u8; 688| 22.4k| output_index += advance_output_bytes; 689| 22.4k| self.consume_bits(litlen_code_bits); 690| 22.4k| continue; 691| 586| } else if output_index + advance_output_bytes == output.len() { 692| 264| debug_assert_eq!(advance_output_bytes, 1); 693| 264| output[output_index] = (litlen_entry >> 16) as u8; 694| 264| output_index += 1; 695| 264| self.consume_bits(litlen_code_bits); 696| 264| break; 697| | } else { 698| 322| debug_assert_eq!(advance_output_bytes, 2); 699| 322| output[output_index] = (litlen_entry >> 16) as u8; 700| 322| self.queued_rle = Some(((litlen_entry >> 24) as u8, 1)); 701| 322| output_index += 1; 702| 322| self.consume_bits(litlen_code_bits); 703| 322| break; 704| | } 705| 90.0k| } 706| | 707| 87.0k| let (length_base, length_extra_bits, litlen_code_bits) = 708| 90.0k| if litlen_entry & EXCEPTIONAL_ENTRY == 0 { 709| 86.6k| ( 710| 86.6k| litlen_entry >> 16, 711| 86.6k| (litlen_entry >> 8) as u8, 712| 86.6k| litlen_code_bits, 713| 86.6k| ) 714| 3.31k| } else if litlen_entry & SECONDARY_TABLE_ENTRY != 0 { 715| 525| let secondary_table_index = 716| 525| (litlen_entry >> 16) + ((bits >> 12) as u32 & (litlen_entry & 0xff)); 717| 525| let secondary_entry = 718| 525| self.compression.secondary_table[secondary_table_index as usize]; 719| 525| let litlen_symbol = secondary_entry >> 4; 720| 525| let litlen_code_bits = (secondary_entry & 0xf) as u8; 721| | 722| 525| if self.nbits < litlen_code_bits { 723| 6| break; 724| 519| } else if litlen_symbol < 256 { 725| 190| self.consume_bits(litlen_code_bits); 726| 190| output[output_index] = litlen_symbol as u8; 727| 190| output_index += 1; 728| 190| continue; 729| 329| } else if litlen_symbol == 256 { 730| 21| self.consume_bits(litlen_code_bits); 731| 21| self.state = match self.last_block { 732| 0| true => State::Checksum, 733| 21| false => State::BlockHeader, 734| | }; 735| 21| break; 736| 308| } 737| | 738| 308| ( 739| 308| LEN_SYM_TO_LEN_BASE[litlen_symbol as usize - 257] as u32, 740| 308| LEN_SYM_TO_LEN_EXTRA[litlen_symbol as usize - 257], 741| 308| litlen_code_bits, 742| 308| ) 743| 2.79k| } else if litlen_code_bits == 0 { 744| 0| return Err(DecompressionError::InvalidLiteralLengthCode); 745| | } else { 746| 2.79k| if self.nbits < litlen_code_bits { 747| 870| break; 748| 1.92k| } 749| 1.92k| self.consume_bits(litlen_code_bits); 750| 1.92k| self.state = match self.last_block { 751| 1.25k| true => State::Checksum, 752| 669| false => State::BlockHeader, 753| | }; 754| 1.92k| break; 755| | }; 756| 87.0k| bits >>= litlen_code_bits; 757| | 758| 87.0k| let length_extra_mask = (1 << length_extra_bits) - 1; 759| 87.0k| let length = length_base as usize + (bits & length_extra_mask) as usize; 760| 87.0k| bits >>= length_extra_bits; 761| | 762| 87.0k| let dist_entry = self.compression.dist_table[(bits & 0x1ff) as usize]; 763| 87.0k| let (dist_base, dist_extra_bits, dist_code_bits) = if dist_entry & LITERAL_ENTRY != 0 { 764| 86.4k| ( 765| 86.4k| (dist_entry >> 16) as u16, 766| 86.4k| (dist_entry >> 8) as u8 & 0xf, 767| 86.4k| dist_entry as u8, 768| 86.4k| ) 769| 588| } else if self.nbits > litlen_code_bits + length_extra_bits + 9 { 770| 384| if dist_entry >> 8 == 0 { 771| 21| return Err(DecompressionError::InvalidDistanceCode); 772| 363| } 773| | 774| 363| let secondary_table_index = 775| 363| (dist_entry >> 16) + ((bits >> 9) as u32 & (dist_entry & 0xff)); 776| 363| let secondary_entry = 777| 363| self.compression.dist_secondary_table[secondary_table_index as usize]; 778| 363| let dist_symbol = (secondary_entry >> 4) as usize; 779| 363| if dist_symbol >= 30 { 780| 0| return Err(DecompressionError::InvalidDistanceCode); 781| 363| } 782| | 783| 363| ( 784| 363| DIST_SYM_TO_DIST_BASE[dist_symbol], 785| 363| DIST_SYM_TO_DIST_EXTRA[dist_symbol], 786| 363| (secondary_entry & 0xf) as u8, 787| 363| ) 788| | } else { 789| 204| break; 790| | }; 791| 86.7k| bits >>= dist_code_bits; 792| | 793| 86.7k| let dist = dist_base as usize + (bits & ((1 << dist_extra_bits) - 1)) as usize; 794| 86.7k| let total_bits = 795| 86.7k| litlen_code_bits + length_extra_bits + dist_code_bits + dist_extra_bits; 796| | 797| 86.7k| if self.nbits < total_bits { 798| 1.32k| break; 799| 85.4k| } else if dist > output_index { 800| 95| return Err(DecompressionError::DistanceTooFarBack); 801| 85.3k| } 802| | 803| 85.3k| self.consume_bits(total_bits); 804| | 805| 85.3k| let copy_length = length.min(output.len() - output_index); 806| 85.3k| if dist == 1 { 807| 24.1k| let last = output[output_index - 1]; 808| 24.1k| output[output_index..][..copy_length].fill(last); 809| | 810| 24.1k| if copy_length < length { 811| 7.40k| self.queued_rle = Some((last, length - copy_length)); 812| 7.40k| output_index = output.len(); 813| 7.40k| break; 814| 16.7k| } 815| 61.1k| } else if output_index + length + 15 <= output.len() { 816| 40.5k| let start = output_index - dist; 817| 40.5k| output.copy_within(start..start + 16, output_index); 818| | 819| 40.5k| if length > 16 || dist < 16 { 820| 3.18M| for i in (0..length).step_by(dist.min(16)).skip(1) { 821| 3.18M| output.copy_within(start + i..start + i + 16, output_index + i); 822| 3.18M| } 823| 1.55k| } 824| | } else { 825| 20.6k| if dist < copy_length { 826| 304k| for i in 0..copy_length { 827| 304k| output[output_index + i] = output[output_index + i - dist]; 828| 304k| } 829| | } else { 830| 9.29k| output.copy_within( 831| 9.29k| output_index - dist..output_index + copy_length - dist, 832| 9.29k| output_index, 833| | ) 834| | } 835| | 836| 20.6k| if copy_length < length { 837| 19.7k| self.queued_backref = Some((dist, length - copy_length)); 838| 19.7k| output_index = output.len(); 839| 19.7k| break; 840| 867| } 841| | } 842| 58.1k| output_index += copy_length; 843| | } 844| | 845| 846k| if self.state == State::CompressedData 846| 833k| && self.queued_backref.is_none() 847| 245k| && self.queued_rle.is_none() 848| 8.46k| && self.nbits >= 15 849| 4.99k| && self.peak_bits(15) as u16 & self.compression.eof_mask == self.compression.eof_code 850| | { 851| 759| self.consume_bits(self.compression.eof_bits); 852| 759| self.state = match self.last_block { 853| 727| true => State::Checksum, 854| 32| false => State::BlockHeader, 855| | }; 856| 845k| } 857| | 858| 846k| Ok(output_index) 859| 846k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor17read_block_header: 184| 22.3k| fn read_block_header(&mut self, remaining_input: &mut &[u8]) -> Result<(), DecompressionError> { 185| 22.3k| self.fill_buffer(remaining_input); 186| 22.3k| if self.nbits < 10 { 187| 430| return Ok(()); 188| 21.9k| } 189| | 190| 21.9k| let start = self.peak_bits(3); 191| 21.9k| self.last_block = start & 1 != 0; 192| 21.9k| match start >> 1 { 193| | 0b00 => { 194| 1.15k| let align_bits = (self.nbits - 3) % 8; 195| 1.15k| let header_bits = 3 + 32 + align_bits; 196| 1.15k| if self.nbits < header_bits { 197| 213| return Ok(()); 198| 946| } 199| | 200| 946| let len = (self.peak_bits(align_bits + 19) >> (align_bits + 3)) as u16; 201| 946| let nlen = (self.peak_bits(header_bits) >> (align_bits + 19)) as u16; 202| 946| if nlen != !len { 203| 74| return Err(DecompressionError::InvalidUncompressedBlockLength); 204| 872| } 205| | 206| 872| self.state = State::UncompressedData; 207| 872| self.uncompressed_bytes_left = len; 208| 872| self.consume_bits(header_bits); 209| 872| Ok(()) 210| | } 211| | 0b01 => { 212| 8.35k| 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| 8.35k| if self.peak_bits(7) == 0 { 218| 2.04k| self.consume_bits(7); 219| 2.04k| if self.last_block { 220| 18| self.state = State::Checksum; 221| 18| return Ok(()); 222| 2.02k| } 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| 3.02k| while self.nbits >= 10 && self.peak_bits(10) == 0b010 { 230| 1.00k| self.consume_bits(10); 231| 1.00k| self.fill_buffer(remaining_input); 232| 1.00k| } 233| 2.02k| return self.read_block_header(remaining_input); 234| 6.31k| } 235| | 236| | // Build decoding tables if the previous block wasn't also a fixed block. 237| 6.31k| if !self.fixed_table { 238| 4.04k| self.fixed_table = true; 239| 32.3k| for chunk in self.compression.litlen_table.chunks_exact_mut(512) { 240| 32.3k| chunk.copy_from_slice(&FIXED_LITLEN_TABLE); 241| 32.3k| } 242| 64.6k| for chunk in self.compression.dist_table.chunks_exact_mut(32) { 243| 64.6k| chunk.copy_from_slice(&FIXED_DIST_TABLE); 244| 64.6k| } 245| 4.04k| self.compression.eof_bits = 7; 246| 4.04k| self.compression.eof_code = 0; 247| 4.04k| self.compression.eof_mask = 0x7f; 248| 2.27k| } 249| | 250| 6.31k| self.state = State::CompressedData; 251| 6.31k| Ok(()) 252| | } 253| | 0b10 => { 254| 12.3k| if self.nbits < 17 { 255| 86| return Ok(()); 256| 12.2k| } 257| | 258| 12.2k| self.header.hlit = (self.peak_bits(8) >> 3) as usize + 257; 259| 12.2k| self.header.hdist = (self.peak_bits(13) >> 8) as usize + 1; 260| 12.2k| self.header.hclen = (self.peak_bits(17) >> 13) as usize + 4; 261| 12.2k| if self.header.hlit > 286 { 262| 4| return Err(DecompressionError::InvalidHlit); 263| 12.2k| } 264| 12.2k| if self.header.hdist > 30 { 265| 6| return Err(DecompressionError::InvalidHdist); 266| 12.2k| } 267| | 268| 12.2k| self.consume_bits(17); 269| 12.2k| self.state = State::CodeLengthCodes; 270| 12.2k| self.fixed_table = false; 271| 12.2k| Ok(()) 272| | } 273| 28| 0b11 => Err(DecompressionError::InvalidBlockType), 274| 0| _ => unreachable!(), 275| | } 276| 22.3k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor17read_code_lengths: 317| 12.5k| fn read_code_lengths(&mut self, remaining_input: &mut &[u8]) -> Result<(), DecompressionError> { 318| 12.5k| let total_lengths = self.header.hlit + self.header.hdist; 319| 881k| while self.header.num_lengths_read < total_lengths { 320| 869k| self.fill_buffer(remaining_input); 321| 869k| if self.nbits < 7 { 322| 312| return Ok(()); 323| 869k| } 324| | 325| 869k| let code = self.peak_bits(7); 326| 869k| let entry = self.header.table[code as usize]; 327| 869k| let length = (entry & 0x7) as u8; 328| 869k| let symbol = (entry >> 16) as u8; 329| | 330| 869k| debug_assert!(length != 0); 331| 869k| match symbol { 332| 869k| 0..=15 => { 333| 761k| self.header.code_lengths[self.header.num_lengths_read] = symbol; 334| 761k| self.header.num_lengths_read += 1; 335| 761k| self.consume_bits(length); 336| 761k| } 337| 107k| 16..=18 => { 338| 107k| let (base_repeat, extra_bits) = match symbol { 339| 48.1k| 16 => (3, 2), 340| 29.2k| 17 => (3, 3), 341| 29.9k| 18 => (11, 7), 342| 0| _ => unreachable!(), 343| | }; 344| | 345| 107k| if self.nbits < length + extra_bits { 346| 282| return Ok(()); 347| 107k| } 348| | 349| 107k| let value = match symbol { 350| | 16 => { 351| 48.0k| self.header.code_lengths[self 352| 48.0k| .header 353| 48.0k| .num_lengths_read 354| 48.0k| .checked_sub(1) 355| 48.0k| .ok_or(DecompressionError::InvalidCodeLengthRepeat)?] 356| | // TODO: is this right? 357| | } 358| 29.2k| 17 => 0, 359| 29.7k| 18 => 0, 360| 0| _ => unreachable!(), 361| | }; 362| | 363| 107k| let repeat = 364| 107k| (self.peak_bits(length + extra_bits) >> length) as usize + base_repeat; 365| 107k| if self.header.num_lengths_read + repeat > total_lengths { 366| 27| return Err(DecompressionError::InvalidCodeLengthRepeat); 367| 107k| } 368| | 369| 2.70M| for i in 0..repeat { 370| 2.70M| self.header.code_lengths[self.header.num_lengths_read + i] = value; 371| 2.70M| } 372| 107k| self.header.num_lengths_read += repeat; 373| 107k| self.consume_bits(length + extra_bits); 374| | } 375| 0| _ => unreachable!(), 376| | } 377| | } 378| | 379| 11.9k| self.header 380| 11.9k| .code_lengths 381| 11.9k| .copy_within(self.header.hlit..total_lengths, 288); 382| 168k| for i in self.header.hlit..288 { 383| 168k| self.header.code_lengths[i] = 0; 384| 168k| } 385| 212k| for i in 288 + self.header.hdist..320 { 386| 212k| self.header.code_lengths[i] = 0; 387| 212k| } 388| | 389| 11.9k| Self::build_tables( 390| 11.9k| self.header.hlit, 391| 11.9k| &self.header.code_lengths, 392| 11.9k| &mut self.compression, 393| 196| )?; 394| 11.7k| self.state = State::CompressedData; 395| 11.7k| Ok(()) 396| 12.5k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor22read_code_length_codes: 278| 12.4k| fn read_code_length_codes( 279| 12.4k| &mut self, 280| 12.4k| remaining_input: &mut &[u8], 281| 12.4k| ) -> Result<(), DecompressionError> { 282| 12.4k| self.fill_buffer(remaining_input); 283| 12.4k| if self.nbits as usize + remaining_input.len() * 8 < 3 * self.header.hclen { 284| 235| return Ok(()); 285| 12.2k| } 286| | 287| 12.2k| let mut code_length_lengths = [0; 19]; 288| 214k| for i in 0..self.header.hclen { 289| 214k| code_length_lengths[CLCL_ORDER[i]] = self.peak_bits(3) as u8; 290| 214k| 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| 214k| if i == 17 { 295| 9.44k| self.fill_buffer(remaining_input); 296| 205k| } 297| | } 298| | 299| 12.2k| let mut codes = [0; 19]; 300| 12.2k| if !build_table( 301| 12.2k| &code_length_lengths, 302| 12.2k| &[], 303| 12.2k| &mut codes, 304| 12.2k| &mut self.header.table, 305| 12.2k| &mut Vec::new(), 306| 12.2k| false, 307| 12.2k| false, 308| 12.2k| ) { 309| 89| return Err(DecompressionError::BadCodeLengthHuffmanTree); 310| 12.1k| } 311| | 312| 12.1k| self.state = State::CodeLengths; 313| 12.1k| self.header.num_lengths_read = 0; 314| 12.1k| Ok(()) 315| 12.4k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor3new: 120| 11.8k| pub fn new() -> Self { 121| 11.8k| Self { 122| 11.8k| buffer: 0, 123| 11.8k| nbits: 0, 124| 11.8k| compression: CompressedBlock { 125| 11.8k| litlen_table: Box::new([0; 4096]), 126| 11.8k| dist_table: Box::new([0; 512]), 127| 11.8k| secondary_table: Vec::new(), 128| 11.8k| dist_secondary_table: Vec::new(), 129| 11.8k| eof_code: 0, 130| 11.8k| eof_mask: 0, 131| 11.8k| eof_bits: 0, 132| 11.8k| }, 133| 11.8k| header: BlockHeader { 134| 11.8k| hlit: 0, 135| 11.8k| hdist: 0, 136| 11.8k| hclen: 0, 137| 11.8k| table: [0; 128], 138| 11.8k| num_lengths_read: 0, 139| 11.8k| code_lengths: [0; 320], 140| 11.8k| }, 141| 11.8k| uncompressed_bytes_left: 0, 142| 11.8k| queued_rle: None, 143| 11.8k| queued_backref: None, 144| 11.8k| checksum: Adler32::new(), 145| 11.8k| state: State::ZlibHeader, 146| 11.8k| last_block: false, 147| 11.8k| ignore_adler32: false, 148| 11.8k| fixed_table: false, 149| 11.8k| } 150| 11.8k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor4read: 879| 839k| pub fn read( 880| 839k| &mut self, 881| 839k| input: &[u8], 882| 839k| output: &mut [u8], 883| 839k| output_position: usize, 884| 839k| end_of_input: bool, 885| 839k| ) -> Result<(usize, usize), DecompressionError> { 886| 839k| if let State::Done = self.state { 887| 0| return Ok((0, 0)); 888| 839k| } 889| | 890| 839k| assert!(output_position <= output.len()); 891| | 892| 839k| let mut remaining_input = input; 893| 839k| let mut output_index = output_position; 894| | 895| 839k| if let Some((data, len)) = self.queued_rle.take() { 896| 236k| let n = len.min(output.len() - output_index); 897| 236k| output[output_index..][..n].fill(data); 898| 236k| output_index += n; 899| 236k| if n < len { 900| 6| self.queued_rle = Some((data, len - n)); 901| 6| return Ok((0, n)); 902| 236k| } 903| 603k| } 904| 839k| if let Some((dist, len)) = self.queued_backref.take() { 905| 586k| let n = len.min(output.len() - output_index); 906| 75.3M| for i in 0..n { 907| 75.3M| output[output_index + i] = output[output_index + i - dist]; 908| 75.3M| } 909| 586k| output_index += n; 910| 586k| if n < len { 911| 15| self.queued_backref = Some((dist, len - n)); 912| 15| return Ok((0, n)); 913| 586k| } 914| 252k| } 915| | 916| | // Main decoding state machine. 917| 839k| let mut last_state = None; 918| 1.74M| while last_state != Some(self.state) { 919| 905k| last_state = Some(self.state); 920| 905k| match self.state { 921| | State::ZlibHeader => { 922| 9.25k| self.fill_buffer(&mut remaining_input); 923| 9.25k| if self.nbits < 16 { 924| 1.55k| break; 925| 7.70k| } 926| | 927| 7.70k| let input0 = self.peak_bits(8); 928| 7.70k| let input1 = self.peak_bits(16) >> 8 & 0xff; 929| 7.70k| if input0 & 0x0f != 0x08 930| 7.64k| || (input0 & 0xf0) > 0x70 931| 7.63k| || input1 & 0x20 != 0 932| 7.62k| || (input0 << 8 | input1) % 31 != 0 933| | { 934| 86| return Err(DecompressionError::BadZlibHeader); 935| 7.61k| } 936| | 937| 7.61k| self.consume_bits(16); 938| 7.61k| self.state = State::BlockHeader; 939| | } 940| | State::BlockHeader => { 941| 20.3k| self.read_block_header(&mut remaining_input)?; 942| | } 943| | State::CodeLengthCodes => { 944| 12.4k| self.read_code_length_codes(&mut remaining_input)?; 945| | } 946| | State::CodeLengths => { 947| 12.5k| self.read_code_lengths(&mut remaining_input)?; 948| | } 949| | State::CompressedData => { 950| | output_index = 951| 846k| self.read_compressed(&mut remaining_input, output, output_index)? 952| | } 953| | State::UncompressedData => { 954| | // Drain any bytes from our buffer. 955| 1.26k| debug_assert_eq!(self.nbits % 8, 0); 956| 2.85k| while self.nbits > 0 957| 1.67k| && self.uncompressed_bytes_left > 0 958| 1.60k| && output_index < output.len() 959| 1.59k| { 960| 1.59k| output[output_index] = self.peak_bits(8) as u8; 961| 1.59k| self.consume_bits(8); 962| 1.59k| output_index += 1; 963| 1.59k| self.uncompressed_bytes_left -= 1; 964| 1.59k| } 965| | // Buffer may contain one additional byte. Clear it to avoid confusion. 966| 1.26k| if self.nbits == 0 { 967| 1.18k| self.buffer = 0; 968| 1.18k| } 969| | 970| | // Copy subsequent bytes directly from the input. 971| 1.26k| let copy_bytes = (self.uncompressed_bytes_left as usize) 972| 1.26k| .min(remaining_input.len()) 973| 1.26k| .min(output.len() - output_index); 974| 1.26k| output[output_index..][..copy_bytes] 975| 1.26k| .copy_from_slice(&remaining_input[..copy_bytes]); 976| 1.26k| remaining_input = &remaining_input[copy_bytes..]; 977| 1.26k| output_index += copy_bytes; 978| 1.26k| self.uncompressed_bytes_left -= copy_bytes as u16; 979| | 980| 1.26k| if self.uncompressed_bytes_left == 0 { 981| 812| self.state = if self.last_block { 982| 3| State::Checksum 983| | } else { 984| 809| State::BlockHeader 985| | }; 986| 449| } 987| | } 988| | State::Checksum => { 989| 3.18k| self.fill_buffer(&mut remaining_input); 990| | 991| 3.18k| let align_bits = self.nbits % 8; 992| 3.18k| if self.nbits >= 32 + align_bits { 993| 2.90k| self.checksum.write(&output[output_position..output_index]); 994| 2.90k| 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| 2.90k| self.state = State::Done; 1004| 2.90k| self.consume_bits(32); 1005| 2.90k| break; 1006| 280| } 1007| | } 1008| 0| State::Done => unreachable!(), 1009| | } 1010| | } 1011| | 1012| 839k| if !self.ignore_adler32 && self.state != State::Done { 1013| 158k| self.checksum.write(&output[output_position..output_index]); 1014| 680k| } 1015| | 1016| 839k| if self.state == State::Done || !end_of_input || output_index == output.len() { 1017| 838k| let input_left = remaining_input.len(); 1018| 838k| Ok((input.len() - input_left, output_index - output_position)) 1019| | } else { 1020| 324| Err(DecompressionError::InsufficientInput) 1021| | } 1022| 839k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor7is_done: 1025| 1.51M| pub fn is_done(&self) -> bool { 1026| 1.51M| self.state == State::Done 1027| 1.51M| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor9peak_bits: 174| 1.28M| fn peak_bits(&mut self, nbits: u8) -> u64 { 175| 1.28M| debug_assert!(nbits <= 56 && nbits <= self.nbits); 176| 1.28M| self.buffer & ((1u64 << nbits) - 1) 177| 1.28M| } _RNvNtCsh5m7Dv6WxNY_8fdeflate10decompress25decompress_to_vec_bounded: 1063| 2.18k|pub fn decompress_to_vec_bounded( 1064| 2.18k| input: &[u8], 1065| 2.18k| maxlen: usize, 1066| 2.18k|) -> Result, BoundedDecompressionError> { 1067| 2.18k| let mut decoder = Decompressor::new(); 1068| 2.18k| let mut output = vec![0; 1024.min(maxlen)]; 1069| 2.18k| let mut input_index = 0; 1070| 2.18k| let mut output_index = 0; 1071| | loop { 1072| 160k| let (consumed, produced) = 1073| 160k| decoder.read(&input[input_index..], &mut output, output_index, true)?; 1074| 160k| input_index += consumed; 1075| 160k| output_index += produced; 1076| 160k| if decoder.is_done() || output_index == maxlen { 1077| 1.77k| break; 1078| 158k| } 1079| 158k| output.resize((output_index + 32 * 1024).min(maxlen), 0); 1080| | } 1081| 1.77k| output.resize(output_index, 0); 1082| | 1083| 1.77k| if decoder.is_done() { 1084| 1.77k| Ok(output) 1085| | } else { 1086| 0| Err(BoundedDecompressionError::OutputTooLarge { 1087| 0| partial_output: output, 1088| 0| }) 1089| | } 1090| 2.18k|} _RNvXs0_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB5_25BoundedDecompressionErrorINtNtCs6SNw0SRvItZ_4core7convert4FromNtB5_18DecompressionErrorE4from: 1056| 407| fn from(inner: DecompressionError) -> Self { 1057| 407| BoundedDecompressionError::DecompressionError { inner } 1058| 407| } _RNCNvNtCsh5m7Dv6WxNY_8fdeflate7huffman11build_table0B5_: 46| 8.94k| let symbol = lengths.iter().position(|&l| l == 1).unwrap(); _RNvNtCsh5m7Dv6WxNY_8fdeflate7huffman11build_table: 18| 35.3k|pub fn build_table( 19| 35.3k| lengths: &[u8], 20| 35.3k| entries: &[u32], 21| 35.3k| codes: &mut [u16], 22| 35.3k| primary_table: &mut [u32], 23| 35.3k| secondary_table: &mut Vec, 24| 35.3k| is_distance_table: bool, 25| 35.3k| double_literal: bool, 26| 35.3k|) -> bool { 27| | // Count the number of symbols with each code length. 28| 35.3k| let mut histogram = [0; 16]; 29| 3.90M| for &length in lengths { 30| 3.86M| histogram[length as usize] += 1; 31| 3.86M| } 32| | 33| | // Determine the maximum code length. 34| 35.3k| let mut max_length = 15; 35| 397k| while max_length > 1 && histogram[max_length] == 0 { 36| 362k| max_length -= 1; 37| 362k| } 38| | 39| | // Handle zero and one symbol huffman codes (which are only allowed for distance codes). 40| 35.3k| if is_distance_table { 41| 11.1k| if max_length == 0 { 42| 0| primary_table.fill(0); 43| 0| secondary_table.clear(); 44| 0| return true; 45| 11.1k| } else if max_length == 1 && histogram[1] == 1 { 46| 4.28k| let symbol = lengths.iter().position(|&l| l == 1).unwrap(); 47| 4.28k| codes[symbol] = 0; 48| 4.28k| let entry = entries 49| 4.28k| .get(symbol) 50| 4.28k| .cloned() 51| 4.28k| .unwrap_or((symbol as u32) << 16) 52| 4.28k| | 1; 53| 1.09M| for chunk in primary_table.chunks_mut(2) { 54| 1.09M| chunk[0] = entry; 55| 1.09M| chunk[1] = 0; 56| 1.09M| } 57| 4.28k| return true; 58| 6.85k| } 59| 24.1k| } 60| | 61| | // Sort symbols by code length. Given the histogram, we can determine the starting offset 62| | // for each code length. 63| 31.0k| let mut offsets = [0; 16]; 64| 31.0k| let mut codespace_used = 0; 65| 31.0k| offsets[1] = histogram[0]; 66| 132k| for i in 1..max_length { 67| 132k| offsets[i + 1] = offsets[i] + histogram[i]; 68| 132k| codespace_used = (codespace_used << 1) + histogram[i]; 69| 132k| } 70| 31.0k| codespace_used = (codespace_used << 1) + histogram[max_length]; 71| | 72| | // Check that the provided lengths form a valid Huffman tree. 73| 31.0k| if codespace_used != (1 << max_length) { 74| 274| return false; 75| 30.7k| } 76| | 77| | // Sort the symbols by code length. 78| 30.7k| let mut next_index = offsets; 79| 30.7k| let mut sorted_symbols = [0; 288]; 80| 3.70M| for symbol in 0..lengths.len() { 81| 3.70M| let length = lengths[symbol]; 82| 3.70M| sorted_symbols[next_index[length as usize]] = symbol; 83| 3.70M| next_index[length as usize] += 1; 84| 3.70M| } 85| | 86| 30.7k| let mut codeword = 0u16; 87| 30.7k| let mut i = histogram[0]; 88| | 89| | // Populate the primary decoding table 90| 30.7k| let primary_table_bits = primary_table.len().ilog2() as usize; 91| 30.7k| let primary_table_mask = (1 << primary_table_bits) - 1; 92| 288k| for length in 1..=primary_table_bits { 93| 288k| let current_table_end = 1 << length; 94| | 95| | // Loop over all symbols with the current code length and set their table entries. 96| 788k| for _ in 0..histogram[length] { 97| 788k| let symbol = sorted_symbols[i]; 98| 788k| i += 1; 99| 788k| 100| 788k| primary_table[codeword as usize] = entries 101| 788k| .get(symbol) 102| 788k| .cloned() 103| 788k| .unwrap_or((symbol as u32) << 16) 104| 788k| | length as u32; 105| 788k| 106| 788k| codes[symbol] = codeword; 107| 788k| codeword = next_codeword(codeword, current_table_end as u16); 108| 788k| } 109| | 110| 288k| if double_literal { 111| 654k| for len1 in 1..(length - 1) { 112| 654k| let len2 = length - len1; 113| 1.64M| for sym1_index in offsets[len1]..next_index[len1] { 114| 3.10M| for sym2_index in offsets[len2]..next_index[len2] { 115| 3.10M| let sym1 = sorted_symbols[sym1_index]; 116| 3.10M| let sym2 = sorted_symbols[sym2_index]; 117| 3.10M| 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| 145k| } 131| | 132| | // If we aren't at the maximum table size, double the size of the table. 133| 288k| if length < primary_table_bits { 134| 257k| primary_table.copy_within(0..current_table_end, current_table_end); 135| 257k| } 136| | } 137| | 138| | // Populate the secondary decoding table. 139| 30.7k| secondary_table.clear(); 140| 30.7k| if max_length > primary_table_bits { 141| 4.31k| let mut subtable_start = 0; 142| 4.31k| let mut subtable_prefix = !0; 143| 9.50k| for length in (primary_table_bits + 1)..=max_length { 144| 9.50k| let subtable_size = 1 << (length - primary_table_bits); 145| 9.50k| for _ in 0..histogram[length] { 146| | // If the codeword's prefix doesn't match the current subtable, create a new 147| | // subtable. 148| 183k| if codeword & primary_table_mask != subtable_prefix { 149| 58.5k| subtable_prefix = codeword & primary_table_mask; 150| 58.5k| subtable_start = secondary_table.len(); 151| 58.5k| primary_table[subtable_prefix as usize] = ((subtable_start as u32) << 16) 152| 58.5k| | EXCEPTIONAL_ENTRY 153| 58.5k| | SECONDARY_TABLE_ENTRY 154| 58.5k| | (subtable_size as u32 - 1); 155| 58.5k| secondary_table.resize(subtable_start + subtable_size, 0); 156| 124k| } 157| | 158| | // Lookup the symbol. 159| 183k| let symbol = sorted_symbols[i]; 160| 183k| i += 1; 161| | 162| | // Insert the symbol into the secondary table and advance to the next codeword. 163| 183k| codes[symbol] = codeword; 164| 183k| secondary_table[subtable_start + (codeword >> primary_table_bits) as usize] = 165| 183k| ((symbol as u16) << 4) | (length as u16); 166| 183k| codeword = next_codeword(codeword, 1 << length); 167| | } 168| | 169| | // If there are more codes with the same subtable prefix, extend the subtable. 170| 9.50k| if length < max_length && codeword & primary_table_mask == subtable_prefix { 171| 3.75k| secondary_table.extend_from_within(subtable_start..); 172| 3.75k| let subtable_size = secondary_table.len() - subtable_start; 173| 3.75k| primary_table[subtable_prefix as usize] = ((subtable_start as u32) << 16) 174| 3.75k| | EXCEPTIONAL_ENTRY 175| 3.75k| | SECONDARY_TABLE_ENTRY 176| 3.75k| | (subtable_size as u32 - 1); 177| 5.75k| } 178| | } 179| 26.4k| } 180| | 181| 30.7k| true 182| 35.3k|} _RNvNtCsh5m7Dv6WxNY_8fdeflate7huffman13next_codeword: 5| 972k|fn next_codeword(mut codeword: u16, table_size: u16) -> u16 { 6| 972k| if codeword == table_size - 1 { 7| 30.7k| return codeword; 8| 941k| } 9| | 10| 941k| let adv = (u16::BITS - 1) - (codeword ^ (table_size - 1)).leading_zeros(); 11| 941k| let bit = 1 << adv; 12| 941k| codeword &= bit - 1; 13| 941k| codeword |= bit; 14| 941k| codeword 15| 972k|} 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| } _RNvNvCs89KXAlqehWX_17fuzzer_script_png1__19___libfuzzer_sys_run: 293| 9.46k| fn __libfuzzer_sys_run($bytes: &[u8]) -> $rty { 294| | $body 295| 9.46k| } rust_fuzzer_test_input: 261| 9.46k| 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.46k| 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.46k| } 275| | 276| 9.46k| let result = ::libfuzzer_sys::Corpus::from(__libfuzzer_sys_run(bytes)); 277| 9.46k| result.to_libfuzzer_code() 278| 9.46k| } LLVMFuzzerTestOneInput: 59| 9.46k|pub unsafe fn test_input_wrap(data: *const u8, size: usize) -> i32 { 60| 9.46k| 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.46k| match test_input { 66| 9.46k| 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.46k|} _RNCNvCs7Clpp3Dxqfy_13libfuzzer_sys15test_input_wrap0B3_: 60| 9.46k| let test_input = ::std::panic::catch_unwind(|| { 61| 9.46k| let data_slice = ::std::slice::from_raw_parts(data, size); 62| 9.46k| rust_fuzzer_test_input(data_slice) 63| 9.46k| }); _RNCNvCs7Clpp3Dxqfy_13libfuzzer_sys25rust_libfuzzer_debug_path0B3_: 78| 1| RUST_LIBFUZZER_DEBUG_PATH.get_or_init(|| std::env::var("RUST_LIBFUZZER_DEBUG_PATH").ok()) _RNvCs7Clpp3Dxqfy_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|} _RNvCs7Clpp3Dxqfy_13libfuzzer_sys25rust_libfuzzer_debug_path: 76| 9.46k|pub fn rust_libfuzzer_debug_path() -> &'static Option { 77| | static RUST_LIBFUZZER_DEBUG_PATH: OnceLock> = OnceLock::new(); 78| 9.46k| RUST_LIBFUZZER_DEBUG_PATH.get_or_init(|| std::env::var("RUST_LIBFUZZER_DEBUG_PATH").ok()) 79| 9.46k|} _RNvMs_Cs7Clpp3Dxqfy_13libfuzzer_sysNtB4_6Corpus17to_libfuzzer_code: 40| 9.46k| pub fn to_libfuzzer_code(self) -> i32 { 41| 9.46k| match self { 42| 9.46k| Corpus::Keep => 0, 43| 0| Corpus::Reject => -1, 44| | } 45| 9.46k| } _RNvXCs7Clpp3Dxqfy_13libfuzzer_sysNtB2_6CorpusINtNtCs6SNw0SRvItZ_4core7convert4FromuE4from: 30| 9.46k| fn from(_: ()) -> Self { 31| 9.46k| Self::Keep 32| 9.46k| } _RNvMs_NtCs1jiJzeRTgBH_6moxcms3datNtB4_13ColorDateTime14new_from_slice: 81| 985| pub fn new_from_slice(slice: &[u8]) -> Result { 82| 985| if slice.len() != 12 { 83| 0| return Err(CmsError::InvalidProfile); 84| 985| } 85| 985| let year = u16::from_be_bytes([slice[0], slice[1]]); 86| 985| let month = u16::from_be_bytes([slice[2], slice[3]]); 87| 985| let day_of_the_month = u16::from_be_bytes([slice[4], slice[5]]); 88| 985| let hours = u16::from_be_bytes([slice[6], slice[7]]); 89| 985| let minutes = u16::from_be_bytes([slice[8], slice[9]]); 90| 985| let seconds = u16::from_be_bytes([slice[10], slice[11]]); 91| 985| Ok(ColorDateTime { 92| 985| year, 93| 985| month, 94| 985| day_of_the_month, 95| 985| hours, 96| 985| minutes, 97| 985| seconds, 98| 985| }) 99| 985| } _RNvMs_NtCs1jiJzeRTgBH_6moxcms3datNtB4_13ColorDateTime3now: 102| 927| pub fn now() -> Self { 103| | #[cfg(not(target_arch = "wasm32"))] 104| 927| let now = match SystemTime::now().duration_since(UNIX_EPOCH) { 105| 927| 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| 927| let mut days = (now.as_secs() / 86_400) as i64; 113| 927| let secs_of_day = (now.as_secs() % 86_400) as i64; 114| | 115| 927| let mut year = 1970; 116| | loop { 117| 52.8k| let year_days = if is_leap(year) { 366 } else { 365 }; 118| 52.8k| if days >= year_days { 119| 51.9k| days -= year_days; 120| 51.9k| year += 1; 121| 51.9k| } else { 122| 927| break; 123| | } 124| | } 125| | 126| 927| let mut month = 1; 127| | loop { 128| 6.48k| let mdays = days_in_month(year, month); 129| 6.48k| if days >= mdays as i64 { 130| 5.56k| days -= mdays as i64; 131| 5.56k| month += 1; 132| 5.56k| } else { 133| 927| break; 134| | } 135| | } 136| 927| let day = days + 1; // days from zero based to 1 base 137| | 138| 927| let hour = secs_of_day / 3600; 139| 927| let min = (secs_of_day % 3600) / 60; 140| 927| let sec = secs_of_day % 60; 141| 927| Self { 142| 927| year: year as u16, 143| 927| month: month as u16, 144| 927| day_of_the_month: day as u16, 145| 927| hours: hour as u16, 146| 927| minutes: min as u16, 147| 927| seconds: sec as u16, 148| 927| } 149| 927| } _RNvNtCs1jiJzeRTgBH_6moxcms3dat13days_in_month: 49| 6.48k|fn days_in_month(year: i32, month: i32) -> i32 { 50| 6.48k| match month { 51| 927| 1 => 31, 52| | 2 => { 53| 927| if is_leap(year) { 54| 0| 29 55| | } else { 56| 927| 28 57| | } 58| | } 59| 927| 3 => 31, 60| 927| 4 => 30, 61| 927| 5 => 31, 62| 927| 6 => 30, 63| 927| 7 => 31, 64| 0| 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| 6.48k|} _RNvNtCs1jiJzeRTgBH_6moxcms3dat7is_leap: 45| 53.7k|fn is_leap(year: i32) -> bool { 46| 53.7k| (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) 47| 53.7k|} _RNvXNtCs1jiJzeRTgBH_6moxcms3datNtB2_13ColorDateTimeNtNtCs6SNw0SRvItZ_4core7default7Default7default: 74| 927| fn default() -> Self { 75| 927| Self::now() 76| 927| } _RNvMs19_NtCs1jiJzeRTgBH_6moxcms6matrixNtB6_3Xyz3newB8_: 1066| 953| pub const fn new(x: $im_type, y: $im_type, z: $im_type) -> Self { 1067| 953| Self { x, y, z } 1068| 953| } _RNvMss_NtCs1jiJzeRTgBH_6moxcms6matrixNtB5_3Xyz7to_xyzd: 1244| 927| pub fn to_xyzd(self) -> Xyzd { 1245| 927| Xyzd { 1246| 927| x: self.x as f64, 1247| 927| y: self.y as f64, 1248| 927| z: self.z as f64, 1249| 927| } 1250| 927| } _RNvMse_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_13ProfileHeader14new_from_slice: 686| 1.56k| pub(crate) fn new_from_slice(slice: &[u8]) -> Result { 687| 1.56k| if slice.len() < size_of::() { 688| 3| return Err(CmsError::InvalidProfile); 689| 1.55k| } 690| 1.55k| let mut cursor = std::io::Cursor::new(slice); 691| 1.55k| let mut buffer = [0u8; size_of::()]; 692| 1.55k| cursor 693| 1.55k| .read_exact(&mut buffer) 694| 1.55k| .map_err(|_| CmsError::InvalidProfile)?; 695| | 696| 953| let header = Self { 697| 1.55k| size: u32::from_be_bytes(buffer[0..4].try_into().unwrap()), 698| 1.55k| cmm_type: u32::from_be_bytes(buffer[4..8].try_into().unwrap()), 699| 1.55k| version: ProfileVersion::try_from(u32::from_be_bytes( 700| 1.55k| buffer[8..12].try_into().unwrap(), 701| 44| ))?, 702| 1.51k| profile_class: ProfileClass::try_from(u32::from_be_bytes( 703| 1.51k| buffer[12..16].try_into().unwrap(), 704| 354| ))?, 705| 1.15k| data_color_space: DataColorSpace::try_from(u32::from_be_bytes( 706| 1.15k| buffer[16..20].try_into().unwrap(), 707| 87| ))?, 708| 1.07k| pcs: DataColorSpace::try_from(u32::from_be_bytes(buffer[20..24].try_into().unwrap()))?, 709| 985| creation_date_time: ColorDateTime::new_from_slice(buffer[24..36].try_into().unwrap())?, 710| 985| signature: ProfileSignature::try_from(u32::from_be_bytes( 711| 985| buffer[36..40].try_into().unwrap(), 712| 32| ))?, 713| 953| platform: u32::from_be_bytes(buffer[40..44].try_into().unwrap()), 714| 953| flags: u32::from_be_bytes(buffer[44..48].try_into().unwrap()), 715| 953| device_manufacturer: u32::from_be_bytes(buffer[48..52].try_into().unwrap()), 716| 953| device_model: u32::from_be_bytes(buffer[52..56].try_into().unwrap()), 717| 953| device_attributes: buffer[56..64].try_into().unwrap(), 718| 953| rendering_intent: RenderingIntent::try_from(u32::from_be_bytes( 719| 953| buffer[64..68].try_into().unwrap(), 720| 0| ))?, 721| 953| illuminant: Xyz::new( 722| 953| s15_fixed16_number_to_float(i32::from_be_bytes(buffer[68..72].try_into().unwrap())), 723| 953| s15_fixed16_number_to_float(i32::from_be_bytes(buffer[72..76].try_into().unwrap())), 724| 953| s15_fixed16_number_to_float(i32::from_be_bytes(buffer[76..80].try_into().unwrap())), 725| | ), 726| 953| creator: u32::from_be_bytes(buffer[80..84].try_into().unwrap()), 727| 953| profile_id: buffer[84..100].try_into().unwrap(), 728| 953| reserved: buffer[100..128].try_into().unwrap(), 729| 953| tag_count: u32::from_be_bytes(buffer[128..132].try_into().unwrap()), 730| | }; 731| 953| Ok(header) 732| 1.56k| } _RNvMsn_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_12ColorProfile14new_from_slice: 978| 1.56k| pub fn new_from_slice(slice: &[u8]) -> Result { 979| 1.56k| Self::new_from_slice_with_options(slice, Default::default()) 980| 1.56k| } _RNvMsn_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_12ColorProfile27new_from_slice_with_options: 982| 1.56k| pub fn new_from_slice_with_options( 983| 1.56k| slice: &[u8], 984| 1.56k| options: ParsingOptions, 985| 1.56k| ) -> Result { 986| 1.56k| let header = ProfileHeader::new_from_slice(slice)?; 987| 953| let tags_count = header.tag_count as usize; 988| 953| if slice.len() >= options.max_profile_size { 989| 0| return Err(CmsError::InvalidProfile); 990| 953| } 991| 953| let tags_end = tags_count 992| 953| .safe_mul(TAG_SIZE)? 993| 953| .safe_add(size_of::())?; 994| 953| if slice.len() < tags_end { 995| 26| return Err(CmsError::InvalidProfile); 996| 927| } 997| 927| let tags_slice = &slice[size_of::()..tags_end]; 998| 927| let mut profile = ColorProfile { 999| 927| rendering_intent: header.rendering_intent, 1000| 927| pcs: header.pcs, 1001| 927| profile_class: header.profile_class, 1002| 927| color_space: header.data_color_space, 1003| 927| white_point: header.illuminant.to_xyzd(), 1004| 927| version_internal: header.version, 1005| 927| creation_date_time: header.creation_date_time, 1006| 927| ..Default::default() 1007| 927| }; 1008| 927| let color_space = profile.color_space; 1009| 20.9k| for tag in tags_slice.chunks_exact(TAG_SIZE) { 1010| 20.9k| let tag_value = u32::from_be_bytes([tag[0], tag[1], tag[2], tag[3]]); 1011| 20.9k| let tag_entry = u32::from_be_bytes([tag[4], tag[5], tag[6], tag[7]]); 1012| 20.9k| let tag_size = u32::from_be_bytes([tag[8], tag[9], tag[10], tag[11]]) as usize; 1013| | // Just ignore unknown tags 1014| 20.9k| if let Ok(tag) = Tag::try_from(tag_value) { 1015| 4.70k| match tag { 1016| | Tag::RedXyz => { 1017| 527| if color_space == DataColorSpace::Rgb { 1018| | profile.red_colorant = 1019| 527| Self::read_xyz_tag(slice, tag_entry as usize, tag_size)?; 1020| 0| } 1021| | } 1022| | Tag::GreenXyz => { 1023| 275| if color_space == DataColorSpace::Rgb { 1024| | profile.green_colorant = 1025| 275| Self::read_xyz_tag(slice, tag_entry as usize, tag_size)?; 1026| 0| } 1027| | } 1028| | Tag::BlueXyz => { 1029| 333| if color_space == DataColorSpace::Rgb { 1030| | profile.blue_colorant = 1031| 333| Self::read_xyz_tag(slice, tag_entry as usize, tag_size)?; 1032| 0| } 1033| | } 1034| | Tag::RedToneReproduction => { 1035| 120| if color_space == DataColorSpace::Rgb { 1036| 120| profile.red_trc = Self::read_trc_tag_s( 1037| 120| slice, 1038| 120| tag_entry as usize, 1039| 120| tag_size, 1040| 120| &options, 1041| 83| )?; 1042| 0| } 1043| | } 1044| | Tag::GreenToneReproduction => { 1045| 36| if color_space == DataColorSpace::Rgb { 1046| 36| profile.green_trc = Self::read_trc_tag_s( 1047| 36| slice, 1048| 36| tag_entry as usize, 1049| 36| tag_size, 1050| 36| &options, 1051| 1| )?; 1052| 0| } 1053| | } 1054| | Tag::BlueToneReproduction => { 1055| 18| if color_space == DataColorSpace::Rgb { 1056| 16| profile.blue_trc = Self::read_trc_tag_s( 1057| 16| slice, 1058| 16| tag_entry as usize, 1059| 16| tag_size, 1060| 16| &options, 1061| 1| )?; 1062| 2| } 1063| | } 1064| | Tag::GreyToneReproduction => { 1065| 56| if color_space == DataColorSpace::Gray { 1066| 46| profile.gray_trc = Self::read_trc_tag_s( 1067| 46| slice, 1068| 46| tag_entry as usize, 1069| 46| tag_size, 1070| 46| &options, 1071| 36| )?; 1072| 10| } 1073| | } 1074| | Tag::MediaWhitePoint => { 1075| | profile.media_white_point = 1076| 791| 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| 1| if (profile.profile_class == ProfileClass::InputDevice 1091| 1| || profile.profile_class == ProfileClass::DisplayDevice) 1092| 1| && (profile.color_space == DataColorSpace::Rgb 1093| 0| || profile.color_space == DataColorSpace::YCbr 1094| 0| || profile.color_space == DataColorSpace::Xyz) 1095| | { 1096| | profile.cicp = 1097| 1| 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| 591| 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| 820| profile.copyright = 1137| 864| Self::read_string_tag(slice, tag_entry as usize, tag_size)?; 1138| | } 1139| | Tag::ProfileDescription => { 1140| 1.06k| profile.description = 1141| 1.08k| 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| 0| 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| 1| 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| 16.2k| } 1174| | } 1175| | 1176| 495| Ok(profile) 1177| 1.56k| } _RNvXNtCs1jiJzeRTgBH_6moxcms7profileNtB2_16ProfileSignatureINtNtCs6SNw0SRvItZ_4core7convert7TryFrommE8try_fromB4_: 54| 985| fn try_from(value: u32) -> Result { 55| 985| if value == u32::from_ne_bytes(*b"acsp").to_be() { 56| 953| return Ok(ProfileSignature::Acsp); 57| 32| } 58| 32| Err(CmsError::InvalidProfile) 59| 985| } _RNvXs0_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_14ProfileVersionINtNtCs6SNw0SRvItZ_4core7convert7TryFrommE8try_from: 90| 1.55k| fn try_from(value: u32) -> Result { 91| | // First try exact match for known versions 92| 1.55k| match value { 93| 1| 0x02000000 => return Ok(ProfileVersion::V2_0), 94| 1| 0x02100000 => return Ok(ProfileVersion::V2_1), 95| 147| 0x02200000 => return Ok(ProfileVersion::V2_2), 96| 1| 0x02300000 => return Ok(ProfileVersion::V2_3), 97| 769| 0x02400000 => return Ok(ProfileVersion::V2_4), 98| 1| 0x04000000 => return Ok(ProfileVersion::V4_0), 99| 0| 0x04100000 => return Ok(ProfileVersion::V4_1), 100| 1| 0x04200000 => return Ok(ProfileVersion::V4_2), 101| 0| 0x04300000 => return Ok(ProfileVersion::V4_3), 102| 1| 0x04400000 => return Ok(ProfileVersion::V4_4), 103| 635| _ => {} 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| 635| let major = (value >> 24) & 0xFF; 109| 635| 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| 635| match major { 114| | 0 => { 115| | // Version 0.x is invalid - reject 116| 16| Err(CmsError::InvalidProfile) 117| | } 118| | 2 => { 119| | // v2.x - map to the appropriate v2 minor version or highest known 120| 412| match minor { 121| 51| 0 => Ok(ProfileVersion::V2_0), 122| 18| 1 => Ok(ProfileVersion::V2_1), 123| 203| 2 => Ok(ProfileVersion::V2_2), 124| 39| 3 => Ok(ProfileVersion::V2_3), 125| 101| _ => 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| 35| Ok(ProfileVersion::V2_4) 131| | } 132| | 4 => { 133| | // v4.x - map to the appropriate v4 minor version or highest known 134| 144| match minor { 135| 57| 0 => Ok(ProfileVersion::V4_0), 136| 15| 1 => Ok(ProfileVersion::V4_1), 137| 24| 2 => Ok(ProfileVersion::V4_2), 138| 28| 3 => Ok(ProfileVersion::V4_3), 139| 20| _ => 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| 28| Err(CmsError::InvalidProfile) 146| | } 147| | } 148| 1.55k| } _RNvXs3_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_12ProfileClassINtNtCs6SNw0SRvItZ_4core7convert7TryFrommE8try_from: 269| 1.51k| fn try_from(value: u32) -> Result { 270| 1.51k| if value == u32::from_ne_bytes(*b"scnr").to_be() { 271| 160| return Ok(ProfileClass::InputDevice); 272| 1.35k| } else if value == u32::from_ne_bytes(*b"mntr").to_be() { 273| 825| return Ok(ProfileClass::DisplayDevice); 274| 528| } else if value == u32::from_ne_bytes(*b"prtr").to_be() { 275| 174| return Ok(ProfileClass::OutputDevice); 276| 354| } else if value == u32::from_ne_bytes(*b"link").to_be() { 277| 0| return Ok(ProfileClass::DeviceLink); 278| 354| } else if value == u32::from_ne_bytes(*b"spac").to_be() { 279| 0| return Ok(ProfileClass::ColorSpace); 280| 354| } else if value == u32::from_ne_bytes(*b"abst").to_be() { 281| 0| return Ok(ProfileClass::Abstract); 282| 354| } else if value == u32::from_ne_bytes(*b"nmcl").to_be() { 283| 0| return Ok(ProfileClass::Named); 284| 354| } 285| 354| Err(CmsError::InvalidProfile) 286| 1.51k| } _RNvXs7_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_14DataColorSpaceINtNtCs6SNw0SRvItZ_4core7convert7TryFrommE8try_from: 346| 2.23k| fn try_from(value: u32) -> Result { 347| 2.23k| if value == u32::from_ne_bytes(*b"XYZ ").to_be() { 348| 985| return Ok(DataColorSpace::Xyz); 349| 1.24k| } else if value == u32::from_ne_bytes(*b"Lab ").to_be() { 350| 0| return Ok(DataColorSpace::Lab); 351| 1.24k| } else if value == u32::from_ne_bytes(*b"Luv ").to_be() { 352| 0| return Ok(DataColorSpace::Luv); 353| 1.24k| } else if value == u32::from_ne_bytes(*b"YCbr").to_be() { 354| 0| return Ok(DataColorSpace::YCbr); 355| 1.24k| } else if value == u32::from_ne_bytes(*b"Yxy ").to_be() { 356| 0| return Ok(DataColorSpace::Yxy); 357| 1.24k| } else if value == u32::from_ne_bytes(*b"RGB ").to_be() { 358| 792| return Ok(DataColorSpace::Rgb); 359| 454| } else if value == u32::from_ne_bytes(*b"GRAY").to_be() { 360| 280| return Ok(DataColorSpace::Gray); 361| 174| } else if value == u32::from_ne_bytes(*b"HSV ").to_be() { 362| 0| return Ok(DataColorSpace::Hsv); 363| 174| } else if value == u32::from_ne_bytes(*b"HLS ").to_be() { 364| 0| return Ok(DataColorSpace::Hls); 365| 174| } else if value == u32::from_ne_bytes(*b"CMYK").to_be() { 366| 0| return Ok(DataColorSpace::Cmyk); 367| 174| } else if value == u32::from_ne_bytes(*b"CMY ").to_be() { 368| 0| return Ok(DataColorSpace::Cmy); 369| 174| } else if value == u32::from_ne_bytes(*b"2CLR").to_be() { 370| 0| return Ok(DataColorSpace::Color2); 371| 174| } else if value == u32::from_ne_bytes(*b"3CLR").to_be() { 372| 0| return Ok(DataColorSpace::Color3); 373| 174| } else if value == u32::from_ne_bytes(*b"4CLR").to_be() { 374| 0| return Ok(DataColorSpace::Color4); 375| 174| } else if value == u32::from_ne_bytes(*b"5CLR").to_be() { 376| 0| return Ok(DataColorSpace::Color5); 377| 174| } else if value == u32::from_ne_bytes(*b"6CLR").to_be() { 378| 0| return Ok(DataColorSpace::Color6); 379| 174| } else if value == u32::from_ne_bytes(*b"7CLR").to_be() { 380| 0| return Ok(DataColorSpace::Color7); 381| 174| } else if value == u32::from_ne_bytes(*b"8CLR").to_be() { 382| 0| return Ok(DataColorSpace::Color8); 383| 174| } else if value == u32::from_ne_bytes(*b"9CLR").to_be() { 384| 0| return Ok(DataColorSpace::Color9); 385| 174| } else if value == u32::from_ne_bytes(*b"ACLR").to_be() { 386| 0| return Ok(DataColorSpace::Color10); 387| 174| } else if value == u32::from_ne_bytes(*b"BCLR").to_be() { 388| 0| return Ok(DataColorSpace::Color11); 389| 174| } else if value == u32::from_ne_bytes(*b"CCLR").to_be() { 390| 0| return Ok(DataColorSpace::Color12); 391| 174| } else if value == u32::from_ne_bytes(*b"DCLR").to_be() { 392| 0| return Ok(DataColorSpace::Color13); 393| 174| } else if value == u32::from_ne_bytes(*b"ECLR").to_be() { 394| 0| return Ok(DataColorSpace::Color14); 395| 174| } else if value == u32::from_ne_bytes(*b"FCLR").to_be() { 396| 0| return Ok(DataColorSpace::Color15); 397| 174| } 398| 174| Err(CmsError::InvalidProfile) 399| 2.23k| } _RNvXsc_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_15RenderingIntentINtNtCs6SNw0SRvItZ_4core7convert7TryFrommE8try_fromB7_: 605| 953| 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| 953| match value { 613| 212| 0 => Ok(RenderingIntent::Perceptual), 614| 0| 1 => Ok(RenderingIntent::RelativeColorimetric), 615| 0| 2 => Ok(RenderingIntent::Saturation), 616| 679| 3 => Ok(RenderingIntent::AbsoluteColorimetric), 617| 62| _ => Ok(RenderingIntent::Perceptual), 618| | } 619| 953| } _RNvXsm_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_14ParsingOptionsNtNtCs6SNw0SRvItZ_4core7default7Default7default: 963| 1.56k| fn default() -> Self { 964| 1.56k| Self { 965| 1.56k| max_profile_size: MAX_PROFILE_SIZE, 966| 1.56k| max_allowed_clut_size: 10_000_000, 967| 1.56k| max_allowed_trc_size: 40_000, 968| 1.56k| } 969| 1.56k| } _RNvMNtCs1jiJzeRTgBH_6moxcms6readerNtNtB4_7profile12ColorProfile12read_trc_tag: 713| 218| pub(crate) fn read_trc_tag( 714| 218| slice: &[u8], 715| 218| entry: usize, 716| 218| tag_size: usize, 717| 218| read_size: &mut usize, 718| 218| options: &ParsingOptions, 719| 218| ) -> Result, CmsError> { 720| 218| if slice.len() < entry.safe_add(4)? { 721| 71| return Ok(None); 722| 147| } 723| 147| let small_tag = &slice[entry..entry + 4]; 724| | // We require always recognize tone curves. 725| 147| let curve_type = TagTypeDefinition::from(u32::from_be_bytes([ 726| 147| small_tag[0], 727| 147| small_tag[1], 728| 147| small_tag[2], 729| 147| small_tag[3], 730| 147| ])); 731| 147| if tag_size != 0 && tag_size < TAG_SIZE { 732| 14| return Ok(None); 733| 133| } 734| 133| let last_tag_offset = if tag_size != 0 { 735| 122| tag_size + entry 736| | } else { 737| 11| slice.len() 738| | }; 739| 133| if last_tag_offset > slice.len() { 740| 68| return Err(CmsError::MalformedTrcCurve("Data exhausted".to_string())); 741| 65| } 742| 65| let tag = &slice[entry..last_tag_offset]; 743| 65| if tag.len() < TAG_SIZE { 744| 2| return Err(CmsError::MalformedTrcCurve("Data exhausted".to_string())); 745| 63| } 746| 63| if curve_type == TagTypeDefinition::LutToneCurve { 747| 25| let entry_count = u32::from_be_bytes([tag[8], tag[9], tag[10], tag[11]]) as usize; 748| 25| if entry_count == 0 { 749| 7| return Ok(Some(ToneReprCurve::Lut(vec![]))); 750| 18| } 751| 18| if entry_count > options.max_allowed_trc_size { 752| 10| return Err(CmsError::CurveLutIsTooLarge); 753| 8| } 754| 8| let curve_end = entry_count.safe_mul(size_of::())?.safe_add(12)?; 755| 8| if tag.len() < curve_end { 756| 3| return Err(CmsError::MalformedTrcCurve( 757| 3| "Curve end ends to early".to_string(), 758| 3| )); 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| 218| } _RNvMNtCs1jiJzeRTgBH_6moxcms6readerNtNtB4_7profile12ColorProfile12read_xyz_tagB4_: 935| 2.51k| pub(crate) fn read_xyz_tag( 936| 2.51k| slice: &[u8], 937| 2.51k| entry: usize, 938| 2.51k| tag_size: usize, 939| 2.51k| ) -> Result { 940| 2.51k| if tag_size < TAG_SIZE { 941| 86| return Ok(Xyzd::default()); 942| 2.43k| } 943| 2.43k| let last_tag_offset = tag_size.safe_add(entry)?; 944| 2.43k| if last_tag_offset > slice.len() { 945| 237| return Err(CmsError::InvalidProfile); 946| 2.19k| } 947| 2.19k| let tag = &slice[entry..entry + 12]; 948| 2.19k| let tag_type = u32::from_be_bytes([tag[0], tag[1], tag[2], tag[3]]); 949| 2.19k| let def = TagTypeDefinition::from(tag_type); 950| 2.19k| if def != TagTypeDefinition::Xyz { 951| 2.16k| return Ok(Xyzd::default()); 952| 26| } 953| | 954| 26| let tag = &slice[entry..last_tag_offset]; 955| 26| if tag.len() < 20 { 956| 6| return Err(CmsError::InvalidProfile); 957| 20| } 958| 20| let q15_16_x = i32::from_be_bytes([tag[8], tag[9], tag[10], tag[11]]); 959| 20| let q15_16_y = i32::from_be_bytes([tag[12], tag[13], tag[14], tag[15]]); 960| 20| let q15_16_z = i32::from_be_bytes([tag[16], tag[17], tag[18], tag[19]]); 961| 20| let x = s15_fixed16_number_to_double(q15_16_x); 962| 20| let y = s15_fixed16_number_to_double(q15_16_y); 963| 20| let z = s15_fixed16_number_to_double(q15_16_z); 964| 20| Ok(Xyzd { x, y, z }) 965| 2.51k| } _RNvMNtCs1jiJzeRTgBH_6moxcms6readerNtNtB4_7profile12ColorProfile13read_cicp_tag: 967| 1| pub(crate) fn read_cicp_tag( 968| 1| slice: &[u8], 969| 1| entry: usize, 970| 1| tag_size: usize, 971| 1| ) -> Result, CmsError> { 972| 1| if tag_size < TAG_SIZE { 973| 0| return Ok(None); 974| 1| } 975| 1| let last_tag_offset = tag_size.safe_add(entry)?; 976| 1| if last_tag_offset > slice.len() { 977| 1| return Err(CmsError::InvalidProfile); 978| 0| } 979| 0| let tag = &slice[entry..last_tag_offset]; 980| 0| if tag.len() < 12 { 981| 0| return Err(CmsError::InvalidProfile); 982| 0| } 983| 0| let tag_type = u32::from_be_bytes([tag[0], tag[1], tag[2], tag[3]]); 984| 0| let def = TagTypeDefinition::from(tag_type); 985| 0| if def != TagTypeDefinition::Cicp { 986| 0| 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| 1| } _RNvMNtCs1jiJzeRTgBH_6moxcms6readerNtNtB4_7profile12ColorProfile14read_trc_tag_s: 703| 218| pub(crate) fn read_trc_tag_s( 704| 218| slice: &[u8], 705| 218| entry: usize, 706| 218| tag_size: usize, 707| 218| options: &ParsingOptions, 708| 218| ) -> Result, CmsError> { 709| 218| let mut _empty = 0usize; 710| 218| Self::read_trc_tag(slice, entry, tag_size, &mut _empty, options) 711| 218| } _RNvMNtCs1jiJzeRTgBH_6moxcms6readerNtNtB4_7profile12ColorProfile15read_string_tag: 176| 1.95k| pub(crate) fn read_string_tag( 177| 1.95k| slice: &[u8], 178| 1.95k| entry: usize, 179| 1.95k| tag_size: usize, 180| 1.95k| ) -> Result, CmsError> { 181| 1.95k| let tag_size = if tag_size == 0 { TAG_SIZE } else { tag_size }; 182| 1.95k| if tag_size < 4 { 183| 11| return Ok(None); 184| 1.94k| } 185| 1.94k| let last_tag_offset = tag_size.safe_add(entry)?; 186| 1.94k| if last_tag_offset > slice.len() { 187| 65| return Err(CmsError::InvalidProfile); 188| 1.87k| } 189| 1.87k| let tag = &slice[entry..last_tag_offset]; 190| 1.87k| if tag.len() < 8 { 191| 6| return Ok(None); 192| 1.87k| } 193| 1.87k| let tag_type = 194| 1.87k| TagTypeDefinition::from(u32::from_be_bytes([tag[0], tag[1], tag[2], tag[3]])); 195| | // Ignore unknown 196| 1.87k| if tag_type == TagTypeDefinition::Text { 197| 46| let sliced_from_to_end = &tag[8..tag.len()]; 198| 46| let str = String::from_utf8_lossy(sliced_from_to_end) 199| 46| .trim_end_matches('\0') 200| 46| .to_string(); 201| 46| return Ok(Some(ProfileText::PlainString(str))); 202| 1.82k| } 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| 1.82k| } else if tag_type == TagTypeDefinition::Description { 268| 393| if tag.len() < 12 { 269| 1| return Err(CmsError::InvalidProfile); 270| 392| } 271| 392| let ascii_length = u32::from_be_bytes([tag[8], tag[9], tag[10], tag[11]]) as usize; 272| 392| let ascii_end = 12usize.safe_add(ascii_length)?; 273| 392| if tag.len() < ascii_end { 274| 1| return Err(CmsError::InvalidProfile); 275| 391| } 276| 391| let sliced = &tag[12..ascii_end]; 277| 391| let ascii_string = String::from_utf8_lossy(sliced) 278| 391| .trim_end_matches('\0') 279| 391| .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| 391| let unicode_offset = ascii_end; 285| 391| let (unicode_code, unicode_string) = 286| 391| self::read_desc_unicode(tag, unicode_offset)?.unwrap_or((0, String::new())); 287| | 288| 391| return Ok(Some(ProfileText::Description(DescriptionString { 289| 391| ascii_string, 290| 391| unicode_language_code: unicode_code, 291| 391| unicode_string, 292| 391| mac_string: "".to_string(), 293| 391| script_code_code: -1, 294| 391| }))); 295| 1.43k| } 296| 1.43k| Ok(None) 297| 1.95k| } _RNvNtCs1jiJzeRTgBH_6moxcms6reader16utf16be_to_utf16: 74| 216|fn utf16be_to_utf16(slice: &[u8]) -> Result, CmsError> { 75| 216| let mut vec = try_vec![0u16; slice.len() / 2]; 76| 6.43k| for (dst, chunk) in vec.iter_mut().zip(slice.chunks_exact(2)) { 77| 6.43k| *dst = u16::from_be_bytes([chunk[0], chunk[1]]); 78| 6.43k| } 79| 216| Ok(vec) 80| 216|} _RNvNtCs1jiJzeRTgBH_6moxcms6reader17read_desc_unicode: 85| 391|fn read_desc_unicode(tag: &[u8], unicode_offset: usize) -> Result, CmsError> { 86| 391| if tag.len() < unicode_offset.safe_add(8)? { 87| 12| return Ok(None); 88| 379| } 89| 379| let header = &tag[unicode_offset..unicode_offset.safe_add(8)?]; 90| 379| let language_code = u32::from_be_bytes([header[0], header[1], header[2], header[3]]); 91| 379| let unicode_length = u32::from_be_bytes([header[4], header[5], header[6], header[7]]) as usize; 92| 379| if unicode_length == 0 { 93| 40| return Ok(Some((language_code, String::new()))); 94| 339| } 95| 339| let byte_length = unicode_length.safe_mul(2)?; 96| 339| let str_start = unicode_offset.safe_add(8)?; 97| 339| if tag.len() < str_start.safe_add(byte_length)? { 98| 123| return Ok(None); 99| 216| } 100| 216| let uc_data = &tag[str_start..str_start.safe_add(byte_length)?]; 101| 216| let wc = utf16be_to_utf16(uc_data)?; 102| 216| let s = String::from_utf16_lossy(&wc) 103| 216| .trim_end_matches('\0') 104| 216| .to_string(); 105| 216| Ok(Some((language_code, s))) 106| 391|} _RNvNtCs1jiJzeRTgBH_6moxcms6reader27s15_fixed16_number_to_floatB3_: 45| 2.85k|pub(crate) const fn s15_fixed16_number_to_float(a: i32) -> f32 { 46| 2.85k| a as f32 / 65536. 47| 2.85k|} _RNvNtCs1jiJzeRTgBH_6moxcms6reader28s15_fixed16_number_to_doubleB3_: 50| 60|pub(crate) const fn s15_fixed16_number_to_double(a: i32) -> f64 { 51| 60| a as f64 / 65536. 52| 60|} _RNvXs1_NtCs1jiJzeRTgBH_6moxcms9safe_mathjINtB5_7SafeAddjE8safe_add: 48| 7.60k| fn safe_add(&self, other: $type_name) -> Result<$type_name, CmsError> { 49| 7.60k| if let Some(result) = self.checked_add(other) { 50| 7.60k| return Ok(result); 51| 0| } 52| 0| Err(CmsError::OverflowingError) 53| 7.60k| } _RNvXs6_NtCs1jiJzeRTgBH_6moxcms9safe_mathjINtB5_7SafeMuljE8safe_mul: 68| 1.30k| fn safe_mul(&self, other: $type_name) -> Result<$type_name, CmsError> { 69| 1.30k| if let Some(result) = self.checked_mul(other) { 70| 1.30k| return Ok(result); 71| 0| } 72| 0| Err(CmsError::OverflowingError) 73| 1.30k| } _RNvXNtCs1jiJzeRTgBH_6moxcms3tagNtB2_3TagINtNtCs6SNw0SRvItZ_4core7convert7TryFrommE8try_from: 70| 20.9k| fn try_from(value: u32) -> Result { 71| 20.9k| if value == u32::from_ne_bytes(*b"rXYZ").to_be() { 72| 527| return Ok(Self::RedXyz); 73| 20.4k| } else if value == u32::from_ne_bytes(*b"gXYZ").to_be() { 74| 275| return Ok(Self::GreenXyz); 75| 20.1k| } else if value == u32::from_ne_bytes(*b"bXYZ").to_be() { 76| 333| return Ok(Self::BlueXyz); 77| 19.7k| } else if value == u32::from_ne_bytes(*b"rTRC").to_be() { 78| 120| return Ok(Self::RedToneReproduction); 79| 19.6k| } else if value == u32::from_ne_bytes(*b"gTRC").to_be() { 80| 36| return Ok(Self::GreenToneReproduction); 81| 19.6k| } else if value == u32::from_ne_bytes(*b"bTRC").to_be() { 82| 18| return Ok(Self::BlueToneReproduction); 83| 19.6k| } else if value == u32::from_ne_bytes(*b"kTRC").to_be() { 84| 56| return Ok(Self::GreyToneReproduction); 85| 19.5k| } else if value == u32::from_ne_bytes(*b"wtpt").to_be() { 86| 791| return Ok(Self::MediaWhitePoint); 87| 18.7k| } else if value == u32::from_ne_bytes(*b"cicp").to_be() { 88| 1| return Ok(Self::CodeIndependentPoints); 89| 18.7k| } else if value == u32::from_ne_bytes(*b"chad").to_be() { 90| 0| return Ok(Self::ChromaticAdaptation); 91| 18.7k| } else if value == u32::from_ne_bytes(*b"bkpt").to_be() { 92| 591| return Ok(Self::BlackPoint); 93| 18.1k| } else if value == u32::from_ne_bytes(*b"A2B0").to_be() { 94| 0| return Ok(Self::DeviceToPcsLutPerceptual); 95| 18.1k| } else if value == u32::from_ne_bytes(*b"A2B1").to_be() { 96| 0| return Ok(Self::DeviceToPcsLutColorimetric); 97| 18.1k| } else if value == u32::from_ne_bytes(*b"A2B2").to_be() { 98| 0| return Ok(Self::DeviceToPcsLutSaturation); 99| 18.1k| } else if value == u32::from_ne_bytes(*b"B2A0").to_be() { 100| 0| return Ok(Self::PcsToDeviceLutPerceptual); 101| 18.1k| } else if value == u32::from_ne_bytes(*b"B2A1").to_be() { 102| 0| return Ok(Self::PcsToDeviceLutColorimetric); 103| 18.1k| } else if value == u32::from_ne_bytes(*b"B2A2").to_be() { 104| 0| return Ok(Self::PcsToDeviceLutSaturation); 105| 18.1k| } else if value == u32::from_ne_bytes(*b"desc").to_be() { 106| 1.08k| return Ok(Self::ProfileDescription); 107| 17.0k| } else if value == u32::from_ne_bytes(*b"cprt").to_be() { 108| 864| return Ok(Self::Copyright); 109| 16.2k| } else if value == u32::from_ne_bytes(*b"vued").to_be() { 110| 0| return Ok(Self::ViewingConditionsDescription); 111| 16.2k| } else if value == u32::from_ne_bytes(*b"dmnd").to_be() { 112| 0| return Ok(Self::DeviceManufacturer); 113| 16.2k| } else if value == u32::from_ne_bytes(*b"dmdd").to_be() { 114| 0| return Ok(Self::DeviceModel); 115| 16.2k| } else if value == u32::from_ne_bytes(*b"gamt").to_be() { 116| 0| return Ok(Self::Gamut); 117| 16.2k| } else if value == u32::from_ne_bytes(*b"lumi").to_be() { 118| 0| return Ok(Self::Luminance); 119| 16.2k| } else if value == u32::from_ne_bytes(*b"meas").to_be() { 120| 0| return Ok(Self::Measurement); 121| 16.2k| } else if value == u32::from_ne_bytes(*b"chrm").to_be() { 122| 1| return Ok(Self::Chromaticity); 123| 16.2k| } else if value == u32::from_ne_bytes(*b"view").to_be() { 124| 0| return Ok(Self::ObserverConditions); 125| 16.2k| } else if value == u32::from_ne_bytes(*b"targ").to_be() { 126| 1| return Ok(Self::CharTarget); 127| 16.2k| } else if value == u32::from_ne_bytes(*b"tech").to_be() { 128| 0| return Ok(Self::Technology); 129| 16.2k| } else if value == u32::from_ne_bytes(*b"calt").to_be() { 130| 0| return Ok(Self::CalibrationDateTime); 131| 16.2k| } 132| 16.2k| Err(CmsError::UnknownTag(value)) 133| 20.9k| } _RNvXs0_NtCs1jiJzeRTgBH_6moxcms3tagNtB5_17TagTypeDefinitionINtNtCs6SNw0SRvItZ_4core7convert4FrommE4from: 199| 4.21k| fn from(value: u32) -> Self { 200| 4.21k| if value == u32::from_ne_bytes(*b"mluc").to_be() { 201| 0| return TagTypeDefinition::MultiLocalizedUnicode; 202| 4.21k| } else if value == u32::from_ne_bytes(*b"desc").to_be() { 203| 400| return TagTypeDefinition::Description; 204| 3.81k| } else if value == u32::from_ne_bytes(*b"text").to_be() { 205| 47| return TagTypeDefinition::Text; 206| 3.76k| } else if value == u32::from_ne_bytes(*b"mAB ").to_be() { 207| 0| return TagTypeDefinition::MabLut; 208| 3.76k| } else if value == u32::from_ne_bytes(*b"mBA ").to_be() { 209| 0| return TagTypeDefinition::MbaLut; 210| 3.76k| } else if value == u32::from_ne_bytes(*b"para").to_be() { 211| 0| return TagTypeDefinition::ParametricToneCurve; 212| 3.76k| } else if value == u32::from_ne_bytes(*b"curv").to_be() { 213| 26| return TagTypeDefinition::LutToneCurve; 214| 3.73k| } else if value == u32::from_ne_bytes(*b"XYZ ").to_be() { 215| 33| return TagTypeDefinition::Xyz; 216| 3.70k| } else if value == u32::from_ne_bytes(*b"mpet").to_be() { 217| 0| return TagTypeDefinition::MultiProcessElement; 218| 3.70k| } else if value == u32::from_ne_bytes(*b"view").to_be() { 219| 0| return TagTypeDefinition::DefViewingConditions; 220| 3.70k| } else if value == u32::from_ne_bytes(*b"sig ").to_be() { 221| 1| return TagTypeDefinition::Signature; 222| 3.70k| } else if value == u32::from_ne_bytes(*b"cicp").to_be() { 223| 0| return TagTypeDefinition::Cicp; 224| 3.70k| } else if value == u32::from_ne_bytes(*b"dtim").to_be() { 225| 0| return TagTypeDefinition::DateTime; 226| 3.70k| } else if value == u32::from_ne_bytes(*b"meas").to_be() { 227| 0| return TagTypeDefinition::Measurement; 228| 3.70k| } else if value == u32::from_ne_bytes(*b"sf32").to_be() { 229| 0| return TagTypeDefinition::S15Fixed16Array; 230| 3.70k| } else if value == u32::from_ne_bytes(*b"uf32").to_be() { 231| 0| return TagTypeDefinition::U16Fixed16Array; 232| 3.70k| } else if value == u32::from_ne_bytes(*b"ui16").to_be() { 233| 0| return TagTypeDefinition::U16Array; 234| 3.70k| } else if value == u32::from_ne_bytes(*b"ui32").to_be() { 235| 0| return TagTypeDefinition::U32Array; 236| 3.70k| } else if value == u32::from_ne_bytes(*b"ui64").to_be() { 237| 0| return TagTypeDefinition::U64Array; 238| 3.70k| } else if value == u32::from_ne_bytes(*b"ui08").to_be() { 239| 0| return TagTypeDefinition::U8Array; 240| 3.70k| } 241| 3.70k| TagTypeDefinition::NotAllowed 242| 4.21k| } _RNvXs4_NtCs2ICmcE5qjLx_10num_traits10identitieshNtB5_4Zero4zeroCs4rpmEmvDwFM_5image: 42| 4.27k| fn zero() -> $t { 43| | $v 44| 4.27k| } _RNvXs6_NtCs2ICmcE5qjLx_10num_traits10identitiestNtB5_4Zero4zeroCs4rpmEmvDwFM_5image: 42| 1.50k| fn zero() -> $t { 43| | $v 44| 1.50k| } _RNCNvNtCshdzP3jLBsmJ_3png5adam718expand_adam7_bytes0B5_: 309| 1.52G| .map(move |i| (i * samp_mul + samp_off) * u64::from(bytes_pp)) _RNCNvNtCshdzP3jLBsmJ_3png5adam718expand_adam7_bytess_0B5_: 311| 1.52G| .map(move |i| i as usize + byte_start) _RNvMNtCshdzP3jLBsmJ_3png5adam7NtB2_9Adam7Info14pass_constants: 66| 23.2M| fn pass_constants(&self) -> PassConstants { 67| 23.2M| PassConstants::PASSES[self.pass as usize - 1] 68| 23.2M| } _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.62k| fn init_pass(&mut self) { 176| 6.62k| let info = PassConstants::PASSES[self.current_pass as usize - 1]; 177| 6.62k| self.line_width = info.count_samples(self.width); 178| 6.62k| self.lines = info.count_lines(self.height); 179| 6.62k| self.line = 0; 180| 6.62k| } _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| 23.2M|pub fn expand_pass( 349| 23.2M| img: &mut [u8], 350| 23.2M| img_row_stride: usize, 351| 23.2M| interlaced_row: &[u8], 352| 23.2M| interlace_info: &Adam7Info, 353| 23.2M| bits_per_pixel: u8, 354| 23.2M|) { 355| 23.2M| 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| 22.8M| let byte_indices = expand_adam7_bytes(img_row_stride, interlace_info, 1); 390| | 391| 614M| for (bytepos, &px) in byte_indices.zip(interlaced_row) { 392| 614M| img[bytepos] = px; 393| 614M| } 394| | } 395| | 16 => { 396| 156k| let byte_indices = expand_adam7_bytes(img_row_stride, interlace_info, 2); 397| | 398| 211M| for (bytepos, px) in byte_indices.zip(interlaced_row.chunks(2)) { 399| 211M| img[bytepos..][..2].copy_from_slice(px); 400| 211M| } 401| | } 402| | _ => { 403| 239k| debug_assert!(bits_per_pixel % 8 == 0); 404| 239k| let bytes_pp = bits_per_pixel / 8; 405| 239k| let byte_indices = expand_adam7_bytes(img_row_stride, interlace_info, bytes_pp); 406| | 407| 696M| for (bytepos, px) in byte_indices.zip(interlaced_row.chunks(bytes_pp.into())) { 408| 696M| img[bytepos..][..px.len()].copy_from_slice(px); 409| 696M| } 410| | } 411| | } 412| 23.2M|} _RNvNtCshdzP3jLBsmJ_3png5adam718expand_adam7_bytes: 288| 23.2M|fn expand_adam7_bytes( 289| 23.2M| row_stride_in_bytes: usize, 290| 23.2M| info: &Adam7Info, 291| 23.2M| bytes_pp: u8, 292| 23.2M|) -> impl Iterator { 293| 23.2M| let (line_mul, line_off, samp_mul, samp_off) = { 294| 23.2M| let constants = info.pass_constants(); 295| 23.2M| ( 296| 23.2M| // Convert each to their respectively required type from u8. 297| 23.2M| usize::from(constants.y_sampling), 298| 23.2M| usize::from(constants.y_offset), 299| 23.2M| u64::from(constants.x_sampling), 300| 23.2M| u64::from(constants.x_offset), 301| 23.2M| ) 302| 23.2M| }; 303| | 304| | // the equivalent line number in progressive scan 305| 23.2M| let prog_line = line_mul * info.line as usize + line_off; 306| 23.2M| let byte_start = prog_line * row_stride_in_bytes; 307| | 308| 23.2M| (0..u64::from(info.samples)) 309| 23.2M| .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| 23.2M| .map(move |i| i as usize + byte_start) 312| 23.2M|} _RNvXs1_NtCshdzP3jLBsmJ_3png5adam7NtB5_13Adam7IteratorNtNtNtNtCs6SNw0SRvItZ_4core4iter6traits8iterator8Iterator4next: 186| 23.2M| fn next(&mut self) -> Option { 187| 23.2M| if self.line < self.lines && self.line_width > 0 { 188| 23.2M| let this_line = self.line; 189| 23.2M| self.line += 1; 190| 23.2M| Some(Adam7Info { 191| 23.2M| pass: self.current_pass, 192| 23.2M| line: this_line, 193| 23.2M| width: self.width, 194| 23.2M| samples: self.line_width, 195| 23.2M| }) 196| 4.40k| } else if self.current_pass < 7 { 197| 4.15k| self.current_pass += 1; 198| 4.15k| self.init_pass(); 199| 4.15k| self.next() 200| | } else { 201| 253| None 202| | } 203| 23.2M| } _RNvNtCshdzP3jLBsmJ_3png5chunk11is_critical: 67| 30.9k|pub fn is_critical(ChunkType(type_): ChunkType) -> bool { 68| 30.9k| type_[0] & 32 == 0 69| 30.9k|} _RNvMNtCshdzP3jLBsmJ_3png6commonNtB2_9ColorType10samples_u8: 31| 93.3M| pub(crate) fn samples_u8(self) -> u8 { 32| | use self::ColorType::*; 33| 93.3M| match self { 34| 92.2M| Grayscale | Indexed => 1, 35| 222k| Rgb => 3, 36| 745k| GrayscaleAlpha => 2, 37| 96.0k| Rgba => 4, 38| | } 39| 93.3M| } _RNvMNtCshdzP3jLBsmJ_3png6commonNtB2_9ColorType15bytes_per_pixel: 87| 6.05k| 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.05k| self.samples() * ((bit_depth as usize + 7) >> 3) 91| 6.05k| } _RNvMNtCshdzP3jLBsmJ_3png6commonNtB2_9ColorType22checked_raw_row_length: 53| 23.3M| 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| 23.3M| let bits = u64::from(width) * u64::from(self.samples_u8()) * u64::from(depth.into_u8()); 56| 23.3M| TryFrom::try_from(1 + bits.div_ceil(8)).ok() 57| 23.3M| } _RNvMNtCshdzP3jLBsmJ_3png6commonNtB2_9ColorType22is_combination_invalid: 73| 9.21k| 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.21k| ((bit_depth == BitDepth::One || bit_depth == BitDepth::Two || bit_depth == BitDepth::Four) 77| 4.00k| && (self == ColorType::Rgb 78| 4.00k| || self == ColorType::GrayscaleAlpha 79| 4.00k| || self == ColorType::Rgba)) 80| 9.21k| || (bit_depth == BitDepth::Sixteen && self == ColorType::Indexed) 81| 9.21k| } _RNvMNtCshdzP3jLBsmJ_3png6commonNtB2_9ColorType25raw_row_length_from_width: 59| 69.8M| pub(crate) fn raw_row_length_from_width(self, depth: BitDepth, width: u32) -> usize { 60| 69.8M| let samples = width as usize * self.samples(); 61| 69.8M| 1 + match depth { 62| 894k| BitDepth::Sixteen => samples * 2, 63| 68.6M| BitDepth::Eight => samples, 64| 269k| subbyte => { 65| 269k| let samples_per_byte = 8 / subbyte as usize; 66| 269k| let whole = samples / samples_per_byte; 67| 269k| let fract = usize::from(samples % samples_per_byte > 0); 68| 269k| whole + fract 69| | } 70| | } 71| 69.8M| } _RNvMNtCshdzP3jLBsmJ_3png6commonNtB2_9ColorType7from_u8: 42| 9.22k| pub fn from_u8(n: u8) -> Option { 43| 9.22k| match n { 44| 4.36k| 0 => Some(ColorType::Grayscale), 45| 1.34k| 2 => Some(ColorType::Rgb), 46| 1.77k| 3 => Some(ColorType::Indexed), 47| 462| 4 => Some(ColorType::GrayscaleAlpha), 48| 1.26k| 6 => Some(ColorType::Rgba), 49| 7| _ => None, 50| | } 51| 9.22k| } _RNvMNtCshdzP3jLBsmJ_3png6commonNtB2_9ColorType7samples: 27| 69.9M| pub fn samples(self) -> usize { 28| 69.9M| self.samples_u8().into() 29| 69.9M| } _RNvMs0_NtCshdzP3jLBsmJ_3png6commonNtB5_4Unit7from_u8: 160| 417| pub fn from_u8(n: u8) -> Option { 161| 417| match n { 162| 14| 0 => Some(Unit::Unspecified), 163| 58| 1 => Some(Unit::Meter), 164| 345| _ => None, 165| | } 166| 417| } _RNvMs1_NtCshdzP3jLBsmJ_3png6commonNtB5_9DisposeOp7from_u8: 183| 245| pub fn from_u8(n: u8) -> Option { 184| 245| match n { 185| 134| 0 => Some(DisposeOp::None), 186| 106| 1 => Some(DisposeOp::Background), 187| 1| 2 => Some(DisposeOp::Previous), 188| 4| _ => None, 189| | } 190| 245| } _RNvMs3_NtCshdzP3jLBsmJ_3png6commonNtB5_7BlendOp7from_u8: 216| 241| pub fn from_u8(n: u8) -> Option { 217| 241| match n { 218| 228| 0 => Some(BlendOp::Source), 219| 12| 1 => Some(BlendOp::Over), 220| 1| _ => None, 221| | } 222| 241| } _RNvMs_NtCshdzP3jLBsmJ_3png6commonNtB4_8BitDepth7from_u8: 123| 69.8M| pub fn from_u8(n: u8) -> Option { 124| 69.8M| match n { 125| 2.57k| 1 => Some(BitDepth::One), 126| 688| 2 => Some(BitDepth::Two), 127| 750| 4 => Some(BitDepth::Four), 128| 68.9M| 8 => Some(BitDepth::Eight), 129| 894k| 16 => Some(BitDepth::Sixteen), 130| 19| _ => None, 131| | } 132| 69.8M| } _RNvMs_NtCshdzP3jLBsmJ_3png6commonNtB4_8BitDepth7into_u8: 134| 23.3M| pub(crate) fn into_u8(self) -> u8 { 135| 23.3M| self as u8 136| 23.3M| } _RNvMsb_NtCshdzP3jLBsmJ_3png6commonNtB5_11ScaledFloat11from_scaled: 458| 366| pub fn from_scaled(val: u32) -> Self { 459| 366| Self(val) 460| 366| } _RNvMsd_NtCshdzP3jLBsmJ_3png6commonNtB5_19SrgbRenderingIntent8from_raw: 544| 284| pub(crate) fn from_raw(raw: u8) -> Option { 545| 284| match raw { 546| 44| 0 => Some(SrgbRenderingIntent::Perceptual), 547| 40| 1 => Some(SrgbRenderingIntent::RelativeColorimetric), 548| 0| 2 => Some(SrgbRenderingIntent::Saturation), 549| 0| 3 => Some(SrgbRenderingIntent::AbsoluteColorimetric), 550| 200| _ => None, 551| | } 552| 284| } _RNvMsf_NtCshdzP3jLBsmJ_3png6commonNtB5_4Info15bytes_per_pixel: 772| 6.05k| 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.05k| self.color_type.bytes_per_pixel(self.bit_depth) 776| 6.05k| } _RNvMsf_NtCshdzP3jLBsmJ_3png6commonNtB5_4Info17bpp_in_prediction: 785| 6.05k| pub(crate) fn bpp_in_prediction(&self) -> BytesPerPixel { 786| 6.05k| BytesPerPixel::from_usize(self.bytes_per_pixel()) 787| 6.05k| } _RNvMsf_NtCshdzP3jLBsmJ_3png6commonNtB5_4Info22checked_raw_row_length: 799| 27.5k| pub(crate) fn checked_raw_row_length(&self) -> Option { 800| 27.5k| self.color_type 801| 27.5k| .checked_raw_row_length(self.bit_depth, self.width) 802| 27.5k| } _RNvMsf_NtCshdzP3jLBsmJ_3png6commonNtB5_4Info25raw_row_length_from_width: 805| 23.2M| pub fn raw_row_length_from_width(&self, width: u32) -> usize { 806| 23.2M| self.color_type 807| 23.2M| .raw_row_length_from_width(self.bit_depth, width) 808| 23.2M| } _RNvMsf_NtCshdzP3jLBsmJ_3png6commonNtB5_4Info4size: 747| 32.5k| pub fn size(&self) -> (u32, u32) { 748| 32.5k| (self.width, self.height) 749| 32.5k| } _RNvMsg_NtCshdzP3jLBsmJ_3png6commonNtB5_13BytesPerPixel10from_usize: 841| 6.05k| pub(crate) fn from_usize(bpp: usize) -> Self { 842| 6.05k| match bpp { 843| 3.41k| 1 => BytesPerPixel::One, 844| 981| 2 => BytesPerPixel::Two, 845| 614| 3 => BytesPerPixel::Three, 846| 388| 4 => BytesPerPixel::Four, 847| 419| 6 => BytesPerPixel::Six, // Only rgb×16bit 848| 238| 8 => BytesPerPixel::Eight, // Only rgba×16bit 849| 0| _ => unreachable!("Not a possible byte rounded pixel width"), 850| | } 851| 6.05k| } _RNvXse_NtCshdzP3jLBsmJ_3png6commonNtB5_4InfoNtNtCs6SNw0SRvItZ_4core7default7Default7default: 705| 9.18k| fn default() -> Info<'static> { 706| 9.18k| Info { 707| 9.18k| width: 0, 708| 9.18k| height: 0, 709| 9.18k| bit_depth: BitDepth::Eight, 710| 9.18k| color_type: ColorType::Grayscale, 711| 9.18k| interlaced: false, 712| 9.18k| palette: None, 713| 9.18k| sbit: None, 714| 9.18k| trns: None, 715| 9.18k| gama_chunk: None, 716| 9.18k| chrm_chunk: None, 717| 9.18k| bkgd: None, 718| 9.18k| pixel_dims: None, 719| 9.18k| frame_control: None, 720| 9.18k| animation_control: None, 721| 9.18k| source_gamma: None, 722| 9.18k| source_chromaticities: None, 723| 9.18k| srgb: None, 724| 9.18k| icc_profile: None, 725| 9.18k| coding_independent_code_points: None, 726| 9.18k| mastering_display_color_volume: None, 727| 9.18k| content_light_level: None, 728| 9.18k| exif_metadata: None, 729| 9.18k| uncompressed_latin1_text: Vec::new(), 730| 9.18k| compressed_latin1_text: Vec::new(), 731| 9.18k| utf8_text: Vec::new(), 732| 9.18k| } 733| 9.18k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder14interlace_infoNtB2_13InterlaceInfo11line_number: 38| 23.2M| pub(crate) fn line_number(&self) -> u32 { 39| 23.2M| match self { 40| 3.38k| InterlaceInfo::Null(NullInfo { line }) => *line, 41| 23.2M| InterlaceInfo::Adam7(Adam7Info { line, .. }) => *line, 42| | } 43| 23.2M| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder14interlace_infoNtB2_13InterlaceInfo14get_adam7_info: 45| 23.2M| pub(crate) fn get_adam7_info(&self) -> Option<&Adam7Info> { 46| 23.2M| match self { 47| 0| InterlaceInfo::Null(_) => None, 48| 23.2M| InterlaceInfo::Adam7(adam7info) => Some(adam7info), 49| | } 50| 23.2M| } _RNvMs_NtNtCshdzP3jLBsmJ_3png7decoder14interlace_infoNtB4_17InterlaceInfoIter3new: 60| 6.05k| pub fn new(width: u32, height: u32, interlaced: bool) -> Self { 61| 6.05k| if interlaced { 62| 2.47k| Self(IterImpl::Adam7(Adam7Iterator::new(width, height))) 63| | } else { 64| 3.58k| Self(IterImpl::None(0..height)) 65| | } 66| 6.05k| } _RNvMs_NtNtCshdzP3jLBsmJ_3png7decoder14interlace_infoNtB4_17InterlaceInfoIter5empty: 56| 9.18k| pub fn empty() -> Self { 57| 9.18k| Self(IterImpl::None(0..0)) 58| 9.18k| } _RNvXs0_NtNtCshdzP3jLBsmJ_3png7decoder14interlace_infoNtB5_17InterlaceInfoIterNtNtNtNtCs6SNw0SRvItZ_4core4iter6traits8iterator8Iterator4next: 72| 23.7M| fn next(&mut self) -> Option { 73| 23.7M| match self.0 { 74| 23.2M| IterImpl::Adam7(ref mut adam7) => Some(InterlaceInfo::Adam7(adam7.next()?)), 75| 525k| IterImpl::None(ref mut height) => Some(InterlaceInfo::Null(NullInfo { 76| 525k| line: height.next()?, 77| | })), 78| | } 79| 23.7M| } _RNCNCNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB9_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE19next_interlaced_row00Cs4rpmEmvDwFM_5image: 533| 23.2M| option.map(move |interlace| { 534| 23.2M| let output_line_size = self.output_line_size_for_interlace_info(&interlace); 535| 23.2M| InterlacedRow { 536| 23.2M| data: &self.scratch_buffer[..output_line_size], 537| 23.2M| interlace, 538| 23.2M| } 539| 23.2M| }) _RNCNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB7_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE10next_frame0Cs4rpmEmvDwFM_5image: 472| 3.38k| .map(|info| info.line_number()) _RNCNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB7_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE19next_interlaced_row0Cs4rpmEmvDwFM_5image: 532| 23.2M| result.map(move |option| { 533| 23.2M| 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| 23.2M| }) _RNCNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB7_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE23next_raw_interlaced_row0Cs4rpmEmvDwFM_5image: 712| 1.34M| .with_unfilled_buffer(|buffer| self.decoder.decode_image_data(Some(buffer))); _RNvMs3_NtCshdzP3jLBsmJ_3png7decoderINtB5_7DecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE10set_limitsCs4rpmEmvDwFM_5image: 177| 9.46k| pub fn set_limits(&mut self, limits: Limits) { 178| 9.46k| self.read_decoder.set_limits(limits); 179| 9.46k| } _RNvMs3_NtCshdzP3jLBsmJ_3png7decoderINtB5_7DecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE15new_with_limitsCs4rpmEmvDwFM_5image: 132| 9.46k| pub fn new_with_limits(r: R, limits: Limits) -> Decoder { 133| 9.46k| let mut read_decoder = ReadDecoder::new(r); 134| 9.46k| read_decoder.set_limits(limits); 135| | 136| 9.46k| Decoder { 137| 9.46k| read_decoder, 138| 9.46k| transform: Transformations::IDENTITY, 139| 9.46k| } 140| 9.46k| } _RNvMs3_NtCshdzP3jLBsmJ_3png7decoderINtB5_7DecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE16read_header_infoCs4rpmEmvDwFM_5image: 187| 18.6k| pub fn read_header_info(&mut self) -> Result<&Info<'static>, DecodingError> { 188| 18.6k| self.read_decoder.read_header_info() 189| 18.6k| } _RNvMs3_NtCshdzP3jLBsmJ_3png7decoderINtB5_7DecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE19set_transformationsCs4rpmEmvDwFM_5image: 250| 9.18k| pub fn set_transformations(&mut self, transform: Transformations) { 251| 9.18k| self.transform = transform; 252| 9.18k| } _RNvMs3_NtCshdzP3jLBsmJ_3png7decoderINtB5_7DecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE21set_ignore_text_chunkCs4rpmEmvDwFM_5image: 265| 9.46k| pub fn set_ignore_text_chunk(&mut self, ignore_text_chunk: bool) { 266| 9.46k| self.read_decoder.set_ignore_text_chunk(ignore_text_chunk); 267| 9.46k| } _RNvMs3_NtCshdzP3jLBsmJ_3png7decoderINtB5_7DecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE9read_infoCs4rpmEmvDwFM_5image: 192| 9.18k| pub fn read_info(mut self) -> Result, DecodingError> { 193| 9.18k| let info = self.read_header_info()?; 194| 9.18k| let unfiltering_buffer = UnfilteringBuffer::new(info); 195| | 196| 9.18k| let mut reader = Reader { 197| 9.18k| decoder: self.read_decoder, 198| 9.18k| bpp: BytesPerPixel::One, 199| 9.18k| subframe: SubframeInfo::not_yet_init(), 200| 9.18k| remaining_frames: 0, // Temporary value - fixed below after reading `acTL` and `fcTL`. 201| 9.18k| unfiltering_buffer, 202| 9.18k| transform: self.transform, 203| 9.18k| transform_fn: None, 204| 9.18k| scratch_buffer: Vec::new(), 205| 9.18k| finished: false, 206| 9.18k| }; 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.18k| if reader.info().checked_raw_row_length().is_none() { 216| 0| return Err(DecodingError::LimitsExceeded); 217| 9.18k| } 218| | 219| | // Check if the output buffer has a valid size. 220| | // 221| | // FIXME: see above and 222| | // 223| 9.18k| if reader.output_buffer_size().is_none() { 224| 51| return Err(DecodingError::LimitsExceeded); 225| 9.13k| } 226| | 227| 9.13k| reader.read_until_image_data()?; 228| | 229| 6.02k| reader.remaining_frames = match reader.info().animation_control.as_ref() { 230| 5.96k| None => 1, // No `acTL` => only expecting `IDAT` frame. 231| 64| 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| 64| let mut num_frames = animation.num_frames; 235| 64| if reader.info().frame_control.is_none() { 236| 63| // No `fcTL` before `IDAT` => `IDAT` is not part of the animation, but 237| 63| // represents an *extra*, default frame for non-APNG-aware decoders. 238| 63| num_frames += 1; 239| 63| } 240| 64| num_frames 241| | } 242| | }; 243| 6.02k| Ok(reader) 244| 9.18k| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE10next_frameCs4rpmEmvDwFM_5image: 416| 5.78k| pub fn next_frame(&mut self, buf: &mut [u8]) -> Result { 417| 5.78k| if self.remaining_frames == 0 { 418| 0| return Err(DecodingError::Parameter( 419| 0| ParameterErrorKind::PolledAfterEndOfImage.into(), 420| 0| )); 421| 5.78k| } 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| 5.78k| } 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| 5.78k| let required_len = self 431| 5.78k| .output_buffer_size() 432| 5.78k| .ok_or(DecodingError::LimitsExceeded)?; 433| | 434| 5.78k| 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| 5.78k| } 443| | 444| 5.78k| let (color_type, bit_depth) = self.output_color_type(); 445| 5.78k| let output_info = OutputInfo { 446| 5.78k| width: self.subframe.width, 447| 5.78k| height: self.subframe.height, 448| 5.78k| color_type, 449| 5.78k| bit_depth, 450| 5.78k| line_size: self.unguarded_output_line_size(self.subframe.width), 451| 5.78k| }; 452| | 453| 5.78k| 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| 23.2M| data: row, 461| 23.2M| interlace, 462| | .. 463| 23.2M| }) = self.next_interlaced_row()? 464| 23.2M| { 465| 23.2M| // `unwrap` won't panic, because we checked `self.info().interlaced` above. 466| 23.2M| let adam7info = interlace.get_adam7_info().unwrap(); 467| 23.2M| expand(buf, stride, row, adam7info, bits_pp); 468| 23.2M| } 469| | } else { 470| 3.38k| let current_interlace_info = self.subframe.current_interlace_info.as_ref(); 471| 3.38k| let already_done_rows = current_interlace_info 472| 3.38k| .map(|info| info.line_number()) 473| 3.38k| .unwrap_or(self.subframe.height); 474| | 475| 523k| for row in buf 476| 3.38k| .chunks_exact_mut(output_info.line_size) 477| 3.38k| .take(self.subframe.height as usize) 478| 3.38k| .skip(already_done_rows as usize) 479| | { 480| 523k| self.next_interlaced_row_impl(self.subframe.rowlen, row)?; 481| | } 482| | } 483| | 484| | // Advance over the rest of data for this (sub-)frame. 485| 1.86k| self.finish_decoding()?; 486| | 487| 1.72k| Ok(output_info) 488| 5.78k| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE15finish_decodingCs4rpmEmvDwFM_5image: 499| 2.11k| 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.11k| 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.11k| if !self.subframe.consumed_and_flushed { 506| 2.04k| self.decoder.finish_decoding_image_data()?; 507| 1.72k| self.mark_subframe_as_consumed_and_flushed(); 508| 73| } 509| | 510| 1.79k| Ok(()) 511| 2.11k| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE16output_line_sizeCs4rpmEmvDwFM_5image: 692| 23.2M| pub fn output_line_size(&self, width: u32) -> Option { 693| 23.2M| let (color, depth) = self.output_color_type(); 694| 23.2M| 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| 23.2M| (length <= isize::MAX as usize).then_some(length) 697| 23.2M| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE17output_color_typeCs4rpmEmvDwFM_5image: 629| 69.8M| pub fn output_color_type(&self) -> (ColorType, BitDepth) { 630| | use crate::common::ColorType::*; 631| 69.8M| let t = self.transform; 632| 69.8M| let info = self.info(); 633| 69.8M| if t == Transformations::IDENTITY { 634| 0| (info.color_type, info.bit_depth) 635| | } else { 636| 69.8M| let bits = match info.bit_depth as u8 { 637| 892k| 16 if t.intersects(Transformations::STRIP_16) => 8, 638| 69.8M| n if n < 8 639| 804k| && (t.contains(Transformations::EXPAND) 640| 804k| || t.contains(Transformations::ALPHA)) => 641| | { 642| 804k| 8 643| | } 644| 69.0M| n => n, 645| | }; 646| 69.8M| let color_type = 647| 69.8M| if t.contains(Transformations::EXPAND) || t.contains(Transformations::ALPHA) { 648| 69.8M| let has_trns = info.trns.is_some() || t.contains(Transformations::ALPHA); 649| 69.3M| match info.color_type { 650| 481k| Grayscale if has_trns => GrayscaleAlpha, 651| 22.0k| Rgb if has_trns => Rgba, 652| 23.4k| Indexed if has_trns => Rgba, 653| 26.1k| Indexed => Rgb, 654| 69.2M| ct => ct, 655| | } 656| | } else { 657| 0| info.color_type 658| | }; 659| 69.8M| (color_type, BitDepth::from_u8(bits).unwrap()) 660| | } 661| 69.8M| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE18output_buffer_sizeCs4rpmEmvDwFM_5image: 668| 14.9k| pub fn output_buffer_size(&self) -> Option { 669| 14.9k| let (width, height) = self.info().size(); 670| 14.9k| 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| 14.9k| let linelen = color.checked_raw_row_length(depth, width)?.checked_sub(1)?; 676| 14.9k| let height = usize::try_from(height).ok()?; 677| 14.9k| let imglen = linelen.checked_mul(height)?; 678| | // Ensure that it fits into address space not only `usize` to allocate. 679| 14.9k| (imglen <= isize::MAX as usize).then_some(imglen) 680| 14.9k| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE19next_interlaced_rowCs4rpmEmvDwFM_5image: 524| 23.2M| pub fn next_interlaced_row(&mut self) -> Result>, DecodingError> { 525| 23.2M| let mut output_buffer = mem::take(&mut self.scratch_buffer); 526| 23.2M| let max_line_size = self 527| 23.2M| .output_line_size(self.info().width) 528| 23.2M| .ok_or(DecodingError::LimitsExceeded)?; 529| 23.2M| output_buffer.resize(max_line_size, 0u8); 530| 23.2M| let result = self.read_row(&mut output_buffer); 531| 23.2M| self.scratch_buffer = output_buffer; 532| 23.2M| 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| 23.2M| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE21read_until_image_dataCs4rpmEmvDwFM_5image: 368| 9.13k| fn read_until_image_data(&mut self) -> Result<(), DecodingError> { 369| 9.13k| self.decoder.read_until_image_data()?; 370| | 371| 6.05k| self.subframe = SubframeInfo::new(self.info()); 372| 6.05k| self.bpp = self.info().bpp_in_prediction(); 373| | 374| 6.05k| 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.58k| (self.subframe.rowlen as u64) * self.subframe.height as u64 386| | }; 387| 6.05k| self.unfiltering_buffer.start_frame(frame_bytes); 388| | 389| | // Allocate output buffer. 390| 6.05k| let buflen = self.unguarded_output_line_size(self.subframe.width); 391| 6.05k| self.decoder.reserve_bytes(buflen)?; 392| | 393| 6.02k| Ok(()) 394| 9.13k| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE23next_raw_interlaced_rowCs4rpmEmvDwFM_5image: 700| 23.7M| 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| 24.4M| while self.unfiltering_buffer.mutable_len_of_curr_row() < rowlen { 703| 1.34M| if self.subframe.consumed_and_flushed { 704| 27| return Err(DecodingError::Format( 705| 27| FormatErrorInner::NoMoreImageData.into(), 706| 27| )); 707| 1.34M| } 708| | 709| 1.34M| assert!(self.unfiltering_buffer.remaining_bytes() > 0); 710| 1.34M| let completion_status = self 711| 1.34M| .unfiltering_buffer 712| 1.34M| .with_unfilled_buffer(|buffer| self.decoder.decode_image_data(Some(buffer))); 713| 689k| match completion_status { 714| 689k| Ok(ImageDataCompletionStatus::ExpectingMoreData) => (), 715| 29| Ok(ImageDataCompletionStatus::Done) => self.mark_subframe_as_consumed_and_flushed(), 716| 649k| Err(DecodingError::IoError(e)) 717| 651k| if e.kind() == std::io::ErrorKind::UnexpectedEof 718| 651k| && self.unfiltering_buffer.readable_len_of_curr_row() >= rowlen => 719| | { 720| 649k| return self 721| 649k| .unfiltering_buffer 722| 649k| .unfilter_curr_row_using_scratch_buffer(rowlen, self.bpp); 723| | } 724| 3.56k| Err(other_error) => return Err(other_error), 725| | } 726| | } 727| | 728| 23.1M| self.unfiltering_buffer 729| 23.1M| .unfilter_curr_row_in_place(rowlen, self.bpp) 730| 23.7M| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE24next_interlaced_row_implCs4rpmEmvDwFM_5image: 605| 23.7M| fn next_interlaced_row_impl( 606| 23.7M| &mut self, 607| 23.7M| rowlen: usize, 608| 23.7M| output_buffer: &mut [u8], 609| 23.7M| ) -> Result<(), DecodingError> { 610| 23.7M| self.next_raw_interlaced_row(rowlen)?; 611| 23.7M| let row = self.unfiltering_buffer.prev_row(); 612| 23.7M| assert_eq!(row.len(), rowlen - 1); 613| | 614| | // Apply transformations and write resulting data to buffer. 615| 23.7M| let transform_fn = { 616| 23.7M| if self.transform_fn.is_none() { 617| 4.21k| self.transform_fn = Some(create_transform_fn(self.info(), self.transform)?); 618| 23.7M| } 619| 23.7M| self.transform_fn.as_deref().unwrap() 620| | }; 621| 23.7M| transform_fn(row, output_buffer, self.info()); 622| | 623| 23.7M| self.subframe.current_interlace_info = self.subframe.interlace_info_iter.next(); 624| 23.7M| Ok(()) 625| 23.7M| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE26unguarded_output_line_sizeCs4rpmEmvDwFM_5image: 683| 46.5M| pub(crate) fn unguarded_output_line_size(&self, width: u32) -> usize { 684| 46.5M| let (color, depth) = self.output_color_type(); 685| 46.5M| color.raw_row_length_from_width(depth, width) - 1 686| 46.5M| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE35output_line_size_for_interlace_infoCs4rpmEmvDwFM_5image: 580| 46.5M| fn output_line_size_for_interlace_info(&self, interlace: &InterlaceInfo) -> usize { 581| 46.5M| let width = match interlace { 582| 46.5M| InterlaceInfo::Adam7(Adam7Info { samples: width, .. }) => *width, 583| 0| InterlaceInfo::Null(_) => self.subframe.width, 584| | }; 585| 46.5M| self.unguarded_output_line_size(width) 586| 46.5M| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE37mark_subframe_as_consumed_and_flushedCs4rpmEmvDwFM_5image: 490| 1.75k| fn mark_subframe_as_consumed_and_flushed(&mut self) { 491| 1.75k| assert!(self.remaining_frames > 0); 492| 1.75k| self.remaining_frames -= 1; 493| | 494| 1.75k| self.subframe.consumed_and_flushed = true; 495| 1.75k| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE4infoCs4rpmEmvDwFM_5image: 399| 140M| pub fn info(&self) -> &Info<'static> { 400| 140M| self.decoder.info().unwrap() 401| 140M| } _RNvMs4_NtCshdzP3jLBsmJ_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE8read_rowCs4rpmEmvDwFM_5image: 551| 23.2M| pub fn read_row( 552| 23.2M| &mut self, 553| 23.2M| output_buffer: &mut [u8], 554| 23.2M| ) -> Result, DecodingError> { 555| 23.2M| let interlace = match self.subframe.current_interlace_info.as_ref() { 556| | None => { 557| 253| self.finish_decoding()?; 558| 71| return Ok(None); 559| | } 560| 23.2M| Some(interlace) => *interlace, 561| | }; 562| 23.2M| if interlace.line_number() == 0 { 563| 5.95k| self.unfiltering_buffer.reset_prev_row(); 564| 23.2M| } 565| 23.2M| let rowlen = match interlace { 566| 0| InterlaceInfo::Null(_) => self.subframe.rowlen, 567| 23.2M| InterlaceInfo::Adam7(Adam7Info { samples: width, .. }) => { 568| 23.2M| self.info().raw_row_length_from_width(width) 569| | } 570| | }; 571| | 572| 23.2M| let output_line_size = self.output_line_size_for_interlace_info(&interlace); 573| 23.2M| let output_buffer = &mut output_buffer[..output_line_size]; 574| | 575| 23.2M| self.next_interlaced_row_impl(rowlen, output_buffer)?; 576| | 577| 23.2M| Ok(Some(interlace)) 578| 23.2M| } _RNvMs5_NtCshdzP3jLBsmJ_3png7decoderNtB5_12SubframeInfo12not_yet_init: 734| 9.18k| fn not_yet_init() -> Self { 735| 9.18k| SubframeInfo { 736| 9.18k| width: 0, 737| 9.18k| height: 0, 738| 9.18k| rowlen: 0, 739| 9.18k| current_interlace_info: None, 740| 9.18k| interlace_info_iter: InterlaceInfoIter::empty(), 741| 9.18k| consumed_and_flushed: false, 742| 9.18k| } 743| 9.18k| } _RNvMs5_NtCshdzP3jLBsmJ_3png7decoderNtB5_12SubframeInfo3new: 745| 6.05k| 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.05k| let (width, height) = if let Some(fc) = info.frame_control { 749| 1| (fc.width, fc.height) 750| | } else { 751| 6.05k| (info.width, info.height) 752| | }; 753| | 754| 6.05k| let mut interlace_info_iter = InterlaceInfoIter::new(width, height, info.interlaced); 755| 6.05k| let current_interlace_info = interlace_info_iter.next(); 756| 6.05k| SubframeInfo { 757| 6.05k| width, 758| 6.05k| height, 759| 6.05k| rowlen: info.raw_row_length_from_width(width), 760| 6.05k| current_interlace_info, 761| 6.05k| interlace_info_iter, 762| 6.05k| consumed_and_flushed: false, 763| 6.05k| } 764| 6.05k| } _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| 30| Err(DecodingError::LimitsExceeded) 77| | } 78| 43.3k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE10set_limitsCs4rpmEmvDwFM_5image: 39| 18.9k| pub fn set_limits(&mut self, limits: Limits) { 40| 18.9k| self.decoder.limits = limits; 41| 18.9k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE11decode_nextCs4rpmEmvDwFM_5image: 62| 1.49M| fn decode_next( 63| 1.49M| &mut self, 64| 1.49M| image_data: Option<&mut UnfilterBuf<'_>>, 65| 1.49M| ) -> Result { 66| 843k| let (consumed, result) = { 67| 1.49M| let buf = self.reader.fill_buf()?; 68| 1.49M| if buf.is_empty() { 69| 654k| return Err(DecodingError::IoError(ErrorKind::UnexpectedEof.into())); 70| 844k| } 71| 844k| self.decoder.update(buf, image_data)? 72| | }; 73| 843k| self.reader.consume(consumed); 74| 843k| Ok(result) 75| 1.49M| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE13reserve_bytesCs4rpmEmvDwFM_5image: 43| 6.05k| pub fn reserve_bytes(&mut self, bytes: usize) -> Result<(), DecodingError> { 44| 6.05k| self.decoder.limits.reserve_bytes(bytes) 45| 6.05k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE16read_header_infoCs4rpmEmvDwFM_5image: 80| 18.6k| pub fn read_header_info(&mut self) -> Result<&Info<'static>, DecodingError> { 81| 37.1k| while self.info().is_none() { 82| 18.7k| if let Decoded::ChunkComplete(chunk::IEND) = self.decode_next(None)? { 83| 0| unreachable!() 84| 18.4k| } 85| | } 86| 18.3k| Ok(self.info().unwrap()) 87| 18.6k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE17decode_image_dataCs4rpmEmvDwFM_5image: 113| 1.34M| pub fn decode_image_data( 114| 1.34M| &mut self, 115| 1.34M| image_data: Option<&mut UnfilterBuf<'_>>, 116| 1.34M| ) -> Result { 117| 1.34M| match self.decode_next(image_data)? { 118| 679k| Decoded::ImageData => Ok(ImageDataCompletionStatus::ExpectingMoreData), 119| 1.75k| Decoded::ImageDataFlushed => Ok(ImageDataCompletionStatus::Done), 120| | // Ignore other events that may happen within an `IDAT` / `fdAT` chunks sequence. 121| 12.9k| _ => Ok(ImageDataCompletionStatus::ExpectingMoreData), 122| | } 123| 1.34M| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE21read_until_image_dataCs4rpmEmvDwFM_5image: 92| 9.13k| pub fn read_until_image_data(&mut self) -> Result<(), DecodingError> { 93| | loop { 94| 133k| match self.decode_next(None)? { 95| 6.05k| 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| 124k| _ => {} 104| | } 105| | } 106| 6.05k| Ok(()) 107| 9.13k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE21set_ignore_text_chunkCs4rpmEmvDwFM_5image: 47| 9.46k| pub fn set_ignore_text_chunk(&mut self, ignore_text_chunk: bool) { 48| 9.46k| self.decoder.set_ignore_text_chunk(ignore_text_chunk); 49| 9.46k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE26finish_decoding_image_dataCs4rpmEmvDwFM_5image: 128| 2.04k| pub fn finish_decoding_image_data(&mut self) -> Result<(), DecodingError> { 129| | loop { 130| 5.41k| if let ImageDataCompletionStatus::Done = self.decode_image_data(None)? { 131| 1.72k| return Ok(()); 132| 3.37k| } 133| | } 134| 2.04k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE3newCs4rpmEmvDwFM_5image: 25| 9.46k| pub fn new(r: R) -> Self { 26| 9.46k| Self { 27| 9.46k| reader: r, 28| 9.46k| decoder: StreamingDecoder::new(), 29| 9.46k| } 30| 9.46k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE4infoCs4rpmEmvDwFM_5image: 144| 140M| pub fn info(&self) -> Option<&Info<'static>> { 145| 140M| self.decoder.info.as_ref() 146| 140M| } _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder10parse_itxt0Bb_: 1884| 76| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingCompressionFlag))?; _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder10parse_itxts0_0Bb_: 1892| 50.5k| .position(|&b| b == 0) _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder10parse_itxts1_0Bb_: 1893| 408| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))? _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder10parse_itxts2_0Bb_: 1900| 22.5k| .position(|&b| b == 0) _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder10parse_itxts3_0Bb_: 1901| 426| .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| 200| let rendering_intent = crate::SrgbRenderingIntent::from_raw(raw).ok_or_else(|| { 1523| 200| FormatError::from(FormatErrorInner::InvalidSrgbRenderingIntent(raw)) 1524| 200| })?; _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder10parse_ztxt0Bb_: 1864| 72| .ok_or_else(|| DecodingError::from(TextDecodingError::InvalidCompressionMethod))?; _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder11parse_chunk0Bb_: 1134| 19.1k| parse_result = parse_result.map_err(|e| { 1135| 9| 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| 9| 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| 19.1k| e => e, 1146| | } 1147| 19.1k| }); _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder13split_keyword0Bb_: 1831| 249k| .position(|&b| b == 0) _RNCNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB7_16StreamingDecoder13split_keywords_0Bb_: 1832| 1.92k| .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.46k| pub fn set_ignore_text_chunk(&mut self, ignore_text_chunk: bool) { 512| 9.46k| self.ignore_text_chunk = ignore_text_chunk; 513| 9.46k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10next_state: 710| 1.03M| fn next_state( 711| 1.03M| &mut self, 712| 1.03M| buf: &[u8], 713| 1.03M| image_data: Option<&mut UnfilterBuf<'_>>, 714| 1.03M| ) -> Result<(usize, Decoded), DecodingError> { 715| | use self::State::*; 716| | 717| | // Driver should ensure that state is never None 718| 1.03M| let state = self.state.take().unwrap(); 719| | 720| 1.03M| 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| 268k| self.parse_u32(kind, &buf[0..4], image_data, CONSUMED_BYTES) 735| | } else { 736| 442| let remaining_count = 4 - accumulated_count; 737| 442| let consumed_bytes = { 738| 442| let available_count = min(remaining_count, buf.len()); 739| 442| bytes[accumulated_count..accumulated_count + available_count] 740| 442| .copy_from_slice(&buf[0..available_count]); 741| 442| accumulated_count += available_count; 742| 442| available_count 743| | }; 744| | 745| 442| if accumulated_count < 4 { 746| 442| self.state = Some(U32 { 747| 442| kind, 748| 442| bytes, 749| 442| accumulated_count, 750| 442| }); 751| 442| 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| 82.4k| ReadChunkData(type_str) => { 759| 82.4k| debug_assert!(type_str != IDAT && type_str != chunk::fdAT); 760| 82.4k| if self.current_chunk.remaining == 0 { 761| 5.92k| self.state = Some(State::new_u32(U32ValueKind::Crc(type_str))); 762| 5.92k| Ok((0, Decoded::Nothing)) 763| | } else { 764| | let ChunkState { 765| 76.5k| crc, 766| 76.5k| remaining, 767| 76.5k| raw_bytes, 768| | type_: _, 769| 76.5k| action, 770| 76.5k| } = &mut self.current_chunk; 771| | 772| 76.5k| let buf_avail = raw_bytes.capacity() - raw_bytes.len(); 773| 76.5k| let bytes_avail = min(buf.len(), buf_avail); 774| 76.5k| let n = min(*remaining, bytes_avail as u32); 775| 76.5k| let buf = &buf[..n as usize]; 776| | 777| 76.5k| if !self.decode_options.ignore_crc { 778| 76.5k| crc.update(buf); 779| 76.5k| } 780| | 781| 76.5k| if *action == ChunkAction::Process { 782| 65.6k| if raw_bytes.len() == raw_bytes.capacity() { 783| 5.50k| if self.limits.bytes == 0 { 784| 0| return Err(DecodingError::LimitsExceeded); 785| 5.50k| } 786| | 787| | // Double the size of the Vec, but not beyond the allocation limit. 788| 5.50k| debug_assert!(raw_bytes.capacity() > 0); 789| 5.50k| let reserve_size = raw_bytes.capacity().min(self.limits.bytes); 790| | 791| 5.50k| self.limits.reserve_bytes(reserve_size)?; 792| 5.50k| raw_bytes.reserve_exact(reserve_size); 793| 60.0k| } 794| 65.6k| raw_bytes.extend_from_slice(buf); 795| 10.9k| } 796| | 797| 76.5k| *remaining -= n; 798| 76.5k| if *remaining == 0 { 799| 64.8k| debug_assert!(type_str != IDAT && type_str != chunk::fdAT); 800| 64.8k| self.state = Some(State::new_u32(U32ValueKind::Crc(type_str))); 801| 11.6k| } else { 802| 11.6k| self.state = Some(ReadChunkData(type_str)); 803| 11.6k| } 804| 76.5k| Ok((n as usize, Decoded::Nothing)) 805| | } 806| | } 807| 680k| ImageData(type_str) => { 808| 680k| debug_assert!(type_str == IDAT || type_str == chunk::fdAT); 809| 680k| let len = std::cmp::min(buf.len(), self.current_chunk.remaining as usize); 810| 680k| let buf = &buf[..len]; 811| | 812| 680k| let consumed = if let Some(image_data) = image_data { 813| 679k| self.inflater.decompress(buf, image_data)? 814| | } else { 815| 1.12k| len 816| | }; 817| | 818| 679k| if !self.decode_options.ignore_crc { 819| 679k| self.current_chunk.crc.update(&buf[..consumed]); 820| 679k| } 821| | 822| 679k| self.current_chunk.remaining -= consumed as u32; 823| 679k| if self.current_chunk.remaining == 0 { 824| 7.47k| self.state = Some(State::new_u32(U32ValueKind::Crc(type_str))); 825| 672k| } else { 826| 672k| self.state = Some(ImageData(type_str)); 827| 672k| } 828| 679k| Ok((consumed, Decoded::ImageData)) 829| | } 830| | } 831| 1.03M| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_actl: 1236| 894| fn parse_actl(&mut self) -> Result<(), DecodingError> { 1237| 894| let info = self.info.as_mut().unwrap(); 1238| 894| if self.have_idat { 1239| 0| Err(DecodingError::Format( 1240| 0| FormatErrorInner::AfterIdat { kind: chunk::acTL }.into(), 1241| 0| )) 1242| 894| } else if info.animation_control.is_some() { 1243| 294| Err(DecodingError::Format( 1244| 294| FormatErrorInner::DuplicateChunk { kind: chunk::acTL }.into(), 1245| 294| )) 1246| | } else { 1247| 600| let mut buf = &self.current_chunk.raw_bytes[..]; 1248| 600| let actl = AnimationControl { 1249| 600| num_frames: buf.read_be()?, 1250| 600| 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| 600| if actl.num_frames == 0 { 1255| 66| return Ok(()); 1256| 534| } 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| 534| if actl.num_frames > 0x7FFFFFFF || actl.num_plays > 0x7FFFFFFF { 1263| 455| return Ok(()); 1264| 79| } 1265| | 1266| 79| info.animation_control = Some(actl); 1267| 79| Ok(()) 1268| | } 1269| 894| } _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| 199| if info.palette.is_none() { 1940| 1| return Err(DecodingError::IoError( 1941| 1| std::io::ErrorKind::InvalidData.into(), 1942| 1| )); 1943| 198| }; 1944| 198| 1 1945| | } 1946| 639| ColorType::Grayscale | ColorType::GrayscaleAlpha => 2, 1947| 401| 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| 29| } 1955| | 1956| 29| info.bkgd = Some(Cow::Owned(vec)); 1957| 29| 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| 491| fn parse_cicp(&mut self) -> Result<(), DecodingError> { 1533| 491| 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| 491| 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| 244| } else if info.palette.is_some() { 1541| 223| return Err(DecodingError::Format( 1542| 223| FormatErrorInner::AfterPlte { kind: chunk::cICP }.into(), 1543| 223| )); 1544| 21| } else if self.have_idat { 1545| 0| return Err(DecodingError::Format( 1546| 0| FormatErrorInner::AfterIdat { kind: chunk::cICP }.into(), 1547| 0| )); 1548| 21| } 1549| | 1550| 21| let mut buf = &*self.current_chunk.raw_bytes; 1551| 21| let color_primaries: u8 = buf.read_be()?; 1552| 21| let transfer_function: u8 = buf.read_be()?; 1553| 21| let matrix_coefficients: u8 = buf.read_be()?; 1554| 16| let is_video_full_range_image = { 1555| 21| let flag: u8 = buf.read_be()?; 1556| 21| match flag { 1557| 16| 0 => false, 1558| 0| 1 => true, 1559| | _ => { 1560| 5| return Err(DecodingError::IoError( 1561| 5| std::io::ErrorKind::InvalidData.into(), 1562| 5| )); 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| 16| if matrix_coefficients != 0 { 1570| 3| return Err(DecodingError::IoError( 1571| 3| std::io::ErrorKind::InvalidData.into(), 1572| 3| )); 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| 491| } _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| 738| fn parse_exif(&mut self) -> Result<(), DecodingError> { 1674| 738| let info = self.info.as_mut().unwrap(); 1675| 738| if info.exif_metadata.is_some() { 1676| 646| return Err(DecodingError::Format( 1677| 646| FormatErrorInner::DuplicateChunk { kind: chunk::eXIf }.into(), 1678| 646| )); 1679| 92| } 1680| | 1681| 92| info.exif_metadata = Some(self.current_chunk.raw_bytes.clone().into()); 1682| 92| Ok(()) 1683| 738| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_fctl: 1167| 333| fn parse_fctl(&mut self) -> Result<(), DecodingError> { 1168| 333| let mut buf = &self.current_chunk.raw_bytes[..]; 1169| 333| let next_seq_no = buf.read_be()?; 1170| | 1171| | // Assuming that fcTL is required before *every* fdAT-sequence 1172| 333| self.current_seq_no = Some(if let Some(seq_no) = self.current_seq_no { 1173| 49| if next_seq_no != seq_no + 1 { 1174| 48| return Err(DecodingError::Format( 1175| 48| FormatErrorInner::ApngOrder { 1176| 48| expected: seq_no + 1, 1177| 48| present: next_seq_no, 1178| 48| } 1179| 48| .into(), 1180| 48| )); 1181| 1| } 1182| 1| next_seq_no 1183| | } else { 1184| 284| if next_seq_no != 0 { 1185| 40| return Err(DecodingError::Format( 1186| 40| FormatErrorInner::ApngOrder { 1187| 40| expected: 0, 1188| 40| present: next_seq_no, 1189| 40| } 1190| 40| .into(), 1191| 40| )); 1192| 244| } 1193| 244| 0 1194| | }); 1195| 245| self.inflater.reset(); 1196| 245| self.ready_for_fdat_chunks = self.have_idat; 1197| 240| let fc = FrameControl { 1198| 245| sequence_number: next_seq_no, 1199| 245| width: buf.read_be()?, 1200| 245| height: buf.read_be()?, 1201| 245| x_offset: buf.read_be()?, 1202| 245| y_offset: buf.read_be()?, 1203| 245| delay_num: buf.read_be()?, 1204| 245| delay_den: buf.read_be()?, 1205| | dispose_op: { 1206| 245| let dispose_op = buf.read_be()?; 1207| 245| match DisposeOp::from_u8(dispose_op) { 1208| 241| Some(dispose_op) => dispose_op, 1209| | None => { 1210| 4| return Err(DecodingError::Format( 1211| 4| FormatErrorInner::InvalidDisposeOp(dispose_op).into(), 1212| 4| )) 1213| | } 1214| | } 1215| | }, 1216| | blend_op: { 1217| 241| let blend_op = buf.read_be()?; 1218| 241| match BlendOp::from_u8(blend_op) { 1219| 240| 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| 240| self.info.as_ref().unwrap().validate(&fc)?; 1229| 184| if !self.have_idat { 1230| 184| 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| 333| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_gama: 1484| 386| fn parse_gama(&mut self) -> Result<(), DecodingError> { 1485| 386| let info = self.info.as_mut().unwrap(); 1486| 386| if self.have_idat { 1487| 0| Err(DecodingError::Format( 1488| 0| FormatErrorInner::AfterIdat { kind: chunk::gAMA }.into(), 1489| 0| )) 1490| 386| } else if info.gama_chunk.is_some() { 1491| 209| Err(DecodingError::Format( 1492| 209| FormatErrorInner::DuplicateChunk { kind: chunk::gAMA }.into(), 1493| 209| )) 1494| | } else { 1495| 177| let mut buf = &self.current_chunk.raw_bytes[..]; 1496| 177| let source_gamma: u32 = buf.read_be()?; 1497| 177| if source_gamma == 0 { 1498| 75| return Err(DecodingError::Format( 1499| 75| FormatErrorInner::BadGammaValue.into(), 1500| 75| )); 1501| 102| } 1502| | 1503| 102| let source_gamma = ScaledFloat::from_scaled(source_gamma); 1504| 102| info.gama_chunk = Some(source_gamma); 1505| 102| Ok(()) 1506| | } 1507| 386| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_iccp: 1685| 2.84k| fn parse_iccp(&mut self) -> Result<(), DecodingError> { 1686| 2.84k| if self.have_idat { 1687| 0| Err(DecodingError::Format( 1688| 0| FormatErrorInner::AfterIdat { kind: chunk::iCCP }.into(), 1689| 0| )) 1690| 2.84k| } else if self.have_iccp { 1691| 658| Err(DecodingError::Format( 1692| 658| FormatErrorInner::DuplicateChunk { kind: chunk::iCCP }.into(), 1693| 658| )) 1694| | } else { 1695| 2.19k| self.have_iccp = true; 1696| 2.19k| let _ = self.parse_iccp_raw(); 1697| 2.19k| Ok(()) 1698| | } 1699| 2.84k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_ihdr: 1744| 9.24k| fn parse_ihdr(&mut self) -> Result<(), DecodingError> { 1745| 9.24k| if self.info.is_some() { 1746| 2| return Err(DecodingError::Format( 1747| 2| FormatErrorInner::DuplicateChunk { kind: IHDR }.into(), 1748| 2| )); 1749| 9.24k| } 1750| 9.24k| let mut buf = &self.current_chunk.raw_bytes[..]; 1751| 9.24k| let width = buf.read_be()?; 1752| 9.24k| let height = buf.read_be()?; 1753| 9.24k| if width == 0 || height == 0 { 1754| 2| return Err(DecodingError::Format( 1755| 2| FormatErrorInner::InvalidDimensions.into(), 1756| 2| )); 1757| 9.24k| } 1758| 9.24k| let bit_depth = buf.read_be()?; 1759| 9.24k| let bit_depth = match BitDepth::from_u8(bit_depth) { 1760| 9.22k| Some(bits) => bits, 1761| | None => { 1762| 19| return Err(DecodingError::Format( 1763| 19| FormatErrorInner::InvalidBitDepth(bit_depth).into(), 1764| 19| )) 1765| | } 1766| | }; 1767| 9.22k| let color_type = buf.read_be()?; 1768| 9.22k| let color_type = match ColorType::from_u8(color_type) { 1769| 9.21k| Some(color_type) => { 1770| 9.21k| 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.21k| color_type 1780| | } 1781| | } 1782| | None => { 1783| 7| return Err(DecodingError::Format( 1784| 7| FormatErrorInner::InvalidColorType(color_type).into(), 1785| 7| )) 1786| | } 1787| | }; 1788| 9.21k| match buf.read_be()? { 1789| | // compression method 1790| 9.20k| 0u8 => (), 1791| 9| n => { 1792| 9| return Err(DecodingError::Format( 1793| 9| FormatErrorInner::UnknownCompressionMethod(n).into(), 1794| 9| )) 1795| | } 1796| | } 1797| 9.20k| match buf.read_be()? { 1798| | // filter method 1799| 9.19k| 0u8 => (), 1800| 7| n => { 1801| 7| return Err(DecodingError::Format( 1802| 7| FormatErrorInner::UnknownFilterMethod(n).into(), 1803| 7| )) 1804| | } 1805| | } 1806| 9.19k| let interlaced = match buf.read_be()? { 1807| 6.12k| 0u8 => false, 1808| 3.06k| 1 => true, 1809| 6| n => { 1810| 6| return Err(DecodingError::Format( 1811| 6| FormatErrorInner::UnknownInterlaceMethod(n).into(), 1812| 6| )) 1813| | } 1814| | }; 1815| | 1816| 9.18k| self.info = Some(Info { 1817| 9.18k| width, 1818| 9.18k| height, 1819| 9.18k| bit_depth, 1820| 9.18k| color_type, 1821| 9.18k| interlaced, 1822| 9.18k| ..Default::default() 1823| 9.18k| }); 1824| | 1825| 9.18k| Ok(()) 1826| 9.24k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_itxt: 1876| 14.3k| fn parse_itxt(&mut self) -> Result<(), DecodingError> { 1877| 14.3k| let buf = &self.current_chunk.raw_bytes[..]; 1878| 14.3k| self.limits.reserve_bytes(buf.len())?; 1879| | 1880| 14.3k| let (keyword_slice, value_slice) = Self::split_keyword(buf)?; 1881| | 1882| 12.9k| let compression_flag = *value_slice 1883| 12.9k| .first() 1884| 12.9k| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingCompressionFlag))?; 1885| | 1886| 12.8k| let compression_method = *value_slice 1887| 12.8k| .get(1) 1888| 12.8k| .ok_or_else(|| DecodingError::from(TextDecodingError::InvalidCompressionMethod))?; 1889| | 1890| 12.8k| let second_null_byte_index = value_slice[2..] 1891| 12.8k| .iter() 1892| 12.8k| .position(|&b| b == 0) 1893| 12.8k| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))? 1894| | + 2; 1895| | 1896| 12.4k| let language_tag_slice = &value_slice[2..second_null_byte_index]; 1897| | 1898| 12.4k| let third_null_byte_index = value_slice[second_null_byte_index + 1..] 1899| 12.4k| .iter() 1900| 12.4k| .position(|&b| b == 0) 1901| 12.4k| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))? 1902| 11.9k| + (second_null_byte_index + 1); 1903| | 1904| 11.9k| let translated_keyword_slice = 1905| 11.9k| &value_slice[second_null_byte_index + 1..third_null_byte_index]; 1906| | 1907| 11.9k| let text_slice = &value_slice[third_null_byte_index + 1..]; 1908| | 1909| 11.9k| self.info.as_mut().unwrap().utf8_text.push( 1910| 11.9k| ITXtChunk::decode( 1911| 11.9k| keyword_slice, 1912| 11.9k| compression_flag, 1913| 11.9k| compression_method, 1914| 11.9k| language_tag_slice, 1915| 11.9k| translated_keyword_slice, 1916| 11.9k| text_slice, 1917| | ) 1918| 11.9k| .map_err(DecodingError::from)?, 1919| | ); 1920| | 1921| 10.0k| Ok(()) 1922| 14.3k| } _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| 793| fn parse_phys(&mut self) -> Result<(), DecodingError> { 1411| 793| let info = self.info.as_mut().unwrap(); 1412| 793| if self.have_idat { 1413| 0| Err(DecodingError::Format( 1414| 0| FormatErrorInner::AfterIdat { kind: chunk::pHYs }.into(), 1415| 0| )) 1416| 793| } else if info.pixel_dims.is_some() { 1417| 376| Err(DecodingError::Format( 1418| 376| FormatErrorInner::DuplicateChunk { kind: chunk::pHYs }.into(), 1419| 376| )) 1420| | } else { 1421| 417| let mut buf = &self.current_chunk.raw_bytes[..]; 1422| 417| let xppu = buf.read_be()?; 1423| 417| let yppu = buf.read_be()?; 1424| 417| let unit = buf.read_be()?; 1425| 417| let unit = match Unit::from_u8(unit) { 1426| 72| Some(unit) => unit, 1427| | None => { 1428| 345| return Err(DecodingError::Format( 1429| 345| FormatErrorInner::InvalidUnit(unit).into(), 1430| 345| )) 1431| | } 1432| | }; 1433| 72| let pixel_dims = PixelDimensions { xppu, yppu, unit }; 1434| 72| info.pixel_dims = Some(pixel_dims); 1435| 72| Ok(()) 1436| | } 1437| 793| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_plte: 1271| 1.30k| fn parse_plte(&mut self) -> Result<(), DecodingError> { 1272| 1.30k| let info = self.info.as_mut().unwrap(); 1273| 1.30k| if info.palette.is_some() { 1274| | // Only one palette is allowed 1275| 1| Err(DecodingError::Format( 1276| 1| FormatErrorInner::DuplicateChunk { kind: chunk::PLTE }.into(), 1277| 1| )) 1278| | } else { 1279| 1.30k| info.palette = Some(Cow::Owned(self.current_chunk.raw_bytes.clone())); 1280| 1.30k| Ok(()) 1281| | } 1282| 1.30k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_sbit: 1284| 4.35k| fn parse_sbit(&mut self) -> Result<(), DecodingError> { 1285| 4.35k| let info = self.info.as_mut().unwrap(); 1286| 4.35k| if info.palette.is_some() { 1287| 196| return Err(DecodingError::Format( 1288| 196| FormatErrorInner::AfterPlte { kind: chunk::sBIT }.into(), 1289| 196| )); 1290| 4.16k| } 1291| | 1292| 4.16k| if self.have_idat { 1293| 0| return Err(DecodingError::Format( 1294| 0| FormatErrorInner::AfterIdat { kind: chunk::sBIT }.into(), 1295| 0| )); 1296| 4.16k| } 1297| | 1298| 4.16k| if info.sbit.is_some() { 1299| 196| return Err(DecodingError::Format( 1300| 196| FormatErrorInner::DuplicateChunk { kind: chunk::sBIT }.into(), 1301| 196| )); 1302| 3.96k| } 1303| | 1304| 3.96k| 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.96k| let sample_depth = if color_type == ColorType::Indexed { 1307| 3.09k| BitDepth::Eight 1308| | } else { 1309| 867| bit_depth 1310| | }; 1311| 3.96k| let vec = self.current_chunk.raw_bytes.clone(); 1312| 3.96k| let len = vec.len(); 1313| | 1314| | // expected lenth of the chunk 1315| 3.96k| let expected = match color_type { 1316| 805| ColorType::Grayscale => 1, 1317| 3.15k| ColorType::Rgb | ColorType::Indexed => 3, 1318| 5| ColorType::GrayscaleAlpha => 2, 1319| 4| ColorType::Rgba => 4, 1320| | }; 1321| | 1322| | // Check if the sbit chunk size is valid. 1323| 3.96k| 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.62k| } 1333| | 1334| 8.35k| for sbit in &vec { 1335| 8.33k| if *sbit < 1 || *sbit > sample_depth as u8 { 1336| 3.60k| return Err(DecodingError::Format( 1337| 3.60k| FormatErrorInner::InvalidSbit { 1338| 3.60k| sample_depth, 1339| 3.60k| sbit: *sbit, 1340| 3.60k| } 1341| 3.60k| .into(), 1342| 3.60k| )); 1343| 4.72k| } 1344| | } 1345| 17| info.sbit = Some(Cow::Owned(vec)); 1346| 17| Ok(()) 1347| 4.35k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_srgb: 1509| 495| fn parse_srgb(&mut self) -> Result<(), DecodingError> { 1510| 495| let info = self.info.as_mut().unwrap(); 1511| 495| if self.have_idat { 1512| 0| Err(DecodingError::Format( 1513| 0| FormatErrorInner::AfterIdat { kind: chunk::sRGB }.into(), 1514| 0| )) 1515| 495| } else if info.srgb.is_some() { 1516| 211| Err(DecodingError::Format( 1517| 211| FormatErrorInner::DuplicateChunk { kind: chunk::sRGB }.into(), 1518| 211| )) 1519| | } else { 1520| 284| let mut buf = &self.current_chunk.raw_bytes[..]; 1521| 284| let raw: u8 = buf.read_be()?; // BE is is nonsense for single bytes, but this way the size is checked. 1522| 284| let rendering_intent = crate::SrgbRenderingIntent::from_raw(raw).ok_or_else(|| { 1523| | FormatError::from(FormatErrorInner::InvalidSrgbRenderingIntent(raw)) 1524| 200| })?; 1525| | 1526| | // Set srgb and override source gamma and chromaticities. 1527| 84| info.srgb = Some(rendering_intent); 1528| 84| Ok(()) 1529| | } 1530| 495| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_text: 1841| 7.39k| fn parse_text(&mut self) -> Result<(), DecodingError> { 1842| 7.39k| let buf = &self.current_chunk.raw_bytes[..]; 1843| 7.39k| self.limits.reserve_bytes(buf.len())?; 1844| | 1845| 7.39k| let (keyword_slice, value_slice) = Self::split_keyword(buf)?; 1846| | 1847| 6.22k| self.info 1848| 6.22k| .as_mut() 1849| 6.22k| .unwrap() 1850| 6.22k| .uncompressed_latin1_text 1851| 6.22k| .push(TEXtChunk::decode(keyword_slice, value_slice).map_err(DecodingError::from)?); 1852| | 1853| 6.22k| Ok(()) 1854| 7.39k| } _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| 507| return Err(DecodingError::Format( 1353| 507| FormatErrorInner::DuplicateChunk { kind: chunk::PLTE }.into(), 1354| 507| )); 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| 464| if len < 2 { 1362| 238| return Err(DecodingError::Format( 1363| 238| FormatErrorInner::ShortPalette { expected: 2, len }.into(), 1364| 238| )); 1365| 226| } 1366| 226| if bit_depth < 16 { 1367| 134| vec[0] = vec[1]; 1368| 134| vec.truncate(1); 1369| 134| } 1370| 226| info.trns = Some(Cow::Owned(vec)); 1371| 226| Ok(()) 1372| | } 1373| | ColorType::Rgb => { 1374| 225| if len < 6 { 1375| 196| return Err(DecodingError::Format( 1376| 196| FormatErrorInner::ShortPalette { expected: 6, len }.into(), 1377| 196| )); 1378| 29| } 1379| 29| if bit_depth < 16 { 1380| 24| vec[0] = vec[1]; 1381| 24| vec[1] = vec[3]; 1382| 24| vec[2] = vec[5]; 1383| 24| vec.truncate(3); 1384| 24| } 1385| 29| info.trns = Some(Cow::Owned(vec)); 1386| 29| 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| 197| c => Err(DecodingError::Format( 1405| 197| FormatErrorInner::ColorWithBadTrns(c).into(), 1406| 197| )), 1407| | } 1408| 1.68k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder10parse_ztxt: 1856| 8.34k| fn parse_ztxt(&mut self) -> Result<(), DecodingError> { 1857| 8.34k| let buf = &self.current_chunk.raw_bytes[..]; 1858| 8.34k| self.limits.reserve_bytes(buf.len())?; 1859| | 1860| 8.34k| let (keyword_slice, value_slice) = Self::split_keyword(buf)?; 1861| | 1862| 7.44k| let compression_method = *value_slice 1863| 7.44k| .first() 1864| 7.44k| .ok_or_else(|| DecodingError::from(TextDecodingError::InvalidCompressionMethod))?; 1865| | 1866| 7.37k| let text_slice = &value_slice[1..]; 1867| | 1868| 7.37k| self.info.as_mut().unwrap().compressed_latin1_text.push( 1869| 7.37k| ZTXtChunk::decode(keyword_slice, compression_method, text_slice) 1870| 7.37k| .map_err(DecodingError::from)?, 1871| | ); 1872| | 1873| 6.99k| Ok(()) 1874| 8.34k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder11parse_chunk: 1096| 64.0k| fn parse_chunk(&mut self, type_str: ChunkType) -> Result { 1097| 64.0k| let mut parse_result = match type_str { 1098| | // Critical non-data chunks. 1099| 9.24k| IHDR => self.parse_ihdr(), 1100| 1.30k| chunk::PLTE => self.parse_plte(), 1101| 1| chunk::IEND => Ok(()), // TODO: Check chunk size. 1102| | 1103| | // Data chunks handled separately. 1104| 7.42k| chunk::IDAT => Ok(()), 1105| 0| chunk::fdAT => Ok(()), 1106| | 1107| | // Recognized bounded-size ancillary chunks. 1108| 4.35k| chunk::sBIT => self.parse_sbit(), 1109| 1.68k| chunk::tRNS => self.parse_trns(), 1110| 793| chunk::pHYs => self.parse_phys(), 1111| 386| chunk::gAMA => self.parse_gama(), 1112| 894| chunk::acTL => self.parse_actl(), 1113| 333| chunk::fcTL => self.parse_fctl(), 1114| 394| chunk::cHRM => self.parse_chrm(), 1115| 495| chunk::sRGB => self.parse_srgb(), 1116| 491| 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| 738| chunk::eXIf => self.parse_exif(), 1123| 2.84k| chunk::iCCP => self.parse_iccp(), 1124| 7.39k| chunk::tEXt => self.parse_text(), 1125| 8.34k| chunk::zTXt => self.parse_ztxt(), 1126| 14.3k| 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| 64.0k| 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| 19.1k| match parse_result { 1150| 44.8k| Ok(()) => Ok(Decoded::ChunkComplete(type_str)), 1151| | Err(DecodingError::Format(_)) 1152| 19.1k| 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.8k| Ok(Decoded::BadAncillaryChunk(type_str)) 1162| | } 1163| 347| Err(e) => Err(e), 1164| | } 1165| 64.0k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder11start_chunk: 1038| 72.0k| fn start_chunk(&mut self, type_str: ChunkType, length: u32) -> Result { 1039| 59.9k| let target_length = match type_str { 1040| 9.30k| IHDR => 13..=13, 1041| 1.31k| chunk::PLTE => 3..=768, 1042| 3| chunk::IEND => 0..=0, 1043| 4.61k| chunk::sBIT => 1..=4, 1044| 2.01k| chunk::tRNS => 1..=256, 1045| 1.76k| chunk::pHYs => 9..=9, 1046| 614| chunk::gAMA => 4..=4, 1047| 1.01k| chunk::acTL => 8..=8, 1048| 335| chunk::fcTL => 26..=26, 1049| 589| chunk::cHRM => 32..=32, 1050| 1.40k| chunk::sRGB => 1..=1, 1051| 568| chunk::cICP => 4..=4, 1052| 522| chunk::mDCV => 24..=24, 1053| 456| chunk::cLLI => 8..=8, 1054| 1.74k| chunk::bKGD => 1..=6, 1055| | 1056| | // Unbounded size chunks 1057| 753| chunk::eXIf => 0..=u32::MAX >> 1, // TODO: allow skipping. 1058| 2.87k| chunk::iCCP if !self.decode_options.ignore_iccp_chunk => 0..=u32::MAX >> 1, 1059| 7.41k| chunk::tEXt if !self.decode_options.ignore_text_chunk => 0..=u32::MAX >> 1, 1060| 8.35k| chunk::zTXt if !self.decode_options.ignore_text_chunk => 0..=u32::MAX >> 1, 1061| 14.3k| chunk::iTXt if !self.decode_options.ignore_text_chunk => 0..=u32::MAX >> 1, 1062| | 1063| 0| chunk::IDAT | chunk::fdAT => unreachable!(), 1064| | 1065| 12.0k| _ if is_critical(type_str) => { 1066| 328| return Err(DecodingError::Format( 1067| 328| FormatErrorInner::UnrecognizedCriticalChunk { type_str }.into(), 1068| 328| )); 1069| | } 1070| | _ => { 1071| 11.7k| self.current_chunk.action = ChunkAction::Skip; 1072| 11.7k| return Ok(State::ReadChunkData(type_str)); 1073| | } 1074| | }; 1075| | 1076| 59.9k| 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.30k| 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.25k| _ => { 1086| 3.25k| self.current_chunk.action = ChunkAction::Reject; 1087| 3.25k| } 1088| | } 1089| 56.6k| } else { 1090| 56.6k| self.current_chunk.action = ChunkAction::Process; 1091| 56.6k| } 1092| | 1093| 59.9k| Ok(State::ReadChunkData(type_str)) 1094| 72.0k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder13split_keyword: 1828| 30.0k| fn split_keyword(buf: &[u8]) -> Result<(&[u8], &[u8]), DecodingError> { 1829| 30.0k| let null_byte_index = buf 1830| 30.0k| .iter() 1831| 30.0k| .position(|&b| b == 0) 1832| 30.0k| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))?; 1833| | 1834| 28.1k| if null_byte_index == 0 || null_byte_index > 79 { 1835| 1.49k| return Err(DecodingError::from(TextDecodingError::InvalidKeywordSize)); 1836| 26.6k| } 1837| | 1838| 26.6k| Ok((&buf[..null_byte_index], &buf[null_byte_index + 1..])) 1839| 30.0k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder14parse_iccp_raw: 1701| 2.19k| fn parse_iccp_raw(&mut self) -> Result<(), DecodingError> { 1702| 2.19k| let info = self.info.as_mut().unwrap(); 1703| 2.19k| let mut buf = &self.current_chunk.raw_bytes[..]; 1704| | 1705| | // read profile name 1706| 27.6k| for len in 0..=80 { 1707| 27.6k| let raw: u8 = buf.read_be()?; 1708| 27.5k| if (raw == 0 && len == 0) || (raw != 0 && len == 80) { 1709| 2| return Err(DecodingError::from(TextDecodingError::InvalidKeywordSize)); 1710| 27.5k| } 1711| 27.5k| if raw == 0 { 1712| 2.15k| break; 1713| 25.4k| } 1714| | } 1715| | 1716| 2.15k| match buf.read_be()? { 1717| | // compression method 1718| 2.14k| 0u8 => (), 1719| 8| n => { 1720| 8| return Err(DecodingError::Format( 1721| 8| FormatErrorInner::UnknownCompressionMethod(n).into(), 1722| 8| )) 1723| | } 1724| | } 1725| | 1726| 2.14k| match fdeflate::decompress_to_vec_bounded(buf, self.limits.bytes) { 1727| 1.76k| Ok(profile) => { 1728| 1.76k| self.limits.reserve_bytes(profile.len())?; 1729| 1.76k| info.icc_profile = Some(Cow::Owned(profile)); 1730| | } 1731| 381| Err(fdeflate::BoundedDecompressionError::DecompressionError { inner: err }) => { 1732| 381| return Err(DecodingError::Format( 1733| 381| FormatErrorInner::CorruptFlateStream { err }.into(), 1734| 381| )) 1735| | } 1736| | Err(fdeflate::BoundedDecompressionError::OutputTooLarge { .. }) => { 1737| 0| return Err(DecodingError::LimitsExceeded); 1738| | } 1739| | } 1740| | 1741| 1.76k| Ok(()) 1742| 2.19k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder16new_with_options: 593| 9.46k| pub fn new_with_options(decode_options: DecodeOptions) -> StreamingDecoder { 594| 9.46k| let mut inflater = ZlibStream::new(); 595| 9.46k| inflater.set_ignore_adler32(decode_options.ignore_adler32); 596| | 597| 9.46k| StreamingDecoder { 598| 9.46k| state: Some(State::new_u32(U32ValueKind::Signature1stU32)), 599| 9.46k| current_chunk: ChunkState { 600| 9.46k| type_: ChunkType([0; 4]), 601| 9.46k| crc: Crc32::new(), 602| 9.46k| remaining: 0, 603| 9.46k| raw_bytes: Vec::with_capacity(CHUNK_BUFFER_SIZE), 604| 9.46k| action: ChunkAction::Process, 605| 9.46k| }, 606| 9.46k| inflater, 607| 9.46k| info: None, 608| 9.46k| current_seq_no: None, 609| 9.46k| have_idat: false, 610| 9.46k| have_iccp: false, 611| 9.46k| ready_for_idat_chunks: true, 612| 9.46k| ready_for_fdat_chunks: false, 613| 9.46k| decode_options, 614| 9.46k| limits: Limits { bytes: usize::MAX }, 615| 9.46k| } 616| 9.46k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder21set_ignore_text_chunk: 635| 9.46k| pub fn set_ignore_text_chunk(&mut self, ignore_text_chunk: bool) { 636| 9.46k| self.decode_options.set_ignore_text_chunk(ignore_text_chunk); 637| 9.46k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder3new: 589| 9.46k| pub fn new() -> StreamingDecoder { 590| 9.46k| StreamingDecoder::new_with_options(DecodeOptions::default()) 591| 9.46k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder6update: 680| 844k| pub fn update( 681| 844k| &mut self, 682| 844k| mut buf: &[u8], 683| 844k| mut image_data: Option<&mut UnfilterBuf<'_>>, 684| 844k| ) -> Result<(usize, Decoded), DecodingError> { 685| 844k| if self.state.is_none() { 686| 0| return Err(DecodingError::Parameter( 687| 0| ParameterErrorKind::PolledAfterFatalError.into(), 688| 0| )); 689| 844k| } 690| | 691| 844k| let len = buf.len(); 692| 1.03M| while !buf.is_empty() { 693| 1.03M| let image_data = image_data.as_deref_mut(); 694| | 695| 1.03M| match self.next_state(buf, image_data) { 696| 187k| Ok((bytes, Decoded::Nothing)) => buf = &buf[bytes..], 697| 842k| Ok((bytes, result)) => { 698| 842k| buf = &buf[bytes..]; 699| 842k| return Ok((len - buf.len(), result)); 700| | } 701| 1.65k| Err(err) => { 702| 1.65k| debug_assert!(self.state.is_none()); 703| 1.65k| return Err(err); 704| | } 705| | } 706| | } 707| 806| Ok((len - buf.len(), Decoded::Nothing)) 708| 844k| } _RNvMs9_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_16StreamingDecoder9parse_u32: 833| 268k| fn parse_u32( 834| 268k| &mut self, 835| 268k| kind: U32ValueKind, 836| 268k| u32_be_bytes: &[u8], 837| 268k| image_data: Option<&mut UnfilterBuf<'_>>, 838| 268k| consumed_bytes: usize, 839| 268k| ) -> Result<(usize, Decoded), DecodingError> { 840| 268k| debug_assert_eq!(u32_be_bytes.len(), 4); 841| 268k| let bytes = u32_be_bytes.try_into().unwrap(); 842| 268k| let val = u32::from_be_bytes(bytes); 843| | 844| 268k| match kind { 845| | U32ValueKind::Signature1stU32 => { 846| 9.44k| if bytes == [137, 80, 78, 71] { 847| 9.39k| self.state = Some(State::new_u32(U32ValueKind::Signature2ndU32)); 848| 9.39k| Ok((consumed_bytes, Decoded::Nothing)) 849| | } else { 850| 50| Err(DecodingError::Format( 851| 50| FormatErrorInner::InvalidSignature.into(), 852| 50| )) 853| | } 854| | } 855| | U32ValueKind::Signature2ndU32 => { 856| 9.39k| if bytes == [13, 10, 26, 10] { 857| 9.35k| self.state = Some(State::new_u32(U32ValueKind::Length)); 858| 9.35k| Ok((consumed_bytes, Decoded::Nothing)) 859| | } else { 860| 37| Err(DecodingError::Format( 861| 37| FormatErrorInner::InvalidSignature.into(), 862| 37| )) 863| | } 864| | } 865| | U32ValueKind::Length => { 866| 85.6k| self.state = Some(State::new_u32(U32ValueKind::Type { length: val })); 867| 85.6k| Ok((consumed_bytes, Decoded::Nothing)) 868| | } 869| 85.5k| U32ValueKind::Type { length } => { 870| 85.5k| let type_str = ChunkType(bytes); 871| 85.5k| 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.5k| } 876| 85.5k| if type_str != self.current_chunk.type_ 877| 35.4k| && (self.current_chunk.type_ == IDAT || self.current_chunk.type_ == chunk::fdAT) 878| | { 879| 1.94k| let finished = match image_data { 880| 220| Some(image_data) => self.inflater.finish(image_data)?, 881| 1.72k| 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| 1.77k| self.state = Some(State::U32 { 888| 1.77k| kind, 889| 1.77k| bytes, 890| 1.77k| accumulated_count: 4 - consumed_bytes, 891| 1.77k| }); 892| | 893| 1.77k| 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| 1.75k| self.current_chunk.type_ = type_str; 898| 1.75k| self.ready_for_idat_chunks = false; 899| 1.75k| self.ready_for_fdat_chunks = false; 900| 1.75k| 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| 20| return Ok((0, Decoded::ImageData)); 906| | } 907| 83.5k| } 908| | 909| 83.5k| self.current_chunk.type_ = type_str; 910| 83.5k| if !self.decode_options.ignore_crc { 911| 83.5k| self.current_chunk.crc.reset(); 912| 83.5k| self.current_chunk.crc.update(&type_str.0); 913| 83.5k| } 914| 83.5k| self.current_chunk.remaining = length; 915| 83.5k| self.current_chunk.raw_bytes.clear(); 916| | 917| 83.5k| 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.5k| 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.5k| } 944| 11.5k| self.have_idat = true; 945| 11.5k| self.current_chunk.action = ChunkAction::Process; 946| 11.5k| Some(State::ImageData(type_str)) 947| | } 948| 72.0k| _ => Some(self.start_chunk(type_str, length)?), 949| | }; 950| 83.1k| Ok((consumed_bytes, Decoded::ChunkBegin(length, type_str))) 951| | } 952| 78.1k| 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| 78.1k| let sum = if self.decode_options.ignore_crc { 957| 0| val 958| | } else { 959| 78.1k| self.current_chunk.crc.clone().finalize() 960| | }; 961| | 962| 78.1k| if val == sum || CHECKSUM_DISABLED { 963| 78.1k| 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| 64.0k| debug_assert!(self.state.is_none()); 968| 64.0k| let decoded = self.parse_chunk(type_str)?; 969| | 970| 63.6k| if type_str != IEND { 971| 63.6k| self.state = Some(State::new_u32(U32ValueKind::Length)); 972| 63.6k| } 973| 63.6k| Ok((consumed_bytes, decoded)) 974| | } 975| | ChunkAction::Skip => { 976| 10.9k| self.state = Some(State::new_u32(U32ValueKind::Length)); 977| 10.9k| Ok(( 978| 10.9k| consumed_bytes, 979| 10.9k| Decoded::SkippedAncillaryChunk(self.current_chunk.type_), 980| 10.9k| )) 981| | } 982| | ChunkAction::Reject => { 983| 3.17k| self.state = Some(State::new_u32(U32ValueKind::Length)); 984| 3.17k| 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| 268k| } _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| 37| fn from(err: io::Error) -> DecodingError { 431| 37| DecodingError::IoError(err) 432| 37| } _RNvXs3_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_13DecodingErrorINtNtCs6SNw0SRvItZ_4core7convert4FromNtB5_11FormatErrorE4from: 436| 200| fn from(err: FormatError) -> DecodingError { 437| 200| DecodingError::Format(err) 438| 200| } _RNvXs4_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtB5_11FormatErrorINtNtCs6SNw0SRvItZ_4core7convert4FromNtB5_16FormatErrorInnerE4from: 442| 23.7M| fn from(inner: FormatErrorInner) -> Self { 443| 23.7M| FormatError { inner } 444| 23.7M| } _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.46k| fn default() -> Self { 476| 9.46k| Self { 477| 9.46k| ignore_adler32: true, 478| 9.46k| ignore_crc: false, 479| 9.46k| ignore_text_chunk: false, 480| 9.46k| ignore_iccp_chunk: false, 481| 9.46k| skip_ancillary_crc_failures: true, 482| 9.46k| } 483| 9.46k| } _RNvMsa_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtNtB9_6common4Info22validate_default_image: 1962| 184| 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| 184| if fc.x_offset != 0 1972| 147| || fc.y_offset != 0 1973| 114| || fc.width != self.width 1974| 81| || fc.height != self.height 1975| | { 1976| 132| return Err(DecodingError::Format( 1977| 132| FormatErrorInner::BadSubFrameBounds {}.into(), 1978| 132| )); 1979| 52| } 1980| 52| Ok(()) 1981| 184| } _RNvMsa_NtNtCshdzP3jLBsmJ_3png7decoder6streamNtNtB9_6common4Info8validate: 1983| 240| fn validate(&self, fc: &FrameControl) -> Result<(), DecodingError> { 1984| 240| if fc.width == 0 || fc.height == 0 { 1985| 2| return Err(DecodingError::Format( 1986| 2| FormatErrorInner::InvalidDimensions.into(), 1987| 2| )); 1988| 238| } 1989| | 1990| | // Validate mathematically: fc.width + fc.x_offset <= self.width 1991| 238| 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| 238| let in_y_bounds = Some(fc.height) <= self.height.checked_sub(fc.y_offset); 1994| | 1995| 238| if !in_x_bounds || !in_y_bounds { 1996| 54| return Err(DecodingError::Format( 1997| 54| // TODO: do we want to display the bad bounds? 1998| 54| FormatErrorInner::BadSubFrameBounds {}.into(), 1999| 54| )); 2000| 184| } 2001| | 2002| 184| Ok(()) 2003| 240| } _RINvNtNtCshdzP3jLBsmJ_3png7decoder9transform11unpack_bitsNCNvB2_14expand_gray_u80EB6_: 90| 470k|fn unpack_bits(input: &[u8], output: &mut [u8], channels: usize, bit_depth: u8, func: F) 91| 470k|where 92| 470k| F: Fn(u8, &mut [u8]), 93| |{ 94| | // Only [1, 2, 4, 8] are valid bit depths 95| 470k| 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| 470k| assert!((8 / bit_depth as usize * channels).saturating_mul(input.len()) >= output.len()); 99| | 100| 470k| let mut buf_chunks = output.chunks_exact_mut(channels); 101| 470k| 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| 470k| 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| 470k| let mask = ((1u16 << bit_depth) - 1) as u8; 118| | 119| | // These variables are initialized in the loop 120| 470k| let mut shift = -1; 121| 470k| let mut curr = 0; 122| | 123| 681M| for chunk in buf_chunks { 124| 681M| if shift < 0 { 125| 144M| shift = 8 - bit_depth as i32; 126| 144M| curr = *iter.next().expect("input for unpack bits is not empty"); 127| 537M| } 128| | 129| 681M| let pixel = (curr >> shift) & mask; 130| 681M| func(pixel, chunk); 131| | 132| 681M| shift -= bit_depth as i32; 133| | } 134| | } 135| 470k|} _RINvNtNtCshdzP3jLBsmJ_3png7decoder9transform11unpack_bitsNCNvB2_24expand_gray_u8_with_trns0EB6_: 90| 1.96k|fn unpack_bits(input: &[u8], output: &mut [u8], channels: usize, bit_depth: u8, func: F) 91| 1.96k|where 92| 1.96k| F: Fn(u8, &mut [u8]), 93| |{ 94| | // Only [1, 2, 4, 8] are valid bit depths 95| 1.96k| 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| 1.96k| assert!((8 / bit_depth as usize * channels).saturating_mul(input.len()) >= output.len()); 99| | 100| 1.96k| let mut buf_chunks = output.chunks_exact_mut(channels); 101| 1.96k| 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| 1.96k| 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| 1.96k| let mask = ((1u16 << bit_depth) - 1) as u8; 118| | 119| | // These variables are initialized in the loop 120| 1.96k| let mut shift = -1; 121| 1.96k| let mut curr = 0; 122| | 123| 114M| for chunk in buf_chunks { 124| 114M| if shift < 0 { 125| 15.4M| shift = 8 - bit_depth as i32; 126| 15.4M| curr = *iter.next().expect("input for unpack bits is not empty"); 127| 99.2M| } 128| | 129| 114M| let pixel = (curr >> shift) & mask; 130| 114M| func(pixel, chunk); 131| | 132| 114M| shift -= bit_depth as i32; 133| | } 134| | } 135| 1.96k|} _RNCNvNtNtCshdzP3jLBsmJ_3png7decoder9transform14expand_gray_u80B7_: 183| 681M| unpack_bits(row, buffer, 1, info.bit_depth as u8, |val, chunk| { 184| 681M| chunk[0] = val * scaling_factor 185| 681M| }); _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.8M| 0 195| | } else { 196| 98.8M| 0xFF 197| | } 198| | } else { 199| 0| 0xFF 200| | }; 201| 114M| chunk[0] = pixel * scaling_factor 202| 114M| }); _RNvNtNtCshdzP3jLBsmJ_3png7decoder9transform14expand_gray_u8: 181| 470k|fn expand_gray_u8(row: &[u8], buffer: &mut [u8], info: &Info) { 182| 470k| let scaling_factor = (255) / ((1u16 << info.bit_depth as u8) - 1) as u8; 183| 470k| unpack_bits(row, buffer, 1, info.bit_depth as u8, |val, chunk| { 184| | chunk[0] = val * scaling_factor 185| | }); 186| 470k|} _RNvNtNtCshdzP3jLBsmJ_3png7decoder9transform16expand_trns_line: 137| 4.15k|fn expand_trns_line(input: &[u8], output: &mut [u8], info: &Info) { 138| 4.15k| let channels = info.color_type.samples(); 139| 4.15k| let trns = info.trns.as_deref(); 140| 40.9M| for (input, output) in input 141| 4.15k| .chunks_exact(channels) 142| 4.15k| .zip(output.chunks_exact_mut(channels + 1)) 143| | { 144| 40.9M| output[..channels].copy_from_slice(input); 145| 40.9M| output[channels] = if Some(input) == trns { 0 } else { 0xFF }; 146| | } 147| 4.15k|} _RNvNtNtCshdzP3jLBsmJ_3png7decoder9transform18expand_trns_line16: 149| 161k|fn expand_trns_line16(input: &[u8], output: &mut [u8], info: &Info) { 150| 161k| let channels = info.color_type.samples(); 151| 161k| let trns = info.trns.as_deref(); 152| 7.80M| for (input, output) in input 153| 161k| .chunks_exact(channels * 2) 154| 161k| .zip(output.chunks_exact_mut(channels * 2 + 2)) 155| | { 156| 7.80M| output[..channels * 2].copy_from_slice(input); 157| 7.80M| if Some(input) == trns { 158| 5.62k| output[channels * 2] = 0; 159| 5.62k| output[channels * 2 + 1] = 0 160| | } else { 161| 7.79M| output[channels * 2] = 0xFF; 162| 7.79M| output[channels * 2 + 1] = 0xFF 163| | }; 164| | } 165| 161k|} _RNvNtNtCshdzP3jLBsmJ_3png7decoder9transform19create_transform_fn: 20| 4.21k|pub fn create_transform_fn( 21| 4.21k| info: &Info, 22| 4.21k| transform: Transformations, 23| 4.21k|) -> Result { 24| 4.21k| let color_type = info.color_type; 25| 4.21k| let bit_depth = info.bit_depth as u8; 26| 4.21k| let trns = info.trns.is_some() || transform.contains(Transformations::ALPHA); 27| 4.21k| let expand = 28| 4.21k| transform.contains(Transformations::EXPAND) || transform.contains(Transformations::ALPHA); 29| 4.21k| let strip16 = bit_depth == 16 && transform.contains(Transformations::STRIP_16); 30| 716| match color_type { 31| 1.13k| ColorType::Indexed if expand => { 32| 1.13k| if info.palette.is_none() { 33| 21| Err(DecodingError::Format( 34| 21| FormatErrorInner::PaletteRequired.into(), 35| 21| )) 36| 1.11k| } 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| 1.11k| Ok(if trns { 47| 89| palette::create_expansion_into_rgba8(info) 48| | } else { 49| 1.02k| palette::create_expansion_into_rgb8(info) 50| | }) 51| | } 52| | } 53| 1.91k| ColorType::Grayscale | ColorType::GrayscaleAlpha if bit_depth < 8 && expand => { 54| 1.08k| Ok(Box::new(if trns { 55| 81| expand_gray_u8_with_trns 56| 1.00k| } else { 57| 1.00k| expand_gray_u8 58| 1.00k| })) 59| | } 60| 831| ColorType::Grayscale | ColorType::Rgb if expand && trns => { 61| 135| Ok(Box::new(if bit_depth == 8 { 62| 48| expand_trns_line 63| 87| } else if strip16 { 64| 0| expand_trns_and_strip_line16 65| 0| } else { 66| 87| assert_eq!(bit_depth, 16); 67| 87| 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.87k| _ => Ok(Box::new(copy_row)), 76| | } 77| 4.21k|} _RNvNtNtCshdzP3jLBsmJ_3png7decoder9transform24expand_gray_u8_with_trns: 188| 1.96k|fn expand_gray_u8_with_trns(row: &[u8], buffer: &mut [u8], info: &Info) { 189| 1.96k| let scaling_factor = (255) / ((1u16 << info.bit_depth as u8) - 1) as u8; 190| 1.96k| let trns = info.trns.as_deref(); 191| 1.96k| 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| 1.96k|} _RNvNtNtCshdzP3jLBsmJ_3png7decoder9transform8copy_row: 79| 23.0M|fn copy_row(row: &[u8], output_buffer: &mut [u8], _: &Info) { 80| 23.0M| output_buffer.copy_from_slice(row); 81| 23.0M|} _RINvNtNtCshdzP3jLBsmJ_3png7decoder9transform11unpack_bitsNCNvNtB2_7palette16expand_into_rgb80EB6_: 90| 53.0k|fn unpack_bits(input: &[u8], output: &mut [u8], channels: usize, bit_depth: u8, func: F) 91| 53.0k|where 92| 53.0k| F: Fn(u8, &mut [u8]), 93| |{ 94| | // Only [1, 2, 4, 8] are valid bit depths 95| 53.0k| 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| 53.0k| assert!((8 / bit_depth as usize * channels).saturating_mul(input.len()) >= output.len()); 99| | 100| 53.0k| let mut buf_chunks = output.chunks_exact_mut(channels); 101| 53.0k| 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| 53.0k| 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| 53.0k| let mask = ((1u16 << bit_depth) - 1) as u8; 118| | 119| | // These variables are initialized in the loop 120| 53.0k| let mut shift = -1; 121| 53.0k| let mut curr = 0; 122| | 123| 96.3M| for chunk in buf_chunks { 124| 96.2M| if shift < 0 { 125| 12.1M| shift = 8 - bit_depth as i32; 126| 12.1M| curr = *iter.next().expect("input for unpack bits is not empty"); 127| 84.1M| } 128| | 129| 96.2M| let pixel = (curr >> shift) & mask; 130| 96.2M| func(pixel, chunk); 131| | 132| 96.2M| shift -= bit_depth as i32; 133| | } 134| | } 135| 53.0k|} _RINvNtNtCshdzP3jLBsmJ_3png7decoder9transform11unpack_bitsNCNvNtB2_7palette26expand_paletted_into_rgba80EB6_: 90| 8.94k|fn unpack_bits(input: &[u8], output: &mut [u8], channels: usize, bit_depth: u8, func: F) 91| 8.94k|where 92| 8.94k| F: Fn(u8, &mut [u8]), 93| |{ 94| | // Only [1, 2, 4, 8] are valid bit depths 95| 8.94k| 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| 8.94k| assert!((8 / bit_depth as usize * channels).saturating_mul(input.len()) >= output.len()); 99| | 100| 8.94k| let mut buf_chunks = output.chunks_exact_mut(channels); 101| 8.94k| 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| 8.94k| if bit_depth == 8 { 113| 54.5k| for (&curr, chunk) in iter.zip(&mut buf_chunks) { 114| 54.5k| func(curr, chunk); 115| 54.5k| } 116| | } else { 117| 2.41k| let mask = ((1u16 << bit_depth) - 1) as u8; 118| | 119| | // These variables are initialized in the loop 120| 2.41k| let mut shift = -1; 121| 2.41k| let mut curr = 0; 122| | 123| 1.11M| for chunk in buf_chunks { 124| 1.11M| if shift < 0 { 125| 150k| shift = 8 - bit_depth as i32; 126| 150k| curr = *iter.next().expect("input for unpack bits is not empty"); 127| 962k| } 128| | 129| 1.11M| let pixel = (curr >> shift) & mask; 130| 1.11M| func(pixel, chunk); 131| | 132| 1.11M| shift -= bit_depth as i32; 133| | } 134| | } 135| 8.94k|} _RNCNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette16expand_into_rgb80B9_: 109| 96.2M| unpack_bits(row, buffer, 3, info.bit_depth as u8, |i, chunk| { 110| 96.2M| let rgba = &rgba_palette[i as usize]; 111| 96.2M| chunk[0] = rgba[0]; 112| 96.2M| chunk[1] = rgba[1]; 113| 96.2M| chunk[2] = rgba[2]; 114| 96.2M| }) _RNCNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette26create_expansion_into_rgb80B9_: 26| 3.92k| Box::new(move |input, output, _info| expand_8bit_into_rgb8(input, output, &rgba_palette)) _RNCNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette26create_expansion_into_rgb8s_0B9_: 28| 53.0k| Box::new(move |input, output, info| expand_into_rgb8(input, output, info, &rgba_palette)) _RNCNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette26expand_paletted_into_rgba80B9_: 123| 1.16M| unpack_bits(row, buffer, 4, info.bit_depth as u8, |i, chunk| { 124| 1.16M| chunk.copy_from_slice(&rgba_palette[i as usize]); 125| 1.16M| }); _RNCNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette27create_expansion_into_rgba80B9_: 34| 8.94k| Box::new(move |input, output, info| { 35| 8.94k| expand_paletted_into_rgba8(input, output, info, &rgba_palette) 36| 8.94k| }) _RNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette16expand_into_rgb8: 108| 53.0k|fn expand_into_rgb8(row: &[u8], buffer: &mut [u8], info: &Info, rgba_palette: &[[u8; 4]; 256]) { 109| 53.0k| 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| 53.0k|} _RNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette19create_rgba_palette: 39| 1.11k|fn create_rgba_palette(info: &Info) -> [[u8; 4]; 256] { 40| 1.11k| let palette = info.palette.as_deref().expect("Caller should verify"); 41| 1.11k| 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| 1.11k| let trns = if trns.len() <= palette.len() / 3 { 51| 1.07k| trns 52| | } else { 53| 37| &[] 54| | }; 55| | 56| | // Default to black, opaque entries. 57| 1.11k| 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| 1.11k| let mut palette_iter = palette; 63| 1.11k| let mut rgba_iter = &mut rgba_palette[..]; 64| 3.28k| while palette_iter.len() >= 4 { 65| 2.17k| // Copying 4 bytes at a time is more efficient than copying 3. 66| 2.17k| // OTOH, this clobbers the alpha value in `rgba_iter[0][3]` - we 67| 2.17k| // need to fix this later. 68| 2.17k| rgba_iter[0].copy_from_slice(&palette_iter[0..4]); 69| 2.17k| 70| 2.17k| palette_iter = &palette_iter[3..]; 71| 2.17k| rgba_iter = &mut rgba_iter[1..]; 72| 2.17k| } 73| 1.11k| if !palette_iter.is_empty() { 74| 1.11k| rgba_iter[0][0..3].copy_from_slice(&palette_iter[0..3]); 75| 1.11k| } 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| 1.11k| for (alpha, rgba) in trns.iter().copied().zip(rgba_palette.iter_mut()) { 82| 335| rgba[3] = alpha; 83| 335| } 84| | 85| | // Unclobber the remaining alpha values. 86| 2.95k| for rgba in rgba_palette[trns.len()..(palette.len() / 3)].iter_mut() { 87| 2.95k| rgba[3] = 0xFF; 88| 2.95k| } 89| | 90| 1.11k| rgba_palette 91| 1.11k|} _RNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette21expand_8bit_into_rgb8: 93| 3.92k|fn expand_8bit_into_rgb8(mut input: &[u8], mut output: &mut [u8], rgba_palette: &[[u8; 4]; 256]) { 94| 462k| while output.len() >= 4 { 95| 458k| // Copying 4 bytes at a time is more efficient than 3. 96| 458k| let rgba = &rgba_palette[input[0] as usize]; 97| 458k| output[0..4].copy_from_slice(rgba); 98| 458k| 99| 458k| input = &input[1..]; 100| 458k| output = &mut output[3..]; 101| 458k| } 102| 3.92k| if !output.is_empty() { 103| 3.92k| let rgba = &rgba_palette[input[0] as usize]; 104| 3.92k| output[0..3].copy_from_slice(&rgba[0..3]); 105| 3.92k| } 106| 3.92k|} _RNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette26create_expansion_into_rgb8: 22| 1.02k|pub fn create_expansion_into_rgb8(info: &Info) -> TransformFn { 23| 1.02k| let rgba_palette = create_rgba_palette(info); 24| | 25| 1.02k| if info.bit_depth == BitDepth::Eight { 26| 59| Box::new(move |input, output, _info| expand_8bit_into_rgb8(input, output, &rgba_palette)) 27| | } else { 28| 962| Box::new(move |input, output, info| expand_into_rgb8(input, output, info, &rgba_palette)) 29| | } 30| 1.02k|} _RNvNtNtNtCshdzP3jLBsmJ_3png7decoder9transform7palette26expand_paletted_into_rgba8: 117| 8.94k|fn expand_paletted_into_rgba8( 118| 8.94k| row: &[u8], 119| 8.94k| buffer: &mut [u8], 120| 8.94k| info: &Info, 121| 8.94k| rgba_palette: &[[u8; 4]; 256], 122| 8.94k|) { 123| 8.94k| unpack_bits(row, buffer, 4, info.bit_depth as u8, |i, chunk| { 124| | chunk.copy_from_slice(&rgba_palette[i as usize]); 125| | }); 126| 8.94k|} _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_6stream13DecodingErrorEECs4rpmEmvDwFM_5image: 166| 1.34M| pub fn with_unfilled_buffer(&mut self, f: F) -> T 167| 1.34M| where 168| 1.34M| F: FnOnce(&mut UnfilterBuf<'_>) -> T, 169| | { 170| | // Potentially shift the buffer left to avoid unbounded growth. 171| 1.34M| let discard_size = self.available.min(match &self.prev_row { 172| 1.09M| PrevRow::None | PrevRow::Scratch(_) => self.current_start, 173| 247k| PrevRow::InPlace(prev_start) => *prev_start, 174| | }); 175| 1.34M| 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.75k| && self.filled >= self.data_stream.len() / 2 182| 1.75k| { 183| 1.75k| self.shift_buffer_left(discard_size); 184| 1.34M| } 185| | 186| 1.34M| if self.filled + Self::GROWTH_BYTES > self.data_stream.len() { 187| 647k| self.data_stream.resize(self.filled + Self::GROWTH_BYTES, 0); 188| 694k| } 189| | 190| 1.34M| if self.remaining_bytes < usize::MAX as u64 191| 1.34M| && self.filled.saturating_add(self.remaining_bytes as usize) < self.data_stream.len() 192| 43.9k| { 193| 43.9k| self.data_stream 194| 43.9k| .resize(self.filled + self.remaining_bytes as usize, 0); 195| 1.29M| } 196| | 197| 1.34M| let old_filled = self.filled; 198| 1.34M| let ret = f(&mut UnfilterBuf { 199| 1.34M| buffer: &mut self.data_stream, 200| 1.34M| filled: &mut self.filled, 201| 1.34M| available: &mut self.available, 202| 1.34M| }); 203| 1.34M| assert!(self.filled >= old_filled); 204| 1.34M| self.remaining_bytes -= (self.filled - old_filled) as u64; 205| | 206| 1.34M| if self.remaining_bytes == 0 { 207| 2.05k| self.available = self.filled; 208| 1.33M| } 209| | 210| 1.34M| self.debug_assert_invariants(); 211| 1.34M| ret 212| 1.34M| } _RNCNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB4_17UnfilteringBuffer3new0B8_: 63| 9.18k| .and_then(|v| v.checked_mul(info.height.min(128) as usize)) _RNCNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB4_17UnfilteringBuffer3news0_0B8_: 81| 9.18k| .and_then(|v| v.checked_mul(4)) _RNCNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB4_17UnfilteringBuffer3news1_0B8_: 86| 9.18k| .and_then(|v| checked_next_multiple_of(v, 64)) _RNCNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB4_17UnfilteringBuffer3news_0B8_: 66| 9.18k| .and_then(|v| checked_next_multiple_of(v, 256)) _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer11start_frame: 120| 6.05k| pub fn start_frame(&mut self, frame_bytes: u64) { 121| 6.05k| self.data_stream.clear(); 122| 6.05k| self.prev_row = PrevRow::None; 123| 6.05k| self.current_start = 0; 124| 6.05k| self.filled = 0; 125| 6.05k| self.available = 0; 126| 6.05k| self.remaining_bytes = frame_bytes; 127| 6.05k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer14reset_prev_row: 109| 23.7M| 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| 23.7M| if let PrevRow::Scratch(buf) = &mut self.prev_row { 113| 647k| self.scratch_buffer = std::mem::take(buf); 114| 23.1M| } 115| | 116| 23.7M| self.prev_row = PrevRow::None; 117| 23.7M| self.debug_assert_invariants(); 118| 23.7M| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer15curr_row_filter: 244| 23.7M| fn curr_row_filter(&self) -> Result { 245| 23.7M| let filter = self.data_stream[self.current_start]; 246| 23.7M| RowFilter::from_u8(filter).ok_or(DecodingError::Format( 247| 23.7M| FormatErrorInner::UnknownFilterMethod(filter).into(), 248| 23.7M| )) 249| 23.7M| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer15remaining_bytes: 129| 1.34M| pub fn remaining_bytes(&self) -> u64 { 130| 1.34M| self.remaining_bytes 131| 1.34M| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer17shift_buffer_left: 216| 1.75k| 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.75k| 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.75k| if let Some(16..) = self.data_stream.len().checked_sub(self.filled) { 228| 994| self.data_stream.copy_within(discard_size..self.filled, 0); 229| 994| } else { 230| 762| self.data_stream.copy_within(discard_size.., 0); 231| 762| } 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.75k| self.current_start -= discard_size; 236| 1.75k| self.available -= discard_size; 237| 1.75k| self.filled -= discard_size; 238| 1.75k| match &mut self.prev_row { 239| 57| PrevRow::None | PrevRow::Scratch(_) => (), 240| 1.69k| PrevRow::InPlace(prev_start) => *prev_start -= discard_size, 241| | } 242| 1.75k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer23debug_assert_invariants: 37| 48.9M| fn debug_assert_invariants(&self) {} _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer23mutable_len_of_curr_row: 146| 24.4M| pub fn mutable_len_of_curr_row(&self) -> usize { 147| 24.4M| self.available.saturating_sub(self.current_start) 148| 24.4M| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer24readable_len_of_curr_row: 155| 651k| pub fn readable_len_of_curr_row(&self) -> usize { 156| 651k| self.filled - self.current_start 157| 651k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer26unfilter_curr_row_in_place: 257| 23.1M| pub fn unfilter_curr_row_in_place( 258| 23.1M| &mut self, 259| 23.1M| rowlen: usize, 260| 23.1M| bpp: BytesPerPixel, 261| 23.1M| ) -> Result<(), DecodingError> { 262| 23.1M| 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| 23.1M| debug_assert!(self.mutable_len_of_curr_row() >= rowlen); 267| | 268| 23.1M| let filter = self.curr_row_filter()?; 269| 23.1M| let (prev, row) = self.data_stream.split_at_mut(self.current_start); 270| 23.1M| let prev: &[u8] = self.prev_row.as_slice(prev); 271| 23.1M| let row = &mut row[1..rowlen]; // Skip the `RowFilter` byte. 272| 23.1M| debug_assert!(prev.is_empty() || prev.len() == row.len()); 273| | 274| 23.1M| unfilter(filter, bpp, prev, row); 275| | 276| 23.1M| self.reset_prev_row(); 277| 23.1M| self.prev_row = PrevRow::InPlace(self.current_start + 1); 278| 23.1M| self.current_start += rowlen; 279| 23.1M| self.debug_assert_invariants(); 280| | 281| 23.1M| Ok(()) 282| 23.1M| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer38unfilter_curr_row_using_scratch_buffer: 291| 649k| pub fn unfilter_curr_row_using_scratch_buffer( 292| 649k| &mut self, 293| 649k| rowlen: usize, 294| 649k| bpp: BytesPerPixel, 295| 649k| ) -> Result<(), DecodingError> { 296| 649k| debug_assert!(rowlen >= 2); // 1 byte for `RowFilter` and at least 1 byte of pixel data. 297| 649k| 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| 649k| debug_assert!(self.mutable_len_of_curr_row() < rowlen); 302| | 303| 649k| let filter = self.curr_row_filter()?; 304| | 305| 648k| let mut row = std::mem::take(&mut self.scratch_buffer); 306| 648k| row.resize(rowlen - 1, 0); 307| 648k| row.as_mut_slice() 308| 648k| .copy_from_slice(&self.data_stream[self.current_start + 1..][..rowlen - 1]); 309| | 310| 648k| let prev = self.prev_row(); 311| 648k| debug_assert!(prev.is_empty() || prev.len() == (rowlen - 1)); 312| | 313| 648k| unfilter(filter, bpp, prev, &mut row); 314| | 315| 648k| self.reset_prev_row(); 316| 648k| self.prev_row = PrevRow::Scratch(row); 317| 648k| self.current_start += rowlen; 318| | 319| 648k| self.debug_assert_invariants(); 320| | 321| 648k| Ok(()) 322| 649k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer3new: 49| 9.18k| 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.18k| let data_stream_capacity = { 54| 9.18k| let max_data = info 55| 9.18k| .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.18k| .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.18k| .and_then(|v| checked_next_multiple_of(v, 256)) 67| 9.18k| .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.18k| max_data.min(128 * 1024) 72| | }; 73| | 74| 9.18k| 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.18k| let rowlen_pot = info 78| 9.18k| .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.18k| .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.18k| .and_then(|v| checked_next_multiple_of(v, 64)) 87| 9.18k| .unwrap_or(isize::MAX as usize); 88| | // But never shift back before we have a number of pages freed. 89| 9.18k| rowlen_pot.max(128 * 1024) 90| | }; 91| | 92| 9.18k| let result = Self { 93| 9.18k| data_stream: Vec::with_capacity(data_stream_capacity), 94| 9.18k| prev_row: PrevRow::None, 95| 9.18k| current_start: 0, 96| 9.18k| filled: 0, 97| 9.18k| available: 0, 98| 9.18k| shift_back_limit, 99| 9.18k| remaining_bytes: u64::MAX, 100| 9.18k| scratch_buffer: Vec::new(), 101| 9.18k| }; 102| | 103| 9.18k| result.debug_assert_invariants(); 104| 9.18k| result 105| 9.18k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer8prev_row: 134| 24.4M| pub fn prev_row(&self) -> &[u8] { 135| 24.4M| self.prev_row 136| 24.4M| .as_slice(&self.data_stream[..self.current_start]) 137| 24.4M| } _RNvMs_NtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_bufferNtB4_7PrevRow8as_slice: 355| 47.5M| fn as_slice<'a>(&'a self, buf: &'a [u8]) -> &'a [u8] { 356| 47.5M| match self { 357| 7.42k| PrevRow::None => &[], 358| 46.2M| PrevRow::InPlace(prev_start) => &buf[*prev_start..], 359| 1.29M| PrevRow::Scratch(scratch) => scratch.as_slice(), 360| | } 361| 47.5M| } _RNvNtNtCshdzP3jLBsmJ_3png7decoder18unfiltering_buffer24checked_next_multiple_of: 364| 18.3k|fn checked_next_multiple_of(val: usize, factor: usize) -> Option { 365| 18.3k| if factor == 0 { 366| 0| return None; 367| 18.3k| } 368| | 369| 18.3k| let remainder = val % factor; 370| | 371| 18.3k| if remainder > 0 { 372| 16.8k| val.checked_add(factor - remainder) 373| | } else { 374| 1.49k| Some(val) 375| | } 376| 18.3k|} _RNCNvMNtNtCshdzP3jLBsmJ_3png7decoder4zlibNtB4_10ZlibStream6finish0B8_: 162| 1| .map_err(|err| { 163| 1| DecodingError::Format(FormatErrorInner::CorruptFlateStream { err }.into()) 164| 1| })?; _RNCNvMs0_NtNtCshdzP3jLBsmJ_3png7decoder4zlibNtB7_11UnfilterBuf10decompress0Bb_: 233| 621| .map_err(|err| { 234| 621| DecodingError::Format(FormatErrorInner::CorruptFlateStream { err }.into()) 235| 621| })?; _RNvMNtNtCshdzP3jLBsmJ_3png7decoder4zlibNtB2_10ZlibStream10decompress: 109| 679k| pub(crate) fn decompress( 110| 679k| &mut self, 111| 679k| data: &[u8], 112| 679k| image_data: &mut UnfilterBuf<'_>, 113| 679k| ) -> 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| 679k| if self.state.is_done() { 118| 421| return Ok(data.len()); 119| 678k| } 120| | 121| 678k| if !self.started && self.ignore_adler32 { 122| 5.66k| self.state.ignore_adler32(); 123| 673k| } 124| | 125| 678k| let in_consumed = image_data.decompress(&mut self.state, data)?; 126| 678k| self.started = true; 127| | 128| 678k| Ok(in_consumed) 129| 679k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder4zlibNtB2_10ZlibStream18set_ignore_adler32: 93| 9.46k| pub(crate) fn set_ignore_adler32(&mut self, flag: bool) -> bool { 94| 9.46k| if !self.started { 95| 9.46k| self.ignore_adler32 = flag; 96| 9.46k| true 97| | } else { 98| 0| false 99| | } 100| 9.46k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder4zlibNtB2_10ZlibStream3new: 73| 9.46k| pub(crate) fn new() -> Self { 74| 9.46k| ZlibStream { 75| 9.46k| state: Box::new(Decompressor::new()), 76| 9.46k| started: false, 77| 9.46k| ignore_adler32: true, 78| 9.46k| } 79| 9.46k| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder4zlibNtB2_10ZlibStream5reset: 81| 245| pub(crate) fn reset(&mut self) { 82| 245| self.started = false; 83| 245| *self.state = Decompressor::new(); 84| 245| } _RNvMNtNtCshdzP3jLBsmJ_3png7decoder4zlibNtB2_10ZlibStream6finish: 138| 220| pub(crate) fn finish( 139| 220| &mut self, 140| 220| image_data: &mut UnfilterBuf<'_>, 141| 220| ) -> Result { 142| 220| if !self.started || self.state.is_done() { 143| 26| return Ok(true); 144| 194| } 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| 194| if *image_data.filled == image_data.buffer.len() { 151| 0| return Ok(true); 152| 194| } 153| | 154| 194| let (_, out_consumed) = self 155| 194| .state 156| 194| .read( 157| 194| &[], 158| 194| &mut image_data.buffer[*image_data.available..], 159| 194| *image_data.filled - *image_data.available, 160| | false, 161| | ) 162| 194| .map_err(|err| { 163| | DecodingError::Format(FormatErrorInner::CorruptFlateStream { err }.into()) 164| 1| })?; 165| 193| *image_data.filled += out_consumed; 166| | 167| 193| if self.state.is_done() { 168| 3| *image_data.available = *image_data.filled; 169| 3| return Ok(true); 170| 190| } 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| 190| if *image_data.filled == image_data.buffer.len() { 176| 20| *image_data.available = 177| 20| (*image_data.available).max(image_data.filled.saturating_sub(LOOKBACK_SIZE)); 178| 20| return Ok(false); 179| 170| } 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| 170| Err(DecodingError::Format( 186| 170| FormatErrorInner::CorruptFlateStream { 187| 170| err: fdeflate::DecompressionError::InsufficientInput, 188| 170| } 189| 170| .into(), 190| 170| )) 191| 220| } _RNvMs0_NtNtCshdzP3jLBsmJ_3png7decoder4zlibNtB5_11UnfilterBuf10decompressB9_: 220| 678k| fn decompress( 221| 678k| &mut self, 222| 678k| decompressor: &mut fdeflate::Decompressor, 223| 678k| input: &[u8], 224| 678k| ) -> Result { 225| 678k| let output_limit = (*self.filled + UnfilteringBuffer::GROWTH_BYTES).min(self.buffer.len()); 226| 678k| let (in_consumed, out_consumed) = decompressor 227| 678k| .read( 228| 678k| input, 229| 678k| &mut self.buffer[*self.available..output_limit], 230| 678k| *self.filled - *self.available, 231| | false, 232| | ) 233| 678k| .map_err(|err| { 234| | DecodingError::Format(FormatErrorInner::CorruptFlateStream { err }.into()) 235| 621| })?; 236| | 237| 678k| *self.filled += out_consumed; 238| 678k| if decompressor.is_done() { 239| 1.12k| *self.available = *self.filled; 240| 676k| } 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| 666k| if new_available > *self.available { 247| 665k| *self.available = new_available; 248| 665k| } 249| 10.5k| } 250| | 251| 678k| Ok(in_consumed) 252| 678k| } _RNCNvNtCshdzP3jLBsmJ_3png6filter8unfilter0B5_: 123| 285M| current.iter_mut().reduce(|&mut prev, curr| { 124| 285M| *curr = curr.wrapping_add(prev); 125| 285M| curr 126| 285M| }); _RNCNvNtCshdzP3jLBsmJ_3png6filter8unfilters_0B5_: 204| 44.0M| current.iter_mut().reduce(|&mut prev, curr| { 205| 44.0M| *curr = curr.wrapping_add(prev / 2); 206| 44.0M| curr 207| 44.0M| }); _RNvMs2_NtCshdzP3jLBsmJ_3png6filterNtB5_9RowFilter7from_u8: 79| 23.7M| pub fn from_u8(n: u8) -> Option { 80| 23.7M| match n { 81| 23.3M| 0 => Some(Self::NoFilter), 82| 123k| 1 => Some(Self::Sub), 83| 63.3k| 2 => Some(Self::Up), 84| 173k| 3 => Some(Self::Avg), 85| 34.1k| 4 => Some(Self::Paeth), 86| 127| _ => None, 87| | } 88| 23.7M| } _RNvNtCshdzP3jLBsmJ_3png6filter8unfilter: 102| 23.7M|pub(crate) fn unfilter( 103| 23.7M| mut filter: RowFilter, 104| 23.7M| tbpp: BytesPerPixel, 105| 23.7M| previous: &[u8], 106| 23.7M| current: &mut [u8], 107| 23.7M|) { 108| | use self::RowFilter::*; 109| | 110| | // If the previous row is empty, then treat it as if it were filled with zeros. 111| 23.7M| if previous.is_empty() { 112| 7.42k| if filter == Paeth { 113| 737| filter = Sub; 114| 6.68k| } else if filter == Up { 115| 576| filter = NoFilter; 116| 6.11k| } 117| 23.7M| } 118| | 119| 173k| match filter { 120| 23.3M| NoFilter => {} 121| 124k| 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| 41.4k| let mut prev = [0; 2]; 130| 165M| for chunk in current.chunks_exact_mut(2) { 131| 165M| let new_chunk = [ 132| 165M| chunk[0].wrapping_add(prev[0]), 133| 165M| chunk[1].wrapping_add(prev[1]), 134| 165M| ]; 135| 165M| *TryInto::<&mut [u8; 2]>::try_into(chunk).unwrap() = new_chunk; 136| 165M| prev = new_chunk; 137| 165M| } 138| | } 139| | BytesPerPixel::Three => { 140| 23.4k| let mut prev = [0; 3]; 141| 162M| for chunk in current.chunks_exact_mut(3) { 142| 162M| let new_chunk = [ 143| 162M| chunk[0].wrapping_add(prev[0]), 144| 162M| chunk[1].wrapping_add(prev[1]), 145| 162M| chunk[2].wrapping_add(prev[2]), 146| 162M| ]; 147| 162M| *TryInto::<&mut [u8; 3]>::try_into(chunk).unwrap() = new_chunk; 148| 162M| prev = new_chunk; 149| 162M| } 150| | } 151| | BytesPerPixel::Four => { 152| 10.7k| let mut prev = [0; 4]; 153| 165M| for chunk in current.chunks_exact_mut(4) { 154| 165M| let new_chunk = [ 155| 165M| chunk[0].wrapping_add(prev[0]), 156| 165M| chunk[1].wrapping_add(prev[1]), 157| 165M| chunk[2].wrapping_add(prev[2]), 158| 165M| chunk[3].wrapping_add(prev[3]), 159| 165M| ]; 160| 165M| *TryInto::<&mut [u8; 4]>::try_into(chunk).unwrap() = new_chunk; 161| 165M| prev = new_chunk; 162| 165M| } 163| | } 164| | BytesPerPixel::Six => { 165| 4.75k| let mut prev = [0; 6]; 166| 15.0M| for chunk in current.chunks_exact_mut(6) { 167| 15.0M| let new_chunk = [ 168| 15.0M| chunk[0].wrapping_add(prev[0]), 169| 15.0M| chunk[1].wrapping_add(prev[1]), 170| 15.0M| chunk[2].wrapping_add(prev[2]), 171| 15.0M| chunk[3].wrapping_add(prev[3]), 172| 15.0M| chunk[4].wrapping_add(prev[4]), 173| 15.0M| chunk[5].wrapping_add(prev[5]), 174| 15.0M| ]; 175| 15.0M| *TryInto::<&mut [u8; 6]>::try_into(chunk).unwrap() = new_chunk; 176| 15.0M| prev = new_chunk; 177| 15.0M| } 178| | } 179| | BytesPerPixel::Eight => { 180| 932| let mut prev = [0; 8]; 181| 7.14M| for chunk in current.chunks_exact_mut(8) { 182| 7.14M| let new_chunk = [ 183| 7.14M| chunk[0].wrapping_add(prev[0]), 184| 7.14M| chunk[1].wrapping_add(prev[1]), 185| 7.14M| chunk[2].wrapping_add(prev[2]), 186| 7.14M| chunk[3].wrapping_add(prev[3]), 187| 7.14M| chunk[4].wrapping_add(prev[4]), 188| 7.14M| chunk[5].wrapping_add(prev[5]), 189| 7.14M| chunk[6].wrapping_add(prev[6]), 190| 7.14M| chunk[7].wrapping_add(prev[7]), 191| 7.14M| ]; 192| 7.14M| *TryInto::<&mut [u8; 8]>::try_into(chunk).unwrap() = new_chunk; 193| 7.14M| prev = new_chunk; 194| 7.14M| } 195| | } 196| | }, 197| | Up => { 198| 119M| for (curr, &above) in current.iter_mut().zip(previous) { 199| 119M| *curr = curr.wrapping_add(above); 200| 119M| } 201| | } 202| 173k| Avg if previous.is_empty() => match tbpp { 203| | BytesPerPixel::One => { 204| 345| current.iter_mut().reduce(|&mut prev, curr| { 205| | *curr = curr.wrapping_add(prev / 2); 206| | curr 207| | }); 208| | } 209| | BytesPerPixel::Two => { 210| 288| let mut prev = [0; 2]; 211| 46.4M| for chunk in current.chunks_exact_mut(2) { 212| 46.4M| let new_chunk = [ 213| 46.4M| chunk[0].wrapping_add(prev[0] / 2), 214| 46.4M| chunk[1].wrapping_add(prev[1] / 2), 215| 46.4M| ]; 216| 46.4M| *TryInto::<&mut [u8; 2]>::try_into(chunk).unwrap() = new_chunk; 217| 46.4M| prev = new_chunk; 218| 46.4M| } 219| | } 220| | BytesPerPixel::Three => { 221| 147| let mut prev = [0; 3]; 222| 30.5M| for chunk in current.chunks_exact_mut(3) { 223| 30.5M| let new_chunk = [ 224| 30.5M| chunk[0].wrapping_add(prev[0] / 2), 225| 30.5M| chunk[1].wrapping_add(prev[1] / 2), 226| 30.5M| chunk[2].wrapping_add(prev[2] / 2), 227| 30.5M| ]; 228| 30.5M| *TryInto::<&mut [u8; 3]>::try_into(chunk).unwrap() = new_chunk; 229| 30.5M| prev = new_chunk; 230| 30.5M| } 231| | } 232| | BytesPerPixel::Four => { 233| 213| let mut prev = [0; 4]; 234| 49.7M| for chunk in current.chunks_exact_mut(4) { 235| 49.7M| let new_chunk = [ 236| 49.7M| chunk[0].wrapping_add(prev[0] / 2), 237| 49.7M| chunk[1].wrapping_add(prev[1] / 2), 238| 49.7M| chunk[2].wrapping_add(prev[2] / 2), 239| 49.7M| chunk[3].wrapping_add(prev[3] / 2), 240| 49.7M| ]; 241| 49.7M| *TryInto::<&mut [u8; 4]>::try_into(chunk).unwrap() = new_chunk; 242| 49.7M| prev = new_chunk; 243| 49.7M| } 244| | } 245| | BytesPerPixel::Six => { 246| 111| let mut prev = [0; 6]; 247| 1.17M| for chunk in current.chunks_exact_mut(6) { 248| 1.17M| let new_chunk = [ 249| 1.17M| chunk[0].wrapping_add(prev[0] / 2), 250| 1.17M| chunk[1].wrapping_add(prev[1] / 2), 251| 1.17M| chunk[2].wrapping_add(prev[2] / 2), 252| 1.17M| chunk[3].wrapping_add(prev[3] / 2), 253| 1.17M| chunk[4].wrapping_add(prev[4] / 2), 254| 1.17M| chunk[5].wrapping_add(prev[5] / 2), 255| 1.17M| ]; 256| 1.17M| *TryInto::<&mut [u8; 6]>::try_into(chunk).unwrap() = new_chunk; 257| 1.17M| prev = new_chunk; 258| 1.17M| } 259| | } 260| | BytesPerPixel::Eight => { 261| 146| let mut prev = [0; 8]; 262| 353k| for chunk in current.chunks_exact_mut(8) { 263| 353k| let new_chunk = [ 264| 353k| chunk[0].wrapping_add(prev[0] / 2), 265| 353k| chunk[1].wrapping_add(prev[1] / 2), 266| 353k| chunk[2].wrapping_add(prev[2] / 2), 267| 353k| chunk[3].wrapping_add(prev[3] / 2), 268| 353k| chunk[4].wrapping_add(prev[4] / 2), 269| 353k| chunk[5].wrapping_add(prev[5] / 2), 270| 353k| chunk[6].wrapping_add(prev[6] / 2), 271| 353k| chunk[7].wrapping_add(prev[7] / 2), 272| 353k| ]; 273| 353k| *TryInto::<&mut [u8; 8]>::try_into(chunk).unwrap() = new_chunk; 274| 353k| prev = new_chunk; 275| 353k| } 276| | } 277| | }, 278| 172k| Avg => match tbpp { 279| | BytesPerPixel::One => { 280| 48.3k| let mut lprev = [0; 1]; 281| 24.5M| for (chunk, above) in current.chunks_exact_mut(1).zip(previous.chunks_exact(1)) { 282| 24.5M| let new_chunk = 283| 24.5M| [chunk[0].wrapping_add(((above[0] as u16 + lprev[0] as u16) / 2) as u8)]; 284| 24.5M| *TryInto::<&mut [u8; 1]>::try_into(chunk).unwrap() = new_chunk; 285| 24.5M| lprev = new_chunk; 286| 24.5M| } 287| | } 288| | BytesPerPixel::Two => { 289| 65.4k| let mut lprev = [0; 2]; 290| 1.79M| for (chunk, above) in current.chunks_exact_mut(2).zip(previous.chunks_exact(2)) { 291| 1.79M| let new_chunk = [ 292| 1.79M| chunk[0].wrapping_add(((above[0] as u16 + lprev[0] as u16) / 2) as u8), 293| 1.79M| chunk[1].wrapping_add(((above[1] as u16 + lprev[1] as u16) / 2) as u8), 294| 1.79M| ]; 295| 1.79M| *TryInto::<&mut [u8; 2]>::try_into(chunk).unwrap() = new_chunk; 296| 1.79M| lprev = new_chunk; 297| 1.79M| } 298| | } 299| | BytesPerPixel::Three => { 300| 2.35k| let mut lprev = [0; 3]; 301| 29.3M| for (chunk, above) in current.chunks_exact_mut(3).zip(previous.chunks_exact(3)) { 302| 29.3M| let new_chunk = [ 303| 29.3M| chunk[0].wrapping_add(((above[0] as u16 + lprev[0] as u16) / 2) as u8), 304| 29.3M| chunk[1].wrapping_add(((above[1] as u16 + lprev[1] as u16) / 2) as u8), 305| 29.3M| chunk[2].wrapping_add(((above[2] as u16 + lprev[2] as u16) / 2) as u8), 306| 29.3M| ]; 307| 29.3M| *TryInto::<&mut [u8; 3]>::try_into(chunk).unwrap() = new_chunk; 308| 29.3M| lprev = new_chunk; 309| 29.3M| } 310| | } 311| | BytesPerPixel::Four => { 312| 49.9k| let mut lprev = [0; 4]; 313| 66.0M| for (chunk, above) in current.chunks_exact_mut(4).zip(previous.chunks_exact(4)) { 314| 66.0M| let new_chunk = [ 315| 66.0M| chunk[0].wrapping_add(((above[0] as u16 + lprev[0] as u16) / 2) as u8), 316| 66.0M| chunk[1].wrapping_add(((above[1] as u16 + lprev[1] as u16) / 2) as u8), 317| 66.0M| chunk[2].wrapping_add(((above[2] as u16 + lprev[2] as u16) / 2) as u8), 318| 66.0M| chunk[3].wrapping_add(((above[3] as u16 + lprev[3] as u16) / 2) as u8), 319| 66.0M| ]; 320| 66.0M| *TryInto::<&mut [u8; 4]>::try_into(chunk).unwrap() = new_chunk; 321| 66.0M| lprev = new_chunk; 322| 66.0M| } 323| | } 324| | BytesPerPixel::Six => { 325| 1.91k| let mut lprev = [0; 6]; 326| 12.1M| for (chunk, above) in current.chunks_exact_mut(6).zip(previous.chunks_exact(6)) { 327| 12.1M| let new_chunk = [ 328| 12.1M| chunk[0].wrapping_add(((above[0] as u16 + lprev[0] as u16) / 2) as u8), 329| 12.1M| chunk[1].wrapping_add(((above[1] as u16 + lprev[1] as u16) / 2) as u8), 330| 12.1M| chunk[2].wrapping_add(((above[2] as u16 + lprev[2] as u16) / 2) as u8), 331| 12.1M| chunk[3].wrapping_add(((above[3] as u16 + lprev[3] as u16) / 2) as u8), 332| 12.1M| chunk[4].wrapping_add(((above[4] as u16 + lprev[4] as u16) / 2) as u8), 333| 12.1M| chunk[5].wrapping_add(((above[5] as u16 + lprev[5] as u16) / 2) as u8), 334| 12.1M| ]; 335| 12.1M| *TryInto::<&mut [u8; 6]>::try_into(chunk).unwrap() = new_chunk; 336| 12.1M| lprev = new_chunk; 337| 12.1M| } 338| | } 339| | BytesPerPixel::Eight => { 340| 4.21k| let mut lprev = [0; 8]; 341| 1.94M| for (chunk, above) in current.chunks_exact_mut(8).zip(previous.chunks_exact(8)) { 342| 1.94M| let new_chunk = [ 343| 1.94M| chunk[0].wrapping_add(((above[0] as u16 + lprev[0] as u16) / 2) as u8), 344| 1.94M| chunk[1].wrapping_add(((above[1] as u16 + lprev[1] as u16) / 2) as u8), 345| 1.94M| chunk[2].wrapping_add(((above[2] as u16 + lprev[2] as u16) / 2) as u8), 346| 1.94M| chunk[3].wrapping_add(((above[3] as u16 + lprev[3] as u16) / 2) as u8), 347| 1.94M| chunk[4].wrapping_add(((above[4] as u16 + lprev[4] as u16) / 2) as u8), 348| 1.94M| chunk[5].wrapping_add(((above[5] as u16 + lprev[5] as u16) / 2) as u8), 349| 1.94M| chunk[6].wrapping_add(((above[6] as u16 + lprev[6] as u16) / 2) as u8), 350| 1.94M| chunk[7].wrapping_add(((above[7] as u16 + lprev[7] as u16) / 2) as u8), 351| 1.94M| ]; 352| 1.94M| *TryInto::<&mut [u8; 8]>::try_into(chunk).unwrap() = new_chunk; 353| 1.94M| lprev = new_chunk; 354| 1.94M| } 355| | } 356| | }, 357| 33.3k| Paeth => paeth::unfilter(tbpp, previous, current), 358| | } 359| 23.7M|} _RNvNtNtCshdzP3jLBsmJ_3png6filter5paeth17filter_paeth_stbi: 28| 330M|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| 330M| let thresh = c * 3 - (a + b); 38| 330M| let lo = a.min(b); 39| 330M| let hi = a.max(b); 40| 330M| let t0 = if hi <= thresh { lo } else { c }; 41| 330M| let t1 = if thresh <= lo { hi } else { t0 }; 42| 330M| t1 as u8 43| 330M|} _RNvNtNtCshdzP3jLBsmJ_3png6filter5paeth8unfilter: 221| 33.3k|pub(super) fn unfilter(tbpp: BytesPerPixel, previous: &[u8], current: &mut [u8]) { 222| | // Paeth filter pixels: 223| | // C B D 224| | // A X 225| 33.3k| match tbpp { 226| | BytesPerPixel::One => { 227| | const BPP: usize = 1; 228| 5.60k| let mut a_bpp = [0; BPP]; 229| 5.60k| let mut c_bpp = [0; BPP]; 230| | 231| 39.0M| for (c, p) in current 232| 5.60k| .chunks_exact_mut(BPP) 233| 5.60k| .zip(previous.chunks_exact(BPP)) 234| | { 235| 78.1M| for i in 0..BPP { 236| 39.0M| c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i])); 237| 39.0M| } 238| | 239| 39.0M| a_bpp = [c[0] as i16]; 240| 39.0M| c_bpp = [p[0] as i16]; 241| | } 242| | } 243| | BytesPerPixel::Two => { 244| | const BPP: usize = 2; 245| 18.1k| let mut a_bpp = [0; BPP]; 246| 18.1k| let mut c_bpp = [0; BPP]; 247| | 248| 23.4M| for (c, p) in current 249| 18.1k| .chunks_exact_mut(BPP) 250| 18.1k| .zip(previous.chunks_exact(BPP)) 251| | { 252| 70.3M| for i in 0..BPP { 253| 46.8M| c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i])); 254| 46.8M| } 255| | 256| 23.4M| a_bpp = [c[0] as i16, c[1] as i16]; 257| 23.4M| 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.50k| let mut a_bpp = [0; BPP]; 271| 2.50k| let mut c_bpp = [0; BPP]; 272| | 273| 27.2M| for (c, p) in current 274| 2.50k| .chunks_exact_mut(BPP) 275| 2.50k| .zip(previous.chunks_exact(BPP)) 276| | { 277| 108M| for i in 0..BPP { 278| 81.7M| c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i])); 279| 81.7M| } 280| | 281| 27.2M| a_bpp = [c[0] as i16, c[1] as i16, c[2] as i16]; 282| 27.2M| 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.15k| let mut a_bpp = [0; BPP]; 295| 2.15k| let mut c_bpp = [0; BPP]; 296| | 297| 21.5M| for (c, p) in current 298| 2.15k| .chunks_exact_mut(BPP) 299| 2.15k| .zip(previous.chunks_exact(BPP)) 300| | { 301| 107M| for i in 0..BPP { 302| 86.3M| c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i])); 303| 86.3M| } 304| | 305| 21.5M| a_bpp = [c[0] as i16, c[1] as i16, c[2] as i16, c[3] as i16]; 306| 21.5M| 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.58k| let mut a_bpp = [0; BPP]; 312| 4.58k| let mut c_bpp = [0; BPP]; 313| | 314| 11.9M| for (c, p) in current 315| 4.58k| .chunks_exact_mut(BPP) 316| 4.58k| .zip(previous.chunks_exact(BPP)) 317| | { 318| 83.7M| for i in 0..BPP { 319| 71.7M| c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i])); 320| 71.7M| } 321| | 322| 11.9M| a_bpp = [ 323| 11.9M| c[0] as i16, 324| 11.9M| c[1] as i16, 325| 11.9M| c[2] as i16, 326| 11.9M| c[3] as i16, 327| 11.9M| c[4] as i16, 328| 11.9M| c[5] as i16, 329| 11.9M| ]; 330| 11.9M| c_bpp = [ 331| 11.9M| p[0] as i16, 332| 11.9M| p[1] as i16, 333| 11.9M| p[2] as i16, 334| 11.9M| p[3] as i16, 335| 11.9M| p[4] as i16, 336| 11.9M| p[5] as i16, 337| 11.9M| ]; 338| | } 339| | } 340| | BytesPerPixel::Eight => { 341| | const BPP: usize = 8; 342| 327| let mut a_bpp = [0; BPP]; 343| 327| let mut c_bpp = [0; BPP]; 344| | 345| 547k| for (c, p) in current 346| 327| .chunks_exact_mut(BPP) 347| 327| .zip(previous.chunks_exact(BPP)) 348| | { 349| 4.92M| for i in 0..BPP { 350| 4.37M| c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i])); 351| 4.37M| } 352| | 353| 547k| a_bpp = [ 354| 547k| c[0] as i16, 355| 547k| c[1] as i16, 356| 547k| c[2] as i16, 357| 547k| c[3] as i16, 358| 547k| c[4] as i16, 359| 547k| c[5] as i16, 360| 547k| c[6] as i16, 361| 547k| c[7] as i16, 362| 547k| ]; 363| 547k| c_bpp = [ 364| 547k| p[0] as i16, 365| 547k| p[1] as i16, 366| 547k| p[2] as i16, 367| 547k| p[3] as i16, 368| 547k| p[4] as i16, 369| 547k| p[5] as i16, 370| 547k| p[6] as i16, 371| 547k| p[7] as i16, 372| 547k| ]; 373| | } 374| | } 375| | } 376| 33.3k|} _RNCNvNtCshdzP3jLBsmJ_3png13text_metadata17decode_iso_8859_10B5_: 158| 981k| text.iter().map(|&b| b as char).collect() _RNvMNtCshdzP3jLBsmJ_3png13text_metadataNtB2_9TEXtChunk6decode: 199| 6.22k| pub(crate) fn decode( 200| 6.22k| keyword_slice: &[u8], 201| 6.22k| text_slice: &[u8], 202| 6.22k| ) -> Result { 203| 6.22k| if keyword_slice.is_empty() || keyword_slice.len() > 79 { 204| 0| return Err(TextDecodingError::InvalidKeywordSize); 205| 6.22k| } 206| | 207| 6.22k| Ok(Self { 208| 6.22k| keyword: decode_iso_8859_1(keyword_slice), 209| 6.22k| text: decode_iso_8859_1(text_slice), 210| 6.22k| }) 211| 6.22k| } _RNvMs0_NtCshdzP3jLBsmJ_3png13text_metadataNtB5_9ZTXtChunk26decompress_text_with_limit: 283| 37| pub fn decompress_text_with_limit(&mut self, limit: usize) -> Result<(), DecodingError> { 284| 37| match &self.text { 285| 37| OptCompressed::Compressed(v) => { 286| 37| let uncompressed_raw = match fdeflate::decompress_to_vec_bounded(&v[..], limit) { 287| 15| Ok(s) => s, 288| | Err(BoundedDecompressionError::OutputTooLarge { .. }) => { 289| 0| return Err(DecodingError::from( 290| 0| TextDecodingError::OutOfDecompressionSpace, 291| 0| )); 292| | } 293| | Err(_) => { 294| 22| return Err(DecodingError::from(TextDecodingError::InflationError)); 295| | } 296| | }; 297| 15| self.text = OptCompressed::Uncompressed(decode_iso_8859_1(&uncompressed_raw)); 298| | } 299| 0| OptCompressed::Uncompressed(_) => {} 300| | }; 301| 15| Ok(()) 302| 37| } _RNvMs0_NtCshdzP3jLBsmJ_3png13text_metadataNtB5_9ZTXtChunk6decode: 258| 7.37k| pub(crate) fn decode( 259| 7.37k| keyword_slice: &[u8], 260| 7.37k| compression_method: u8, 261| 7.37k| text_slice: &[u8], 262| 7.37k| ) -> Result { 263| 7.37k| if keyword_slice.is_empty() || keyword_slice.len() > 79 { 264| 0| return Err(TextDecodingError::InvalidKeywordSize); 265| 7.37k| } 266| | 267| 7.37k| if compression_method != 0 { 268| 379| return Err(TextDecodingError::InvalidCompressionMethod); 269| 6.99k| } 270| | 271| 6.99k| Ok(Self { 272| 6.99k| keyword: decode_iso_8859_1(keyword_slice), 273| 6.99k| text: OptCompressed::Compressed(text_slice.to_vec()), 274| 6.99k| }) 275| 7.37k| } _RNvMs0_NtCshdzP3jLBsmJ_3png13text_metadataNtB5_9ZTXtChunk8get_text: 306| 15| pub fn get_text(&self) -> Result { 307| 15| 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| 15| OptCompressed::Uncompressed(s) => Ok(s.clone()), 314| | } 315| 15| } _RNvMs2_NtCshdzP3jLBsmJ_3png13text_metadataNtB5_9ITXtChunk26decompress_text_with_limit: 453| 11| pub fn decompress_text_with_limit(&mut self, limit: usize) -> Result<(), DecodingError> { 454| 11| match &self.text { 455| 4| OptCompressed::Compressed(v) => { 456| 4| 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| 4| 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| 7| OptCompressed::Uncompressed(_) => {} 473| | }; 474| 7| Ok(()) 475| 11| } _RNvMs2_NtCshdzP3jLBsmJ_3png13text_metadataNtB5_9ITXtChunk6decode: 401| 11.9k| pub(crate) fn decode( 402| 11.9k| keyword_slice: &[u8], 403| 11.9k| compression_flag: u8, 404| 11.9k| compression_method: u8, 405| 11.9k| language_tag_slice: &[u8], 406| 11.9k| translated_keyword_slice: &[u8], 407| 11.9k| text_slice: &[u8], 408| 11.9k| ) -> Result { 409| 11.9k| if keyword_slice.is_empty() || keyword_slice.len() > 79 { 410| 0| return Err(TextDecodingError::InvalidKeywordSize); 411| 11.9k| } 412| 11.9k| let keyword = decode_iso_8859_1(keyword_slice); 413| | 414| 11.9k| let compressed = match compression_flag { 415| 9.32k| 0 => false, 416| 2.43k| 1 => true, 417| 224| _ => return Err(TextDecodingError::InvalidCompressionFlag), 418| | }; 419| | 420| 11.7k| if compressed && compression_method != 0 { 421| 209| return Err(TextDecodingError::InvalidCompressionMethod); 422| 11.5k| } 423| | 424| 11.5k| let language_tag = decode_ascii(language_tag_slice)?.to_owned(); 425| | 426| 10.7k| let translated_keyword = std::str::from_utf8(translated_keyword_slice) 427| 10.7k| .map_err(|_| TextDecodingError::Unrepresentable)? 428| 10.6k| .to_string(); 429| 10.6k| let text = if compressed { 430| 2.02k| OptCompressed::Compressed(text_slice.to_vec()) 431| | } else { 432| | OptCompressed::Uncompressed( 433| 8.61k| String::from_utf8(text_slice.to_vec()) 434| 8.61k| .map_err(|_| TextDecodingError::Unrepresentable)?, 435| | ) 436| | }; 437| | 438| 10.0k| Ok(Self { 439| 10.0k| keyword, 440| 10.0k| compressed, 441| 10.0k| language_tag, 442| 10.0k| translated_keyword, 443| 10.0k| text, 444| 10.0k| }) 445| 11.9k| } _RNvMs2_NtCshdzP3jLBsmJ_3png13text_metadataNtB5_9ITXtChunk8get_text: 479| 7| pub fn get_text(&self) -> Result { 480| 7| 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| 7| OptCompressed::Uncompressed(s) => Ok(s.clone()), 488| | } 489| 7| } _RNvNtCshdzP3jLBsmJ_3png13text_metadata12decode_ascii: 177| 11.5k|fn decode_ascii(text: &[u8]) -> Result<&str, TextDecodingError> { 178| 11.5k| 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| 10.7k| Ok(std::str::from_utf8(text).expect("unreachable")) 182| | } else { 183| 824| Err(TextDecodingError::Unrepresentable) 184| | } 185| 11.5k|} _RNvNtCshdzP3jLBsmJ_3png13text_metadata17decode_iso_8859_1: 157| 31.4k|fn decode_iso_8859_1(text: &[u8]) -> String { 158| 31.4k| text.iter().map(|&b| b as char).collect() 159| 31.4k|} _RNvXNtCshdzP3jLBsmJ_3png6traitsRShINtB2_12ReadBytesExthE7read_beB4_: 7| 77.1k| fn read_be(&mut self) -> io::Result<$output_type> { 8| 77.1k| let mut bytes = [0u8; std::mem::size_of::<$output_type>()]; 9| 77.1k| self.read_exact(&mut bytes)?; 10| 77.0k| Ok(<$output_type>::from_be_bytes(bytes)) 11| 77.1k| } _RNvXs0_NtCshdzP3jLBsmJ_3png6traitsRShINtB5_12ReadBytesExtmE7read_beB7_: 7| 22.2k| fn read_be(&mut self) -> io::Result<$output_type> { 8| 22.2k| let mut bytes = [0u8; std::mem::size_of::<$output_type>()]; 9| 22.2k| self.read_exact(&mut bytes)?; 10| 22.2k| Ok(<$output_type>::from_be_bytes(bytes)) 11| 22.2k| } _RNvXs_NtCshdzP3jLBsmJ_3png6traitsRShINtB4_12ReadBytesExttE7read_beB6_: 7| 594| fn read_be(&mut self) -> io::Result<$output_type> { 8| 594| let mut bytes = [0u8; std::mem::size_of::<$output_type>()]; 9| 594| self.read_exact(&mut bytes)?; 10| 594| Ok(<$output_type>::from_be_bytes(bytes)) 11| 594| } _RNvNtNtCs2divbjE383Z_12simd_adler323imp4avx213get_imp_innerB5_: 10| 11.8k|fn get_imp_inner() -> Option { 11| 11.8k| if std::is_x86_feature_detected!("avx2") { 12| 11.8k| Some(imp::update) 13| | } else { 14| 0| None 15| | } 16| 11.8k|} _RNvNtNtCs2divbjE383Z_12simd_adler323imp4avx27get_imp: 4| 11.8k|pub fn get_imp() -> Option { 5| 11.8k| get_imp_inner() 6| 11.8k|} _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp10reduce_add: 143| 1.90M| unsafe fn reduce_add(v: __m256i) -> u32 { 144| 1.90M| let sum = _mm_add_epi32(_mm256_castsi256_si128(v), _mm256_extracti128_si256(v, 1)); 145| 1.90M| let hi = _mm_unpackhi_epi64(sum, sum); 146| | 147| 1.90M| let sum = _mm_add_epi32(hi, sum); 148| 1.90M| let hi = _mm_shuffle_epi32(sum, crate::imp::_MM_SHUFFLE(2, 3, 0, 1)); 149| | 150| 1.90M| let sum = _mm_add_epi32(sum, hi); 151| | 152| 1.90M| _mm_cvtsi128_si32(sum) as _ 153| 1.90M| } _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp10update_impB7_: 57| 161k| unsafe fn update_imp(a: u16, b: u16, data: &[u8]) -> (u16, u16) { 58| 161k| let mut a = a as u32; 59| 161k| let mut b = b as u32; 60| | 61| 161k| let chunks = data.chunks_exact(CHUNK_SIZE); 62| 161k| let remainder = chunks.remainder(); 63| 953k| for chunk in chunks { 64| 791k| update_chunk_block(&mut a, &mut b, chunk); 65| 791k| } 66| | 67| 161k| update_block(&mut a, &mut b, remainder); 68| | 69| 161k| (a as u16, b as u16) 70| 161k| } _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp11get_weights: 156| 952k| unsafe fn get_weights() -> __m256i { 157| 952k| _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| 952k| } _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp12update_blockB7_: 89| 161k| unsafe fn update_block(a: &mut u32, b: &mut u32, chunk: &[u8]) { 90| 161k| 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| 161k| for byte in reduce_add_blocks(a, b, chunk) { 98| 50.4k| *a += *byte as u32; 99| 50.4k| *b += *a; 100| 50.4k| } 101| | 102| 161k| *a %= MOD; 103| 161k| *b %= MOD; 104| 161k| } _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp17reduce_add_blocks: 107| 953k| unsafe fn reduce_add_blocks<'a>(a: &mut u32, b: &mut u32, chunk: &'a [u8]) -> &'a [u8] { 108| 953k| if chunk.len() < BLOCK_SIZE { 109| 196| return chunk; 110| 952k| } 111| | 112| 952k| let blocks = chunk.chunks_exact(BLOCK_SIZE); 113| 952k| let blocks_remainder = blocks.remainder(); 114| | 115| 952k| let one_v = _mm256_set1_epi16(1); 116| 952k| let zero_v = _mm256_setzero_si256(); 117| 952k| let weights = get_weights(); 118| | 119| 952k| let mut p_v = _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, (*a * blocks.len() as u32) as _); 120| 952k| let mut a_v = _mm256_setzero_si256(); 121| 952k| let mut b_v = _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, *b as _); 122| | 123| 163M| for block in blocks { 124| 162M| let block_ptr = block.as_ptr() as *const _; 125| 162M| let block = _mm256_loadu_si256(block_ptr); 126| 162M| 127| 162M| p_v = _mm256_add_epi32(p_v, a_v); 128| 162M| 129| 162M| a_v = _mm256_add_epi32(a_v, _mm256_sad_epu8(block, zero_v)); 130| 162M| let mad = _mm256_maddubs_epi16(block, weights); 131| 162M| b_v = _mm256_add_epi32(b_v, _mm256_madd_epi16(mad, one_v)); 132| 162M| } 133| | 134| 952k| b_v = _mm256_add_epi32(b_v, _mm256_slli_epi32(p_v, 5)); 135| | 136| 952k| *a += reduce_add(a_v); 137| 952k| *b = reduce_add(b_v); 138| | 139| 952k| blocks_remainder 140| 953k| } _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp18update_chunk_blockB7_: 73| 791k| unsafe fn update_chunk_block(a: &mut u32, b: &mut u32, chunk: &[u8]) { 74| 791k| 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| 791k| reduce_add_blocks(a, b, chunk); 83| | 84| 791k| *a %= MOD; 85| 791k| *b %= MOD; 86| 791k| } _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp6update: 51| 161k| pub fn update(a: u16, b: u16, data: &[u8]) -> (u16, u16) { 52| 161k| unsafe { update_imp(a, b, data) } 53| 161k| } _RNvNtNtCs2divbjE383Z_12simd_adler323imp6avx51213get_imp_innerB5_: 44| 11.8k|fn get_imp_inner() -> Option { 45| 11.8k| None 46| 11.8k|} _RNvNtNtCs2divbjE383Z_12simd_adler323imp6avx5127get_imp: 4| 11.8k|pub fn get_imp() -> Option { 5| 11.8k| get_imp_inner() 6| 11.8k|} _RNvNtCs2divbjE383Z_12simd_adler323imp7get_imp: 17| 11.8k|pub fn get_imp() -> Adler32Imp { 18| 11.8k| avx512::get_imp() 19| 11.8k| .or_else(neon::get_imp) 20| 11.8k| .or_else(avx2::get_imp) 21| 11.8k| .or_else(ssse3::get_imp) 22| 11.8k| .or_else(sse2::get_imp) 23| 11.8k| .or_else(wasm::get_imp) 24| 11.8k| .unwrap_or(scalar::update) 25| 11.8k|} _RNvNtNtCs2divbjE383Z_12simd_adler323imp4neon7get_imp: 9| 11.8k|pub fn get_imp() -> Option { 10| 11.8k| None 11| 11.8k|} _RNvMCs2divbjE383Z_12simd_adler32NtB2_7Adler323new: 125| 11.8k| pub fn new() -> Self { 126| 11.8k| Default::default() 127| 11.8k| } _RNvMCs2divbjE383Z_12simd_adler32NtB2_7Adler325write: 149| 161k| pub fn write(&mut self, data: &[u8]) { 150| 161k| let (a, b) = (self.update)(self.a, self.b, data); 151| | 152| 161k| self.a = a; 153| 161k| self.b = b; 154| 161k| } _RNvXs_Cs2divbjE383Z_12simd_adler32NtB4_7Adler32NtNtCs6SNw0SRvItZ_4core7default7Default7default: 195| 11.8k| fn default() -> Self { 196| 11.8k| Self { 197| 11.8k| a: 1, 198| 11.8k| b: 0, 199| 11.8k| update: get_imp(), 200| 11.8k| } 201| 11.8k| } _RNCNCNvXs_NtNtCs4rpmEmvDwFM_5image6codecs3pngINtB8_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBc_2io7decoder12ImageDecoder13iptc_metadata00Bc_: 348| 2.00k| .find(|chunk| IPTC_KEYS.iter().any(|key| chunk.keyword.contains(key))) _RNCNCNvXs_NtNtCs4rpmEmvDwFM_5image6codecs3pngINtB8_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBc_2io7decoder12ImageDecoder13iptc_metadatas0_00Bc_: 364| 843| .find(|chunk| IPTC_KEYS.iter().any(|key| chunk.keyword.contains(key))) _RNCNvNtNtCs4rpmEmvDwFM_5image6codecs3png27big_endian_to_native_endian0B7_: 271| 104M| 2 => buf.as_chunks_mut::<2>().0.iter_mut().for_each(|c| { 272| 104M| *c = u16::from_be_bytes(*c).to_ne_bytes(); 273| 104M| }), _RNCNvXs_NtNtCs4rpmEmvDwFM_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder11icc_profile0Ba_: 309| 1.59k| Ok(reader.info().icc_profile.as_ref().map(|x| x.to_vec())) _RNCNvXs_NtNtCs4rpmEmvDwFM_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder12xmp_metadata0Ba_: 325| 384| .find(|chunk| chunk.keyword == XMP_KEY) _RNCNvXs_NtNtCs4rpmEmvDwFM_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder12xmp_metadatas_0Ba_: 333| 7| .map(|text| Some(text.into_bytes())) _RNCNvXs_NtNtCs4rpmEmvDwFM_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder13exif_metadata0Ba_: 314| 44| Ok(reader.info().exif_metadata.as_ref().map(|x| x.to_vec())) _RNCNvXs_NtNtCs4rpmEmvDwFM_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder13iptc_metadata0Ba_: 348| 1.01k| .find(|chunk| IPTC_KEYS.iter().any(|key| chunk.keyword.contains(key))) _RNCNvXs_NtNtCs4rpmEmvDwFM_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder13iptc_metadatas0_0Ba_: 364| 424| .find(|chunk| IPTC_KEYS.iter().any(|key| chunk.keyword.contains(key))) _RNCNvXs_NtNtCs4rpmEmvDwFM_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder13iptc_metadatas_0Ba_: 356| 15| .map(|text| Some(text.into_bytes())) _RNvMNtNtCs4rpmEmvDwFM_5image6codecs3pngINtB2_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE11with_limitsB6_: 53| 9.46k| pub fn with_limits(r: R, limits: Limits) -> PngDecoder { 54| 9.46k| let max_bytes = usize::try_from(limits.max_alloc.unwrap_or(u64::MAX)).unwrap_or(usize::MAX); 55| 9.46k| let mut decoder = png::Decoder::new_with_limits(r, png::Limits { bytes: max_bytes }); 56| 9.46k| decoder.set_ignore_text_chunk(false); 57| | 58| 9.46k| PngDecoder { 59| 9.46k| decoder: Some(decoder), 60| 9.46k| // We'll replace this once we have a reader. 61| 9.46k| color_type: ColorType::L8, 62| 9.46k| reader: None, 63| 9.46k| limits, 64| 9.46k| } 65| 9.46k| } _RNvMNtNtCs4rpmEmvDwFM_5image6codecs3pngINtB2_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE15color_type_infoB6_: 189| 5.78k| fn color_type_info(info: &png::Info<'_>) -> ExtendedColorType { 190| 5.78k| match (info.color_type, info.bit_depth) { 191| 1.00k| (png::ColorType::Grayscale, png::BitDepth::One) => ExtendedColorType::L1, 192| 180| (png::ColorType::Grayscale, png::BitDepth::Two) => ExtendedColorType::L2, 193| 372| (png::ColorType::Grayscale, png::BitDepth::Four) => ExtendedColorType::L4, 194| 489| (png::ColorType::Grayscale, png::BitDepth::Eight) => ExtendedColorType::L8, 195| 730| (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| 217| (png::ColorType::GrayscaleAlpha, png::BitDepth::Eight) => ExtendedColorType::La8, 200| 134| (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| 593| (png::ColorType::Rgb, png::BitDepth::Eight) => ExtendedColorType::Rgb8, 205| 410| (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| 239| (png::ColorType::Rgba, png::BitDepth::Eight) => ExtendedColorType::Rgba8, 210| 233| (png::ColorType::Rgba, png::BitDepth::Sixteen) => ExtendedColorType::Rgba16, 211| 984| (png::ColorType::Indexed, png::BitDepth::One) => ExtendedColorType::Unknown(1), 212| 48| (png::ColorType::Indexed, png::BitDepth::Two) => ExtendedColorType::Unknown(2), 213| 36| (png::ColorType::Indexed, png::BitDepth::Four) => ExtendedColorType::Unknown(4), 214| 108| (png::ColorType::Indexed, png::BitDepth::Eight) => ExtendedColorType::Unknown(8), 215| 0| (png::ColorType::Indexed, png::BitDepth::Sixteen) => ExtendedColorType::Unknown(16), 216| | } 217| 5.78k| } _RNvMNtNtCs4rpmEmvDwFM_5image6codecs3pngINtB2_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE21text_decompress_limitB6_: 221| 12.0k| fn text_decompress_limit(&mut self) -> usize { 222| 12.0k| let max = png::text_metadata::DECOMPRESSION_LIMIT as u64; 223| 12.0k| self.limits.max_alloc.unwrap_or(max).min(max) as usize 224| 12.0k| } _RNvMNtNtCs4rpmEmvDwFM_5image6codecs3pngINtB2_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE24ensure_reader_and_headerB6_: 67| 50.9k| fn ensure_reader_and_header(&mut self) -> ImageResult<&mut png::Reader> { 68| 50.9k| 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| 41.4k| return self.reader.as_mut().ok_or_else(|| unreachable!()); 72| 9.46k| } 73| | 74| 9.46k| let Some(mut decoder) = self.decoder.take() else { 75| 0| return Err(reader_finished_already()); 76| | }; 77| | 78| 9.46k| self.limits.check_support(&crate::LimitSupport::default())?; 79| | 80| 9.46k| let info = decoder.read_header_info().map_err(ImageError::from_png)?; 81| 9.18k| 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.18k| decoder.set_transformations(png::Transformations::EXPAND); 87| 9.18k| let reader = decoder.read_info().map_err(ImageError::from_png)?; 88| 6.02k| let (color_type, bits) = reader.output_color_type(); 89| | 90| 6.02k| let color_type = match (color_type, bits) { 91| 1.99k| (png::ColorType::Grayscale, png::BitDepth::Eight) => ColorType::L8, 92| 660| (png::ColorType::Grayscale, png::BitDepth::Sixteen) => ColorType::L16, 93| 342| (png::ColorType::GrayscaleAlpha, png::BitDepth::Eight) => ColorType::La8, 94| 224| (png::ColorType::GrayscaleAlpha, png::BitDepth::Sixteen) => ColorType::La16, 95| 1.79k| (png::ColorType::Rgb, png::BitDepth::Eight) => ColorType::Rgb8, 96| 414| (png::ColorType::Rgb, png::BitDepth::Sixteen) => ColorType::Rgb16, 97| 360| (png::ColorType::Rgba, png::BitDepth::Eight) => ColorType::Rgba8, 98| 241| (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.02k| self.color_type = color_type; 145| 6.02k| Ok(self.reader.insert(reader)) 146| 50.9k| } _RNvMNtNtCs4rpmEmvDwFM_5image6codecs3pngINtB2_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE3newB6_: 48| 9.46k| pub fn new(r: R) -> PngDecoder { 49| 9.46k| Self::with_limits(r, Limits::no_limits()) 50| 9.46k| } _RNvXs_NtNtCs4rpmEmvDwFM_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder10read_imageB8_: 372| 5.78k| fn read_image(&mut self, buf: &mut [u8]) -> ImageResult { 373| 5.78k| let layout = self.prepare_image()?; 374| 5.78k| assert_eq!(u64::try_from(buf.len()), Ok(layout.total_bytes())); 375| | 376| 5.78k| let reader = self.ensure_reader_and_header()?; 377| 5.78k| let original_color_type = Self::color_type_info(reader.info()); 378| 5.78k| reader.next_frame(buf).map_err(ImageError::from_png)?; 379| | 380| 1.72k| big_endian_to_native_endian(buf, layout.layout.color); 381| | 382| 1.72k| Ok(DecodedImageAttributes { 383| 1.72k| original_color_type: Some(original_color_type), 384| 1.72k| ..DecodedImageAttributes::default() 385| 1.72k| }) 386| 5.78k| } _RNvXs_NtNtCs4rpmEmvDwFM_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder10set_limitsB8_: 388| 9.46k| fn set_limits(&mut self, limits: Limits) -> ImageResult<()> { 389| 9.46k| limits.check_support(&crate::LimitSupport::default())?; 390| | 391| 9.46k| if let Some(decoder) = &mut self.decoder { 392| 9.46k| decoder.set_limits(png::Limits { 393| 9.46k| bytes: match limits.max_alloc { 394| 0| None => usize::MAX, 395| 9.46k| Some(limit) => limit.try_into().unwrap_or(usize::MAX), 396| | }, 397| | }); 398| | 399| 9.46k| self.limits = limits; 400| 9.46k| Ok(()) 401| | } else { 402| 0| Err(decoding_started_already()) 403| | } 404| 9.46k| } _RNvXs_NtNtCs4rpmEmvDwFM_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder11icc_profileB8_: 307| 6.02k| fn icc_profile(&mut self) -> ImageResult>> { 308| 6.02k| let reader = self.ensure_reader_and_header()?; 309| 6.02k| Ok(reader.info().icc_profile.as_ref().map(|x| x.to_vec())) 310| 6.02k| } _RNvXs_NtNtCs4rpmEmvDwFM_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder12xmp_metadataB8_: 317| 6.02k| fn xmp_metadata(&mut self) -> ImageResult>> { 318| 6.02k| let decompression_limit = self.text_decompress_limit(); 319| 6.02k| let reader = self.ensure_reader_and_header()?; 320| | 321| 6.02k| if let Some(mut itx_chunk) = reader 322| 6.02k| .info() 323| 6.02k| .utf8_text 324| 6.02k| .iter() 325| 6.02k| .find(|chunk| chunk.keyword == XMP_KEY) 326| 6.02k| .cloned() 327| | { 328| 11| itx_chunk 329| 11| .decompress_text_with_limit(decompression_limit) 330| 11| .map_err(ImageError::from_png)?; 331| 7| return itx_chunk 332| 7| .get_text() 333| 7| .map(|text| Some(text.into_bytes())) 334| 7| .map_err(ImageError::from_png); 335| 6.01k| } 336| | 337| 6.01k| Ok(None) 338| 6.02k| } _RNvXs_NtNtCs4rpmEmvDwFM_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder13exif_metadataB8_: 312| 6.02k| fn exif_metadata(&mut self) -> ImageResult>> { 313| 6.02k| let reader = self.ensure_reader_and_header()?; 314| 6.02k| Ok(reader.info().exif_metadata.as_ref().map(|x| x.to_vec())) 315| 6.02k| } _RNvXs_NtNtCs4rpmEmvDwFM_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder13iptc_metadataB8_: 340| 6.02k| fn iptc_metadata(&mut self) -> ImageResult>> { 341| 6.02k| let decompression_limit = self.text_decompress_limit(); 342| 6.02k| let reader = self.ensure_reader_and_header()?; 343| | 344| 6.02k| if let Some(mut text_chunk) = reader 345| 6.02k| .info() 346| 6.02k| .compressed_latin1_text 347| 6.02k| .iter() 348| 6.02k| .find(|chunk| IPTC_KEYS.iter().any(|key| chunk.keyword.contains(key))) 349| 6.02k| .cloned() 350| | { 351| 37| text_chunk 352| 37| .decompress_text_with_limit(decompression_limit) 353| 37| .map_err(ImageError::from_png)?; 354| 15| return text_chunk 355| 15| .get_text() 356| 15| .map(|text| Some(text.into_bytes())) 357| 15| .map_err(ImageError::from_png); 358| 5.99k| } 359| | 360| 5.99k| if let Some(text_chunk) = reader 361| 5.99k| .info() 362| 5.99k| .uncompressed_latin1_text 363| 5.99k| .iter() 364| 5.99k| .find(|chunk| IPTC_KEYS.iter().any(|key| chunk.keyword.contains(key))) 365| 5.99k| .cloned() 366| | { 367| 11| return Ok(Some(text_chunk.text.into_bytes())); 368| 5.98k| } 369| 5.98k| Ok(None) 370| 6.02k| } _RNvXs_NtNtCs4rpmEmvDwFM_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder13prepare_imageB8_: 280| 21.0k| fn prepare_image(&mut self) -> ImageResult { 281| 21.0k| let reader = self.ensure_reader_and_header()?; 282| 17.5k| let (width, height) = reader.info().size(); 283| 17.5k| Ok(DecoderPreparedImage::new(width, height, self.color_type)) 284| 21.0k| } _RNvXs_NtNtCs4rpmEmvDwFM_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder17format_attributesB8_: 286| 9.48k| fn format_attributes(&self) -> FormatAttributes { 287| 9.48k| FormatAttributes { 288| 9.48k| // is any sort of iTXT chunk. 289| 9.48k| // FIXME: we do not collect these in advance. 290| 9.48k| xmp: DecodedMetadataHint::InHeader, 291| 9.48k| // is any sort of iTXT chunk. 292| 9.48k| // FIXME: we do not collect these in advance. 293| 9.48k| iptc: DecodedMetadataHint::InHeader, 294| 9.48k| // see iCCP chunk order. 295| 9.48k| icc: DecodedMetadataHint::InHeader, 296| 9.48k| // see eXIf chunk order. 297| 9.48k| exif: DecodedMetadataHint::InHeader, 298| 9.48k| ..FormatAttributes::default() 299| 9.48k| } 300| 9.48k| } _RNvNtNtCs4rpmEmvDwFM_5image6codecs3png27big_endian_to_native_endian: 266| 1.72k|fn big_endian_to_native_endian(buf: &mut [u8], color: ColorType) { 267| 1.72k| let bytes_per_channel = color.bytes_per_pixel() / color.channel_count(); 268| | 269| 1.72k| match bytes_per_channel { 270| 1.45k| 1 => (), // No reodering necessary for u8 271| 274| 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.72k|} _RNvMs4_NtNtCs4rpmEmvDwFM_5image6codecs3pngNtNtB9_5error10ImageError8from_png: 959| 7.51k| fn from_png(err: png::DecodingError) -> ImageError { 960| | use png::DecodingError::*; 961| 7.51k| match err { 962| 5.58k| IoError(err) => ImageError::IoError(err), 963| | // The input image was not a valid PNG. 964| 1.84k| err @ Format(_) => { 965| 1.84k| 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| 81| ImageError::Limits(LimitError::from_kind(LimitErrorKind::InsufficientMemory)) 976| | } 977| | } 978| 7.51k| } _RNvMNtCs4rpmEmvDwFM_5image5colorNtB2_9ColorType13channel_count: 89| 1.72k| pub fn channel_count(self) -> u8 { 90| 1.72k| let e: ExtendedColorType = self.into(); 91| 1.72k| e.channel_count() 92| 1.72k| } _RNvMNtCs4rpmEmvDwFM_5image5colorNtB2_9ColorType15bytes_per_pixel: 47| 19.3k| pub fn bytes_per_pixel(self) -> u8 { 48| 19.3k| match self { 49| 6.34k| ColorType::L8 => 1, 50| 3.20k| ColorType::L16 | ColorType::La8 => 2, 51| 6.01k| ColorType::Rgb8 => 3, 52| 1.78k| ColorType::Rgba8 | ColorType::La16 | ColorType::L32F => 4, 53| 1.23k| ColorType::Rgb16 => 6, 54| 733| ColorType::Rgba16 | ColorType::La32F => 8, 55| 0| ColorType::Rgb32F => 3 * 4, 56| 0| ColorType::Rgba32F => 4 * 4, 57| | } 58| 19.3k| } _RNvMs_NtCs4rpmEmvDwFM_5image5colorNtB4_17ExtendedColorType13channel_count: 186| 1.72k| pub fn channel_count(self) -> u8 { 187| 1.72k| match self { 188| | ExtendedColorType::A8 189| | | ExtendedColorType::L1 190| | | ExtendedColorType::L2 191| | | ExtendedColorType::L4 192| | | ExtendedColorType::L8 193| | | ExtendedColorType::L16 194| | | ExtendedColorType::L32F 195| 718| | ExtendedColorType::Unknown(_) => 1, 196| | ExtendedColorType::La1 197| | | ExtendedColorType::La2 198| | | ExtendedColorType::La4 199| | | ExtendedColorType::La8 200| | | ExtendedColorType::La16 201| 33| | 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| 913| | 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| 64| | ExtendedColorType::Cmyk16 => 4, 220| | } 221| 1.72k| } _RNvXs0_NtCs4rpmEmvDwFM_5image5colorNtB5_17ExtendedColorTypeINtNtCs6SNw0SRvItZ_4core7convert4FromNtB5_9ColorTypeE4from: 316| 1.72k| fn from(c: ColorType) -> Self { 317| 1.72k| match c { 318| 492| ColorType::L8 => ExtendedColorType::L8, 319| 15| ColorType::La8 => ExtendedColorType::La8, 320| 901| ColorType::Rgb8 => ExtendedColorType::Rgb8, 321| 46| ColorType::Rgba8 => ExtendedColorType::Rgba8, 322| 226| ColorType::L16 => ExtendedColorType::L16, 323| 18| ColorType::La16 => ExtendedColorType::La16, 324| 12| ColorType::Rgb16 => ExtendedColorType::Rgb16, 325| 18| 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.72k| } _RINvMs_NtCs4rpmEmvDwFM_5image5errorNtB5_13DecodingError3newNtNtNtCshdzP3jLBsmJ_3png7decoder6stream13DecodingErrorEB7_: 226| 1.84k| pub fn new(format: ImageFormatHint, err: impl Into>) -> Self { 227| 1.84k| DecodingError { 228| 1.84k| format, 229| 1.84k| underlying: Some(err.into()), 230| 1.84k| } 231| 1.84k| } _RNvMs2_NtCs4rpmEmvDwFM_5image5errorNtB5_10LimitError9from_kind: 298| 328| pub fn from_kind(kind: LimitErrorKind) -> Self { 299| 328| LimitError { kind } 300| 328| } _RNvXs6_NtCs4rpmEmvDwFM_5image5errorNtB5_15ImageFormatHintINtNtCs6SNw0SRvItZ_4core7convert4FromNtNtNtB7_2io6format11ImageFormatE4from: 328| 1.84k| fn from(format: ImageFormat) -> Self { 329| 1.84k| ImageFormatHint::Exact(format) 330| 1.84k| } _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16check_image_fits0Bb_: 635| 901| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_len0Bb_: 640| 901| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_lens_0Bb_: 641| 901| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color3RgbtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16check_image_fits0Bb_: 635| 12| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color3RgbtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_len0Bb_: 640| 12| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color3RgbtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_lens_0Bb_: 641| 12| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4LumahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16check_image_fits0Bb_: 635| 492| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4LumahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_len0Bb_: 640| 492| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4LumahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_lens_0Bb_: 641| 492| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4LumatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16check_image_fits0Bb_: 635| 226| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4LumatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_len0Bb_: 640| 226| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4LumatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_lens_0Bb_: 641| 226| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16check_image_fits0Bb_: 635| 46| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_len0Bb_: 640| 46| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_lens_0Bb_: 641| 46| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4RgbatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16check_image_fits0Bb_: 635| 18| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4RgbatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_len0Bb_: 640| 18| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4RgbatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_lens_0Bb_: 641| 18| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color5LumaAhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16check_image_fits0Bb_: 635| 15| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color5LumaAhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_len0Bb_: 640| 15| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color5LumaAhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_lens_0Bb_: 641| 15| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16check_image_fits0Bb_: 635| 18| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_len0Bb_: 640| 18| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_lens_0Bb_: 641| 18| .and_then(|size| size.checked_mul(height as usize)) _RNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16check_image_fitsB9_: 633| 901| fn check_image_fits(width: u32, height: u32, len: usize) -> bool { 634| 901| let checked_len = Self::image_buffer_len(width, height); 635| 901| checked_len.is_some_and(|min_len| min_len <= len) 636| 901| } _RNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_lenB9_: 638| 901| fn image_buffer_len(width: u32, height: u32) -> Option { 639| 901| Some(

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

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

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

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

::CHANNEL_COUNT as usize) 640| 15| .and_then(|size| size.checked_mul(width as usize)) 641| 15| .and_then(|size| size.checked_mul(height as usize)) 642| 15| } _RNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE8from_rawB9_: 511| 15| pub fn from_raw(width: u32, height: u32, buf: Container) -> Option> { 512| 15| if Self::check_image_fits(width, height, buf.len()) { 513| 15| Some(ImageBuffer { 514| 15| data: buf, 515| 15| width, 516| 15| height, 517| 15| color: Cicp::SRGB.into_rgb(), 518| 15| _phantom: PhantomData, 519| 15| }) 520| | } else { 521| 0| None 522| | } 523| 15| } _RNvMsn_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16check_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_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_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_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE8from_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| } _RNvMsr_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE17set_rgb_primariesB9_: 1076| 901| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 901| self.color.primaries = color; 1078| 901| } _RNvMsr_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE21set_transfer_functionB9_: 1088| 901| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 901| self.color.transfer = tf; 1090| 901| } _RNvMsr_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE17set_rgb_primariesB9_: 1076| 12| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 12| self.color.primaries = color; 1078| 12| } _RNvMsr_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE21set_transfer_functionB9_: 1088| 12| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 12| self.color.transfer = tf; 1090| 12| } _RNvMsr_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4LumahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE17set_rgb_primariesB9_: 1076| 492| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 492| self.color.primaries = color; 1078| 492| } _RNvMsr_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4LumahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE21set_transfer_functionB9_: 1088| 492| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 492| self.color.transfer = tf; 1090| 492| } _RNvMsr_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4LumatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE17set_rgb_primariesB9_: 1076| 226| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 226| self.color.primaries = color; 1078| 226| } _RNvMsr_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4LumatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE21set_transfer_functionB9_: 1088| 226| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 226| self.color.transfer = tf; 1090| 226| } _RNvMsr_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE17set_rgb_primariesB9_: 1076| 46| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 46| self.color.primaries = color; 1078| 46| } _RNvMsr_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE21set_transfer_functionB9_: 1088| 46| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 46| self.color.transfer = tf; 1090| 46| } _RNvMsr_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE17set_rgb_primariesB9_: 1076| 18| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 18| self.color.primaries = color; 1078| 18| } _RNvMsr_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE21set_transfer_functionB9_: 1088| 18| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 18| self.color.transfer = tf; 1090| 18| } _RNvMsr_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE17set_rgb_primariesB9_: 1076| 15| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 15| self.color.primaries = color; 1078| 15| } _RNvMsr_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE21set_transfer_functionB9_: 1088| 15| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 15| self.color.transfer = tf; 1090| 15| } _RNvMsr_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE17set_rgb_primariesB9_: 1076| 18| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 18| self.color.primaries = color; 1078| 18| } _RNvMsr_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE21set_transfer_functionB9_: 1088| 18| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 18| self.color.transfer = tf; 1090| 18| } _RNvXst_NtNtCs4rpmEmvDwFM_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEENtNtCs6SNw0SRvItZ_4core7default7Default7defaultB9_: 1189| 9.46k| fn default() -> Self { 1190| 9.46k| Self { 1191| 9.46k| width: 0, 1192| 9.46k| height: 0, 1193| 9.46k| _phantom: PhantomData, 1194| 9.46k| color: Cicp::SRGB.into_rgb(), 1195| 9.46k| data: Default::default(), 1196| 9.46k| } 1197| 9.46k| } _RNvNtNtCs4rpmEmvDwFM_5image6images8dynimage28load_from_memory_with_format: 1955| 9.46k|pub fn load_from_memory_with_format(buf: &[u8], format: ImageFormat) -> ImageResult { 1956| | // Note: this function (and `load_from_memory`) were supposed to be generic over `AsRef<[u8]>` 1957| | // so that we do not monomorphize copies of all our decoders unless some downsteam crate 1958| | // actually calls one of these functions. See https://github.com/image-rs/image/pull/2470. 1959| | // 1960| | // However the type inference break of this is apparently quite large in the ecosystem so for 1961| | // now they are unfortunately not. See https://github.com/image-rs/image/issues/2585. 1962| 9.46k| let b = io::Cursor::new(buf); 1963| 9.46k| free_functions::load(b, format) 1964| 9.46k|} _RNvMs_NtNtCs4rpmEmvDwFM_5image6images8dynimageNtB4_12DynamicImage10decode_raw: 280| 5.78k| pub(crate) fn decode_raw( 281| 5.78k| &mut self, 282| 5.78k| decoder: &mut dyn ImageDecoder, 283| 5.78k| layout: DecoderPreparedImage, 284| 5.78k| ) -> ImageResult { 285| 5.78k| decoder_to_image(self, decoder, layout) 286| 5.78k| } _RNvMs_NtNtCs4rpmEmvDwFM_5image6images8dynimageNtB4_12DynamicImage17set_rgb_primaries: 929| 1.72k| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 930| 1.72k| dynamic_map!(self, ref mut p, p.set_rgb_primaries(color)); 931| 1.72k| } _RNvMs_NtNtCs4rpmEmvDwFM_5image6images8dynimageNtB4_12DynamicImage21set_transfer_function: 939| 1.72k| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 940| 1.72k| dynamic_map!(self, ref mut p, p.set_transfer_function(tf)); 941| 1.72k| } _RNvNtNtCs4rpmEmvDwFM_5image6images8dynimage16decoder_to_image: 1789| 5.78k|pub(crate) fn decoder_to_image( 1790| 5.78k| image: &mut DynamicImage, 1791| 5.78k| decoder: &mut dyn ImageDecoder, 1792| 5.78k| layout: DecoderPreparedImage, 1793| 5.78k|) -> ImageResult { 1794| | let crate::ImageLayout { 1795| 5.78k| width: w, 1796| 5.78k| height: h, 1797| 5.78k| color: color_type, 1798| | .. 1799| 5.78k| } = layout.layout; 1800| | 1801| | let attr; 1802| | 1803| 5.78k| *image = match color_type { 1804| | ColorType::Rgb8 => { 1805| | let buf; 1806| 1.66k| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1807| 901| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgb8) 1808| | } 1809| | 1810| | ColorType::Rgba8 => { 1811| | let buf; 1812| 348| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1813| 46| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgba8) 1814| | } 1815| | 1816| | ColorType::L8 => { 1817| | let buf; 1818| 1.92k| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1819| 492| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLuma8) 1820| | } 1821| | 1822| | ColorType::La8 => { 1823| | let buf; 1824| 338| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1825| 15| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLumaA8) 1826| | } 1827| | 1828| | ColorType::Rgb16 => { 1829| | let buf; 1830| 406| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1831| 12| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgb16) 1832| | } 1833| | 1834| | ColorType::Rgba16 => { 1835| | let buf; 1836| 237| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1837| 18| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgba16) 1838| | } 1839| | 1840| | ColorType::Rgb32F => { 1841| | let buf; 1842| 0| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1843| 0| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgb32F) 1844| | } 1845| | 1846| | ColorType::Rgba32F => { 1847| | let buf; 1848| 0| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1849| 0| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgba32F) 1850| | } 1851| | 1852| | ColorType::L16 => { 1853| | let buf; 1854| 645| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1855| 226| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLuma16) 1856| | } 1857| | 1858| | ColorType::La16 => { 1859| | let buf; 1860| 219| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1861| 18| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLumaA16) 1862| | } 1863| | 1864| | ColorType::L32F => { 1865| | let buf; 1866| 0| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1867| 0| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLuma32F) 1868| | } 1869| | 1870| | ColorType::La32F => { 1871| | let buf; 1872| 0| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1873| 0| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLumaA32F) 1874| | } 1875| | } 1876| 1.72k| .ok_or_else(|| { 1877| | ImageError::Parameter(ParameterError::from_kind( 1878| | ParameterErrorKind::DimensionMismatch, 1879| | )) 1880| 0| })?; 1881| | 1882| | // Presume SRGB for now. This is the one we convert into in some decoders and the one that is 1883| | // most widely used in the wild. FIXME: add an API to decoder to indicate the color space as a 1884| | // CICP directly or through interpreting the ICC information. 1885| 1.72k| image.set_rgb_primaries(Cicp::SRGB.primaries); 1886| 1.72k| image.set_transfer_function(Cicp::SRGB.transfer); 1887| | 1888| 1.72k| Ok(attr) 1889| 5.78k|} _RNvXse_NtNtCs4rpmEmvDwFM_5image6images8dynimageNtB5_12DynamicImageNtNtCs6SNw0SRvItZ_4core7default7Default7default: 1781| 9.46k| fn default() -> Self { 1782| 9.46k| Self::ImageRgba8(Default::default()) 1783| 9.46k| } _RNvMs1_NtCs4rpmEmvDwFM_5image2ioNtB5_20DecoderPreparedImage11total_bytes: 146| 17.5k| pub fn total_bytes(&self) -> u64 { 147| 17.5k| self.layout.total_bytes() 148| 17.5k| } _RNvMs1_NtCs4rpmEmvDwFM_5image2ioNtB5_20DecoderPreparedImage3new: 132| 17.5k| pub fn new(w: u32, h: u32, color: crate::ColorType) -> DecoderPreparedImage { 133| 17.5k| DecoderPreparedImage { 134| 17.5k| layout: ImageLayout::new(w, h, color), 135| 17.5k| } 136| 17.5k| } _RNvMs_NtCs4rpmEmvDwFM_5image2ioNtB4_11ImageLayout11total_bytes: 91| 17.5k| pub fn total_bytes(&self) -> u64 { 92| 17.5k| let ImageLayout { width, height, .. } = *self; 93| 17.5k| let total_pixels = u64::from(width) * u64::from(height); 94| 17.5k| let bytes_per_pixel = u64::from(self.color.bytes_per_pixel()); 95| 17.5k| total_pixels.saturating_mul(bytes_per_pixel) 96| 17.5k| } _RNvMs_NtCs4rpmEmvDwFM_5image2ioNtB4_11ImageLayout3new: 60| 17.5k| pub fn new(w: u32, h: u32, color: crate::ColorType) -> ImageLayout { 61| 17.5k| ImageLayout { 62| 17.5k| color, 63| 17.5k| width: w, 64| 17.5k| height: h, 65| 17.5k| } 66| 17.5k| } _RNvXs_NtNtCs4rpmEmvDwFM_5image2io7decoderINtNtCshDtJu3Ru83O_5alloc5boxed3BoxDNtB4_12ImageDecoderEL_EB1d_10set_limitsB8_: 318| 9.46k| fn set_limits(&mut self, limits: crate::Limits) -> ImageResult<()> { 319| 9.46k| (**self).set_limits(limits) 320| 9.46k| } _RNvXs_NtNtCs4rpmEmvDwFM_5image2io7decoderINtNtCshDtJu3Ru83O_5alloc5boxed3BoxDNtB4_12ImageDecoderEL_EB1d_13prepare_imageB8_: 297| 9.46k| fn prepare_image(&mut self) -> ImageResult { 298| 9.46k| (**self).prepare_image() 299| 9.46k| } _RNvXs_NtNtCs4rpmEmvDwFM_5image2io7decoderINtNtCshDtJu3Ru83O_5alloc5boxed3BoxDNtB4_12ImageDecoderEL_EB1d_17format_attributesB8_: 294| 6.02k| fn format_attributes(&self) -> FormatAttributes { 295| 6.02k| (**self).format_attributes() 296| 6.02k| } _RINvNtNtCs4rpmEmvDwFM_5image2io14free_functions4loadINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEECs89KXAlqehWX_17fuzzer_script_png: 22| 9.46k|pub fn load(r: R, format: ImageFormat) -> ImageResult { 23| 9.46k| let mut reader = ImageReaderOptions::new(r); 24| 9.46k| reader.set_format(format); 25| 9.46k| reader.decode() 26| 9.46k|} _RINvNtNtCs4rpmEmvDwFM_5image2io14free_functions14decoder_to_vechDNtNtB4_7decoder12ImageDecoderEL_EB6_: 170| 4.27k|pub(crate) fn decoder_to_vec( 171| 4.27k| decoder: &mut (impl ImageDecoder + ?Sized), 172| 4.27k|) -> ImageResult<(Vec, DecodedImageAttributes)> 173| 4.27k|where 174| 4.27k| T: crate::traits::Primitive + bytemuck::Pod, 175| |{ 176| 4.27k| let total_bytes = usize::try_from(decoder.prepare_image()?.total_bytes()); 177| 4.27k| 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.27k| } 182| | 183| 4.27k| let mut buf = vec![num_traits::Zero::zero(); total_bytes.unwrap() / size_of::()]; 184| 4.27k| let attr = decoder.read_image(bytemuck::cast_slice_mut(buf.as_mut_slice()))?; 185| 1.45k| Ok((buf, attr)) 186| 4.27k|} _RINvNtNtCs4rpmEmvDwFM_5image2io14free_functions14decoder_to_vectDNtNtB4_7decoder12ImageDecoderEL_EB6_: 170| 1.50k|pub(crate) fn decoder_to_vec( 171| 1.50k| decoder: &mut (impl ImageDecoder + ?Sized), 172| 1.50k|) -> ImageResult<(Vec, DecodedImageAttributes)> 173| 1.50k|where 174| 1.50k| T: crate::traits::Primitive + bytemuck::Pod, 175| |{ 176| 1.50k| let total_bytes = usize::try_from(decoder.prepare_image()?.total_bytes()); 177| 1.50k| 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.50k| } 182| | 183| 1.50k| let mut buf = vec![num_traits::Zero::zero(); total_bytes.unwrap() / size_of::()]; 184| 1.50k| let attr = decoder.read_image(bytemuck::cast_slice_mut(buf.as_mut_slice()))?; 185| 274| Ok((buf, attr)) 186| 1.50k|} _RNvMNtNtCs4rpmEmvDwFM_5image2io17image_reader_typeINtB2_18ImageReaderOptionsINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE10set_formatCs89KXAlqehWX_17fuzzer_script_png: 139| 9.46k| pub fn set_format(&mut self, format: ImageFormat) { 140| 9.46k| self.format = Some(Format::BuiltIn(format)); 141| 9.46k| } _RNCNvMs3_NtNtCs4rpmEmvDwFM_5image2io17image_reader_typeNtB7_20DecodedImageMetadata13apply_metdata0Bb_: 937| 34| orientation = exif.and_then(|chunk| Orientation::from_exif_chunk(&chunk)); _RNvMNtNtCs4rpmEmvDwFM_5image2io17image_reader_typeINtB2_18ImageReaderOptionsINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE11into_readerB6_: 257| 9.46k| pub fn into_reader(mut self) -> ImageResult> { 258| 9.46k| let format = self.require_format()?; 259| 9.46k| let decoder = Self::make_decoder(format, self.inner, self.spec_compliance)?; 260| 9.46k| let mut reader = ImageReader::from_decoder(decoder); 261| 9.46k| reader.set_limits(self.limits)?; 262| 9.46k| Ok(reader) 263| 9.46k| } _RNvMNtNtCs4rpmEmvDwFM_5image2io17image_reader_typeINtB2_18ImageReaderOptionsINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE12make_decoderB6_: 176| 9.46k| fn make_decoder( 177| 9.46k| format: Format, 178| 9.46k| reader: R, 179| 9.46k| spec_compliance: SpecCompliance, 180| 9.46k| ) -> ImageResult> { 181| | #[allow(unused)] 182| | use crate::codecs::*; 183| | 184| 9.46k| let format = match format { 185| 9.46k| 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.46k| Ok(match format { 200| | #[cfg(feature = "avif-native")] 201| | ImageFormat::Avif => Box::new(avif::AvifDecoder::new(reader)?), 202| | #[cfg(feature = "png")] 203| 9.46k| 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.46k| } _RNvMNtNtCs4rpmEmvDwFM_5image2io17image_reader_typeINtB2_18ImageReaderOptionsINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE14require_formatB6_: 344| 9.46k| fn require_format(&mut self) -> ImageResult { 345| 9.46k| 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.46k| } _RNvMNtNtCs4rpmEmvDwFM_5image2io17image_reader_typeINtB2_18ImageReaderOptionsINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE3newB6_: 107| 9.46k| pub fn new(buffered_reader: R) -> Self { 108| 9.46k| ImageReaderOptions { 109| 9.46k| inner: buffered_reader, 110| 9.46k| format: None, 111| 9.46k| limits: Limits::default(), 112| 9.46k| spec_compliance: SpecCompliance::default(), 113| 9.46k| } 114| 9.46k| } _RNvMNtNtCs4rpmEmvDwFM_5image2io17image_reader_typeINtB2_18ImageReaderOptionsINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE6decodeB6_: 339| 9.46k| pub fn decode(self) -> ImageResult { 340| 9.46k| let (image, _meta) = self.into_reader()?.decode()?; 341| 1.72k| Ok(image) 342| 9.46k| } _RNvMs0_NtNtCs4rpmEmvDwFM_5image2io17image_reader_typeNtB5_13MetadataBlock11is_not_none: 433| 24.1k| fn is_not_none(&self) -> bool { 434| 24.1k| !matches!(self, MetadataBlock::None) 435| 24.1k| } _RNvMs0_NtNtCs4rpmEmvDwFM_5image2io17image_reader_typeNtB5_13MetadataBlock3get: 437| 3.45k| fn get(&mut self) -> ImageResult>> { 438| 3.45k| match self { 439| 1.86k| MetadataBlock::None => Ok(None), 440| 1.59k| 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.45k| } _RNvMs2_NtNtCs4rpmEmvDwFM_5image2io17image_reader_typeNtB5_11ImageReader10set_limits: 801| 9.46k| pub fn set_limits(&mut self, mut limits: Limits) -> ImageResult<()> { 802| 9.46k| if let Some(max_alloc) = &mut limits.max_alloc { 803| 9.46k| // We'll take half for ourselves, half to the decoder. 804| 9.46k| *max_alloc /= 2; 805| 9.46k| } 806| | 807| 9.46k| self.inner.set_limits(limits.clone())?; 808| 9.46k| self.limits = limits; 809| 9.46k| Ok(()) 810| 9.46k| } _RNvMs2_NtNtCs4rpmEmvDwFM_5image2io17image_reader_typeNtB5_11ImageReader12from_decoder: 790| 9.46k| pub fn from_decoder(boxed: Box) -> Self { 791| 9.46k| ImageReader { 792| 9.46k| inner: boxed, 793| 9.46k| settings: ImageReaderSettings::default(), 794| 9.46k| limits: Limits::default(), 795| 9.46k| last_attributes: Default::default(), 796| 9.46k| metadata_buffers: MetadataBuffers::default(), 797| 9.46k| } 798| 9.46k| } _RNvMs2_NtNtCs4rpmEmvDwFM_5image2io17image_reader_typeNtB5_11ImageReader18decode_to_dynimage: 541| 9.46k| pub(crate) fn decode_to_dynimage( 542| 9.46k| &mut self, 543| 9.46k| image: &mut DynamicImage, 544| 9.46k| ) -> ImageResult> { 545| 9.46k| let layout = self.inner.prepare_image()?; 546| 6.02k| self.fill_header_metadata_if_any(); 547| | 548| | // This is technically redundant but it's also cheap. 549| 6.02k| 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.02k| self.limits.reserve(layout.total_bytes())?; 553| | 554| | // Retrieve the raw image data as indicated by the layout. 555| 5.78k| self.last_attributes = image.decode_raw(self.inner.as_mut(), layout)?; 556| | 557| 1.72k| let mut meta = DecodedImageMetadata { 558| 1.72k| inner: self.inner.as_mut(), 559| 1.72k| attributes: &mut self.last_attributes, 560| 1.72k| metadata_buffers: &mut self.metadata_buffers, 561| 1.72k| }; 562| | 563| 1.72k| meta.apply_metdata(&self.settings, image)?; 564| | 565| 1.72k| Ok(meta) 566| 9.46k| } _RNvMs2_NtNtCs4rpmEmvDwFM_5image2io17image_reader_typeNtB5_11ImageReader27fill_header_metadata_if_any: 658| 6.02k| 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.02k| let first_meta_retrieved = self.metadata_buffers.first_meta_retrieved; 664| 6.02k| let format_attrs = self.inner.format_attributes(); 665| | 666| 6.02k| let attributes = [ 667| 6.02k| ( 668| 6.02k| format_attrs.exif, 669| 6.02k| &mut self.metadata_buffers.exif, 670| 6.02k| ::exif_metadata as MetadataFn, 671| 6.02k| ), 672| 6.02k| ( 673| 6.02k| format_attrs.icc, 674| 6.02k| &mut self.metadata_buffers.icc, 675| 6.02k| ::icc_profile as MetadataFn, 676| 6.02k| ), 677| 6.02k| ( 678| 6.02k| format_attrs.xmp, 679| 6.02k| &mut self.metadata_buffers.xmp, 680| 6.02k| ::xmp_metadata as MetadataFn, 681| 6.02k| ), 682| 6.02k| ( 683| 6.02k| format_attrs.iptc, 684| 6.02k| &mut self.metadata_buffers.iptc, 685| 6.02k| ::iptc_metadata as MetadataFn, 686| 6.02k| ), 687| 6.02k| ]; 688| | 689| 30.1k| for (hint, buffer, getter) in attributes { 690| 24.1k| let should_buffer_now = match hint { 691| 24.1k| DecodedMetadataHint::InHeader => !first_meta_retrieved, 692| 0| DecodedMetadataHint::PerImage => true, 693| 0| DecodedMetadataHint::Unsupported | DecodedMetadataHint::None => false, 694| | }; 695| | 696| 24.1k| if !should_buffer_now { 697| 0| continue; 698| 24.1k| } 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.1k| if matches!(hint, DecodedMetadataHint::InHeader) && buffer.is_not_none() { 704| 0| continue; 705| 24.1k| } 706| | 707| 24.1k| match getter(self.inner.as_mut()) { 708| 22.4k| Ok(None) => *buffer = MetadataBlock::None, 709| 1.67k| Ok(Some(metadata)) => *buffer = MetadataBlock::Ok(metadata), 710| 26| Err(err) => { 711| 26| *buffer = MetadataBlock::Err(err); 712| 26| } 713| | } 714| | } 715| | 716| | // Note: on error we do not set this flag. You can try again. 717| 6.02k| self.metadata_buffers.first_meta_retrieved = true; 718| 6.02k| } _RNvMs2_NtNtCs4rpmEmvDwFM_5image2io17image_reader_typeNtB5_11ImageReader6decode: 511| 9.46k| pub fn decode(&mut self) -> ImageResult<(DynamicImage, DecodedImageMetadata<'_>)> { 512| 9.46k| let mut empty = DynamicImage::default(); 513| 9.46k| let meta = self.decode_to_dynimage(&mut empty)?; 514| 1.72k| Ok((empty, meta)) 515| 9.46k| } _RNvMs3_NtNtCs4rpmEmvDwFM_5image2io17image_reader_typeNtB5_20DecodedImageMetadata11icc_profile: 875| 1.72k| pub fn icc_profile(&mut self) -> ImageResult>> { 876| 1.72k| Self::access_block_with( 877| 1.72k| &mut self.metadata_buffers.icc, 878| 1.72k| self.inner.format_attributes().icc, 879| 1.72k| self.inner, 880| 1.72k| ::icc_profile, 881| | ) 882| 1.72k| } _RNvMs3_NtNtCs4rpmEmvDwFM_5image2io17image_reader_typeNtB5_20DecodedImageMetadata13apply_metdata: 904| 1.72k| fn apply_metdata( 905| 1.72k| &mut self, 906| 1.72k| settings: &ImageReaderSettings, 907| 1.72k| image: &mut DynamicImage, 908| 1.72k| ) -> Result<(), ImageError> { 909| | // Run all the metadata extraction which we may need. 910| 1.72k| let icc = self.icc_profile()?; 911| 1.72k| 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.72k| if let Some(icc) = icc { 918| 1.56k| 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.56k| } 931| 168| } 932| | 933| 1.72k| let mut orientation = self.attributes.orientation; 934| | 935| | // Determine which orientation to use. 936| 1.72k| if orientation.is_none() { 937| 1.72k| orientation = exif.and_then(|chunk| Orientation::from_exif_chunk(&chunk)); 938| 0| } 939| | 940| 1.72k| self.attributes.orientation = orientation; 941| | 942| 1.72k| if settings.apply_orientation { 943| 1.72k| if let Some(orient) = orientation { 944| 0| image.apply_orientation(orient); 945| 1.72k| } 946| 0| } 947| | 948| 1.72k| Ok(()) 949| 1.72k| } _RNvMs3_NtNtCs4rpmEmvDwFM_5image2io17image_reader_typeNtB5_20DecodedImageMetadata13exif_metadata: 865| 1.72k| pub fn exif_metadata(&mut self) -> ImageResult>> { 866| 1.72k| Self::access_block_with( 867| 1.72k| &mut self.metadata_buffers.exif, 868| 1.72k| self.inner.format_attributes().exif, 869| 1.72k| self.inner, 870| 1.72k| ::exif_metadata, 871| | ) 872| 1.72k| } _RNvMs3_NtNtCs4rpmEmvDwFM_5image2io17image_reader_typeNtB5_20DecodedImageMetadata17access_block_with: 951| 3.45k| fn access_block_with<'l>( 952| 3.45k| block: &mut MetadataBlock, 953| 3.45k| meta: DecodedMetadataHint, 954| 3.45k| decoder: &mut (dyn ImageDecoder + 'l), 955| 3.45k| access: fn(&'_ mut (dyn ImageDecoder + 'l)) -> ImageResult>>, 956| 3.45k| ) -> ImageResult>> { 957| 3.45k| match meta { 958| | DecodedMetadataHint::InHeader => { 959| 3.45k| if matches!(block, MetadataBlock::ErrorTaken) { 960| | // We can retry this, prefer rechecking from the source. 961| 0| access(decoder) 962| | } else { 963| 3.45k| 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.45k| } _RNvXs1_NtNtCs4rpmEmvDwFM_5image2io17image_reader_typeNtB5_19ImageReaderSettingsNtNtCs6SNw0SRvItZ_4core7default7Default7default: 476| 9.46k| fn default() -> Self { 477| 9.46k| ImageReaderSettings { 478| 9.46k| apply_orientation: true, 479| 9.46k| } 480| 9.46k| } _RNvMs_NtNtCs4rpmEmvDwFM_5image2io6limitsNtB4_6Limits13check_support: 70| 18.9k| pub fn check_support(&self, _supported: &LimitSupport) -> ImageResult<()> { 71| 18.9k| Ok(()) 72| 18.9k| } _RNvMs_NtNtCs4rpmEmvDwFM_5image2io6limitsNtB4_6Limits16check_dimensions: 83| 15.2k| pub fn check_dimensions(&self, width: u32, height: u32) -> ImageResult<()> { 84| 15.2k| 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.2k| } 91| | 92| 15.2k| 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.2k| } 99| | 100| 15.2k| Ok(()) 101| 15.2k| } _RNvMs_NtNtCs4rpmEmvDwFM_5image2io6limitsNtB4_6Limits23check_layout_dimensions: 74| 6.02k| pub(crate) fn check_layout_dimensions( 75| 6.02k| &self, 76| 6.02k| layout: &crate::io::DecoderPreparedImage, 77| 6.02k| ) -> ImageResult<()> { 78| 6.02k| self.check_dimensions(layout.layout.width, layout.layout.height) 79| 6.02k| } _RNvMs_NtNtCs4rpmEmvDwFM_5image2io6limitsNtB4_6Limits7reserve: 105| 6.02k| pub fn reserve(&mut self, amount: u64) -> ImageResult<()> { 106| 6.02k| if let Some(max_alloc) = self.max_alloc.as_mut() { 107| 6.02k| if *max_alloc < amount { 108| 247| return Err(ImageError::Limits(error::LimitError::from_kind( 109| 247| error::LimitErrorKind::InsufficientMemory, 110| 247| ))); 111| 5.78k| } 112| | 113| 5.78k| *max_alloc -= amount; 114| 0| } 115| | 116| 5.78k| Ok(()) 117| 6.02k| } _RNvMs_NtNtCs4rpmEmvDwFM_5image2io6limitsNtB4_6Limits9no_limits: 61| 9.46k| pub fn no_limits() -> Limits { 62| 9.46k| Limits { 63| 9.46k| max_image_width: None, 64| 9.46k| max_image_height: None, 65| 9.46k| max_alloc: None, 66| 9.46k| } 67| 9.46k| } _RNvXNtNtCs4rpmEmvDwFM_5image2io6limitsNtB2_6LimitsNtNtCs6SNw0SRvItZ_4core7default7Default7default: 49| 18.9k| fn default() -> Limits { 50| 18.9k| Limits { 51| 18.9k| max_image_width: None, 52| 18.9k| max_image_height: None, 53| 18.9k| max_alloc: Some(512 * 1024 * 1024), 54| 18.9k| } 55| 18.9k| } _RNvMNtCs4rpmEmvDwFM_5image8metadataNtB2_11Orientation15from_exif_chunk: 95| 34| pub fn from_exif_chunk(chunk: &[u8]) -> Option { 96| 34| Self::from_exif_chunk_inner(chunk).map(|res| res.0) 97| 34| } _RNvMNtCs4rpmEmvDwFM_5image8metadataNtB2_11Orientation21from_exif_chunk_inner: 126| 34| fn from_exif_chunk_inner(chunk: &[u8]) -> Option<(Self, u64, ExifEndian)> { 127| 34| let mut reader = Cursor::new(chunk); 128| | 129| 34| let mut magic = [0; 4]; 130| 34| reader.read_exact(&mut magic).ok()?; 131| | 132| 33| match magic { 133| | [0x49, 0x49, 42, 0] => { 134| 28| return Self::locate_orientation_entry::(&mut reader) 135| 28| .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| 5| _ => {} 142| | } 143| 5| None 144| 34| } _RNvNtCs4rpmEmvDwFM_5image8metadata12cms_provider: 22| 1.56k|pub(crate) fn cms_provider() -> &'static dyn CmsProvider { 23| 1.56k| &moxcms::Moxcms 24| 1.56k|} _RINvMNtCs4rpmEmvDwFM_5image8metadataNtB3_11Orientation24locate_orientation_entryNtCs7zV65YDL4Pm_14byteorder_lite12LittleEndianEB5_: 147| 28| fn locate_orientation_entry(reader: &mut Cursor<&[u8]>) -> Option<(Self, u64)> 148| 28| where 149| 28| B: byteorder_lite::ByteOrder, 150| | { 151| 28| let ifd_offset = reader.read_u32::().ok()?; 152| 28| reader.set_position(u64::from(ifd_offset)); 153| 28| let entries = reader.read_u16::().ok()?; 154| 27| for _ in 0..entries { 155| 373| let tag = reader.read_u16::().ok()?; 156| 352| let format = reader.read_u16::().ok()?; 157| 352| let count = reader.read_u32::().ok()?; 158| 351| let value = reader.read_u16::().ok()?; 159| 350| let _padding = reader.read_u16::().ok()?; 160| 349| 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| 349| } 165| | } 166| | // If we reached this point without returning early, there was no orientation 167| 3| None 168| 28| } _RNvMs7_NtNtCs4rpmEmvDwFM_5image8metadata4cicpNtB5_4Cicp8into_rgb: 1201| 11.1k| pub(crate) const fn into_rgb(self) -> CicpRgb { 1202| 11.1k| CicpRgb { 1203| 11.1k| primaries: self.primaries, 1204| 11.1k| transfer: self.transfer, 1205| 11.1k| // NOTE: if we add support for constant luminance (through the CMS having support for 1206| 11.1k| // the Luma->YCbCr->Rgb expansion natively or otherwise) then consider if we should 1207| 11.1k| // track here whether the matrix was `Identity` or `ChromaticityDerivedNonConstant` so 1208| 11.1k| // that the `ImageBuffer::color_space()` function roundtrips the value. It may be 1209| 11.1k| // important to know whether the non-constant chromaticity was an invention by `image` 1210| 11.1k| // or part of the file. The colorimetry is the same either way. 1211| 11.1k| luminance: DerivedLuminance::NonConstant, 1212| 11.1k| } 1213| 11.1k| } _RNvXNtNtCs4rpmEmvDwFM_5image8metadata6moxcmsNtB2_6MoxcmsNtB4_11CmsProvider9parse_icc: 85| 1.56k| fn parse_icc(&self, icc: &[u8]) -> Option { 86| 1.56k| let profile = moxcms::ColorProfile::new_from_slice(icc).ok()?; 87| 495| 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.56k| }