_RNvMse_NvNtCskrDebHigSPL_3png6common1__NtB5_16InternalBitFlags10intersectsCs1vRhqpPUfvi_5image: 238| 489k| fn intersects(&self, other) { 239| 489k| self.0 & other.0 != <$T as $crate::Bits>::EMPTY _RNvMse_NvNtCskrDebHigSPL_3png6common1__NtB5_16InternalBitFlags8containsCs1vRhqpPUfvi_5image: 242| 162M| fn contains(&self, other) { 243| 162M| self.0 & other.0 == other.0 _RNvMsw_NvNtCskrDebHigSPL_3png6common1__NtB7_15Transformations10intersectsCs1vRhqpPUfvi_5image: 78| 489k| fn intersects(&self, other) { 79| 489k| self.0.intersects(other.0) _RNvMsw_NvNtCskrDebHigSPL_3png6common1__NtB7_15Transformations8containsCs1vRhqpPUfvi_5image: 82| 162M| fn contains(&self, other) { 83| 162M| self.0.contains(other.0) _RNvMse_NvNtCskrDebHigSPL_3png6common1__NtB5_16InternalBitFlags8containsB9_: 242| 10.7k| fn contains(&self, other) { 243| 10.7k| self.0 & other.0 == other.0 _RNvMsw_NvNtCskrDebHigSPL_3png6common1__NtB7_15Transformations8containsB9_: 82| 10.7k| fn contains(&self, other) { 83| 10.7k| self.0.contains(other.0) _RINvNtCs4vLsLh4rAyg_8bytemuck8internal14cast_slice_muthhECs1vRhqpPUfvi_5image: 268| 4.83k|pub(crate) unsafe fn cast_slice_mut(a: &mut [A]) -> &mut [B] { 269| 4.83k| match try_cast_slice_mut(a) { 270| 4.83k| Ok(b) => b, 271| 0| Err(e) => something_went_wrong("cast_slice_mut", e), 272| | } 273| 4.83k|} _RINvNtCs4vLsLh4rAyg_8bytemuck8internal14cast_slice_mutthECs1vRhqpPUfvi_5image: 268| 1.63k|pub(crate) unsafe fn cast_slice_mut(a: &mut [A]) -> &mut [B] { 269| 1.63k| match try_cast_slice_mut(a) { 270| 1.63k| Ok(b) => b, 271| 0| Err(e) => something_went_wrong("cast_slice_mut", e), 272| | } 273| 1.63k|} _RINvNtCs4vLsLh4rAyg_8bytemuck8internal18try_cast_slice_muthhECs1vRhqpPUfvi_5image: 381| 4.83k|pub(crate) unsafe fn try_cast_slice_mut( 382| 4.83k| a: &mut [A], 383| 4.83k|) -> Result<&mut [B], PodCastError> { 384| 4.83k| 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.83k| 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.83k| } else if size_of::() == size_of::() { 392| 4.83k| Ok(unsafe { 393| 4.83k| core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, a.len()) 394| 4.83k| }) 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.83k|} _RINvNtCs4vLsLh4rAyg_8bytemuck8internal18try_cast_slice_mutthECs1vRhqpPUfvi_5image: 381| 1.63k|pub(crate) unsafe fn try_cast_slice_mut( 382| 1.63k| a: &mut [A], 383| 1.63k|) -> Result<&mut [B], PodCastError> { 384| 1.63k| 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.63k| 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.63k| } 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.63k| } else if (size_of::() != 0 && input_bytes % size_of::() == 0) 396| 0| || (size_of::() == 0 && input_bytes == 0) 397| | { 398| 1.63k| let new_len = 399| 1.63k| if size_of::() != 0 { input_bytes / size_of::() } else { 0 }; 400| 1.63k| Ok(unsafe { 401| 1.63k| core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, new_len) 402| 1.63k| }) 403| | } else { 404| 0| Err(PodCastError::OutputSliceWouldHaveSlop) 405| | } 406| 1.63k|} _RINvCs4vLsLh4rAyg_8bytemuck14cast_slice_muthhECs1vRhqpPUfvi_5image: 423| 4.83k|pub fn cast_slice_mut< 424| 4.83k| A: NoUninit + AnyBitPattern, 425| 4.83k| B: NoUninit + AnyBitPattern, 426| 4.83k|>( 427| 4.83k| a: &mut [A], 428| 4.83k|) -> &mut [B] { 429| 4.83k| unsafe { internal::cast_slice_mut(a) } 430| 4.83k|} _RINvCs4vLsLh4rAyg_8bytemuck14cast_slice_mutthECs1vRhqpPUfvi_5image: 423| 1.63k|pub fn cast_slice_mut< 424| 1.63k| A: NoUninit + AnyBitPattern, 425| 1.63k| B: NoUninit + AnyBitPattern, 426| 1.63k|>( 427| 1.63k| a: &mut [A], 428| 1.63k|) -> &mut [B] { 429| 1.63k| unsafe { internal::cast_slice_mut(a) } 430| 1.63k|} _RINvYINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShENtNtCs7zV65YDL4Pm_14byteorder_lite2io12ReadBytesExt8read_u16NtBR_12LittleEndianECs1vRhqpPUfvi_5image: 109| 1.08k| fn read_u16(&mut self) -> Result { 110| 1.08k| let mut buf = [0; 2]; 111| 1.08k| self.read_exact(&mut buf)?; 112| 1.06k| Ok(T::read_u16(&buf)) 113| 1.08k| } _RINvYINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShENtNtCs7zV65YDL4Pm_14byteorder_lite2io12ReadBytesExt8read_u32NtBR_12LittleEndianECs1vRhqpPUfvi_5image: 214| 289| fn read_u32(&mut self) -> Result { 215| 289| let mut buf = [0; 4]; 216| 289| self.read_exact(&mut buf)?; 217| 284| Ok(T::read_u32(&buf)) 218| 289| } _RNvXs1_Cs7zV65YDL4Pm_14byteorder_liteNtB5_12LittleEndianNtB5_9ByteOrder8read_u16Cs1vRhqpPUfvi_5image: 2059| 1.06k| fn read_u16(buf: &[u8]) -> u16 { 2060| 1.06k| u16::from_le_bytes(buf[..2].try_into().unwrap()) 2061| 1.06k| } _RNvXs1_Cs7zV65YDL4Pm_14byteorder_liteNtB5_12LittleEndianNtB5_9ByteOrder8read_u32Cs1vRhqpPUfvi_5image: 2064| 284| fn read_u32(buf: &[u8]) -> u32 { 2065| 284| u32::from_le_bytes(buf[..4].try_into().unwrap()) 2066| 284| } _RNvNtCslKkLwQ76Gc1_9crc32fast8baseline11update_slow: 78| 887k|pub(crate) fn update_slow(prev: u32, buf: &[u8]) -> u32 { 79| 887k| let mut crc = !prev; 80| | 81| 6.30M| for &byte in buf.iter() { 82| 6.30M| crc = CRC32_TABLE[0][((crc as u8) ^ byte) as usize] ^ (crc >> 8); 83| 6.30M| } 84| | 85| 887k| !crc 86| 887k|} _RNvNtCslKkLwQ76Gc1_9crc32fast8baseline14update_fast_16: 55| 887k|pub(crate) fn update_fast_16(prev: u32, mut buf: &[u8]) -> u32 { 56| | const UNROLL: usize = 4; 57| | const BYTES_AT_ONCE: usize = 16 * UNROLL; 58| | 59| 887k| let mut crc = !prev; 60| | 61| 887k| while buf.len() >= BYTES_AT_ONCE { 62| 0| for _ in 0..UNROLL { 63| 0| crc = fold_16(crc, buf); 64| 0| buf = &buf[16..]; 65| 0| } 66| | } 67| | 68| | // Fold whatever whole 16-byte blocks remain rather than handing them to the 69| | // byte-at-a-time loop. 70| 887k| while buf.len() >= 16 { 71| 0| crc = fold_16(crc, buf); 72| 0| buf = &buf[16..]; 73| 0| } 74| | 75| 887k| update_slow(!crc, buf) 76| 887k|} _RNvMCslKkLwQ76Gc1_9crc32fastNtB2_6Hasher16new_with_initial: 87| 10.1k| pub fn new_with_initial(init: u32) -> Self { 88| 10.1k| Self::new_with_initial_len(init, 0) 89| 10.1k| } _RNvMCslKkLwQ76Gc1_9crc32fastNtB2_6Hasher20new_with_initial_len: 96| 10.1k| pub fn new_with_initial_len(init: u32, amount: u64) -> Self { 97| 10.1k| Self::internal_new_specialized(init, amount) 98| 10.1k| .unwrap_or_else(|| Self::internal_new_baseline(init, amount)) 99| 10.1k| } _RNvMCslKkLwQ76Gc1_9crc32fastNtB2_6Hasher24internal_new_specialized: 112| 10.1k| pub fn internal_new_specialized(init: u32, amount: u64) -> Option { 113| | { 114| 10.1k| if let Some(state) = specialized::State::new(init) { 115| 10.1k| return Some(Hasher { 116| 10.1k| amount, 117| 10.1k| state: State::Specialized(state), 118| 10.1k| }); 119| 0| } 120| | } 121| 0| None 122| 10.1k| } _RNvMCslKkLwQ76Gc1_9crc32fastNtB2_6Hasher3new: 79| 10.1k| pub fn new() -> Self { 80| 10.1k| Self::new_with_initial(DEFAULT_INIT_STATE) 81| 10.1k| } _RNvMCslKkLwQ76Gc1_9crc32fastNtB2_6Hasher5reset: 142| 147k| pub fn reset(&mut self) { 143| 147k| self.amount = 0; 144| 147k| match self.state { 145| 0| State::Baseline(ref mut state) => state.reset(), 146| 147k| State::Specialized(ref mut state) => state.reset(), 147| | } 148| 147k| } _RNvMCslKkLwQ76Gc1_9crc32fastNtB2_6Hasher6update: 125| 971k| pub fn update(&mut self, buf: &[u8]) { 126| 971k| self.amount += buf.len() as u64; 127| 971k| match self.state { 128| 0| State::Baseline(ref mut state) => state.update(buf), 129| 971k| State::Specialized(ref mut state) => state.update(buf), 130| | } 131| 971k| } _RNvMCslKkLwQ76Gc1_9crc32fastNtB2_6Hasher8finalize: 134| 142k| pub fn finalize(self) -> u32 { 135| 142k| match self.state { 136| 0| State::Baseline(state) => state.finalize(), 137| 142k| State::Specialized(state) => state.finalize(), 138| | } 139| 142k| } _RNCNvMNtNtCslKkLwQ76Gc1_9crc32fast11specialized9pclmulqdqNtB4_5State3new0B8_: 90| 10.1k| Self::detect().map(|kind| Self { state, kind }) _RNvMNtNtCslKkLwQ76Gc1_9crc32fast11specialized9pclmulqdqNtB2_5State3new: 88| 10.1k| pub fn new(state: u32) -> Option { 89| | // SAFETY: `detect` only returns a `Kind` whose instructions the CPU supports. 90| 10.1k| Self::detect().map(|kind| Self { state, kind }) 91| 10.1k| } _RNvMNtNtCslKkLwQ76Gc1_9crc32fast11specialized9pclmulqdqNtB2_5State5reset: 110| 147k| pub fn reset(&mut self) { 111| 147k| self.state = 0; 112| 147k| } _RNvMNtNtCslKkLwQ76Gc1_9crc32fast11specialized9pclmulqdqNtB2_5State6detect: 66| 10.1k| fn detect() -> Option { 67| 10.1k| if is_x86_feature_detected!("pclmulqdq") 68| 10.1k| && is_x86_feature_detected!("sse2") 69| 10.1k| && is_x86_feature_detected!("sse4.1") 70| 10.1k| && is_x86_feature_detected!("ssse3") 71| | { 72| | #[cfg(stable_vpclmulqdq)] 73| | { 74| 10.1k| if is_x86_feature_detected!("avx512f") && is_x86_feature_detected!("vpclmulqdq") { 75| 0| return Some(Kind::Avx512); 76| 10.1k| } 77| 10.1k| if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("vpclmulqdq") { 78| 0| return Some(Kind::Avx2); 79| 10.1k| } 80| | } 81| | 82| 10.1k| return Some(Kind::Sse); 83| 0| } 84| | 85| 0| None 86| 10.1k| } _RNvMNtNtCslKkLwQ76Gc1_9crc32fast11specialized9pclmulqdqNtB2_5State6update: 93| 971k| pub fn update(&mut self, buf: &[u8]) { 94| | // SAFETY: `State::new` ensured the CPU supports the instructions for `self.kind`. 95| | self.state = unsafe { 96| 971k| match self.kind { 97| 971k| Kind::Sse => calculate(self.state, buf), 98| | #[cfg(stable_vpclmulqdq)] 99| 0| Kind::Avx2 => calculate_avx2(self.state, buf), 100| | #[cfg(stable_vpclmulqdq)] 101| 0| Kind::Avx512 => calculate_avx512(self.state, buf), 102| | } 103| | } 104| 971k| } _RNvMNtNtCslKkLwQ76Gc1_9crc32fast11specialized9pclmulqdqNtB2_5State8finalize: 106| 142k| pub fn finalize(self) -> u32 { 107| 142k| self.state 108| 142k| } _RNvNtNtCslKkLwQ76Gc1_9crc32fast11specialized9pclmulqdq17reduce_128_to_crc: 331| 83.9k|unsafe fn reduce_128_to_crc(mut x: arch::__m128i, mut data: &[u8]) -> u32 { 332| 83.9k| let k3k4 = arch::_mm_set_epi64x(K4, K3); 333| | 334| | // Fold by 1 over any remaining whole 16-byte blocks. 335| 182k| while data.len() >= 16 { 336| 99.0k| x = reduce128(x, get(&mut data), k3k4); 337| 99.0k| } 338| | 339| | // Fold a final partial block of `n` (1..=15) bytes. The last `n` bytes of the accumulator are 340| | // shifted out (`overflow`) and folded back by 128 bits, while `x` is shifted down to make room 341| | // for the `n` new bytes, which are byte-aligned into the vacated high lanes. The shuffle masks 342| | // are built at runtime from the byte length, avoiding a lookup table. 343| 83.9k| let n = data.len(); 344| 83.9k| if n > 0 { 345| 67.6k| let seq = arch::_mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); 346| 67.6k| let shl = arch::_mm_add_epi8(seq, arch::_mm_set1_epi8(n as i8 - 16)); 347| 67.6k| let shr = arch::_mm_xor_si128(shl, arch::_mm_set1_epi8(-128)); 348| 67.6k| 349| 67.6k| let overflow = arch::_mm_shuffle_epi8(x, shl); 350| 67.6k| x = arch::_mm_shuffle_epi8(x, shr); 351| 67.6k| 352| 67.6k| let mut part = [0u8; 16]; 353| 67.6k| part[..n].copy_from_slice(data); 354| 67.6k| let part = arch::_mm_loadu_si128(part.as_ptr() as *const arch::__m128i); 355| 67.6k| x = arch::_mm_xor_si128(x, arch::_mm_shuffle_epi8(part, shl)); 356| 67.6k| 357| 67.6k| x = reduce128(overflow, x, k3k4); 358| 67.6k| } 359| | 360| | // Perform step 3, reduction from 128 bits to 64 bits. This is 361| | // significantly different from the paper and basically doesn't follow it 362| | // at all. It's not really clear why, but implementations of this algorithm 363| | // in Chrome/Linux diverge in the same way. It is beyond me why this is 364| | // different than the paper, maybe the paper has like errata or something? 365| | // Unclear. 366| | // 367| | // It's also not clear to me what's actually happening here and/or why, but 368| | // algebraically what's happening is: 369| | // 370| | // x = (x[0:63] • K4) ^ x[64:127] // 96 bit result 371| | // x = ((x[0:31] as u64) • K5) ^ x[32:95] // 64 bit result 372| | // 373| | // It's... not clear to me what's going on here. The paper itself is pretty 374| | // vague on this part but definitely uses different constants at least. 375| | // It's not clear to me, reading the paper, where the xor operations are 376| | // happening or why things are shifting around. This implementation... 377| | // appears to work though! 378| 83.9k| let x = arch::_mm_xor_si128( 379| 83.9k| arch::_mm_clmulepi64_si128(x, k3k4, 0x10), 380| 83.9k| arch::_mm_srli_si128(x, 8), 381| | ); 382| 83.9k| let x = arch::_mm_xor_si128( 383| 83.9k| arch::_mm_clmulepi64_si128( 384| 83.9k| arch::_mm_and_si128(x, arch::_mm_set_epi32(0, 0, 0, !0)), 385| 83.9k| arch::_mm_set_epi64x(0, K5), 386| | 0x00, 387| | ), 388| 83.9k| arch::_mm_srli_si128(x, 4), 389| | ); 390| | 391| | // Perform a Barrett reduction from our now 64 bits to 32 bits. The 392| | // algorithm for this is described at the end of the paper, and note that 393| | // this also implements the "bit reflected input" variant. 394| 83.9k| let pu = arch::_mm_set_epi64x(U_PRIME, P_X); 395| | 396| | // T1(x) = ⌊(R(x) % x^32)⌋ • μ 397| 83.9k| let t1 = arch::_mm_clmulepi64_si128( 398| 83.9k| arch::_mm_and_si128(x, arch::_mm_set_epi32(0, 0, 0, !0)), 399| 83.9k| pu, 400| | 0x10, 401| | ); 402| | // T2(x) = ⌊(T1(x) % x^32)⌋ • P(x) 403| 83.9k| let t2 = arch::_mm_clmulepi64_si128( 404| 83.9k| arch::_mm_and_si128(t1, arch::_mm_set_epi32(0, 0, 0, !0)), 405| 83.9k| pu, 406| | 0x00, 407| | ); 408| | // We're doing the bit-reflected variant, so get the upper 32-bits of the 409| | // 64-bit result instead of the lower 32-bits. 410| | // 411| | // C(x) = R(x) ^ T2(x) / x^32 412| 83.9k| !(arch::_mm_extract_epi32(arch::_mm_xor_si128(x, t2), 1) as u32) 413| 83.9k|} _RNvNtNtCslKkLwQ76Gc1_9crc32fast11specialized9pclmulqdq3get: 442| 2.10M|unsafe fn get(a: &mut &[u8]) -> arch::__m128i { 443| 2.10M| debug_assert!(a.len() >= 16); 444| 2.10M| let r = arch::_mm_loadu_si128(a.as_ptr() as *const arch::__m128i); 445| 2.10M| *a = &a[16..]; 446| 2.10M| r 447| 2.10M|} _RNvNtNtCslKkLwQ76Gc1_9crc32fast11specialized9pclmulqdq9calculate: 152| 971k|unsafe fn calculate(crc: u32, mut data: &[u8]) -> u32 { 153| | // Below 16 bytes there isn't even a single full block to load, so use the scalar fallback. 154| 971k| if data.len() < 16 { 155| 887k| return crate::baseline::update_fast_16(crc, data); 156| 83.9k| } 157| | 158| | // For 16..127 bytes a single-accumulator fold-by-1 is enough; the fold-by-4 setup below only 159| | // pays off once there are several 64-byte groups. 160| 83.9k| if data.len() < MIN_FOLD_BY_4_BYTES { 161| 68.1k| let mut x = get(&mut data); 162| 68.1k| x = arch::_mm_xor_si128(x, arch::_mm_cvtsi32_si128(!crc as i32)); 163| 68.1k| return reduce_128_to_crc(x, data); 164| 15.8k| } 165| | 166| | // Step 1: fold by 4 loop 167| 15.8k| let mut x3 = get(&mut data); 168| 15.8k| let mut x2 = get(&mut data); 169| 15.8k| let mut x1 = get(&mut data); 170| 15.8k| let mut x0 = get(&mut data); 171| | 172| | // fold in our initial value, part of the incremental crc checksum 173| 15.8k| x3 = arch::_mm_xor_si128(x3, arch::_mm_cvtsi32_si128(!crc as i32)); 174| | 175| 15.8k| let k1k2 = arch::_mm_set_epi64x(K2, K1); 176| 483k| while data.len() >= 64 { 177| 467k| x3 = reduce128(x3, get(&mut data), k1k2); 178| 467k| x2 = reduce128(x2, get(&mut data), k1k2); 179| 467k| x1 = reduce128(x1, get(&mut data), k1k2); 180| 467k| x0 = reduce128(x0, get(&mut data), k1k2); 181| 467k| } 182| | 183| 15.8k| let k3k4 = arch::_mm_set_epi64x(K4, K3); 184| 15.8k| let mut x = reduce128(x3, x2, k3k4); 185| 15.8k| x = reduce128(x, x1, k3k4); 186| 15.8k| x = reduce128(x, x0, k3k4); 187| | 188| 15.8k| reduce_128_to_crc(x, data) 189| 971k|} _RNvNtNtCslKkLwQ76Gc1_9crc32fast11specialized9pclmulqdq9reduce128B5_: 416| 2.08M|unsafe fn reduce128(a: arch::__m128i, b: arch::__m128i, keys: arch::__m128i) -> arch::__m128i { 417| 2.08M| let t1 = arch::_mm_clmulepi64_si128(a, keys, 0x00); 418| 2.08M| let t2 = arch::_mm_clmulepi64_si128(a, keys, 0x11); 419| 2.08M| arch::_mm_xor_si128(arch::_mm_xor_si128(b, t1), t2) 420| 2.08M|} _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor11fill_buffer: 157| 43.6M| fn fill_buffer(&mut self, input: &mut &[u8]) { 158| 43.6M| if input.len() >= 8 { 159| 43.5M| self.buffer |= u64::from_le_bytes(input[..8].try_into().unwrap()) << self.nbits; 160| 43.5M| *input = &input[(63 - self.nbits as usize) / 8..]; 161| 43.5M| self.nbits |= 56; 162| 43.5M| } else { 163| 127k| let nbytes = input.len().min((63 - self.nbits as usize) / 8); 164| 127k| let mut input_data = [0; 8]; 165| 127k| input_data[..nbytes].copy_from_slice(&input[..nbytes]); 166| 127k| self.buffer |= u64::from_le_bytes(input_data) 167| 127k| .checked_shl(self.nbits as u32) 168| 127k| .unwrap_or(0); 169| 127k| self.nbits += nbytes as u8 * 8; 170| 127k| *input = &input[nbytes..]; 171| 127k| } 172| 43.6M| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor12build_tables: 398| 14.2k| fn build_tables( 399| 14.2k| hlit: usize, 400| 14.2k| code_lengths: &[u8], 401| 14.2k| compression: &mut CompressedBlock, 402| 14.2k| ) -> Result<(), DecompressionError> { 403| | // If there is no code assigned for the EOF symbol then the bitstream is invalid. 404| 14.2k| if code_lengths[256] == 0 { 405| | // TODO: Return a dedicated error in this case. 406| 10| return Err(DecompressionError::BadLiteralLengthHuffmanTree); 407| 14.2k| } 408| | 409| 14.2k| let mut codes = [0; 288]; 410| 14.2k| compression.secondary_table.clear(); 411| 14.2k| if !huffman::build_table( 412| 14.2k| &code_lengths[..hlit], 413| 14.2k| &LITLEN_TABLE_ENTRIES, 414| 14.2k| &mut codes[..hlit], 415| 14.2k| &mut *compression.litlen_table, 416| 14.2k| &mut compression.secondary_table, 417| 14.2k| false, 418| 14.2k| true, 419| 14.2k| ) { 420| 90| return Err(DecompressionError::BadCodeLengthHuffmanTree); 421| 14.1k| } 422| | 423| 14.1k| compression.eof_code = codes[256]; 424| 14.1k| compression.eof_mask = (1 << code_lengths[256]) - 1; 425| 14.1k| compression.eof_bits = code_lengths[256]; 426| | 427| | // Build the distance code table. 428| 14.1k| let lengths = &code_lengths[288..320]; 429| 14.1k| if lengths == [0; 32] { 430| 921| compression.dist_table.fill(0); 431| 921| } else { 432| 13.1k| let mut dist_codes = [0; 32]; 433| 13.1k| if !huffman::build_table( 434| 13.1k| lengths, 435| 13.1k| &tables::DISTANCE_TABLE_ENTRIES, 436| 13.1k| &mut dist_codes, 437| 13.1k| &mut *compression.dist_table, 438| 13.1k| &mut compression.dist_secondary_table, 439| 13.1k| true, 440| 13.1k| false, 441| 13.1k| ) { 442| 104| return Err(DecompressionError::BadDistanceHuffmanTree); 443| 13.0k| } 444| | } 445| | 446| 14.0k| Ok(()) 447| 14.2k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor12consume_bits: 178| 42.7M| fn consume_bits(&mut self, nbits: u8) { 179| 42.7M| debug_assert!(self.nbits >= nbits); 180| 42.7M| self.buffer >>= nbits; 181| 42.7M| self.nbits -= nbits; 182| 42.7M| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor14ignore_adler32: 153| 6.34k| pub fn ignore_adler32(&mut self) { 154| 6.34k| self.ignore_adler32 = true; 155| 6.34k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor15read_compressed: 449| 820k| fn read_compressed( 450| 820k| &mut self, 451| 820k| remaining_input: &mut &[u8], 452| 820k| output: &mut [u8], 453| 820k| mut output_index: usize, 454| 820k| ) -> 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| 820k| self.fill_buffer(remaining_input); 468| 820k| let mut litlen_entry = self.compression.litlen_table[(self.buffer & 0xfff) as usize]; 469| 40.8M| while self.state == State::CompressedData 470| 40.8M| && output_index + 8 <= output.len() 471| 40.8M| && 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| 40.8M| let mut litlen_code_bits = litlen_entry as u8; 477| 40.8M| if litlen_entry & LITERAL_ENTRY != 0 { 478| 2.30M| let litlen_entry2 = self.compression.litlen_table 479| 2.30M| [(self.buffer >> litlen_code_bits & 0xfff) as usize]; 480| 2.30M| let litlen_code_bits2 = litlen_entry2 as u8; 481| 2.30M| let litlen_entry3 = self.compression.litlen_table 482| 2.30M| [(self.buffer >> (litlen_code_bits + litlen_code_bits2) & 0xfff) as usize]; 483| 2.30M| let litlen_code_bits3 = litlen_entry3 as u8; 484| 2.30M| let litlen_entry4 = self.compression.litlen_table[(self.buffer 485| 2.30M| >> (litlen_code_bits + litlen_code_bits2 + litlen_code_bits3) 486| 2.30M| & 0xfff) 487| 2.30M| as usize]; 488| | 489| 2.30M| let advance_output_bytes = ((litlen_entry & 0xf00) >> 8) as usize; 490| 2.30M| output[output_index] = (litlen_entry >> 16) as u8; 491| 2.30M| output[output_index + 1] = (litlen_entry >> 24) as u8; 492| 2.30M| output_index += advance_output_bytes; 493| | 494| 2.30M| if litlen_entry2 & LITERAL_ENTRY != 0 { 495| 1.80M| let advance_output_bytes2 = ((litlen_entry2 & 0xf00) >> 8) as usize; 496| 1.80M| output[output_index] = (litlen_entry2 >> 16) as u8; 497| 1.80M| output[output_index + 1] = (litlen_entry2 >> 24) as u8; 498| 1.80M| output_index += advance_output_bytes2; 499| | 500| 1.80M| if litlen_entry3 & LITERAL_ENTRY != 0 { 501| 1.71M| let advance_output_bytes3 = ((litlen_entry3 & 0xf00) >> 8) as usize; 502| 1.71M| output[output_index] = (litlen_entry3 >> 16) as u8; 503| 1.71M| output[output_index + 1] = (litlen_entry3 >> 24) as u8; 504| 1.71M| output_index += advance_output_bytes3; 505| | 506| 1.71M| litlen_entry = litlen_entry4; 507| 1.71M| self.consume_bits(litlen_code_bits + litlen_code_bits2 + litlen_code_bits3); 508| 1.71M| self.fill_buffer(remaining_input); 509| 1.71M| continue; 510| 88.3k| } else { 511| 88.3k| self.consume_bits(litlen_code_bits + litlen_code_bits2); 512| 88.3k| litlen_entry = litlen_entry3; 513| 88.3k| litlen_code_bits = litlen_code_bits3; 514| 88.3k| self.fill_buffer(remaining_input); 515| 88.3k| bits = self.buffer; 516| 88.3k| } 517| | } else { 518| 500k| self.consume_bits(litlen_code_bits); 519| 500k| bits = self.buffer; 520| 500k| litlen_entry = litlen_entry2; 521| 500k| litlen_code_bits = litlen_code_bits2; 522| 500k| if self.nbits < 48 { 523| 34.5k| self.fill_buffer(remaining_input); 524| 466k| } 525| | } 526| 38.5M| } else { 527| 38.5M| bits = self.buffer; 528| 38.5M| } 529| | 530| | // The next symbol is either a 13+ bit literal, back-reference, or an EOF symbol. 531| 39.0M| let (length_base, length_extra_bits, litlen_code_bits) = 532| 39.1M| if litlen_entry & EXCEPTIONAL_ENTRY == 0 { 533| 38.8M| ( 534| 38.8M| litlen_entry >> 16, 535| 38.8M| (litlen_entry >> 8) as u8, 536| 38.8M| litlen_code_bits, 537| 38.8M| ) 538| 303k| } else if litlen_entry & SECONDARY_TABLE_ENTRY != 0 { 539| 290k| let secondary_table_index = 540| 290k| (litlen_entry >> 16) + ((bits >> 12) as u32 & (litlen_entry & 0xff)); 541| 290k| let secondary_entry = 542| 290k| self.compression.secondary_table[secondary_table_index as usize]; 543| 290k| let litlen_symbol = secondary_entry >> 4; 544| 290k| let litlen_code_bits = (secondary_entry & 0xf) as u8; 545| | 546| 290k| match litlen_symbol { 547| 290k| 0..=255 => { 548| 39.9k| self.consume_bits(litlen_code_bits); 549| 39.9k| litlen_entry = 550| 39.9k| self.compression.litlen_table[(self.buffer & 0xfff) as usize]; 551| 39.9k| self.fill_buffer(remaining_input); 552| 39.9k| output[output_index] = litlen_symbol as u8; 553| 39.9k| output_index += 1; 554| 39.9k| continue; 555| | } 556| | 256 => { 557| 1.59k| self.consume_bits(litlen_code_bits); 558| 1.59k| self.state = match self.last_block { 559| 0| true => State::Checksum, 560| 1.59k| false => State::BlockHeader, 561| | }; 562| 1.59k| break; 563| | } 564| 249k| _ => ( 565| 249k| LEN_SYM_TO_LEN_BASE[litlen_symbol as usize - 257] as u32, 566| 249k| LEN_SYM_TO_LEN_EXTRA[litlen_symbol as usize - 257], 567| 249k| litlen_code_bits, 568| 249k| ), 569| | } 570| 12.6k| } else if litlen_code_bits == 0 { 571| 0| return Err(DecompressionError::InvalidLiteralLengthCode); 572| | } else { 573| 12.6k| self.consume_bits(litlen_code_bits); 574| 12.6k| self.state = match self.last_block { 575| 1.51k| true => State::Checksum, 576| 11.1k| false => State::BlockHeader, 577| | }; 578| 12.6k| break; 579| | }; 580| 39.0M| bits >>= litlen_code_bits; 581| | 582| 39.0M| let length_extra_mask = (1 << length_extra_bits) - 1; 583| 39.0M| let length = length_base as usize + (bits & length_extra_mask) as usize; 584| 39.0M| bits >>= length_extra_bits; 585| | 586| 39.0M| let dist_entry = self.compression.dist_table[(bits & 0x1ff) as usize]; 587| 39.0M| let (dist_base, dist_extra_bits, dist_code_bits) = if dist_entry & LITERAL_ENTRY != 0 { 588| 38.8M| ( 589| 38.8M| (dist_entry >> 16) as u16, 590| 38.8M| (dist_entry >> 8) as u8 & 0xf, 591| 38.8M| dist_entry as u8, 592| 38.8M| ) 593| 275k| } else if dist_entry >> 8 == 0 { 594| 14| return Err(DecompressionError::InvalidDistanceCode); 595| | } else { 596| 275k| let secondary_table_index = 597| 275k| (dist_entry >> 16) + ((bits >> 9) as u32 & (dist_entry & 0xff)); 598| 275k| let secondary_entry = 599| 275k| self.compression.dist_secondary_table[secondary_table_index as usize]; 600| 275k| let dist_symbol = (secondary_entry >> 4) as usize; 601| 275k| if dist_symbol >= 30 { 602| 0| return Err(DecompressionError::InvalidDistanceCode); 603| 275k| } 604| | 605| 275k| ( 606| 275k| DIST_SYM_TO_DIST_BASE[dist_symbol], 607| 275k| DIST_SYM_TO_DIST_EXTRA[dist_symbol], 608| 275k| (secondary_entry & 0xf) as u8, 609| 275k| ) 610| | }; 611| 39.0M| bits >>= dist_code_bits; 612| | 613| 39.0M| let dist = dist_base as usize + (bits & ((1 << dist_extra_bits) - 1)) as usize; 614| 39.0M| if dist > output_index { 615| 63| return Err(DecompressionError::DistanceTooFarBack); 616| 39.0M| } 617| | 618| 39.0M| self.consume_bits( 619| 39.0M| litlen_code_bits + length_extra_bits + dist_code_bits + dist_extra_bits, 620| | ); 621| 39.0M| self.fill_buffer(remaining_input); 622| 39.0M| litlen_entry = self.compression.litlen_table[(self.buffer & 0xfff) as usize]; 623| | 624| 39.0M| let copy_length = length.min(output.len() - output_index); 625| 39.0M| if dist == 1 { 626| 19.7M| let last = output[output_index - 1]; 627| 19.7M| output[output_index..][..copy_length].fill(last); 628| | 629| 19.7M| if copy_length < length { 630| 250k| self.queued_rle = Some((last, length - copy_length)); 631| 250k| output_index = output.len(); 632| 250k| break; 633| 19.4M| } 634| 19.3M| } else if output_index + length + 15 <= output.len() { 635| 18.8M| let start = output_index - dist; 636| 18.8M| output.copy_within(start..start + 16, output_index); 637| | 638| 18.8M| if length > 16 || dist < 16 { 639| 1.39G| for i in (0..length).step_by(dist.min(16)).skip(1) { 640| 1.39G| output.copy_within(start + i..start + i + 16, output_index + i); 641| 1.39G| } 642| 506k| } 643| | } else { 644| 551k| if dist < copy_length { 645| 73.9M| for i in 0..copy_length { 646| 73.9M| output[output_index + i] = output[output_index + i - dist]; 647| 73.9M| } 648| | } else { 649| 23.9k| output.copy_within( 650| 23.9k| output_index - dist..output_index + copy_length - dist, 651| 23.9k| output_index, 652| | ) 653| | } 654| | 655| 551k| if copy_length < length { 656| 516k| self.queued_backref = Some((dist, length - copy_length)); 657| 516k| output_index = output.len(); 658| 516k| break; 659| 34.4k| } 660| | } 661| 38.3M| 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| 908k| while let State::CompressedData = self.state { 669| 894k| self.fill_buffer(remaining_input); 670| 894k| if output_index == output.len() { 671| 772k| break; 672| 122k| } 673| | 674| 122k| let mut bits = self.buffer; 675| 122k| let litlen_entry = self.compression.litlen_table[(bits & 0xfff) as usize]; 676| 122k| let litlen_code_bits = litlen_entry as u8; 677| | 678| 122k| if litlen_entry & LITERAL_ENTRY != 0 { 679| | // Fast path: the next symbol is <= 12 bits and a literal, the table specifies the 680| | // output bytes and we can directly write them to the output buffer. 681| 26.1k| let advance_output_bytes = ((litlen_entry & 0xf00) >> 8) as usize; 682| | 683| 26.1k| if self.nbits < litlen_code_bits { 684| 1.33k| break; 685| 24.8k| } else if output_index + 1 < output.len() { 686| 24.1k| output[output_index] = (litlen_entry >> 16) as u8; 687| 24.1k| output[output_index + 1] = (litlen_entry >> 24) as u8; 688| 24.1k| output_index += advance_output_bytes; 689| 24.1k| self.consume_bits(litlen_code_bits); 690| 24.1k| continue; 691| 645| } else if output_index + advance_output_bytes == output.len() { 692| 295| debug_assert_eq!(advance_output_bytes, 1); 693| 295| output[output_index] = (litlen_entry >> 16) as u8; 694| 295| output_index += 1; 695| 295| self.consume_bits(litlen_code_bits); 696| 295| break; 697| | } else { 698| 350| debug_assert_eq!(advance_output_bytes, 2); 699| 350| output[output_index] = (litlen_entry >> 16) as u8; 700| 350| self.queued_rle = Some(((litlen_entry >> 24) as u8, 1)); 701| 350| output_index += 1; 702| 350| self.consume_bits(litlen_code_bits); 703| 350| break; 704| | } 705| 96.1k| } 706| | 707| 92.8k| let (length_base, length_extra_bits, litlen_code_bits) = 708| 96.1k| if litlen_entry & EXCEPTIONAL_ENTRY == 0 { 709| 92.4k| ( 710| 92.4k| litlen_entry >> 16, 711| 92.4k| (litlen_entry >> 8) as u8, 712| 92.4k| litlen_code_bits, 713| 92.4k| ) 714| 3.65k| } else if litlen_entry & SECONDARY_TABLE_ENTRY != 0 { 715| 647| let secondary_table_index = 716| 647| (litlen_entry >> 16) + ((bits >> 12) as u32 & (litlen_entry & 0xff)); 717| 647| let secondary_entry = 718| 647| self.compression.secondary_table[secondary_table_index as usize]; 719| 647| let litlen_symbol = secondary_entry >> 4; 720| 647| let litlen_code_bits = (secondary_entry & 0xf) as u8; 721| | 722| 647| if self.nbits < litlen_code_bits { 723| 11| break; 724| 636| } else if litlen_symbol < 256 { 725| 269| self.consume_bits(litlen_code_bits); 726| 269| output[output_index] = litlen_symbol as u8; 727| 269| output_index += 1; 728| 269| continue; 729| 367| } else if litlen_symbol == 256 { 730| 14| self.consume_bits(litlen_code_bits); 731| 14| self.state = match self.last_block { 732| 0| true => State::Checksum, 733| 14| false => State::BlockHeader, 734| | }; 735| 14| break; 736| 353| } 737| | 738| 353| ( 739| 353| LEN_SYM_TO_LEN_BASE[litlen_symbol as usize - 257] as u32, 740| 353| LEN_SYM_TO_LEN_EXTRA[litlen_symbol as usize - 257], 741| 353| litlen_code_bits, 742| 353| ) 743| 3.01k| } else if litlen_code_bits == 0 { 744| 0| return Err(DecompressionError::InvalidLiteralLengthCode); 745| | } else { 746| 3.01k| if self.nbits < litlen_code_bits { 747| 871| break; 748| 2.14k| } 749| 2.14k| self.consume_bits(litlen_code_bits); 750| 2.14k| self.state = match self.last_block { 751| 1.30k| true => State::Checksum, 752| 832| false => State::BlockHeader, 753| | }; 754| 2.14k| break; 755| | }; 756| 92.8k| bits >>= litlen_code_bits; 757| | 758| 92.8k| let length_extra_mask = (1 << length_extra_bits) - 1; 759| 92.8k| let length = length_base as usize + (bits & length_extra_mask) as usize; 760| 92.8k| bits >>= length_extra_bits; 761| | 762| 92.8k| let dist_entry = self.compression.dist_table[(bits & 0x1ff) as usize]; 763| 92.8k| let (dist_base, dist_extra_bits, dist_code_bits) = if dist_entry & LITERAL_ENTRY != 0 { 764| 92.1k| ( 765| 92.1k| (dist_entry >> 16) as u16, 766| 92.1k| (dist_entry >> 8) as u8 & 0xf, 767| 92.1k| dist_entry as u8, 768| 92.1k| ) 769| 703| } else if self.nbits > litlen_code_bits + length_extra_bits + 9 { 770| 499| if dist_entry >> 8 == 0 { 771| 19| return Err(DecompressionError::InvalidDistanceCode); 772| 480| } 773| | 774| 480| let secondary_table_index = 775| 480| (dist_entry >> 16) + ((bits >> 9) as u32 & (dist_entry & 0xff)); 776| 480| let secondary_entry = 777| 480| self.compression.dist_secondary_table[secondary_table_index as usize]; 778| 480| let dist_symbol = (secondary_entry >> 4) as usize; 779| 480| if dist_symbol >= 30 { 780| 0| return Err(DecompressionError::InvalidDistanceCode); 781| 480| } 782| | 783| 480| ( 784| 480| DIST_SYM_TO_DIST_BASE[dist_symbol], 785| 480| DIST_SYM_TO_DIST_EXTRA[dist_symbol], 786| 480| (secondary_entry & 0xf) as u8, 787| 480| ) 788| | } else { 789| 204| break; 790| | }; 791| 92.5k| bits >>= dist_code_bits; 792| | 793| 92.5k| let dist = dist_base as usize + (bits & ((1 << dist_extra_bits) - 1)) as usize; 794| 92.5k| let total_bits = 795| 92.5k| litlen_code_bits + length_extra_bits + dist_code_bits + dist_extra_bits; 796| | 797| 92.5k| if self.nbits < total_bits { 798| 1.46k| break; 799| 91.1k| } else if dist > output_index { 800| 73| return Err(DecompressionError::DistanceTooFarBack); 801| 91.0k| } 802| | 803| 91.0k| self.consume_bits(total_bits); 804| | 805| 91.0k| let copy_length = length.min(output.len() - output_index); 806| 91.0k| if dist == 1 { 807| 26.8k| let last = output[output_index - 1]; 808| 26.8k| output[output_index..][..copy_length].fill(last); 809| | 810| 26.8k| if copy_length < length { 811| 8.44k| self.queued_rle = Some((last, length - copy_length)); 812| 8.44k| output_index = output.len(); 813| 8.44k| break; 814| 18.4k| } 815| 64.1k| } else if output_index + length + 15 <= output.len() { 816| 44.5k| let start = output_index - dist; 817| 44.5k| output.copy_within(start..start + 16, output_index); 818| | 819| 44.5k| if length > 16 || dist < 16 { 820| 3.48M| for i in (0..length).step_by(dist.min(16)).skip(1) { 821| 3.48M| output.copy_within(start + i..start + i + 16, output_index + i); 822| 3.48M| } 823| 1.93k| } 824| | } else { 825| 19.6k| if dist < copy_length { 826| 352k| for i in 0..copy_length { 827| 352k| output[output_index + i] = output[output_index + i - dist]; 828| 352k| } 829| | } else { 830| 9.09k| output.copy_within( 831| 9.09k| output_index - dist..output_index + copy_length - dist, 832| 9.09k| output_index, 833| | ) 834| | } 835| | 836| 19.6k| if copy_length < length { 837| 18.5k| self.queued_backref = Some((dist, length - copy_length)); 838| 18.5k| output_index = output.len(); 839| 18.5k| break; 840| 1.16k| } 841| | } 842| 64.0k| output_index += copy_length; 843| | } 844| | 845| 819k| if self.state == State::CompressedData 846| 803k| && self.queued_backref.is_none() 847| 268k| && self.queued_rle.is_none() 848| 8.84k| && self.nbits >= 15 849| 5.19k| && self.peak_bits(15) as u16 & self.compression.eof_mask == self.compression.eof_code 850| | { 851| 682| self.consume_bits(self.compression.eof_bits); 852| 682| self.state = match self.last_block { 853| 593| true => State::Checksum, 854| 89| false => State::BlockHeader, 855| | }; 856| 819k| } 857| | 858| 819k| Ok(output_index) 859| 820k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor17read_block_header: 184| 25.0k| fn read_block_header(&mut self, remaining_input: &mut &[u8]) -> Result<(), DecompressionError> { 185| 25.0k| self.fill_buffer(remaining_input); 186| 25.0k| if self.nbits < 10 { 187| 445| return Ok(()); 188| 24.6k| } 189| | 190| 24.6k| let start = self.peak_bits(3); 191| 24.6k| self.last_block = start & 1 != 0; 192| 24.6k| match start >> 1 { 193| | 0b00 => { 194| 1.28k| let align_bits = (self.nbits - 3) % 8; 195| 1.28k| let header_bits = 3 + 32 + align_bits; 196| 1.28k| if self.nbits < header_bits { 197| 208| return Ok(()); 198| 1.07k| } 199| | 200| 1.07k| let len = (self.peak_bits(align_bits + 19) >> (align_bits + 3)) as u16; 201| 1.07k| let nlen = (self.peak_bits(header_bits) >> (align_bits + 19)) as u16; 202| 1.07k| if nlen != !len { 203| 74| return Err(DecompressionError::InvalidUncompressedBlockLength); 204| 1.00k| } 205| | 206| 1.00k| self.state = State::UncompressedData; 207| 1.00k| self.uncompressed_bytes_left = len; 208| 1.00k| self.consume_bits(header_bits); 209| 1.00k| Ok(()) 210| | } 211| | 0b01 => { 212| 8.69k| 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.69k| if self.peak_bits(7) == 0 { 218| 1.01k| self.consume_bits(7); 219| 1.01k| if self.last_block { 220| 20| self.state = State::Checksum; 221| 20| return Ok(()); 222| 992| } 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| 1.90k| while self.nbits >= 10 && self.peak_bits(10) == 0b010 { 230| 910| self.consume_bits(10); 231| 910| self.fill_buffer(remaining_input); 232| 910| } 233| 992| return self.read_block_header(remaining_input); 234| 7.68k| } 235| | 236| | // Build decoding tables if the previous block wasn't also a fixed block. 237| 7.68k| if !self.fixed_table { 238| 6.42k| self.fixed_table = true; 239| 51.4k| for chunk in self.compression.litlen_table.chunks_exact_mut(512) { 240| 51.4k| chunk.copy_from_slice(&FIXED_LITLEN_TABLE); 241| 51.4k| } 242| 102k| for chunk in self.compression.dist_table.chunks_exact_mut(32) { 243| 102k| chunk.copy_from_slice(&FIXED_DIST_TABLE); 244| 102k| } 245| 6.42k| self.compression.eof_bits = 7; 246| 6.42k| self.compression.eof_code = 0; 247| 6.42k| self.compression.eof_mask = 0x7f; 248| 1.25k| } 249| | 250| 7.68k| self.state = State::CompressedData; 251| 7.68k| Ok(()) 252| | } 253| | 0b10 => { 254| 14.6k| if self.nbits < 17 { 255| 82| return Ok(()); 256| 14.5k| } 257| | 258| 14.5k| self.header.hlit = (self.peak_bits(8) >> 3) as usize + 257; 259| 14.5k| self.header.hdist = (self.peak_bits(13) >> 8) as usize + 1; 260| 14.5k| self.header.hclen = (self.peak_bits(17) >> 13) as usize + 4; 261| 14.5k| if self.header.hlit > 286 { 262| 3| return Err(DecompressionError::InvalidHlit); 263| 14.5k| } 264| 14.5k| if self.header.hdist > 30 { 265| 4| return Err(DecompressionError::InvalidHdist); 266| 14.5k| } 267| | 268| 14.5k| self.consume_bits(17); 269| 14.5k| self.state = State::CodeLengthCodes; 270| 14.5k| self.fixed_table = false; 271| 14.5k| Ok(()) 272| | } 273| 25| 0b11 => Err(DecompressionError::InvalidBlockType), 274| 0| _ => unreachable!(), 275| | } 276| 25.0k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor17read_code_lengths: 317| 14.8k| fn read_code_lengths(&mut self, remaining_input: &mut &[u8]) -> Result<(), DecompressionError> { 318| 14.8k| let total_lengths = self.header.hlit + self.header.hdist; 319| 926k| while self.header.num_lengths_read < total_lengths { 320| 912k| self.fill_buffer(remaining_input); 321| 912k| if self.nbits < 7 { 322| 311| return Ok(()); 323| 912k| } 324| | 325| 912k| let code = self.peak_bits(7); 326| 912k| let entry = self.header.table[code as usize]; 327| 912k| let length = (entry & 0x7) as u8; 328| 912k| let symbol = (entry >> 16) as u8; 329| | 330| 912k| debug_assert!(length != 0); 331| 912k| match symbol { 332| 912k| 0..=15 => { 333| 794k| self.header.code_lengths[self.header.num_lengths_read] = symbol; 334| 794k| self.header.num_lengths_read += 1; 335| 794k| self.consume_bits(length); 336| 794k| } 337| 117k| 16..=18 => { 338| 117k| let (base_repeat, extra_bits) = match symbol { 339| 44.8k| 16 => (3, 2), 340| 32.2k| 17 => (3, 3), 341| 40.7k| 18 => (11, 7), 342| 0| _ => unreachable!(), 343| | }; 344| | 345| 117k| if self.nbits < length + extra_bits { 346| 329| return Ok(()); 347| 117k| } 348| | 349| 117k| let value = match symbol { 350| | 16 => { 351| 44.7k| self.header.code_lengths[self 352| 44.7k| .header 353| 44.7k| .num_lengths_read 354| 44.7k| .checked_sub(1) 355| 44.7k| .ok_or(DecompressionError::InvalidCodeLengthRepeat)?] 356| | // TODO: is this right? 357| | } 358| 32.1k| 17 => 0, 359| 40.6k| 18 => 0, 360| 0| _ => unreachable!(), 361| | }; 362| | 363| 117k| let repeat = 364| 117k| (self.peak_bits(length + extra_bits) >> length) as usize + base_repeat; 365| 117k| if self.header.num_lengths_read + repeat > total_lengths { 366| 25| return Err(DecompressionError::InvalidCodeLengthRepeat); 367| 117k| } 368| | 369| 3.35M| for i in 0..repeat { 370| 3.35M| self.header.code_lengths[self.header.num_lengths_read + i] = value; 371| 3.35M| } 372| 117k| self.header.num_lengths_read += repeat; 373| 117k| self.consume_bits(length + extra_bits); 374| | } 375| 0| _ => unreachable!(), 376| | } 377| | } 378| | 379| 14.2k| self.header 380| 14.2k| .code_lengths 381| 14.2k| .copy_within(self.header.hlit..total_lengths, 288); 382| 187k| for i in self.header.hlit..288 { 383| 187k| self.header.code_lengths[i] = 0; 384| 187k| } 385| 226k| for i in 288 + self.header.hdist..320 { 386| 226k| self.header.code_lengths[i] = 0; 387| 226k| } 388| | 389| 14.2k| Self::build_tables( 390| 14.2k| self.header.hlit, 391| 14.2k| &self.header.code_lengths, 392| 14.2k| &mut self.compression, 393| 204| )?; 394| 14.0k| self.state = State::CompressedData; 395| 14.0k| Ok(()) 396| 14.8k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor22read_code_length_codes: 278| 14.7k| fn read_code_length_codes( 279| 14.7k| &mut self, 280| 14.7k| remaining_input: &mut &[u8], 281| 14.7k| ) -> Result<(), DecompressionError> { 282| 14.7k| self.fill_buffer(remaining_input); 283| 14.7k| if self.nbits as usize + remaining_input.len() * 8 < 3 * self.header.hclen { 284| 243| return Ok(()); 285| 14.4k| } 286| | 287| 14.4k| let mut code_length_lengths = [0; 19]; 288| 255k| for i in 0..self.header.hclen { 289| 255k| code_length_lengths[CLCL_ORDER[i]] = self.peak_bits(3) as u8; 290| 255k| 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| 255k| if i == 17 { 295| 11.9k| self.fill_buffer(remaining_input); 296| 243k| } 297| | } 298| | 299| 14.4k| let mut codes = [0; 19]; 300| 14.4k| if !build_table( 301| 14.4k| &code_length_lengths, 302| 14.4k| &[], 303| 14.4k| &mut codes, 304| 14.4k| &mut self.header.table, 305| 14.4k| &mut Vec::new(), 306| 14.4k| false, 307| 14.4k| false, 308| 14.4k| ) { 309| 104| return Err(DecompressionError::BadCodeLengthHuffmanTree); 310| 14.3k| } 311| | 312| 14.3k| self.state = State::CodeLengths; 313| 14.3k| self.header.num_lengths_read = 0; 314| 14.3k| Ok(()) 315| 14.7k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor3new: 120| 13.1k| pub fn new() -> Self { 121| 13.1k| Self { 122| 13.1k| buffer: 0, 123| 13.1k| nbits: 0, 124| 13.1k| compression: CompressedBlock { 125| 13.1k| litlen_table: Box::new([0; 4096]), 126| 13.1k| dist_table: Box::new([0; 512]), 127| 13.1k| secondary_table: Vec::new(), 128| 13.1k| dist_secondary_table: Vec::new(), 129| 13.1k| eof_code: 0, 130| 13.1k| eof_mask: 0, 131| 13.1k| eof_bits: 0, 132| 13.1k| }, 133| 13.1k| header: BlockHeader { 134| 13.1k| hlit: 0, 135| 13.1k| hdist: 0, 136| 13.1k| hclen: 0, 137| 13.1k| table: [0; 128], 138| 13.1k| num_lengths_read: 0, 139| 13.1k| code_lengths: [0; 320], 140| 13.1k| }, 141| 13.1k| uncompressed_bytes_left: 0, 142| 13.1k| queued_rle: None, 143| 13.1k| queued_backref: None, 144| 13.1k| checksum: Adler32::new(), 145| 13.1k| state: State::ZlibHeader, 146| 13.1k| last_block: false, 147| 13.1k| ignore_adler32: false, 148| 13.1k| fixed_table: false, 149| 13.1k| } 150| 13.1k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor4read: 879| 810k| pub fn read( 880| 810k| &mut self, 881| 810k| input: &[u8], 882| 810k| output: &mut [u8], 883| 810k| output_position: usize, 884| 810k| end_of_input: bool, 885| 810k| ) -> Result<(usize, usize), DecompressionError> { 886| 810k| if let State::Done = self.state { 887| 0| return Ok((0, 0)); 888| 810k| } 889| | 890| 810k| assert!(output_position <= output.len()); 891| | 892| 810k| let mut remaining_input = input; 893| 810k| let mut output_index = output_position; 894| | 895| 810k| if let Some((data, len)) = self.queued_rle.take() { 896| 258k| let n = len.min(output.len() - output_index); 897| 258k| output[output_index..][..n].fill(data); 898| 258k| output_index += n; 899| 258k| if n < len { 900| 5| self.queued_rle = Some((data, len - n)); 901| 5| return Ok((0, n)); 902| 258k| } 903| 552k| } 904| 810k| if let Some((dist, len)) = self.queued_backref.take() { 905| 533k| let n = len.min(output.len() - output_index); 906| 68.4M| for i in 0..n { 907| 68.4M| output[output_index + i] = output[output_index + i - dist]; 908| 68.4M| } 909| 533k| output_index += n; 910| 533k| if n < len { 911| 15| self.queued_backref = Some((dist, len - n)); 912| 15| return Ok((0, n)); 913| 533k| } 914| 277k| } 915| | 916| | // Main decoding state machine. 917| 810k| let mut last_state = None; 918| 1.69M| while last_state != Some(self.state) { 919| 889k| last_state = Some(self.state); 920| 889k| match self.state { 921| | State::ZlibHeader => { 922| 10.6k| self.fill_buffer(&mut remaining_input); 923| 10.6k| if self.nbits < 16 { 924| 1.68k| break; 925| 8.99k| } 926| | 927| 8.99k| let input0 = self.peak_bits(8); 928| 8.99k| let input1 = self.peak_bits(16) >> 8 & 0xff; 929| 8.99k| if input0 & 0x0f != 0x08 930| 8.91k| || (input0 & 0xf0) > 0x70 931| 8.91k| || input1 & 0x20 != 0 932| 8.91k| || (input0 << 8 | input1) % 31 != 0 933| | { 934| 96| return Err(DecompressionError::BadZlibHeader); 935| 8.89k| } 936| | 937| 8.89k| self.consume_bits(16); 938| 8.89k| self.state = State::BlockHeader; 939| | } 940| | State::BlockHeader => { 941| 24.0k| self.read_block_header(&mut remaining_input)?; 942| | } 943| | State::CodeLengthCodes => { 944| 14.7k| self.read_code_length_codes(&mut remaining_input)?; 945| | } 946| | State::CodeLengths => { 947| 14.8k| self.read_code_lengths(&mut remaining_input)?; 948| | } 949| | State::CompressedData => { 950| | output_index = 951| 820k| self.read_compressed(&mut remaining_input, output, output_index)? 952| | } 953| | State::UncompressedData => { 954| | // Drain any bytes from our buffer. 955| 1.39k| debug_assert_eq!(self.nbits % 8, 0); 956| 3.25k| while self.nbits > 0 957| 1.92k| && self.uncompressed_bytes_left > 0 958| 1.85k| && output_index < output.len() 959| 1.85k| { 960| 1.85k| output[output_index] = self.peak_bits(8) as u8; 961| 1.85k| self.consume_bits(8); 962| 1.85k| output_index += 1; 963| 1.85k| self.uncompressed_bytes_left -= 1; 964| 1.85k| } 965| | // Buffer may contain one additional byte. Clear it to avoid confusion. 966| 1.39k| if self.nbits == 0 { 967| 1.32k| self.buffer = 0; 968| 1.32k| } 969| | 970| | // Copy subsequent bytes directly from the input. 971| 1.39k| let copy_bytes = (self.uncompressed_bytes_left as usize) 972| 1.39k| .min(remaining_input.len()) 973| 1.39k| .min(output.len() - output_index); 974| 1.39k| output[output_index..][..copy_bytes] 975| 1.39k| .copy_from_slice(&remaining_input[..copy_bytes]); 976| 1.39k| remaining_input = &remaining_input[copy_bytes..]; 977| 1.39k| output_index += copy_bytes; 978| 1.39k| self.uncompressed_bytes_left -= copy_bytes as u16; 979| | 980| 1.39k| if self.uncompressed_bytes_left == 0 { 981| 944| self.state = if self.last_block { 982| 2| State::Checksum 983| | } else { 984| 942| State::BlockHeader 985| | }; 986| 451| } 987| | } 988| | State::Checksum => { 989| 3.62k| self.fill_buffer(&mut remaining_input); 990| | 991| 3.62k| let align_bits = self.nbits % 8; 992| 3.62k| if self.nbits >= 32 + align_bits { 993| 3.33k| self.checksum.write(&output[output_position..output_index]); 994| 3.33k| if align_bits != 0 { 995| 2.92k| self.consume_bits(align_bits); 996| 2.92k| } 997| | #[cfg(not(fuzzing))] 998| | if !self.ignore_adler32 999| | && (self.peak_bits(32) as u32).swap_bytes() != self.checksum.finish() 1000| | { 1001| | return Err(DecompressionError::WrongChecksum); 1002| | } 1003| 3.33k| self.state = State::Done; 1004| 3.33k| self.consume_bits(32); 1005| 3.33k| break; 1006| 299| } 1007| | } 1008| 0| State::Done => unreachable!(), 1009| | } 1010| | } 1011| | 1012| 810k| if !self.ignore_adler32 && self.state != State::Done { 1013| 127k| self.checksum.write(&output[output_position..output_index]); 1014| 682k| } 1015| | 1016| 810k| if self.state == State::Done || !end_of_input || output_index == output.len() { 1017| 809k| let input_left = remaining_input.len(); 1018| 809k| Ok((input.len() - input_left, output_index - output_position)) 1019| | } else { 1020| 299| Err(DecompressionError::InsufficientInput) 1021| | } 1022| 810k| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor7is_done: 1025| 1.49M| pub fn is_done(&self) -> bool { 1026| 1.49M| self.state == State::Done 1027| 1.49M| } _RNvMs_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB4_12Decompressor9peak_bits: 174| 1.39M| fn peak_bits(&mut self, nbits: u8) -> u64 { 175| 1.39M| debug_assert!(nbits <= 56 && nbits <= self.nbits); 176| 1.39M| self.buffer & ((1u64 << nbits) - 1) 177| 1.39M| } _RNvNtCsh5m7Dv6WxNY_8fdeflate10decompress25decompress_to_vec_bounded: 1063| 2.78k|pub fn decompress_to_vec_bounded( 1064| 2.78k| input: &[u8], 1065| 2.78k| maxlen: usize, 1066| 2.78k|) -> Result, BoundedDecompressionError> { 1067| 2.78k| let mut decoder = Decompressor::new(); 1068| 2.78k| let mut output = vec![0; 1024.min(maxlen)]; 1069| 2.78k| let mut input_index = 0; 1070| 2.78k| let mut output_index = 0; 1071| | loop { 1072| 129k| let (consumed, produced) = 1073| 130k| decoder.read(&input[input_index..], &mut output, output_index, true)?; 1074| 129k| input_index += consumed; 1075| 129k| output_index += produced; 1076| 129k| if decoder.is_done() || output_index == maxlen { 1077| 2.38k| break; 1078| 127k| } 1079| 127k| output.resize((output_index + 32 * 1024).min(maxlen), 0); 1080| | } 1081| 2.38k| output.resize(output_index, 0); 1082| | 1083| 2.38k| if decoder.is_done() { 1084| 2.38k| Ok(output) 1085| | } else { 1086| 0| Err(BoundedDecompressionError::OutputTooLarge { 1087| 0| partial_output: output, 1088| 0| }) 1089| | } 1090| 2.78k|} _RNvXs0_NtCsh5m7Dv6WxNY_8fdeflate10decompressNtB5_25BoundedDecompressionErrorINtNtCs6SNw0SRvItZ_4core7convert4FromNtB5_18DecompressionErrorE4from: 1056| 399| fn from(inner: DecompressionError) -> Self { 1057| 399| BoundedDecompressionError::DecompressionError { inner } 1058| 399| } _RNCNvNtCsh5m7Dv6WxNY_8fdeflate7huffman11build_table0B5_: 46| 9.04k| let symbol = lengths.iter().position(|&l| l == 1).unwrap(); _RNvNtCsh5m7Dv6WxNY_8fdeflate7huffman11build_table: 18| 41.8k|pub fn build_table( 19| 41.8k| lengths: &[u8], 20| 41.8k| entries: &[u32], 21| 41.8k| codes: &mut [u16], 22| 41.8k| primary_table: &mut [u32], 23| 41.8k| secondary_table: &mut Vec, 24| 41.8k| is_distance_table: bool, 25| 41.8k| double_literal: bool, 26| 41.8k|) -> bool { 27| | // Count the number of symbols with each code length. 28| 41.8k| let mut histogram = [0; 16]; 29| 4.64M| for &length in lengths { 30| 4.60M| histogram[length as usize] += 1; 31| 4.60M| } 32| | 33| | // Determine the maximum code length. 34| 41.8k| let mut max_length = 15; 35| 449k| while max_length > 1 && histogram[max_length] == 0 { 36| 407k| max_length -= 1; 37| 407k| } 38| | 39| | // Handle zero and one symbol huffman codes (which are only allowed for distance codes). 40| 41.8k| if is_distance_table { 41| 13.1k| if max_length == 0 { 42| 0| primary_table.fill(0); 43| 0| secondary_table.clear(); 44| 0| return true; 45| 13.1k| } else if max_length == 1 && histogram[1] == 1 { 46| 4.17k| let symbol = lengths.iter().position(|&l| l == 1).unwrap(); 47| 4.17k| codes[symbol] = 0; 48| 4.17k| let entry = entries 49| 4.17k| .get(symbol) 50| 4.17k| .cloned() 51| 4.17k| .unwrap_or((symbol as u32) << 16) 52| 4.17k| | 1; 53| 1.06M| for chunk in primary_table.chunks_mut(2) { 54| 1.06M| chunk[0] = entry; 55| 1.06M| chunk[1] = 0; 56| 1.06M| } 57| 4.17k| return true; 58| 9.02k| } 59| 28.7k| } 60| | 61| | // Sort symbols by code length. Given the histogram, we can determine the starting offset 62| | // for each code length. 63| 37.7k| let mut offsets = [0; 16]; 64| 37.7k| let mut codespace_used = 0; 65| 37.7k| offsets[1] = histogram[0]; 66| 178k| for i in 1..max_length { 67| 178k| offsets[i + 1] = offsets[i] + histogram[i]; 68| 178k| codespace_used = (codespace_used << 1) + histogram[i]; 69| 178k| } 70| 37.7k| codespace_used = (codespace_used << 1) + histogram[max_length]; 71| | 72| | // Check that the provided lengths form a valid Huffman tree. 73| 37.7k| if codespace_used != (1 << max_length) { 74| 298| return false; 75| 37.4k| } 76| | 77| | // Sort the symbols by code length. 78| 37.4k| let mut next_index = offsets; 79| 37.4k| let mut sorted_symbols = [0; 288]; 80| 4.43M| for symbol in 0..lengths.len() { 81| 4.43M| let length = lengths[symbol]; 82| 4.43M| sorted_symbols[next_index[length as usize]] = symbol; 83| 4.43M| next_index[length as usize] += 1; 84| 4.43M| } 85| | 86| 37.4k| let mut codeword = 0u16; 87| 37.4k| let mut i = histogram[0]; 88| | 89| | // Populate the primary decoding table 90| 37.4k| let primary_table_bits = primary_table.len().ilog2() as usize; 91| 37.4k| let primary_table_mask = (1 << primary_table_bits) - 1; 92| 350k| for length in 1..=primary_table_bits { 93| 350k| let current_table_end = 1 << length; 94| | 95| | // Loop over all symbols with the current code length and set their table entries. 96| 853k| for _ in 0..histogram[length] { 97| 853k| let symbol = sorted_symbols[i]; 98| 853k| i += 1; 99| 853k| 100| 853k| primary_table[codeword as usize] = entries 101| 853k| .get(symbol) 102| 853k| .cloned() 103| 853k| .unwrap_or((symbol as u32) << 16) 104| 853k| | length as u32; 105| 853k| 106| 853k| codes[symbol] = codeword; 107| 853k| codeword = next_codeword(codeword, current_table_end as u16); 108| 853k| } 109| | 110| 350k| if double_literal { 111| 776k| for len1 in 1..(length - 1) { 112| 776k| let len2 = length - len1; 113| 1.87M| for sym1_index in offsets[len1]..next_index[len1] { 114| 3.74M| for sym2_index in offsets[len2]..next_index[len2] { 115| 3.74M| let sym1 = sorted_symbols[sym1_index]; 116| 3.74M| let sym2 = sorted_symbols[sym2_index]; 117| 3.74M| if sym1 < 256 && sym2 < 256 { 118| 2.15M| let codeword1 = codes[sym1]; 119| 2.15M| let codeword2 = codes[sym2]; 120| 2.15M| let codeword = codeword1 | (codeword2 << len1); 121| 2.15M| let entry = (sym1 as u32) << 16 122| 2.15M| | (sym2 as u32) << 24 123| 2.15M| | LITERAL_ENTRY 124| 2.15M| | (2 << 8); 125| 2.15M| primary_table[codeword as usize] = entry | (length as u32); 126| 2.15M| } 127| | } 128| | } 129| | } 130| 181k| } 131| | 132| | // If we aren't at the maximum table size, double the size of the table. 133| 350k| if length < primary_table_bits { 134| 312k| primary_table.copy_within(0..current_table_end, current_table_end); 135| 312k| } 136| | } 137| | 138| | // Populate the secondary decoding table. 139| 37.4k| secondary_table.clear(); 140| 37.4k| if max_length > primary_table_bits { 141| 5.47k| let mut subtable_start = 0; 142| 5.47k| let mut subtable_prefix = !0; 143| 13.6k| for length in (primary_table_bits + 1)..=max_length { 144| 13.6k| let subtable_size = 1 << (length - primary_table_bits); 145| 13.6k| for _ in 0..histogram[length] { 146| | // If the codeword's prefix doesn't match the current subtable, create a new 147| | // subtable. 148| 161k| if codeword & primary_table_mask != subtable_prefix { 149| 50.5k| subtable_prefix = codeword & primary_table_mask; 150| 50.5k| subtable_start = secondary_table.len(); 151| 50.5k| primary_table[subtable_prefix as usize] = ((subtable_start as u32) << 16) 152| 50.5k| | EXCEPTIONAL_ENTRY 153| 50.5k| | SECONDARY_TABLE_ENTRY 154| 50.5k| | (subtable_size as u32 - 1); 155| 50.5k| secondary_table.resize(subtable_start + subtable_size, 0); 156| 111k| } 157| | 158| | // Lookup the symbol. 159| 161k| let symbol = sorted_symbols[i]; 160| 161k| i += 1; 161| | 162| | // Insert the symbol into the secondary table and advance to the next codeword. 163| 161k| codes[symbol] = codeword; 164| 161k| secondary_table[subtable_start + (codeword >> primary_table_bits) as usize] = 165| 161k| ((symbol as u16) << 4) | (length as u16); 166| 161k| codeword = next_codeword(codeword, 1 << length); 167| | } 168| | 169| | // If there are more codes with the same subtable prefix, extend the subtable. 170| 13.6k| if length < max_length && codeword & primary_table_mask == subtable_prefix { 171| 6.82k| secondary_table.extend_from_within(subtable_start..); 172| 6.82k| let subtable_size = secondary_table.len() - subtable_start; 173| 6.82k| primary_table[subtable_prefix as usize] = ((subtable_start as u32) << 16) 174| 6.82k| | EXCEPTIONAL_ENTRY 175| 6.82k| | SECONDARY_TABLE_ENTRY 176| 6.82k| | (subtable_size as u32 - 1); 177| 6.84k| } 178| | } 179| 31.9k| } 180| | 181| 37.4k| true 182| 41.8k|} _RNvNtCsh5m7Dv6WxNY_8fdeflate7huffman13next_codeword: 5| 1.01M|fn next_codeword(mut codeword: u16, table_size: u16) -> u16 { 6| 1.01M| if codeword == table_size - 1 { 7| 37.4k| return codeword; 8| 977k| } 9| | 10| 977k| let adv = (u16::BITS - 1) - (codeword ^ (table_size - 1)).leading_zeros(); 11| 977k| let bit = 1 << adv; 12| 977k| codeword &= bit - 1; 13| 977k| codeword |= bit; 14| 977k| codeword 15| 1.01M|} 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| } _RNvNvCsi3bDR6OqnXm_17fuzzer_script_png1__19___libfuzzer_sys_run: 293| 10.1k| fn __libfuzzer_sys_run($bytes: &[u8]) -> $rty { 294| | $body 295| 10.1k| } rust_fuzzer_test_input: 261| 10.1k| 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| 10.1k| 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| 10.1k| } 275| | 276| 10.1k| let result = ::libfuzzer_sys::Corpus::from(__libfuzzer_sys_run(bytes)); 277| 10.1k| result.to_libfuzzer_code() 278| 10.1k| } LLVMFuzzerTestOneInput: 59| 10.1k|pub unsafe fn test_input_wrap(data: *const u8, size: usize) -> i32 { 60| 10.1k| 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| 10.1k| match test_input { 66| 10.1k| 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| 10.1k|} _RNCNvCs40C2i8rLLBy_13libfuzzer_sys15test_input_wrap0B3_: 60| 10.1k| let test_input = ::std::panic::catch_unwind(|| { 61| 10.1k| let data_slice = ::std::slice::from_raw_parts(data, size); 62| 10.1k| rust_fuzzer_test_input(data_slice) 63| 10.1k| }); _RNCNvCs40C2i8rLLBy_13libfuzzer_sys25rust_libfuzzer_debug_path0B3_: 78| 1| RUST_LIBFUZZER_DEBUG_PATH.get_or_init(|| std::env::var("RUST_LIBFUZZER_DEBUG_PATH").ok()) _RNvCs40C2i8rLLBy_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|} _RNvCs40C2i8rLLBy_13libfuzzer_sys25rust_libfuzzer_debug_path: 76| 10.1k|pub fn rust_libfuzzer_debug_path() -> &'static Option { 77| | static RUST_LIBFUZZER_DEBUG_PATH: OnceLock> = OnceLock::new(); 78| 10.1k| RUST_LIBFUZZER_DEBUG_PATH.get_or_init(|| std::env::var("RUST_LIBFUZZER_DEBUG_PATH").ok()) 79| 10.1k|} _RNvMs_Cs40C2i8rLLBy_13libfuzzer_sysNtB4_6Corpus17to_libfuzzer_code: 40| 10.1k| pub fn to_libfuzzer_code(self) -> i32 { 41| 10.1k| match self { 42| 10.1k| Corpus::Keep => 0, 43| 0| Corpus::Reject => -1, 44| | } 45| 10.1k| } _RNvXCs40C2i8rLLBy_13libfuzzer_sysNtB2_6CorpusINtNtCs6SNw0SRvItZ_4core7convert4FromuE4from: 30| 10.1k| fn from(_: ()) -> Self { 31| 10.1k| Self::Keep 32| 10.1k| } _RNvXNtCs1jiJzeRTgBH_6moxcms4cicpNtB2_18CicpColorPrimariesINtNtCs6SNw0SRvItZ_4core7convert7TryFromhE8try_from: 89| 6| fn try_from(value: u8) -> Result { 90| 6| match value { 91| | // Values 0, 3, 13–21, 23–255 are all reserved so all map to the 92| | // same variant. 93| 6| 0 | 3 | 13..=21 | 23..=255 => Ok(Self::Reserved), 94| 0| 1 => Ok(Self::Bt709), 95| 0| 2 => Ok(Self::Unspecified), 96| 0| 4 => Ok(Self::Bt470M), 97| 0| 5 => Ok(Self::Bt470Bg), 98| 0| 6 => Ok(Self::Bt601), 99| 0| 7 => Ok(Self::Smpte240), 100| 0| 8 => Ok(Self::GenericFilm), 101| 0| 9 => Ok(Self::Bt2020), 102| 0| 10 => Ok(Self::Xyz), 103| 0| 11 => Ok(Self::Smpte431), 104| 0| 12 => Ok(Self::Smpte432), 105| 0| 22 => Ok(Self::Ebu3213), 106| 0| _ => Err(CmsError::InvalidCicp), 107| | } 108| 6| } _RNvXs1_NtCs1jiJzeRTgBH_6moxcms4cicpNtB5_23TransferCharacteristicsINtNtCs6SNw0SRvItZ_4core7convert7TryFromhE8try_from: 381| 6| fn try_from(value: u8) -> Result { 382| 6| match value { 383| 6| 0 | 3 | 19..=255 => Ok(Self::Reserved), 384| 0| 1 => Ok(Self::Bt709), 385| 0| 2 => Ok(Self::Unspecified), 386| 0| 4 => Ok(Self::Bt470M), 387| 0| 5 => Ok(Self::Bt470Bg), 388| 0| 6 => Ok(Self::Bt601), 389| 0| 7 => Ok(Self::Smpte240), // unimplemented 390| 0| 8 => Ok(Self::Linear), 391| 0| 9 => Ok(Self::Log100), 392| 0| 10 => Ok(Self::Log100sqrt10), 393| 0| 11 => Ok(Self::Iec61966), // unimplemented 394| 0| 12 => Ok(Self::Bt1361), // unimplemented 395| 0| 13 => Ok(Self::Srgb), 396| 0| 14 => Ok(Self::Bt202010bit), 397| 0| 15 => Ok(Self::Bt202012bit), 398| 0| 16 => Ok(Self::Smpte2084), 399| 0| 17 => Ok(Self::Smpte428), // unimplemented 400| 0| 18 => Ok(Self::Hlg), 401| 0| _ => Err(CmsError::InvalidCicp), 402| | } 403| 6| } _RNvXs6_NtCs1jiJzeRTgBH_6moxcms4cicpNtB5_18MatrixCoefficientsINtNtCs6SNw0SRvItZ_4core7convert7TryFromhE8try_from: 592| 6| fn try_from(value: u8) -> Result { 593| 6| match value { 594| 6| 0 => Ok(MatrixCoefficients::Identity), 595| 0| 1 => Ok(MatrixCoefficients::Bt709), 596| 0| 2 => Ok(MatrixCoefficients::Unspecified), 597| 0| 3 => Ok(MatrixCoefficients::Reserved), 598| 0| 4 => Ok(MatrixCoefficients::Fcc), 599| 0| 5 => Ok(MatrixCoefficients::Bt470Bg), 600| 0| 6 => Ok(MatrixCoefficients::Smpte170m), 601| 0| 7 => Ok(MatrixCoefficients::Smpte240m), 602| 0| 8 => Ok(MatrixCoefficients::YCgCo), 603| 0| 9 => Ok(MatrixCoefficients::Bt2020Ncl), 604| 0| 10 => Ok(MatrixCoefficients::Bt2020Cl), 605| 0| 11 => Ok(MatrixCoefficients::Smpte2085), 606| 0| 12 => Ok(MatrixCoefficients::ChromaticityDerivedNCL), 607| 0| 13 => Ok(MatrixCoefficients::ChromaticityDerivedCL), 608| 0| 14 => Ok(MatrixCoefficients::ICtCp), 609| 0| _ => Err(CmsError::InvalidCicp), 610| | } 611| 6| } _RNvMs_NtCs1jiJzeRTgBH_6moxcms3datNtB4_13ColorDateTime14new_from_slice: 81| 1.33k| pub fn new_from_slice(slice: &[u8]) -> Result { 82| 1.33k| if slice.len() != 12 { 83| 0| return Err(CmsError::InvalidProfile); 84| 1.33k| } 85| 1.33k| let year = u16::from_be_bytes([slice[0], slice[1]]); 86| 1.33k| let month = u16::from_be_bytes([slice[2], slice[3]]); 87| 1.33k| let day_of_the_month = u16::from_be_bytes([slice[4], slice[5]]); 88| 1.33k| let hours = u16::from_be_bytes([slice[6], slice[7]]); 89| 1.33k| let minutes = u16::from_be_bytes([slice[8], slice[9]]); 90| 1.33k| let seconds = u16::from_be_bytes([slice[10], slice[11]]); 91| 1.33k| Ok(ColorDateTime { 92| 1.33k| year, 93| 1.33k| month, 94| 1.33k| day_of_the_month, 95| 1.33k| hours, 96| 1.33k| minutes, 97| 1.33k| seconds, 98| 1.33k| }) 99| 1.33k| } _RNvMs_NtCs1jiJzeRTgBH_6moxcms3datNtB4_13ColorDateTime3now: 102| 1.30k| pub fn now() -> Self { 103| | #[cfg(not(target_arch = "wasm32"))] 104| 1.30k| let now = match SystemTime::now().duration_since(UNIX_EPOCH) { 105| 1.30k| Ok(v) => v, 106| 0| Err(_) => return Self::default(), 107| | }; 108| | #[cfg(target_arch = "wasm32")] 109| | use std::time::Duration; 110| | #[cfg(target_arch = "wasm32")] 111| | let now = Duration::new(365 * 60 * 60 * 24 * 30, 0); 112| 1.30k| let mut days = (now.as_secs() / 86_400) as i64; 113| 1.30k| let secs_of_day = (now.as_secs() % 86_400) as i64; 114| | 115| 1.30k| let mut year = 1970; 116| | loop { 117| 74.1k| let year_days = if is_leap(year) { 366 } else { 365 }; 118| 74.1k| if days >= year_days { 119| 72.8k| days -= year_days; 120| 72.8k| year += 1; 121| 72.8k| } else { 122| 1.30k| break; 123| | } 124| | } 125| | 126| 1.30k| let mut month = 1; 127| | loop { 128| 13.0k| let mdays = days_in_month(year, month); 129| 13.0k| if days >= mdays as i64 { 130| 11.7k| days -= mdays as i64; 131| 11.7k| month += 1; 132| 11.7k| } else { 133| 1.30k| break; 134| | } 135| | } 136| 1.30k| let day = days + 1; // days from zero based to 1 base 137| | 138| 1.30k| let hour = secs_of_day / 3600; 139| 1.30k| let min = (secs_of_day % 3600) / 60; 140| 1.30k| let sec = secs_of_day % 60; 141| 1.30k| Self { 142| 1.30k| year: year as u16, 143| 1.30k| month: month as u16, 144| 1.30k| day_of_the_month: day as u16, 145| 1.30k| hours: hour as u16, 146| 1.30k| minutes: min as u16, 147| 1.30k| seconds: sec as u16, 148| 1.30k| } 149| 1.30k| } _RNvNtCs1jiJzeRTgBH_6moxcms3dat13days_in_month: 49| 13.0k|fn days_in_month(year: i32, month: i32) -> i32 { 50| 13.0k| match month { 51| 1.30k| 1 => 31, 52| | 2 => { 53| 1.30k| if is_leap(year) { 54| 0| 29 55| | } else { 56| 1.30k| 28 57| | } 58| | } 59| 1.30k| 3 => 31, 60| 1.30k| 4 => 30, 61| 1.30k| 5 => 31, 62| 1.30k| 6 => 30, 63| 1.30k| 7 => 31, 64| 1.30k| 8 => 31, 65| 1.30k| 9 => 30, 66| 1.30k| 10 => 31, 67| 0| 11 => 30, 68| 0| 12 => 31, 69| 0| _ => unreachable!("Unknown month"), 70| | } 71| 13.0k|} _RNvNtCs1jiJzeRTgBH_6moxcms3dat7is_leap: 45| 75.4k|fn is_leap(year: i32) -> bool { 46| 75.4k| (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) 47| 75.4k|} _RNvXNtCs1jiJzeRTgBH_6moxcms3datNtB2_13ColorDateTimeNtNtCs6SNw0SRvItZ_4core7default7Default7default: 74| 1.30k| fn default() -> Self { 75| 1.30k| Self::now() 76| 1.30k| } _RNvMs19_NtCs1jiJzeRTgBH_6moxcms6matrixNtB6_3Xyz3newB8_: 1066| 1.30k| pub const fn new(x: $im_type, y: $im_type, z: $im_type) -> Self { 1067| 1.30k| Self { x, y, z } 1068| 1.30k| } _RNvMss_NtCs1jiJzeRTgBH_6moxcms6matrixNtB5_3Xyz7to_xyzd: 1244| 1.30k| pub fn to_xyzd(self) -> Xyzd { 1245| 1.30k| Xyzd { 1246| 1.30k| x: self.x as f64, 1247| 1.30k| y: self.y as f64, 1248| 1.30k| z: self.z as f64, 1249| 1.30k| } 1250| 1.30k| } _RNvMse_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_13ProfileHeader14new_from_slice: 686| 2.16k| pub(crate) fn new_from_slice(slice: &[u8]) -> Result { 687| 2.16k| if slice.len() < size_of::() { 688| 9| return Err(CmsError::InvalidProfile); 689| 2.15k| } 690| 2.15k| let mut cursor = std::io::Cursor::new(slice); 691| 2.15k| let mut buffer = [0u8; size_of::()]; 692| 2.15k| cursor 693| 2.15k| .read_exact(&mut buffer) 694| 2.15k| .map_err(|_| CmsError::InvalidProfile)?; 695| | 696| 1.30k| let header = Self { 697| 2.15k| size: u32::from_be_bytes(buffer[0..4].try_into().unwrap()), 698| 2.15k| cmm_type: u32::from_be_bytes(buffer[4..8].try_into().unwrap()), 699| 2.15k| version: ProfileVersion::try_from(u32::from_be_bytes( 700| 2.15k| buffer[8..12].try_into().unwrap(), 701| 55| ))?, 702| 2.09k| profile_class: ProfileClass::try_from(u32::from_be_bytes( 703| 2.09k| buffer[12..16].try_into().unwrap(), 704| 433| ))?, 705| 1.66k| data_color_space: DataColorSpace::try_from(u32::from_be_bytes( 706| 1.66k| buffer[16..20].try_into().unwrap(), 707| 222| ))?, 708| 1.44k| pcs: DataColorSpace::try_from(u32::from_be_bytes(buffer[20..24].try_into().unwrap()))?, 709| 1.33k| creation_date_time: ColorDateTime::new_from_slice(buffer[24..36].try_into().unwrap())?, 710| 1.33k| signature: ProfileSignature::try_from(u32::from_be_bytes( 711| 1.33k| buffer[36..40].try_into().unwrap(), 712| 33| ))?, 713| 1.30k| platform: u32::from_be_bytes(buffer[40..44].try_into().unwrap()), 714| 1.30k| flags: u32::from_be_bytes(buffer[44..48].try_into().unwrap()), 715| 1.30k| device_manufacturer: u32::from_be_bytes(buffer[48..52].try_into().unwrap()), 716| 1.30k| device_model: u32::from_be_bytes(buffer[52..56].try_into().unwrap()), 717| 1.30k| device_attributes: buffer[56..64].try_into().unwrap(), 718| 1.30k| rendering_intent: RenderingIntent::try_from(u32::from_be_bytes( 719| 1.30k| buffer[64..68].try_into().unwrap(), 720| 0| ))?, 721| 1.30k| illuminant: Xyz::new( 722| 1.30k| s15_fixed16_number_to_float(i32::from_be_bytes(buffer[68..72].try_into().unwrap())), 723| 1.30k| s15_fixed16_number_to_float(i32::from_be_bytes(buffer[72..76].try_into().unwrap())), 724| 1.30k| s15_fixed16_number_to_float(i32::from_be_bytes(buffer[76..80].try_into().unwrap())), 725| | ), 726| 1.30k| creator: u32::from_be_bytes(buffer[80..84].try_into().unwrap()), 727| 1.30k| profile_id: buffer[84..100].try_into().unwrap(), 728| 1.30k| reserved: buffer[100..128].try_into().unwrap(), 729| 1.30k| tag_count: u32::from_be_bytes(buffer[128..132].try_into().unwrap()), 730| | }; 731| 1.30k| Ok(header) 732| 2.16k| } _RNvMsn_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_12ColorProfile14new_from_slice: 978| 2.16k| pub fn new_from_slice(slice: &[u8]) -> Result { 979| 2.16k| Self::new_from_slice_with_options(slice, Default::default()) 980| 2.16k| } _RNvMsn_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_12ColorProfile27new_from_slice_with_options: 982| 2.16k| pub fn new_from_slice_with_options( 983| 2.16k| slice: &[u8], 984| 2.16k| options: ParsingOptions, 985| 2.16k| ) -> Result { 986| 2.16k| let header = ProfileHeader::new_from_slice(slice)?; 987| 1.30k| let tags_count = header.tag_count as usize; 988| 1.30k| if slice.len() >= options.max_profile_size { 989| 0| return Err(CmsError::InvalidProfile); 990| 1.30k| } 991| 1.30k| let tags_end = tags_count 992| 1.30k| .safe_mul(TAG_SIZE)? 993| 1.30k| .safe_add(size_of::())?; 994| 1.30k| if slice.len() < tags_end { 995| 3| return Err(CmsError::InvalidProfile); 996| 1.30k| } 997| 1.30k| let tags_slice = &slice[size_of::()..tags_end]; 998| 1.30k| let mut profile = ColorProfile { 999| 1.30k| rendering_intent: header.rendering_intent, 1000| 1.30k| pcs: header.pcs, 1001| 1.30k| profile_class: header.profile_class, 1002| 1.30k| color_space: header.data_color_space, 1003| 1.30k| white_point: header.illuminant.to_xyzd(), 1004| 1.30k| version_internal: header.version, 1005| 1.30k| creation_date_time: header.creation_date_time, 1006| 1.30k| ..Default::default() 1007| 1.30k| }; 1008| 1.30k| let color_space = profile.color_space; 1009| 32.1k| for tag in tags_slice.chunks_exact(TAG_SIZE) { 1010| 32.1k| let tag_value = u32::from_be_bytes([tag[0], tag[1], tag[2], tag[3]]); 1011| 32.1k| let tag_entry = u32::from_be_bytes([tag[4], tag[5], tag[6], tag[7]]); 1012| 32.1k| let tag_size = u32::from_be_bytes([tag[8], tag[9], tag[10], tag[11]]) as usize; 1013| | // Just ignore unknown tags 1014| 32.1k| if let Ok(tag) = Tag::try_from(tag_value) { 1015| 5.42k| match tag { 1016| | Tag::RedXyz => { 1017| 518| if color_space == DataColorSpace::Rgb { 1018| | profile.red_colorant = 1019| 518| Self::read_xyz_tag(slice, tag_entry as usize, tag_size)?; 1020| 0| } 1021| | } 1022| | Tag::GreenXyz => { 1023| 335| if color_space == DataColorSpace::Rgb { 1024| | profile.green_colorant = 1025| 335| Self::read_xyz_tag(slice, tag_entry as usize, tag_size)?; 1026| 0| } 1027| | } 1028| | Tag::BlueXyz => { 1029| 351| if color_space == DataColorSpace::Rgb { 1030| | profile.blue_colorant = 1031| 351| Self::read_xyz_tag(slice, tag_entry as usize, tag_size)?; 1032| 0| } 1033| | } 1034| | Tag::RedToneReproduction => { 1035| 210| if color_space == DataColorSpace::Rgb { 1036| 208| profile.red_trc = Self::read_trc_tag_s( 1037| 208| slice, 1038| 208| tag_entry as usize, 1039| 208| tag_size, 1040| 208| &options, 1041| 41| )?; 1042| 2| } 1043| | } 1044| | Tag::GreenToneReproduction => { 1045| 63| if color_space == DataColorSpace::Rgb { 1046| 51| profile.green_trc = Self::read_trc_tag_s( 1047| 51| slice, 1048| 51| tag_entry as usize, 1049| 51| tag_size, 1050| 51| &options, 1051| 3| )?; 1052| 12| } 1053| | } 1054| | Tag::BlueToneReproduction => { 1055| 36| if color_space == DataColorSpace::Rgb { 1056| 28| profile.blue_trc = Self::read_trc_tag_s( 1057| 28| slice, 1058| 28| tag_entry as usize, 1059| 28| tag_size, 1060| 28| &options, 1061| 1| )?; 1062| 8| } 1063| | } 1064| | Tag::GreyToneReproduction => { 1065| 137| if color_space == DataColorSpace::Gray { 1066| 125| profile.gray_trc = Self::read_trc_tag_s( 1067| 125| slice, 1068| 125| tag_entry as usize, 1069| 125| tag_size, 1070| 125| &options, 1071| 74| )?; 1072| 12| } 1073| | } 1074| | Tag::MediaWhitePoint => { 1075| | profile.media_white_point = 1076| 910| 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| 58| if (profile.profile_class == ProfileClass::InputDevice 1091| 58| || profile.profile_class == ProfileClass::DisplayDevice) 1092| 58| && (profile.color_space == DataColorSpace::Rgb 1093| 0| || profile.color_space == DataColorSpace::YCbr 1094| 0| || profile.color_space == DataColorSpace::Xyz) 1095| | { 1096| | profile.cicp = 1097| 58| 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| 609| 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| 1.12k| profile.copyright = 1137| 1.17k| Self::read_string_tag(slice, tag_entry as usize, tag_size)?; 1138| | } 1139| | Tag::ProfileDescription => { 1140| 948| profile.description = 1141| 990| Self::read_string_tag(slice, tag_entry as usize, tag_size)?; 1142| | } 1143| | Tag::ViewingConditionsDescription => { 1144| 0| profile.viewing_conditions_description = 1145| 1| Self::read_string_tag(slice, tag_entry as usize, tag_size)?; 1146| | } 1147| | Tag::DeviceModel => { 1148| 0| profile.device_model = 1149| 1| Self::read_string_tag(slice, tag_entry as usize, tag_size)?; 1150| | } 1151| | Tag::DeviceManufacturer => { 1152| 0| profile.device_manufacturer = 1153| 1| 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| 10| 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| 18| Self::read_date_time_tag(slice, tag_entry as usize, tag_size)?; 1171| | } 1172| | } 1173| 26.6k| } 1174| | } 1175| | 1176| 747| Ok(profile) 1177| 2.16k| } _RNvXNtCs1jiJzeRTgBH_6moxcms7profileNtB2_16ProfileSignatureINtNtCs6SNw0SRvItZ_4core7convert7TryFrommE8try_fromB4_: 54| 1.33k| fn try_from(value: u32) -> Result { 55| 1.33k| if value == u32::from_ne_bytes(*b"acsp").to_be() { 56| 1.30k| return Ok(ProfileSignature::Acsp); 57| 33| } 58| 33| Err(CmsError::InvalidProfile) 59| 1.33k| } _RNvXs0_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_14ProfileVersionINtNtCs6SNw0SRvItZ_4core7convert7TryFrommE8try_from: 90| 2.15k| fn try_from(value: u32) -> Result { 91| | // First try exact match for known versions 92| 2.15k| match value { 93| 1| 0x02000000 => return Ok(ProfileVersion::V2_0), 94| 2| 0x02100000 => return Ok(ProfileVersion::V2_1), 95| 365| 0x02200000 => return Ok(ProfileVersion::V2_2), 96| 1| 0x02300000 => return Ok(ProfileVersion::V2_3), 97| 796| 0x02400000 => return Ok(ProfileVersion::V2_4), 98| 1| 0x04000000 => return Ok(ProfileVersion::V4_0), 99| 1| 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| 985| _ => {} 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| 985| let major = (value >> 24) & 0xFF; 109| 985| 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| 985| match major { 114| | 0 => { 115| | // Version 0.x is invalid - reject 116| 19| Err(CmsError::InvalidProfile) 117| | } 118| | 2 => { 119| | // v2.x - map to the appropriate v2 minor version or highest known 120| 668| match minor { 121| 29| 0 => Ok(ProfileVersion::V2_0), 122| 46| 1 => Ok(ProfileVersion::V2_1), 123| 415| 2 => Ok(ProfileVersion::V2_2), 124| 44| 3 => Ok(ProfileVersion::V2_3), 125| 134| _ => 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| 36| Ok(ProfileVersion::V2_4) 131| | } 132| | 4 => { 133| | // v4.x - map to the appropriate v4 minor version or highest known 134| 226| match minor { 135| 74| 0 => Ok(ProfileVersion::V4_0), 136| 31| 1 => Ok(ProfileVersion::V4_1), 137| 51| 2 => Ok(ProfileVersion::V4_2), 138| 35| 3 => Ok(ProfileVersion::V4_3), 139| 35| _ => 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| 36| Err(CmsError::InvalidProfile) 146| | } 147| | } 148| 2.15k| } _RNvXs3_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_12ProfileClassINtNtCs6SNw0SRvItZ_4core7convert7TryFrommE8try_from: 269| 2.09k| fn try_from(value: u32) -> Result { 270| 2.09k| if value == u32::from_ne_bytes(*b"scnr").to_be() { 271| 469| return Ok(ProfileClass::InputDevice); 272| 1.63k| } else if value == u32::from_ne_bytes(*b"mntr").to_be() { 273| 855| return Ok(ProfileClass::DisplayDevice); 274| 775| } else if value == u32::from_ne_bytes(*b"prtr").to_be() { 275| 342| return Ok(ProfileClass::OutputDevice); 276| 433| } else if value == u32::from_ne_bytes(*b"link").to_be() { 277| 0| return Ok(ProfileClass::DeviceLink); 278| 433| } else if value == u32::from_ne_bytes(*b"spac").to_be() { 279| 0| return Ok(ProfileClass::ColorSpace); 280| 433| } else if value == u32::from_ne_bytes(*b"abst").to_be() { 281| 0| return Ok(ProfileClass::Abstract); 282| 433| } else if value == u32::from_ne_bytes(*b"nmcl").to_be() { 283| 0| return Ok(ProfileClass::Named); 284| 433| } 285| 433| Err(CmsError::InvalidProfile) 286| 2.09k| } _RNvXs7_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_14DataColorSpaceINtNtCs6SNw0SRvItZ_4core7convert7TryFrommE8try_from: 346| 3.11k| fn try_from(value: u32) -> Result { 347| 3.11k| if value == u32::from_ne_bytes(*b"XYZ ").to_be() { 348| 1.33k| return Ok(DataColorSpace::Xyz); 349| 1.77k| } else if value == u32::from_ne_bytes(*b"Lab ").to_be() { 350| 0| return Ok(DataColorSpace::Lab); 351| 1.77k| } else if value == u32::from_ne_bytes(*b"Luv ").to_be() { 352| 0| return Ok(DataColorSpace::Luv); 353| 1.77k| } else if value == u32::from_ne_bytes(*b"YCbr").to_be() { 354| 0| return Ok(DataColorSpace::YCbr); 355| 1.77k| } else if value == u32::from_ne_bytes(*b"Yxy ").to_be() { 356| 0| return Ok(DataColorSpace::Yxy); 357| 1.77k| } else if value == u32::from_ne_bytes(*b"RGB ").to_be() { 358| 830| return Ok(DataColorSpace::Rgb); 359| 945| } else if value == u32::from_ne_bytes(*b"GRAY").to_be() { 360| 616| return Ok(DataColorSpace::Gray); 361| 329| } else if value == u32::from_ne_bytes(*b"HSV ").to_be() { 362| 0| return Ok(DataColorSpace::Hsv); 363| 329| } else if value == u32::from_ne_bytes(*b"HLS ").to_be() { 364| 0| return Ok(DataColorSpace::Hls); 365| 329| } else if value == u32::from_ne_bytes(*b"CMYK").to_be() { 366| 0| return Ok(DataColorSpace::Cmyk); 367| 329| } else if value == u32::from_ne_bytes(*b"CMY ").to_be() { 368| 0| return Ok(DataColorSpace::Cmy); 369| 329| } else if value == u32::from_ne_bytes(*b"2CLR").to_be() { 370| 0| return Ok(DataColorSpace::Color2); 371| 329| } else if value == u32::from_ne_bytes(*b"3CLR").to_be() { 372| 0| return Ok(DataColorSpace::Color3); 373| 329| } else if value == u32::from_ne_bytes(*b"4CLR").to_be() { 374| 0| return Ok(DataColorSpace::Color4); 375| 329| } else if value == u32::from_ne_bytes(*b"5CLR").to_be() { 376| 0| return Ok(DataColorSpace::Color5); 377| 329| } else if value == u32::from_ne_bytes(*b"6CLR").to_be() { 378| 0| return Ok(DataColorSpace::Color6); 379| 329| } else if value == u32::from_ne_bytes(*b"7CLR").to_be() { 380| 0| return Ok(DataColorSpace::Color7); 381| 329| } else if value == u32::from_ne_bytes(*b"8CLR").to_be() { 382| 0| return Ok(DataColorSpace::Color8); 383| 329| } else if value == u32::from_ne_bytes(*b"9CLR").to_be() { 384| 0| return Ok(DataColorSpace::Color9); 385| 329| } else if value == u32::from_ne_bytes(*b"ACLR").to_be() { 386| 0| return Ok(DataColorSpace::Color10); 387| 329| } else if value == u32::from_ne_bytes(*b"BCLR").to_be() { 388| 0| return Ok(DataColorSpace::Color11); 389| 329| } else if value == u32::from_ne_bytes(*b"CCLR").to_be() { 390| 0| return Ok(DataColorSpace::Color12); 391| 329| } else if value == u32::from_ne_bytes(*b"DCLR").to_be() { 392| 0| return Ok(DataColorSpace::Color13); 393| 329| } else if value == u32::from_ne_bytes(*b"ECLR").to_be() { 394| 0| return Ok(DataColorSpace::Color14); 395| 329| } else if value == u32::from_ne_bytes(*b"FCLR").to_be() { 396| 0| return Ok(DataColorSpace::Color15); 397| 329| } 398| 329| Err(CmsError::InvalidProfile) 399| 3.11k| } _RNvXsc_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_15RenderingIntentINtNtCs6SNw0SRvItZ_4core7convert7TryFrommE8try_fromB7_: 605| 1.30k| fn try_from(value: u32) -> Result { 606| | // Rendering intent is a big-endian u32 at bytes 64-67 with valid 607| | // values 0-3. Non-conforming profiles (e.g. old Linotype "Lino" 608| | // v2.1 profiles with byte-swapped values) may have invalid values. 609| | // Default to Perceptual rather than rejecting the entire profile, 610| | // since this field is advisory — moxcms uses TransformOptions for 611| | // actual LUT selection. 612| 1.30k| match value { 613| 493| 0 => Ok(RenderingIntent::Perceptual), 614| 0| 1 => Ok(RenderingIntent::RelativeColorimetric), 615| 2| 2 => Ok(RenderingIntent::Saturation), 616| 340| 3 => Ok(RenderingIntent::AbsoluteColorimetric), 617| 469| _ => Ok(RenderingIntent::Perceptual), 618| | } 619| 1.30k| } _RNvXsm_NtCs1jiJzeRTgBH_6moxcms7profileNtB5_14ParsingOptionsNtNtCs6SNw0SRvItZ_4core7default7Default7default: 963| 2.16k| fn default() -> Self { 964| 2.16k| Self { 965| 2.16k| max_profile_size: MAX_PROFILE_SIZE, 966| 2.16k| max_allowed_clut_size: 10_000_000, 967| 2.16k| max_allowed_trc_size: 40_000, 968| 2.16k| } 969| 2.16k| } _RNvMNtCs1jiJzeRTgBH_6moxcms6readerNtNtB4_7profile12ColorProfile12read_trc_tag: 713| 412| pub(crate) fn read_trc_tag( 714| 412| slice: &[u8], 715| 412| entry: usize, 716| 412| tag_size: usize, 717| 412| read_size: &mut usize, 718| 412| options: &ParsingOptions, 719| 412| ) -> Result, CmsError> { 720| 412| if slice.len() < entry.safe_add(4)? { 721| 273| return Ok(None); 722| 139| } 723| 139| let small_tag = &slice[entry..entry + 4]; 724| | // We require always recognize tone curves. 725| 139| let curve_type = TagTypeDefinition::from(u32::from_be_bytes([ 726| 139| small_tag[0], 727| 139| small_tag[1], 728| 139| small_tag[2], 729| 139| small_tag[3], 730| 139| ])); 731| 139| if tag_size != 0 && tag_size < TAG_SIZE { 732| 9| return Ok(None); 733| 130| } 734| 130| let last_tag_offset = if tag_size != 0 { 735| 110| tag_size + entry 736| | } else { 737| 20| slice.len() 738| | }; 739| 130| if last_tag_offset > slice.len() { 740| 64| return Err(CmsError::MalformedTrcCurve("Data exhausted".to_string())); 741| 66| } 742| 66| let tag = &slice[entry..last_tag_offset]; 743| 66| if tag.len() < TAG_SIZE { 744| 6| return Err(CmsError::MalformedTrcCurve("Data exhausted".to_string())); 745| 60| } 746| 60| if curve_type == TagTypeDefinition::LutToneCurve { 747| 18| let entry_count = u32::from_be_bytes([tag[8], tag[9], tag[10], tag[11]]) as usize; 748| 18| if entry_count == 0 { 749| 6| return Ok(Some(ToneReprCurve::Lut(vec![]))); 750| 12| } 751| 12| if entry_count > options.max_allowed_trc_size { 752| 5| return Err(CmsError::CurveLutIsTooLarge); 753| 7| } 754| 7| let curve_end = entry_count.safe_mul(size_of::())?.safe_add(12)?; 755| 7| if tag.len() < curve_end { 756| 2| return Err(CmsError::MalformedTrcCurve( 757| 2| "Curve end ends to early".to_string(), 758| 2| )); 759| 5| } 760| 5| let curve_sliced = &tag[12..curve_end]; 761| 5| let mut curve_values = try_vec![0u16; entry_count]; 762| 31| for (value, curve_value) in curve_sliced.chunks_exact(2).zip(curve_values.iter_mut()) { 763| 31| let gamma_s15 = u16::from_be_bytes([value[0], value[1]]); 764| 31| *curve_value = gamma_s15; 765| 31| } 766| 5| *read_size = curve_end; 767| 5| Ok(Some(ToneReprCurve::Lut(curve_values))) 768| 42| } 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| 42| Err(CmsError::MalformedTrcCurve( 800| 42| "Unknown parametric curve tag".to_string(), 801| 42| )) 802| | } 803| 412| } _RNvMNtCs1jiJzeRTgBH_6moxcms6readerNtNtB4_7profile12ColorProfile12read_xyz_tagB4_: 935| 2.72k| pub(crate) fn read_xyz_tag( 936| 2.72k| slice: &[u8], 937| 2.72k| entry: usize, 938| 2.72k| tag_size: usize, 939| 2.72k| ) -> Result { 940| 2.72k| if tag_size < TAG_SIZE { 941| 173| return Ok(Xyzd::default()); 942| 2.55k| } 943| 2.55k| let last_tag_offset = tag_size.safe_add(entry)?; 944| 2.55k| if last_tag_offset > slice.len() { 945| 280| return Err(CmsError::InvalidProfile); 946| 2.27k| } 947| 2.27k| let tag = &slice[entry..entry + 12]; 948| 2.27k| let tag_type = u32::from_be_bytes([tag[0], tag[1], tag[2], tag[3]]); 949| 2.27k| let def = TagTypeDefinition::from(tag_type); 950| 2.27k| if def != TagTypeDefinition::Xyz { 951| 2.19k| return Ok(Xyzd::default()); 952| 79| } 953| | 954| 79| let tag = &slice[entry..last_tag_offset]; 955| 79| if tag.len() < 20 { 956| 9| return Err(CmsError::InvalidProfile); 957| 70| } 958| 70| let q15_16_x = i32::from_be_bytes([tag[8], tag[9], tag[10], tag[11]]); 959| 70| let q15_16_y = i32::from_be_bytes([tag[12], tag[13], tag[14], tag[15]]); 960| 70| let q15_16_z = i32::from_be_bytes([tag[16], tag[17], tag[18], tag[19]]); 961| 70| let x = s15_fixed16_number_to_double(q15_16_x); 962| 70| let y = s15_fixed16_number_to_double(q15_16_y); 963| 70| let z = s15_fixed16_number_to_double(q15_16_z); 964| 70| Ok(Xyzd { x, y, z }) 965| 2.72k| } _RNvMNtCs1jiJzeRTgBH_6moxcms6readerNtNtB4_7profile12ColorProfile13read_cicp_tag: 967| 58| pub(crate) fn read_cicp_tag( 968| 58| slice: &[u8], 969| 58| entry: usize, 970| 58| tag_size: usize, 971| 58| ) -> Result, CmsError> { 972| 58| if tag_size < TAG_SIZE { 973| 17| return Ok(None); 974| 41| } 975| 41| let last_tag_offset = tag_size.safe_add(entry)?; 976| 41| if last_tag_offset > slice.len() { 977| 28| return Err(CmsError::InvalidProfile); 978| 13| } 979| 13| let tag = &slice[entry..last_tag_offset]; 980| 13| if tag.len() < 12 { 981| 0| return Err(CmsError::InvalidProfile); 982| 13| } 983| 13| let tag_type = u32::from_be_bytes([tag[0], tag[1], tag[2], tag[3]]); 984| 13| let def = TagTypeDefinition::from(tag_type); 985| 13| if def != TagTypeDefinition::Cicp { 986| 7| return Ok(None); 987| 6| } 988| 6| let primaries = CicpColorPrimaries::try_from(tag[8])?; 989| 6| let transfer_characteristics = TransferCharacteristics::try_from(tag[9])?; 990| 6| let matrix_coefficients = MatrixCoefficients::try_from(tag[10])?; 991| 6| let full_range = tag[11] == 1; 992| 6| Ok(Some(CicpProfile { 993| 6| color_primaries: primaries, 994| 6| transfer_characteristics, 995| 6| matrix_coefficients, 996| 6| full_range, 997| 6| })) 998| 58| } _RNvMNtCs1jiJzeRTgBH_6moxcms6readerNtNtB4_7profile12ColorProfile14read_trc_tag_s: 703| 412| pub(crate) fn read_trc_tag_s( 704| 412| slice: &[u8], 705| 412| entry: usize, 706| 412| tag_size: usize, 707| 412| options: &ParsingOptions, 708| 412| ) -> Result, CmsError> { 709| 412| let mut _empty = 0usize; 710| 412| Self::read_trc_tag(slice, entry, tag_size, &mut _empty, options) 711| 412| } _RNvMNtCs1jiJzeRTgBH_6moxcms6readerNtNtB4_7profile12ColorProfile15read_string_tag: 176| 2.17k| pub(crate) fn read_string_tag( 177| 2.17k| slice: &[u8], 178| 2.17k| entry: usize, 179| 2.17k| tag_size: usize, 180| 2.17k| ) -> Result, CmsError> { 181| 2.17k| let tag_size = if tag_size == 0 { TAG_SIZE } else { tag_size }; 182| 2.17k| if tag_size < 4 { 183| 29| return Ok(None); 184| 2.14k| } 185| 2.14k| let last_tag_offset = tag_size.safe_add(entry)?; 186| 2.14k| if last_tag_offset > slice.len() { 187| 95| return Err(CmsError::InvalidProfile); 188| 2.04k| } 189| 2.04k| let tag = &slice[entry..last_tag_offset]; 190| 2.04k| if tag.len() < 8 { 191| 24| return Ok(None); 192| 2.02k| } 193| 2.02k| let tag_type = 194| 2.02k| TagTypeDefinition::from(u32::from_be_bytes([tag[0], tag[1], tag[2], tag[3]])); 195| | // Ignore unknown 196| 2.02k| if tag_type == TagTypeDefinition::Text { 197| 54| let sliced_from_to_end = &tag[8..tag.len()]; 198| 54| let str = String::from_utf8_lossy(sliced_from_to_end) 199| 54| .trim_end_matches('\0') 200| 54| .to_string(); 201| 54| return Ok(Some(ProfileText::PlainString(str))); 202| 1.96k| } 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.96k| } else if tag_type == TagTypeDefinition::Description { 268| 539| if tag.len() < 12 { 269| 1| return Err(CmsError::InvalidProfile); 270| 538| } 271| 538| let ascii_length = u32::from_be_bytes([tag[8], tag[9], tag[10], tag[11]]) as usize; 272| 538| let ascii_end = 12usize.safe_add(ascii_length)?; 273| 538| if tag.len() < ascii_end { 274| 4| return Err(CmsError::InvalidProfile); 275| 534| } 276| 534| let sliced = &tag[12..ascii_end]; 277| 534| let ascii_string = String::from_utf8_lossy(sliced) 278| 534| .trim_end_matches('\0') 279| 534| .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| 534| let unicode_offset = ascii_end; 285| 534| let (unicode_code, unicode_string) = 286| 534| self::read_desc_unicode(tag, unicode_offset)?.unwrap_or((0, String::new())); 287| | 288| 534| return Ok(Some(ProfileText::Description(DescriptionString { 289| 534| ascii_string, 290| 534| unicode_language_code: unicode_code, 291| 534| unicode_string, 292| 534| mac_string: "".to_string(), 293| 534| script_code_code: -1, 294| 534| }))); 295| 1.43k| } 296| 1.43k| Ok(None) 297| 2.17k| } _RNvMNtCs1jiJzeRTgBH_6moxcms6readerNtNtB4_7profile12ColorProfile18read_date_time_tag: 864| 18| pub(crate) fn read_date_time_tag( 865| 18| slice: &[u8], 866| 18| entry: usize, 867| 18| tag_size: usize, 868| 18| ) -> Result, CmsError> { 869| 18| if tag_size < 20 { 870| 0| return Ok(None); 871| 18| } 872| 18| let last_tag_offset = tag_size.safe_add(entry)?; 873| 18| if last_tag_offset > slice.len() { 874| 18| return Err(CmsError::InvalidProfile); 875| 0| } 876| 0| let tag = &slice[entry..entry.safe_add(20)?]; 877| 0| let tag_type = u32::from_be_bytes([tag[0], tag[1], tag[2], tag[3]]); 878| 0| let def = TagTypeDefinition::from(tag_type); 879| 0| if def == TagTypeDefinition::DateTime { 880| 0| let tag_value = &slice[8..20]; 881| 0| let time = ColorDateTime::new_from_slice(tag_value)?; 882| 0| return Ok(Some(time)); 883| 0| } 884| 0| Ok(None) 885| 18| } _RNvNtCs1jiJzeRTgBH_6moxcms6reader16utf16be_to_utf16: 74| 282|fn utf16be_to_utf16(slice: &[u8]) -> Result, CmsError> { 75| 282| let mut vec = try_vec![0u16; slice.len() / 2]; 76| 8.46k| for (dst, chunk) in vec.iter_mut().zip(slice.chunks_exact(2)) { 77| 8.46k| *dst = u16::from_be_bytes([chunk[0], chunk[1]]); 78| 8.46k| } 79| 282| Ok(vec) 80| 282|} _RNvNtCs1jiJzeRTgBH_6moxcms6reader17read_desc_unicode: 85| 534|fn read_desc_unicode(tag: &[u8], unicode_offset: usize) -> Result, CmsError> { 86| 534| if tag.len() < unicode_offset.safe_add(8)? { 87| 23| return Ok(None); 88| 511| } 89| 511| let header = &tag[unicode_offset..unicode_offset.safe_add(8)?]; 90| 511| let language_code = u32::from_be_bytes([header[0], header[1], header[2], header[3]]); 91| 511| let unicode_length = u32::from_be_bytes([header[4], header[5], header[6], header[7]]) as usize; 92| 511| if unicode_length == 0 { 93| 51| return Ok(Some((language_code, String::new()))); 94| 460| } 95| 460| let byte_length = unicode_length.safe_mul(2)?; 96| 460| let str_start = unicode_offset.safe_add(8)?; 97| 460| if tag.len() < str_start.safe_add(byte_length)? { 98| 178| return Ok(None); 99| 282| } 100| 282| let uc_data = &tag[str_start..str_start.safe_add(byte_length)?]; 101| 282| let wc = utf16be_to_utf16(uc_data)?; 102| 282| let s = String::from_utf16_lossy(&wc) 103| 282| .trim_end_matches('\0') 104| 282| .to_string(); 105| 282| Ok(Some((language_code, s))) 106| 534|} _RNvNtCs1jiJzeRTgBH_6moxcms6reader27s15_fixed16_number_to_floatB3_: 45| 3.91k|pub(crate) const fn s15_fixed16_number_to_float(a: i32) -> f32 { 46| 3.91k| a as f32 / 65536. 47| 3.91k|} _RNvNtCs1jiJzeRTgBH_6moxcms6reader28s15_fixed16_number_to_doubleB3_: 50| 210|pub(crate) const fn s15_fixed16_number_to_double(a: i32) -> f64 { 51| 210| a as f64 / 65536. 52| 210|} _RNvXs1_NtCs1jiJzeRTgBH_6moxcms9safe_mathjINtB5_7SafeAddjE8safe_add: 48| 9.25k| fn safe_add(&self, other: $type_name) -> Result<$type_name, CmsError> { 49| 9.25k| if let Some(result) = self.checked_add(other) { 50| 9.25k| return Ok(result); 51| 0| } 52| 0| Err(CmsError::OverflowingError) 53| 9.25k| } _RNvXs6_NtCs1jiJzeRTgBH_6moxcms9safe_mathjINtB5_7SafeMuljE8safe_mul: 68| 1.77k| fn safe_mul(&self, other: $type_name) -> Result<$type_name, CmsError> { 69| 1.77k| if let Some(result) = self.checked_mul(other) { 70| 1.77k| return Ok(result); 71| 0| } 72| 0| Err(CmsError::OverflowingError) 73| 1.77k| } _RNvXNtCs1jiJzeRTgBH_6moxcms3tagNtB2_3TagINtNtCs6SNw0SRvItZ_4core7convert7TryFrommE8try_from: 70| 32.1k| fn try_from(value: u32) -> Result { 71| 32.1k| if value == u32::from_ne_bytes(*b"rXYZ").to_be() { 72| 518| return Ok(Self::RedXyz); 73| 31.6k| } else if value == u32::from_ne_bytes(*b"gXYZ").to_be() { 74| 335| return Ok(Self::GreenXyz); 75| 31.2k| } else if value == u32::from_ne_bytes(*b"bXYZ").to_be() { 76| 351| return Ok(Self::BlueXyz); 77| 30.9k| } else if value == u32::from_ne_bytes(*b"rTRC").to_be() { 78| 210| return Ok(Self::RedToneReproduction); 79| 30.7k| } else if value == u32::from_ne_bytes(*b"gTRC").to_be() { 80| 63| return Ok(Self::GreenToneReproduction); 81| 30.6k| } else if value == u32::from_ne_bytes(*b"bTRC").to_be() { 82| 36| return Ok(Self::BlueToneReproduction); 83| 30.6k| } else if value == u32::from_ne_bytes(*b"kTRC").to_be() { 84| 137| return Ok(Self::GreyToneReproduction); 85| 30.4k| } else if value == u32::from_ne_bytes(*b"wtpt").to_be() { 86| 910| return Ok(Self::MediaWhitePoint); 87| 29.5k| } else if value == u32::from_ne_bytes(*b"cicp").to_be() { 88| 58| return Ok(Self::CodeIndependentPoints); 89| 29.5k| } else if value == u32::from_ne_bytes(*b"chad").to_be() { 90| 0| return Ok(Self::ChromaticAdaptation); 91| 29.5k| } else if value == u32::from_ne_bytes(*b"bkpt").to_be() { 92| 609| return Ok(Self::BlackPoint); 93| 28.8k| } else if value == u32::from_ne_bytes(*b"A2B0").to_be() { 94| 0| return Ok(Self::DeviceToPcsLutPerceptual); 95| 28.8k| } else if value == u32::from_ne_bytes(*b"A2B1").to_be() { 96| 0| return Ok(Self::DeviceToPcsLutColorimetric); 97| 28.8k| } else if value == u32::from_ne_bytes(*b"A2B2").to_be() { 98| 0| return Ok(Self::DeviceToPcsLutSaturation); 99| 28.8k| } else if value == u32::from_ne_bytes(*b"B2A0").to_be() { 100| 0| return Ok(Self::PcsToDeviceLutPerceptual); 101| 28.8k| } else if value == u32::from_ne_bytes(*b"B2A1").to_be() { 102| 0| return Ok(Self::PcsToDeviceLutColorimetric); 103| 28.8k| } else if value == u32::from_ne_bytes(*b"B2A2").to_be() { 104| 0| return Ok(Self::PcsToDeviceLutSaturation); 105| 28.8k| } else if value == u32::from_ne_bytes(*b"desc").to_be() { 106| 990| return Ok(Self::ProfileDescription); 107| 27.9k| } else if value == u32::from_ne_bytes(*b"cprt").to_be() { 108| 1.17k| return Ok(Self::Copyright); 109| 26.7k| } else if value == u32::from_ne_bytes(*b"vued").to_be() { 110| 1| return Ok(Self::ViewingConditionsDescription); 111| 26.7k| } else if value == u32::from_ne_bytes(*b"dmnd").to_be() { 112| 1| return Ok(Self::DeviceManufacturer); 113| 26.7k| } else if value == u32::from_ne_bytes(*b"dmdd").to_be() { 114| 1| return Ok(Self::DeviceModel); 115| 26.7k| } else if value == u32::from_ne_bytes(*b"gamt").to_be() { 116| 0| return Ok(Self::Gamut); 117| 26.7k| } else if value == u32::from_ne_bytes(*b"lumi").to_be() { 118| 0| return Ok(Self::Luminance); 119| 26.7k| } else if value == u32::from_ne_bytes(*b"meas").to_be() { 120| 0| return Ok(Self::Measurement); 121| 26.7k| } else if value == u32::from_ne_bytes(*b"chrm").to_be() { 122| 10| return Ok(Self::Chromaticity); 123| 26.7k| } else if value == u32::from_ne_bytes(*b"view").to_be() { 124| 0| return Ok(Self::ObserverConditions); 125| 26.7k| } else if value == u32::from_ne_bytes(*b"targ").to_be() { 126| 1| return Ok(Self::CharTarget); 127| 26.7k| } else if value == u32::from_ne_bytes(*b"tech").to_be() { 128| 0| return Ok(Self::Technology); 129| 26.7k| } else if value == u32::from_ne_bytes(*b"calt").to_be() { 130| 18| return Ok(Self::CalibrationDateTime); 131| 26.6k| } 132| 26.6k| Err(CmsError::UnknownTag(value)) 133| 32.1k| } _RNvXs0_NtCs1jiJzeRTgBH_6moxcms3tagNtB5_17TagTypeDefinitionINtNtCs6SNw0SRvItZ_4core7convert4FrommE4from: 199| 4.44k| fn from(value: u32) -> Self { 200| 4.44k| if value == u32::from_ne_bytes(*b"mluc").to_be() { 201| 0| return TagTypeDefinition::MultiLocalizedUnicode; 202| 4.44k| } else if value == u32::from_ne_bytes(*b"desc").to_be() { 203| 547| return TagTypeDefinition::Description; 204| 3.89k| } else if value == u32::from_ne_bytes(*b"text").to_be() { 205| 56| return TagTypeDefinition::Text; 206| 3.84k| } else if value == u32::from_ne_bytes(*b"mAB ").to_be() { 207| 0| return TagTypeDefinition::MabLut; 208| 3.84k| } else if value == u32::from_ne_bytes(*b"mBA ").to_be() { 209| 0| return TagTypeDefinition::MbaLut; 210| 3.84k| } else if value == u32::from_ne_bytes(*b"para").to_be() { 211| 0| return TagTypeDefinition::ParametricToneCurve; 212| 3.84k| } else if value == u32::from_ne_bytes(*b"curv").to_be() { 213| 33| return TagTypeDefinition::LutToneCurve; 214| 3.80k| } else if value == u32::from_ne_bytes(*b"XYZ ").to_be() { 215| 81| return TagTypeDefinition::Xyz; 216| 3.72k| } else if value == u32::from_ne_bytes(*b"mpet").to_be() { 217| 0| return TagTypeDefinition::MultiProcessElement; 218| 3.72k| } else if value == u32::from_ne_bytes(*b"view").to_be() { 219| 0| return TagTypeDefinition::DefViewingConditions; 220| 3.72k| } else if value == u32::from_ne_bytes(*b"sig ").to_be() { 221| 1| return TagTypeDefinition::Signature; 222| 3.72k| } else if value == u32::from_ne_bytes(*b"cicp").to_be() { 223| 25| 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.44k| } _RNvXs4_NtCs2ICmcE5qjLx_10num_traits10identitieshNtB5_4Zero4zeroCs1vRhqpPUfvi_5image: 42| 4.83k| fn zero() -> $t { 43| | $v 44| 4.83k| } _RNvXs6_NtCs2ICmcE5qjLx_10num_traits10identitiestNtB5_4Zero4zeroCs1vRhqpPUfvi_5image: 42| 1.63k| fn zero() -> $t { 43| | $v 44| 1.63k| } _RNCNvNtCskrDebHigSPL_3png5adam718expand_adam7_bytes0B5_: 309| 1.43G| .map(move |i| (i * samp_mul + samp_off) * u64::from(bytes_pp)) _RNCNvNtCskrDebHigSPL_3png5adam718expand_adam7_bytess_0B5_: 311| 1.43G| .map(move |i| i as usize + byte_start) _RNvMNtCskrDebHigSPL_3png5adam7NtB2_9Adam7Info14pass_constants: 66| 26.8M| fn pass_constants(&self) -> PassConstants { 67| 26.8M| PassConstants::PASSES[self.pass as usize - 1] 68| 26.8M| } _RNvMs0_NtCskrDebHigSPL_3png5adam7NtB5_13Adam7Iterator3new: 161| 2.54k| pub fn new(width: u32, height: u32) -> Adam7Iterator { 162| 2.54k| let mut this = Adam7Iterator { 163| 2.54k| line: 0, 164| 2.54k| lines: 0, 165| 2.54k| line_width: 0, 166| 2.54k| current_pass: 1, 167| 2.54k| width, 168| 2.54k| height, 169| 2.54k| }; 170| 2.54k| this.init_pass(); 171| 2.54k| this 172| 2.54k| } _RNvMs0_NtCskrDebHigSPL_3png5adam7NtB5_13Adam7Iterator9init_pass: 175| 6.88k| fn init_pass(&mut self) { 176| 6.88k| let info = PassConstants::PASSES[self.current_pass as usize - 1]; 177| 6.88k| self.line_width = info.count_samples(self.width); 178| 6.88k| self.lines = info.count_lines(self.height); 179| 6.88k| self.line = 0; 180| 6.88k| } _RNvMs_NtCskrDebHigSPL_3png5adam7NtB4_13PassConstants11count_lines: 107| 24.6k| pub fn count_lines(self, height: u32) -> u32 { 108| 24.6k| height 109| 24.6k| .saturating_sub(u32::from(self.y_offset)) 110| 24.6k| .div_ceil(u32::from(self.y_sampling)) 111| 24.6k| } _RNvMs_NtCskrDebHigSPL_3png5adam7NtB4_13PassConstants13count_samples: 101| 24.6k| pub fn count_samples(self, width: u32) -> u32 { 102| 24.6k| width 103| 24.6k| .saturating_sub(u32::from(self.x_offset)) 104| 24.6k| .div_ceil(u32::from(self.x_sampling)) 105| 24.6k| } _RNvNtCskrDebHigSPL_3png5adam711expand_pass: 348| 26.8M|pub fn expand_pass( 349| 26.8M| img: &mut [u8], 350| 26.8M| img_row_stride: usize, 351| 26.8M| interlaced_row: &[u8], 352| 26.8M| interlace_info: &Adam7Info, 353| 26.8M| bits_per_pixel: u8, 354| 26.8M|) { 355| 26.8M| 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| 26.5M| let byte_indices = expand_adam7_bytes(img_row_stride, interlace_info, 1); 390| | 391| 722M| for (bytepos, &px) in byte_indices.zip(interlaced_row) { 392| 722M| img[bytepos] = px; 393| 722M| } 394| | } 395| | 16 => { 396| 131k| let byte_indices = expand_adam7_bytes(img_row_stride, interlace_info, 2); 397| | 398| 154M| for (bytepos, px) in byte_indices.zip(interlaced_row.chunks(2)) { 399| 154M| img[bytepos..][..2].copy_from_slice(px); 400| 154M| } 401| | } 402| | _ => { 403| 106k| debug_assert!(bits_per_pixel % 8 == 0); 404| 106k| let bytes_pp = bits_per_pixel / 8; 405| 106k| let byte_indices = expand_adam7_bytes(img_row_stride, interlace_info, bytes_pp); 406| | 407| 560M| for (bytepos, px) in byte_indices.zip(interlaced_row.chunks(bytes_pp.into())) { 408| 560M| img[bytepos..][..px.len()].copy_from_slice(px); 409| 560M| } 410| | } 411| | } 412| 26.8M|} _RNvNtCskrDebHigSPL_3png5adam718expand_adam7_bytes: 288| 26.8M|fn expand_adam7_bytes( 289| 26.8M| row_stride_in_bytes: usize, 290| 26.8M| info: &Adam7Info, 291| 26.8M| bytes_pp: u8, 292| 26.8M|) -> impl Iterator { 293| 26.8M| let (line_mul, line_off, samp_mul, samp_off) = { 294| 26.8M| let constants = info.pass_constants(); 295| 26.8M| ( 296| 26.8M| // Convert each to their respectively required type from u8. 297| 26.8M| usize::from(constants.y_sampling), 298| 26.8M| usize::from(constants.y_offset), 299| 26.8M| u64::from(constants.x_sampling), 300| 26.8M| u64::from(constants.x_offset), 301| 26.8M| ) 302| 26.8M| }; 303| | 304| | // the equivalent line number in progressive scan 305| 26.8M| let prog_line = line_mul * info.line as usize + line_off; 306| 26.8M| let byte_start = prog_line * row_stride_in_bytes; 307| | 308| 26.8M| (0..u64::from(info.samples)) 309| 26.8M| .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| 26.8M| .map(move |i| i as usize + byte_start) 312| 26.8M|} _RNvXs1_NtCskrDebHigSPL_3png5adam7NtB5_13Adam7IteratorNtNtNtNtCs6SNw0SRvItZ_4core4iter6traits8iterator8Iterator4next: 186| 26.8M| fn next(&mut self) -> Option { 187| 26.8M| if self.line < self.lines && self.line_width > 0 { 188| 26.8M| let this_line = self.line; 189| 26.8M| self.line += 1; 190| 26.8M| Some(Adam7Info { 191| 26.8M| pass: self.current_pass, 192| 26.8M| line: this_line, 193| 26.8M| width: self.width, 194| 26.8M| samples: self.line_width, 195| 26.8M| }) 196| 4.60k| } else if self.current_pass < 7 { 197| 4.34k| self.current_pass += 1; 198| 4.34k| self.init_pass(); 199| 4.34k| self.next() 200| | } else { 201| 258| None 202| | } 203| 26.8M| } _RNvNtCskrDebHigSPL_3png5chunk11is_critical: 67| 31.1k|pub fn is_critical(ChunkType(type_): ChunkType) -> bool { 68| 31.1k| type_[0] & 32 == 0 69| 31.1k|} _RNvMNtCskrDebHigSPL_3png6commonNtB2_9ColorType10samples_u8: 31| 107M| pub(crate) fn samples_u8(self) -> u8 { 32| | use self::ColorType::*; 33| 107M| match self { 34| 106M| Grayscale | Indexed => 1, 35| 306k| Rgb => 3, 36| 109k| GrayscaleAlpha => 2, 37| 115k| Rgba => 4, 38| | } 39| 107M| } _RNvMNtCskrDebHigSPL_3png6commonNtB2_9ColorType15bytes_per_pixel: 87| 6.76k| 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.76k| self.samples() * ((bit_depth as usize + 7) >> 3) 91| 6.76k| } _RNvMNtCskrDebHigSPL_3png6commonNtB2_9ColorType22checked_raw_row_length: 53| 26.8M| 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| 26.8M| let bits = u64::from(width) * u64::from(self.samples_u8()) * u64::from(depth.into_u8()); 56| 26.8M| TryFrom::try_from(1 + bits.div_ceil(8)).ok() 57| 26.8M| } _RNvMNtCskrDebHigSPL_3png6commonNtB2_9ColorType22is_combination_invalid: 73| 9.90k| 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.90k| ((bit_depth == BitDepth::One || bit_depth == BitDepth::Two || bit_depth == BitDepth::Four) 77| 4.46k| && (self == ColorType::Rgb 78| 4.46k| || self == ColorType::GrayscaleAlpha 79| 4.46k| || self == ColorType::Rgba)) 80| 9.89k| || (bit_depth == BitDepth::Sixteen && self == ColorType::Indexed) 81| 9.90k| } _RNvMNtCskrDebHigSPL_3png6commonNtB2_9ColorType25raw_row_length_from_width: 59| 80.4M| pub(crate) fn raw_row_length_from_width(self, depth: BitDepth, width: u32) -> usize { 60| 80.4M| let samples = width as usize * self.samples(); 61| 80.4M| 1 + match depth { 62| 490k| BitDepth::Sixteen => samples * 2, 63| 79.4M| BitDepth::Eight => samples, 64| 518k| subbyte => { 65| 518k| let samples_per_byte = 8 / subbyte as usize; 66| 518k| let whole = samples / samples_per_byte; 67| 518k| let fract = usize::from(samples % samples_per_byte > 0); 68| 518k| whole + fract 69| | } 70| | } 71| 80.4M| } _RNvMNtCskrDebHigSPL_3png6commonNtB2_9ColorType7from_u8: 42| 9.90k| pub fn from_u8(n: u8) -> Option { 43| 9.90k| match n { 44| 5.53k| 0 => Some(ColorType::Grayscale), 45| 1.39k| 2 => Some(ColorType::Rgb), 46| 1.27k| 3 => Some(ColorType::Indexed), 47| 423| 4 => Some(ColorType::GrayscaleAlpha), 48| 1.26k| 6 => Some(ColorType::Rgba), 49| 8| _ => None, 50| | } 51| 9.90k| } _RNvMNtCskrDebHigSPL_3png6commonNtB2_9ColorType7samples: 27| 80.4M| pub fn samples(self) -> usize { 28| 80.4M| self.samples_u8().into() 29| 80.4M| } _RNvMs0_NtCskrDebHigSPL_3png6commonNtB5_4Unit7from_u8: 160| 364| pub fn from_u8(n: u8) -> Option { 161| 364| match n { 162| 13| 0 => Some(Unit::Unspecified), 163| 21| 1 => Some(Unit::Meter), 164| 330| _ => None, 165| | } 166| 364| } _RNvMs1_NtCskrDebHigSPL_3png6commonNtB5_9DisposeOp7from_u8: 183| 189| pub fn from_u8(n: u8) -> Option { 184| 189| match n { 185| 93| 0 => Some(DisposeOp::None), 186| 93| 1 => Some(DisposeOp::Background), 187| 0| 2 => Some(DisposeOp::Previous), 188| 3| _ => None, 189| | } 190| 189| } _RNvMs3_NtCskrDebHigSPL_3png6commonNtB5_7BlendOp7from_u8: 216| 186| pub fn from_u8(n: u8) -> Option { 217| 186| match n { 218| 175| 0 => Some(BlendOp::Source), 219| 10| 1 => Some(BlendOp::Over), 220| 1| _ => None, 221| | } 222| 186| } _RNvMs_NtCskrDebHigSPL_3png6commonNtB4_8BitDepth7from_u8: 123| 80.4M| pub fn from_u8(n: u8) -> Option { 124| 80.4M| match n { 125| 2.71k| 1 => Some(BitDepth::One), 126| 694| 2 => Some(BitDepth::Two), 127| 1.07k| 4 => Some(BitDepth::Four), 128| 80.0M| 8 => Some(BitDepth::Eight), 129| 491k| 16 => Some(BitDepth::Sixteen), 130| 21| _ => None, 131| | } 132| 80.4M| } _RNvMs_NtCskrDebHigSPL_3png6commonNtB4_8BitDepth7into_u8: 134| 26.8M| pub(crate) fn into_u8(self) -> u8 { 135| 26.8M| self as u8 136| 26.8M| } _RNvMsb_NtCskrDebHigSPL_3png6commonNtB5_11ScaledFloat11from_scaled: 458| 331| pub fn from_scaled(val: u32) -> Self { 459| 331| Self(val) 460| 331| } _RNvMsd_NtCskrDebHigSPL_3png6commonNtB5_19SrgbRenderingIntent8from_raw: 544| 259| pub(crate) fn from_raw(raw: u8) -> Option { 545| 259| match raw { 546| 16| 0 => Some(SrgbRenderingIntent::Perceptual), 547| 40| 1 => Some(SrgbRenderingIntent::RelativeColorimetric), 548| 0| 2 => Some(SrgbRenderingIntent::Saturation), 549| 0| 3 => Some(SrgbRenderingIntent::AbsoluteColorimetric), 550| 203| _ => None, 551| | } 552| 259| } _RNvMsf_NtCskrDebHigSPL_3png6commonNtB5_4Info15bytes_per_pixel: 772| 6.76k| 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.76k| self.color_type.bytes_per_pixel(self.bit_depth) 776| 6.76k| } _RNvMsf_NtCskrDebHigSPL_3png6commonNtB5_4Info17bpp_in_prediction: 785| 6.76k| pub(crate) fn bpp_in_prediction(&self) -> BytesPerPixel { 786| 6.76k| BytesPerPixel::from_usize(self.bytes_per_pixel()) 787| 6.76k| } _RNvMsf_NtCskrDebHigSPL_3png6commonNtB5_4Info22checked_raw_row_length: 799| 29.6k| pub(crate) fn checked_raw_row_length(&self) -> Option { 800| 29.6k| self.color_type 801| 29.6k| .checked_raw_row_length(self.bit_depth, self.width) 802| 29.6k| } _RNvMsf_NtCskrDebHigSPL_3png6commonNtB5_4Info25raw_row_length_from_width: 805| 26.8M| pub fn raw_row_length_from_width(&self, width: u32) -> usize { 806| 26.8M| self.color_type 807| 26.8M| .raw_row_length_from_width(self.bit_depth, width) 808| 26.8M| } _RNvMsf_NtCskrDebHigSPL_3png6commonNtB5_4Info4size: 747| 36.0k| pub fn size(&self) -> (u32, u32) { 748| 36.0k| (self.width, self.height) 749| 36.0k| } _RNvMsg_NtCskrDebHigSPL_3png6commonNtB5_13BytesPerPixel10from_usize: 841| 6.76k| pub(crate) fn from_usize(bpp: usize) -> Self { 842| 6.76k| match bpp { 843| 3.96k| 1 => BytesPerPixel::One, 844| 1.10k| 2 => BytesPerPixel::Two, 845| 672| 3 => BytesPerPixel::Three, 846| 358| 4 => BytesPerPixel::Four, 847| 410| 6 => BytesPerPixel::Six, // Only rgb×16bit 848| 259| 8 => BytesPerPixel::Eight, // Only rgba×16bit 849| 0| _ => unreachable!("Not a possible byte rounded pixel width"), 850| | } 851| 6.76k| } _RNvXse_NtCskrDebHigSPL_3png6commonNtB5_4InfoNtNtCs6SNw0SRvItZ_4core7default7Default7default: 705| 9.87k| fn default() -> Info<'static> { 706| 9.87k| Info { 707| 9.87k| width: 0, 708| 9.87k| height: 0, 709| 9.87k| bit_depth: BitDepth::Eight, 710| 9.87k| color_type: ColorType::Grayscale, 711| 9.87k| interlaced: false, 712| 9.87k| palette: None, 713| 9.87k| sbit: None, 714| 9.87k| trns: None, 715| 9.87k| gama_chunk: None, 716| 9.87k| chrm_chunk: None, 717| 9.87k| bkgd: None, 718| 9.87k| pixel_dims: None, 719| 9.87k| frame_control: None, 720| 9.87k| animation_control: None, 721| 9.87k| source_gamma: None, 722| 9.87k| source_chromaticities: None, 723| 9.87k| srgb: None, 724| 9.87k| icc_profile: None, 725| 9.87k| coding_independent_code_points: None, 726| 9.87k| mastering_display_color_volume: None, 727| 9.87k| content_light_level: None, 728| 9.87k| exif_metadata: None, 729| 9.87k| uncompressed_latin1_text: Vec::new(), 730| 9.87k| compressed_latin1_text: Vec::new(), 731| 9.87k| utf8_text: Vec::new(), 732| 9.87k| } 733| 9.87k| } _RNvMNtNtCskrDebHigSPL_3png7decoder14interlace_infoNtB2_13InterlaceInfo11line_number: 38| 26.8M| pub(crate) fn line_number(&self) -> u32 { 39| 26.8M| match self { 40| 4.00k| InterlaceInfo::Null(NullInfo { line }) => *line, 41| 26.8M| InterlaceInfo::Adam7(Adam7Info { line, .. }) => *line, 42| | } 43| 26.8M| } _RNvMNtNtCskrDebHigSPL_3png7decoder14interlace_infoNtB2_13InterlaceInfo14get_adam7_info: 45| 26.8M| pub(crate) fn get_adam7_info(&self) -> Option<&Adam7Info> { 46| 26.8M| match self { 47| 0| InterlaceInfo::Null(_) => None, 48| 26.8M| InterlaceInfo::Adam7(adam7info) => Some(adam7info), 49| | } 50| 26.8M| } _RNvMs_NtNtCskrDebHigSPL_3png7decoder14interlace_infoNtB4_17InterlaceInfoIter3new: 60| 6.76k| pub fn new(width: u32, height: u32, interlaced: bool) -> Self { 61| 6.76k| if interlaced { 62| 2.54k| Self(IterImpl::Adam7(Adam7Iterator::new(width, height))) 63| | } else { 64| 4.21k| Self(IterImpl::None(0..height)) 65| | } 66| 6.76k| } _RNvMs_NtNtCskrDebHigSPL_3png7decoder14interlace_infoNtB4_17InterlaceInfoIter5empty: 56| 9.87k| pub fn empty() -> Self { 57| 9.87k| Self(IterImpl::None(0..0)) 58| 9.87k| } _RNvXs0_NtNtCskrDebHigSPL_3png7decoder14interlace_infoNtB5_17InterlaceInfoIterNtNtNtNtCs6SNw0SRvItZ_4core4iter6traits8iterator8Iterator4next: 72| 27.1M| fn next(&mut self) -> Option { 73| 27.1M| match self.0 { 74| 26.8M| IterImpl::Adam7(ref mut adam7) => Some(InterlaceInfo::Adam7(adam7.next()?)), 75| 384k| IterImpl::None(ref mut height) => Some(InterlaceInfo::Null(NullInfo { 76| 384k| line: height.next()?, 77| | })), 78| | } 79| 27.1M| } _RNCNCNvMs4_NtCskrDebHigSPL_3png7decoderINtB9_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE19next_interlaced_row00Cs1vRhqpPUfvi_5image: 533| 26.8M| option.map(move |interlace| { 534| 26.8M| let output_line_size = self.output_line_size_for_interlace_info(&interlace); 535| 26.8M| InterlacedRow { 536| 26.8M| data: &self.scratch_buffer[..output_line_size], 537| 26.8M| interlace, 538| 26.8M| } 539| 26.8M| }) _RNCNvMs4_NtCskrDebHigSPL_3png7decoderINtB7_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE10next_frame0Cs1vRhqpPUfvi_5image: 472| 4.00k| .map(|info| info.line_number()) _RNCNvMs4_NtCskrDebHigSPL_3png7decoderINtB7_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE19next_interlaced_row0Cs1vRhqpPUfvi_5image: 532| 26.8M| result.map(move |option| { 533| 26.8M| 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| 26.8M| }) _RNCNvMs4_NtCskrDebHigSPL_3png7decoderINtB7_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE23next_raw_interlaced_row0Cs1vRhqpPUfvi_5image: 712| 1.44M| .with_unfilled_buffer(|buffer| self.decoder.decode_image_data(Some(buffer))); _RNvMs3_NtCskrDebHigSPL_3png7decoderINtB5_7DecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE10set_limitsCs1vRhqpPUfvi_5image: 177| 10.1k| pub fn set_limits(&mut self, limits: Limits) { 178| 10.1k| self.read_decoder.set_limits(limits); 179| 10.1k| } _RNvMs3_NtCskrDebHigSPL_3png7decoderINtB5_7DecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE15new_with_limitsCs1vRhqpPUfvi_5image: 132| 10.1k| pub fn new_with_limits(r: R, limits: Limits) -> Decoder { 133| 10.1k| let mut read_decoder = ReadDecoder::new(r); 134| 10.1k| read_decoder.set_limits(limits); 135| | 136| 10.1k| Decoder { 137| 10.1k| read_decoder, 138| 10.1k| transform: Transformations::IDENTITY, 139| 10.1k| } 140| 10.1k| } _RNvMs3_NtCskrDebHigSPL_3png7decoderINtB5_7DecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE16read_header_infoCs1vRhqpPUfvi_5image: 187| 20.0k| pub fn read_header_info(&mut self) -> Result<&Info<'static>, DecodingError> { 188| 20.0k| self.read_decoder.read_header_info() 189| 20.0k| } _RNvMs3_NtCskrDebHigSPL_3png7decoderINtB5_7DecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE19set_transformationsCs1vRhqpPUfvi_5image: 250| 9.87k| pub fn set_transformations(&mut self, transform: Transformations) { 251| 9.87k| self.transform = transform; 252| 9.87k| } _RNvMs3_NtCskrDebHigSPL_3png7decoderINtB5_7DecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE21set_ignore_text_chunkCs1vRhqpPUfvi_5image: 265| 10.1k| pub fn set_ignore_text_chunk(&mut self, ignore_text_chunk: bool) { 266| 10.1k| self.read_decoder.set_ignore_text_chunk(ignore_text_chunk); 267| 10.1k| } _RNvMs3_NtCskrDebHigSPL_3png7decoderINtB5_7DecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE9read_infoCs1vRhqpPUfvi_5image: 192| 9.87k| pub fn read_info(mut self) -> Result, DecodingError> { 193| 9.87k| let info = self.read_header_info()?; 194| 9.87k| let unfiltering_buffer = UnfilteringBuffer::new(info); 195| | 196| 9.87k| let mut reader = Reader { 197| 9.87k| decoder: self.read_decoder, 198| 9.87k| bpp: BytesPerPixel::One, 199| 9.87k| subframe: SubframeInfo::not_yet_init(), 200| 9.87k| remaining_frames: 0, // Temporary value - fixed below after reading `acTL` and `fcTL`. 201| 9.87k| unfiltering_buffer, 202| 9.87k| transform: self.transform, 203| 9.87k| transform_fn: None, 204| 9.87k| scratch_buffer: Vec::new(), 205| 9.87k| finished: false, 206| 9.87k| }; 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.87k| if reader.info().checked_raw_row_length().is_none() { 216| 0| return Err(DecodingError::LimitsExceeded); 217| 9.87k| } 218| | 219| | // Check if the output buffer has a valid size. 220| | // 221| | // FIXME: see above and 222| | // 223| 9.87k| if reader.output_buffer_size().is_none() { 224| 53| return Err(DecodingError::LimitsExceeded); 225| 9.82k| } 226| | 227| 9.82k| reader.read_until_image_data()?; 228| | 229| 6.73k| reader.remaining_frames = match reader.info().animation_control.as_ref() { 230| 6.67k| None => 1, // No `acTL` => only expecting `IDAT` frame. 231| 60| 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| 60| let mut num_frames = animation.num_frames; 235| 60| if reader.info().frame_control.is_none() { 236| 60| // No `fcTL` before `IDAT` => `IDAT` is not part of the animation, but 237| 60| // represents an *extra*, default frame for non-APNG-aware decoders. 238| 60| num_frames += 1; 239| 60| } 240| 60| num_frames 241| | } 242| | }; 243| 6.73k| Ok(reader) 244| 9.87k| } _RNvMs4_NtCskrDebHigSPL_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE10next_frameCs1vRhqpPUfvi_5image: 416| 6.47k| pub fn next_frame(&mut self, buf: &mut [u8]) -> Result { 417| 6.47k| if self.remaining_frames == 0 { 418| 0| return Err(DecodingError::Parameter( 419| 0| ParameterErrorKind::PolledAfterEndOfImage.into(), 420| 0| )); 421| 6.47k| } else if self.subframe.consumed_and_flushed { 422| | // Advance until the next `fdAT` 423| | // (along the way we should encounter the fcTL for this frame). 424| 0| self.read_until_image_data()?; 425| 6.47k| } 426| | 427| | // Note that we only check if the buffer size calculation holds in a call to decoding the 428| | // frame. Consequently, we can represent the `Info` and frameless decoding even when the 429| | // target architecture's address space is too small for a frame. However reading the actual 430| 6.47k| let required_len = self 431| 6.47k| .output_buffer_size() 432| 6.47k| .ok_or(DecodingError::LimitsExceeded)?; 433| | 434| 6.47k| if buf.len() < required_len { 435| 0| return Err(DecodingError::Parameter( 436| 0| ParameterErrorKind::ImageBufferSize { 437| 0| expected: required_len, 438| 0| actual: buf.len(), 439| 0| } 440| 0| .into(), 441| 0| )); 442| 6.47k| } 443| | 444| 6.47k| let (color_type, bit_depth) = self.output_color_type(); 445| 6.47k| let output_info = OutputInfo { 446| 6.47k| width: self.subframe.width, 447| 6.47k| height: self.subframe.height, 448| 6.47k| color_type, 449| 6.47k| bit_depth, 450| 6.47k| line_size: self.unguarded_output_line_size(self.subframe.width), 451| 6.47k| }; 452| | 453| 6.47k| if self.info().interlaced { 454| 2.47k| let stride = self.unguarded_output_line_size(self.info().width); 455| 2.47k| let samples = color_type.samples() as u8; 456| 2.47k| let bits_pp = samples * (bit_depth as u8); 457| 2.47k| let expand = crate::adam7::expand_pass; 458| | 459| | while let Some(InterlacedRow { 460| 26.8M| data: row, 461| 26.8M| interlace, 462| | .. 463| 26.8M| }) = self.next_interlaced_row()? 464| 26.8M| { 465| 26.8M| // `unwrap` won't panic, because we checked `self.info().interlaced` above. 466| 26.8M| let adam7info = interlace.get_adam7_info().unwrap(); 467| 26.8M| expand(buf, stride, row, adam7info, bits_pp); 468| 26.8M| } 469| | } else { 470| 4.00k| let current_interlace_info = self.subframe.current_interlace_info.as_ref(); 471| 4.00k| let already_done_rows = current_interlace_info 472| 4.00k| .map(|info| info.line_number()) 473| 4.00k| .unwrap_or(self.subframe.height); 474| | 475| 382k| for row in buf 476| 4.00k| .chunks_exact_mut(output_info.line_size) 477| 4.00k| .take(self.subframe.height as usize) 478| 4.00k| .skip(already_done_rows as usize) 479| | { 480| 382k| self.next_interlaced_row_impl(self.subframe.rowlen, row)?; 481| | } 482| | } 483| | 484| | // Advance over the rest of data for this (sub-)frame. 485| 2.47k| self.finish_decoding()?; 486| | 487| 2.33k| Ok(output_info) 488| 6.47k| } _RNvMs4_NtCskrDebHigSPL_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE15finish_decodingCs1vRhqpPUfvi_5image: 499| 2.73k| 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.73k| 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.73k| if !self.subframe.consumed_and_flushed { 506| 2.65k| self.decoder.finish_decoding_image_data()?; 507| 2.32k| self.mark_subframe_as_consumed_and_flushed(); 508| 80| } 509| | 510| 2.40k| Ok(()) 511| 2.73k| } _RNvMs4_NtCskrDebHigSPL_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE16output_line_sizeCs1vRhqpPUfvi_5image: 692| 26.8M| pub fn output_line_size(&self, width: u32) -> Option { 693| 26.8M| let (color, depth) = self.output_color_type(); 694| 26.8M| 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| 26.8M| (length <= isize::MAX as usize).then_some(length) 697| 26.8M| } _RNvMs4_NtCskrDebHigSPL_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE17output_color_typeCs1vRhqpPUfvi_5image: 629| 80.4M| pub fn output_color_type(&self) -> (ColorType, BitDepth) { 630| | use crate::common::ColorType::*; 631| 80.4M| let t = self.transform; 632| 80.4M| let info = self.info(); 633| 80.4M| if t == Transformations::IDENTITY { 634| 0| (info.color_type, info.bit_depth) 635| | } else { 636| 80.4M| let bits = match info.bit_depth as u8 { 637| 489k| 16 if t.intersects(Transformations::STRIP_16) => 8, 638| 80.4M| n if n < 8 639| 1.55M| && (t.contains(Transformations::EXPAND) 640| 1.55M| || t.contains(Transformations::ALPHA)) => 641| | { 642| 1.55M| 8 643| | } 644| 78.9M| n => n, 645| | }; 646| 80.4M| let color_type = 647| 80.4M| if t.contains(Transformations::EXPAND) || t.contains(Transformations::ALPHA) { 648| 80.4M| let has_trns = info.trns.is_some() || t.contains(Transformations::ALPHA); 649| 80.1M| match info.color_type { 650| 21.2k| Grayscale if has_trns => GrayscaleAlpha, 651| 12.7k| Rgb if has_trns => Rgba, 652| 21.6k| Indexed if has_trns => Rgba, 653| 20.9k| Indexed => Rgb, 654| 80.4M| ct => ct, 655| | } 656| | } else { 657| 0| info.color_type 658| | }; 659| 80.4M| (color_type, BitDepth::from_u8(bits).unwrap()) 660| | } 661| 80.4M| } _RNvMs4_NtCskrDebHigSPL_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE18output_buffer_sizeCs1vRhqpPUfvi_5image: 668| 16.3k| pub fn output_buffer_size(&self) -> Option { 669| 16.3k| let (width, height) = self.info().size(); 670| 16.3k| let (color, depth) = self.output_color_type(); 671| | // The subtraction should always work, but we do this for consistency. Also note that by 672| | // calling `checked_raw_row_length` the row buffer is guaranteed to work whereas if we 673| | // ran other function that didn't include the filter byte that could later fail on an image 674| | // that is `1xN`... 675| 16.3k| let linelen = color.checked_raw_row_length(depth, width)?.checked_sub(1)?; 676| 16.3k| let height = usize::try_from(height).ok()?; 677| 16.3k| let imglen = linelen.checked_mul(height)?; 678| | // Ensure that it fits into address space not only `usize` to allocate. 679| 16.3k| (imglen <= isize::MAX as usize).then_some(imglen) 680| 16.3k| } _RNvMs4_NtCskrDebHigSPL_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE19next_interlaced_rowCs1vRhqpPUfvi_5image: 524| 26.8M| pub fn next_interlaced_row(&mut self) -> Result>, DecodingError> { 525| 26.8M| let mut output_buffer = mem::take(&mut self.scratch_buffer); 526| 26.8M| let max_line_size = self 527| 26.8M| .output_line_size(self.info().width) 528| 26.8M| .ok_or(DecodingError::LimitsExceeded)?; 529| 26.8M| output_buffer.resize(max_line_size, 0u8); 530| 26.8M| let result = self.read_row(&mut output_buffer); 531| 26.8M| self.scratch_buffer = output_buffer; 532| 26.8M| 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| 26.8M| } _RNvMs4_NtCskrDebHigSPL_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE21read_until_image_dataCs1vRhqpPUfvi_5image: 368| 9.82k| fn read_until_image_data(&mut self) -> Result<(), DecodingError> { 369| 9.82k| self.decoder.read_until_image_data()?; 370| | 371| 6.76k| self.subframe = SubframeInfo::new(self.info()); 372| 6.76k| self.bpp = self.info().bpp_in_prediction(); 373| | 374| 6.76k| let frame_bytes = if self.info().interlaced { 375| 2.54k| let mut bytes = 0u64; 376| 20.3k| for pass in crate::adam7::PassConstants::PASSES { 377| 17.7k| bytes += self 378| 17.7k| .info() 379| 17.7k| .raw_row_length_from_width(pass.count_samples(self.subframe.width)) 380| 17.7k| as u64 381| 17.7k| * pass.count_lines(self.subframe.height) as u64; 382| 17.7k| } 383| 2.54k| bytes 384| | } else { 385| 4.21k| (self.subframe.rowlen as u64) * self.subframe.height as u64 386| | }; 387| 6.76k| self.unfiltering_buffer.start_frame(frame_bytes); 388| | 389| | // Allocate output buffer. 390| 6.76k| let buflen = self.unguarded_output_line_size(self.subframe.width); 391| 6.76k| self.decoder.reserve_bytes(buflen)?; 392| | 393| 6.73k| Ok(()) 394| 9.82k| } _RNvMs4_NtCskrDebHigSPL_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE23next_raw_interlaced_rowCs1vRhqpPUfvi_5image: 700| 27.1M| fn next_raw_interlaced_row(&mut self, rowlen: usize) -> Result<(), DecodingError> { 701| | // Read image data until we have at least one full row (but possibly more than one). 702| 27.8M| while self.unfiltering_buffer.mutable_len_of_curr_row() < rowlen { 703| 1.44M| if self.subframe.consumed_and_flushed { 704| 28| return Err(DecodingError::Format( 705| 28| FormatErrorInner::NoMoreImageData.into(), 706| 28| )); 707| 1.44M| } 708| | 709| 1.44M| assert!(self.unfiltering_buffer.remaining_bytes() > 0); 710| 1.44M| let completion_status = self 711| 1.44M| .unfiltering_buffer 712| 1.44M| .with_unfilled_buffer(|buffer| self.decoder.decode_image_data(Some(buffer))); 713| 691k| match completion_status { 714| 691k| Ok(ImageDataCompletionStatus::ExpectingMoreData) => (), 715| 29| Ok(ImageDataCompletionStatus::Done) => self.mark_subframe_as_consumed_and_flushed(), 716| 745k| Err(DecodingError::IoError(e)) 717| 748k| if e.kind() == std::io::ErrorKind::UnexpectedEof 718| 748k| && self.unfiltering_buffer.readable_len_of_curr_row() >= rowlen => 719| | { 720| 745k| return self 721| 745k| .unfiltering_buffer 722| 745k| .unfilter_curr_row_using_scratch_buffer(rowlen, self.bpp); 723| | } 724| 3.62k| Err(other_error) => return Err(other_error), 725| | } 726| | } 727| | 728| 26.4M| self.unfiltering_buffer 729| 26.4M| .unfilter_curr_row_in_place(rowlen, self.bpp) 730| 27.1M| } _RNvMs4_NtCskrDebHigSPL_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE24next_interlaced_row_implCs1vRhqpPUfvi_5image: 605| 27.1M| fn next_interlaced_row_impl( 606| 27.1M| &mut self, 607| 27.1M| rowlen: usize, 608| 27.1M| output_buffer: &mut [u8], 609| 27.1M| ) -> Result<(), DecodingError> { 610| 27.1M| self.next_raw_interlaced_row(rowlen)?; 611| 27.1M| let row = self.unfiltering_buffer.prev_row(); 612| 27.1M| assert_eq!(row.len(), rowlen - 1); 613| | 614| | // Apply transformations and write resulting data to buffer. 615| 27.1M| let transform_fn = { 616| 27.1M| if self.transform_fn.is_none() { 617| 4.90k| self.transform_fn = Some(create_transform_fn(self.info(), self.transform)?); 618| 27.1M| } 619| 27.1M| self.transform_fn.as_deref().unwrap() 620| | }; 621| 27.1M| transform_fn(row, output_buffer, self.info()); 622| | 623| 27.1M| self.subframe.current_interlace_info = self.subframe.interlace_info_iter.next(); 624| 27.1M| Ok(()) 625| 27.1M| } _RNvMs4_NtCskrDebHigSPL_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE26unguarded_output_line_sizeCs1vRhqpPUfvi_5image: 683| 53.6M| pub(crate) fn unguarded_output_line_size(&self, width: u32) -> usize { 684| 53.6M| let (color, depth) = self.output_color_type(); 685| 53.6M| color.raw_row_length_from_width(depth, width) - 1 686| 53.6M| } _RNvMs4_NtCskrDebHigSPL_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE35output_line_size_for_interlace_infoCs1vRhqpPUfvi_5image: 580| 53.6M| fn output_line_size_for_interlace_info(&self, interlace: &InterlaceInfo) -> usize { 581| 53.6M| let width = match interlace { 582| 53.6M| InterlaceInfo::Adam7(Adam7Info { samples: width, .. }) => *width, 583| 0| InterlaceInfo::Null(_) => self.subframe.width, 584| | }; 585| 53.6M| self.unguarded_output_line_size(width) 586| 53.6M| } _RNvMs4_NtCskrDebHigSPL_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE37mark_subframe_as_consumed_and_flushedCs1vRhqpPUfvi_5image: 490| 2.35k| fn mark_subframe_as_consumed_and_flushed(&mut self) { 491| 2.35k| assert!(self.remaining_frames > 0); 492| 2.35k| self.remaining_frames -= 1; 493| | 494| 2.35k| self.subframe.consumed_and_flushed = true; 495| 2.35k| } _RNvMs4_NtCskrDebHigSPL_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE4infoCs1vRhqpPUfvi_5image: 399| 161M| pub fn info(&self) -> &Info<'static> { 400| 161M| self.decoder.info().unwrap() 401| 161M| } _RNvMs4_NtCskrDebHigSPL_3png7decoderINtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE8read_rowCs1vRhqpPUfvi_5image: 551| 26.8M| pub fn read_row( 552| 26.8M| &mut self, 553| 26.8M| output_buffer: &mut [u8], 554| 26.8M| ) -> Result, DecodingError> { 555| 26.8M| let interlace = match self.subframe.current_interlace_info.as_ref() { 556| | None => { 557| 258| self.finish_decoding()?; 558| 79| return Ok(None); 559| | } 560| 26.8M| Some(interlace) => *interlace, 561| | }; 562| 26.8M| if interlace.line_number() == 0 { 563| 6.19k| self.unfiltering_buffer.reset_prev_row(); 564| 26.8M| } 565| 26.8M| let rowlen = match interlace { 566| 0| InterlaceInfo::Null(_) => self.subframe.rowlen, 567| 26.8M| InterlaceInfo::Adam7(Adam7Info { samples: width, .. }) => { 568| 26.8M| self.info().raw_row_length_from_width(width) 569| | } 570| | }; 571| | 572| 26.8M| let output_line_size = self.output_line_size_for_interlace_info(&interlace); 573| 26.8M| let output_buffer = &mut output_buffer[..output_line_size]; 574| | 575| 26.8M| self.next_interlaced_row_impl(rowlen, output_buffer)?; 576| | 577| 26.8M| Ok(Some(interlace)) 578| 26.8M| } _RNvMs5_NtCskrDebHigSPL_3png7decoderNtB5_12SubframeInfo12not_yet_init: 734| 9.87k| fn not_yet_init() -> Self { 735| 9.87k| SubframeInfo { 736| 9.87k| width: 0, 737| 9.87k| height: 0, 738| 9.87k| rowlen: 0, 739| 9.87k| current_interlace_info: None, 740| 9.87k| interlace_info_iter: InterlaceInfoIter::empty(), 741| 9.87k| consumed_and_flushed: false, 742| 9.87k| } 743| 9.87k| } _RNvMs5_NtCskrDebHigSPL_3png7decoderNtB5_12SubframeInfo3new: 745| 6.76k| 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.76k| let (width, height) = if let Some(fc) = info.frame_control { 749| 0| (fc.width, fc.height) 750| | } else { 751| 6.76k| (info.width, info.height) 752| | }; 753| | 754| 6.76k| let mut interlace_info_iter = InterlaceInfoIter::new(width, height, info.interlaced); 755| 6.76k| let current_interlace_info = interlace_info_iter.next(); 756| 6.76k| SubframeInfo { 757| 6.76k| width, 758| 6.76k| height, 759| 6.76k| rowlen: info.raw_row_length_from_width(width), 760| 6.76k| current_interlace_info, 761| 6.76k| interlace_info_iter, 762| 6.76k| consumed_and_flushed: false, 763| 6.76k| } 764| 6.76k| } _RNvMs_NtCskrDebHigSPL_3png7decoderNtB4_6Limits13reserve_bytes: 71| 108k| pub(crate) fn reserve_bytes(&mut self, bytes: usize) -> Result<(), DecodingError> { 72| 108k| if self.bytes >= bytes { 73| 108k| self.bytes -= bytes; 74| 108k| Ok(()) 75| | } else { 76| 21| Err(DecodingError::LimitsExceeded) 77| | } 78| 108k| } _RNvMNtNtCskrDebHigSPL_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE10set_limitsCs1vRhqpPUfvi_5image: 39| 20.3k| pub fn set_limits(&mut self, limits: Limits) { 40| 20.3k| self.decoder.limits = limits; 41| 20.3k| } _RNvMNtNtCskrDebHigSPL_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE11decode_nextCs1vRhqpPUfvi_5image: 62| 1.72M| fn decode_next( 63| 1.72M| &mut self, 64| 1.72M| image_data: Option<&mut UnfilterBuf<'_>>, 65| 1.72M| ) -> Result { 66| 974k| let (consumed, result) = { 67| 1.72M| let buf = self.reader.fill_buf()?; 68| 1.72M| if buf.is_empty() { 69| 751k| return Err(DecodingError::IoError(ErrorKind::UnexpectedEof.into())); 70| 975k| } 71| 975k| self.decoder.update(buf, image_data)? 72| | }; 73| 974k| self.reader.consume(consumed); 74| 974k| Ok(result) 75| 1.72M| } _RNvMNtNtCskrDebHigSPL_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE13reserve_bytesCs1vRhqpPUfvi_5image: 43| 6.76k| pub fn reserve_bytes(&mut self, bytes: usize) -> Result<(), DecodingError> { 44| 6.76k| self.decoder.limits.reserve_bytes(bytes) 45| 6.76k| } _RNvMNtNtCskrDebHigSPL_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE16read_header_infoCs1vRhqpPUfvi_5image: 80| 20.0k| pub fn read_header_info(&mut self) -> Result<&Info<'static>, DecodingError> { 81| 39.9k| while self.info().is_none() { 82| 20.1k| if let Decoded::ChunkComplete(chunk::IEND) = self.decode_next(None)? { 83| 0| unreachable!() 84| 19.8k| } 85| | } 86| 19.7k| Ok(self.info().unwrap()) 87| 20.0k| } _RNvMNtNtCskrDebHigSPL_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE17decode_image_dataCs1vRhqpPUfvi_5image: 113| 1.44M| pub fn decode_image_data( 114| 1.44M| &mut self, 115| 1.44M| image_data: Option<&mut UnfilterBuf<'_>>, 116| 1.44M| ) -> Result { 117| 1.44M| match self.decode_next(image_data)? { 118| 681k| Decoded::ImageData => Ok(ImageDataCompletionStatus::ExpectingMoreData), 119| 2.35k| Decoded::ImageDataFlushed => Ok(ImageDataCompletionStatus::Done), 120| | // Ignore other events that may happen within an `IDAT` / `fdAT` chunks sequence. 121| 14.2k| _ => Ok(ImageDataCompletionStatus::ExpectingMoreData), 122| | } 123| 1.44M| } _RNvMNtNtCskrDebHigSPL_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE21read_until_image_dataCs1vRhqpPUfvi_5image: 92| 9.82k| pub fn read_until_image_data(&mut self) -> Result<(), DecodingError> { 93| | loop { 94| 259k| match self.decode_next(None)? { 95| 6.76k| 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| 249k| _ => {} 104| | } 105| | } 106| 6.76k| Ok(()) 107| 9.82k| } _RNvMNtNtCskrDebHigSPL_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE21set_ignore_text_chunkCs1vRhqpPUfvi_5image: 47| 10.1k| pub fn set_ignore_text_chunk(&mut self, ignore_text_chunk: bool) { 48| 10.1k| self.decoder.set_ignore_text_chunk(ignore_text_chunk); 49| 10.1k| } _RNvMNtNtCskrDebHigSPL_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE26finish_decoding_image_dataCs1vRhqpPUfvi_5image: 128| 2.65k| pub fn finish_decoding_image_data(&mut self) -> Result<(), DecodingError> { 129| | loop { 130| 7.09k| if let ImageDataCompletionStatus::Done = self.decode_image_data(None)? { 131| 2.32k| return Ok(()); 132| 4.44k| } 133| | } 134| 2.65k| } _RNvMNtNtCskrDebHigSPL_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE3newCs1vRhqpPUfvi_5image: 25| 10.1k| pub fn new(r: R) -> Self { 26| 10.1k| Self { 27| 10.1k| reader: r, 28| 10.1k| decoder: StreamingDecoder::new(), 29| 10.1k| } 30| 10.1k| } _RNvMNtNtCskrDebHigSPL_3png7decoder12read_decoderINtB2_11ReadDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE4infoCs1vRhqpPUfvi_5image: 144| 161M| pub fn info(&self) -> Option<&Info<'static>> { 145| 161M| self.decoder.info.as_ref() 146| 161M| } _RNCNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB7_16StreamingDecoder10parse_itxt0Bb_: 1884| 109| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingCompressionFlag))?; _RNCNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB7_16StreamingDecoder10parse_itxts0_0Bb_: 1892| 59.7k| .position(|&b| b == 0) _RNCNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB7_16StreamingDecoder10parse_itxts1_0Bb_: 1893| 417| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))? _RNCNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB7_16StreamingDecoder10parse_itxts2_0Bb_: 1900| 25.8k| .position(|&b| b == 0) _RNCNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB7_16StreamingDecoder10parse_itxts3_0Bb_: 1901| 430| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))? _RNCNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB7_16StreamingDecoder10parse_itxts_0Bb_: 1888| 70| .ok_or_else(|| DecodingError::from(TextDecodingError::InvalidCompressionMethod))?; _RNCNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB7_16StreamingDecoder10parse_srgb0Bb_: 1522| 203| let rendering_intent = crate::SrgbRenderingIntent::from_raw(raw).ok_or_else(|| { 1523| 203| FormatError::from(FormatErrorInner::InvalidSrgbRenderingIntent(raw)) 1524| 203| })?; _RNCNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB7_16StreamingDecoder10parse_ztxt0Bb_: 1864| 72| .ok_or_else(|| DecodingError::from(TextDecodingError::InvalidCompressionMethod))?; _RNCNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB7_16StreamingDecoder11parse_chunk0Bb_: 1134| 19.4k| parse_result = parse_result.map_err(|e| { 1135| 8| 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| 8| 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.4k| e => e, 1146| | } 1147| 19.4k| }); _RNCNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB7_16StreamingDecoder13split_keyword0Bb_: 1831| 388k| .position(|&b| b == 0) _RNCNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB7_16StreamingDecoder13split_keywords_0Bb_: 1832| 1.97k| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))?; _RNvMNtNtCskrDebHigSPL_3png7decoder6streamNtB2_5State7new_u32: 73| 464k| fn new_u32(kind: U32ValueKind) -> Self { 74| 464k| Self::U32 { 75| 464k| kind, 76| 464k| bytes: [0; 4], 77| 464k| accumulated_count: 0, 78| 464k| } 79| 464k| } _RNvMs8_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_13DecodeOptions21set_ignore_text_chunk: 511| 10.1k| pub fn set_ignore_text_chunk(&mut self, ignore_text_chunk: bool) { 512| 10.1k| self.ignore_text_chunk = ignore_text_chunk; 513| 10.1k| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10next_state: 710| 1.29M| fn next_state( 711| 1.29M| &mut self, 712| 1.29M| buf: &[u8], 713| 1.29M| image_data: Option<&mut UnfilterBuf<'_>>, 714| 1.29M| ) -> Result<(usize, Decoded), DecodingError> { 715| | use self::State::*; 716| | 717| | // Driver should ensure that state is never None 718| 1.29M| let state = self.state.take().unwrap(); 719| | 720| 1.29M| match state { 721| | U32 { 722| 463k| kind, 723| 463k| mut bytes, 724| 463k| mut accumulated_count, 725| | } => { 726| 463k| debug_assert!(accumulated_count <= 4); 727| 463k| 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| 463k| self.parse_u32(kind, &buf[0..4], image_data, CONSUMED_BYTES) 735| | } else { 736| 464| let remaining_count = 4 - accumulated_count; 737| 464| let consumed_bytes = { 738| 464| let available_count = min(remaining_count, buf.len()); 739| 464| bytes[accumulated_count..accumulated_count + available_count] 740| 464| .copy_from_slice(&buf[0..available_count]); 741| 464| accumulated_count += available_count; 742| 464| available_count 743| | }; 744| | 745| 464| if accumulated_count < 4 { 746| 464| self.state = Some(U32 { 747| 464| kind, 748| 464| bytes, 749| 464| accumulated_count, 750| 464| }); 751| 464| 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| 147k| ReadChunkData(type_str) => { 759| 147k| debug_assert!(type_str != IDAT && type_str != chunk::fdAT); 760| 147k| if self.current_chunk.remaining == 0 { 761| 5.89k| self.state = Some(State::new_u32(U32ValueKind::Crc(type_str))); 762| 5.89k| Ok((0, Decoded::Nothing)) 763| | } else { 764| | let ChunkState { 765| 141k| crc, 766| 141k| remaining, 767| 141k| raw_bytes, 768| | type_: _, 769| 141k| action, 770| 141k| } = &mut self.current_chunk; 771| | 772| 141k| let buf_avail = raw_bytes.capacity() - raw_bytes.len(); 773| 141k| let bytes_avail = min(buf.len(), buf_avail); 774| 141k| let n = min(*remaining, bytes_avail as u32); 775| 141k| let buf = &buf[..n as usize]; 776| | 777| 141k| if !self.decode_options.ignore_crc { 778| 141k| crc.update(buf); 779| 141k| } 780| | 781| 141k| if *action == ChunkAction::Process { 782| 130k| if raw_bytes.len() == raw_bytes.capacity() { 783| 6.28k| if self.limits.bytes == 0 { 784| 0| return Err(DecodingError::LimitsExceeded); 785| 6.28k| } 786| | 787| | // Double the size of the Vec, but not beyond the allocation limit. 788| 6.28k| debug_assert!(raw_bytes.capacity() > 0); 789| 6.28k| let reserve_size = raw_bytes.capacity().min(self.limits.bytes); 790| | 791| 6.28k| self.limits.reserve_bytes(reserve_size)?; 792| 6.28k| raw_bytes.reserve_exact(reserve_size); 793| 124k| } 794| 130k| raw_bytes.extend_from_slice(buf); 795| 10.7k| } 796| | 797| 141k| *remaining -= n; 798| 141k| if *remaining == 0 { 799| 128k| debug_assert!(type_str != IDAT && type_str != chunk::fdAT); 800| 128k| self.state = Some(State::new_u32(U32ValueKind::Crc(type_str))); 801| 13.4k| } else { 802| 13.4k| self.state = Some(ReadChunkData(type_str)); 803| 13.4k| } 804| 141k| Ok((n as usize, Decoded::Nothing)) 805| | } 806| | } 807| 682k| ImageData(type_str) => { 808| 682k| debug_assert!(type_str == IDAT || type_str == chunk::fdAT); 809| 682k| let len = std::cmp::min(buf.len(), self.current_chunk.remaining as usize); 810| 682k| let buf = &buf[..len]; 811| | 812| 682k| let consumed = if let Some(image_data) = image_data { 813| 680k| self.inflater.decompress(buf, image_data)? 814| | } else { 815| 1.61k| len 816| | }; 817| | 818| 681k| if !self.decode_options.ignore_crc { 819| 681k| self.current_chunk.crc.update(&buf[..consumed]); 820| 681k| } 821| | 822| 681k| self.current_chunk.remaining -= consumed as u32; 823| 681k| if self.current_chunk.remaining == 0 { 824| 8.40k| self.state = Some(State::new_u32(U32ValueKind::Crc(type_str))); 825| 673k| } else { 826| 673k| self.state = Some(ImageData(type_str)); 827| 673k| } 828| 681k| Ok((consumed, Decoded::ImageData)) 829| | } 830| | } 831| 1.29M| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10parse_actl: 1236| 868| fn parse_actl(&mut self) -> Result<(), DecodingError> { 1237| 868| let info = self.info.as_mut().unwrap(); 1238| 868| if self.have_idat { 1239| 0| Err(DecodingError::Format( 1240| 0| FormatErrorInner::AfterIdat { kind: chunk::acTL }.into(), 1241| 0| )) 1242| 868| } else if info.animation_control.is_some() { 1243| 263| Err(DecodingError::Format( 1244| 263| FormatErrorInner::DuplicateChunk { kind: chunk::acTL }.into(), 1245| 263| )) 1246| | } else { 1247| 605| let mut buf = &self.current_chunk.raw_bytes[..]; 1248| 605| let actl = AnimationControl { 1249| 605| num_frames: buf.read_be()?, 1250| 605| 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| 605| if actl.num_frames == 0 { 1255| 66| return Ok(()); 1256| 539| } 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| 539| if actl.num_frames > 0x7FFFFFFF || actl.num_plays > 0x7FFFFFFF { 1263| 462| return Ok(()); 1264| 77| } 1265| | 1266| 77| info.animation_control = Some(actl); 1267| 77| Ok(()) 1268| | } 1269| 868| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10parse_bkgd: 1924| 1.67k| fn parse_bkgd(&mut self) -> Result<(), DecodingError> { 1925| 1.67k| let info = self.info.as_mut().unwrap(); 1926| 1.67k| if info.bkgd.is_some() { 1927| | // Only one bKGD chunk is allowed 1928| 452| return Err(DecodingError::Format( 1929| 452| FormatErrorInner::DuplicateChunk { kind: chunk::bKGD }.into(), 1930| 452| )); 1931| 1.22k| } else if self.have_idat { 1932| 0| return Err(DecodingError::Format( 1933| 0| FormatErrorInner::AfterIdat { kind: chunk::bKGD }.into(), 1934| 0| )); 1935| 1.22k| } 1936| | 1937| 1.22k| let expected = match info.color_type { 1938| | ColorType::Indexed => { 1939| 198| if info.palette.is_none() { 1940| 1| return Err(DecodingError::IoError( 1941| 1| std::io::ErrorKind::InvalidData.into(), 1942| 1| )); 1943| 197| }; 1944| 197| 1 1945| | } 1946| 630| ColorType::Grayscale | ColorType::GrayscaleAlpha => 2, 1947| 395| ColorType::Rgb | ColorType::Rgba => 6, 1948| | }; 1949| 1.22k| let vec = self.current_chunk.raw_bytes.clone(); 1950| 1.22k| if vec.len() != expected { 1951| 1.20k| return Err(DecodingError::Format( 1952| 1.20k| FormatErrorInner::ChunkLengthWrong { kind: chunk::bKGD }.into(), 1953| 1.20k| )); 1954| 22| } 1955| | 1956| 22| info.bkgd = Some(Cow::Owned(vec)); 1957| 22| Ok(()) 1958| 1.67k| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10parse_chrm: 1439| 395| fn parse_chrm(&mut self) -> Result<(), DecodingError> { 1440| 395| let info = self.info.as_mut().unwrap(); 1441| 395| if self.have_idat { 1442| 0| Err(DecodingError::Format( 1443| 0| FormatErrorInner::AfterIdat { kind: chunk::cHRM }.into(), 1444| 0| )) 1445| 395| } 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| 21| let mut buf = &self.current_chunk.raw_bytes[..]; 1451| 21| let white_x: u32 = buf.read_be()?; 1452| 21| let white_y: u32 = buf.read_be()?; 1453| 21| let red_x: u32 = buf.read_be()?; 1454| 21| let red_y: u32 = buf.read_be()?; 1455| 21| let green_x: u32 = buf.read_be()?; 1456| 21| let green_y: u32 = buf.read_be()?; 1457| 21| let blue_x: u32 = buf.read_be()?; 1458| 21| let blue_y: u32 = buf.read_be()?; 1459| | 1460| 21| let source_chromaticities = SourceChromaticities { 1461| 21| white: ( 1462| 21| ScaledFloat::from_scaled(white_x), 1463| 21| ScaledFloat::from_scaled(white_y), 1464| 21| ), 1465| 21| red: ( 1466| 21| ScaledFloat::from_scaled(red_x), 1467| 21| ScaledFloat::from_scaled(red_y), 1468| 21| ), 1469| 21| green: ( 1470| 21| ScaledFloat::from_scaled(green_x), 1471| 21| ScaledFloat::from_scaled(green_y), 1472| 21| ), 1473| 21| blue: ( 1474| 21| ScaledFloat::from_scaled(blue_x), 1475| 21| ScaledFloat::from_scaled(blue_y), 1476| 21| ), 1477| 21| }; 1478| | 1479| 21| info.chrm_chunk = Some(source_chromaticities); 1480| 21| Ok(()) 1481| | } 1482| 395| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10parse_cicp: 1532| 468| fn parse_cicp(&mut self) -> Result<(), DecodingError> { 1533| 468| 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| 468| 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| 221| } else if info.palette.is_some() { 1541| 201| return Err(DecodingError::Format( 1542| 201| FormatErrorInner::AfterPlte { kind: chunk::cICP }.into(), 1543| 201| )); 1544| 20| } else if self.have_idat { 1545| 0| return Err(DecodingError::Format( 1546| 0| FormatErrorInner::AfterIdat { kind: chunk::cICP }.into(), 1547| 0| )); 1548| 20| } 1549| | 1550| 20| let mut buf = &*self.current_chunk.raw_bytes; 1551| 20| let color_primaries: u8 = buf.read_be()?; 1552| 20| let transfer_function: u8 = buf.read_be()?; 1553| 20| let matrix_coefficients: u8 = buf.read_be()?; 1554| 13| let is_video_full_range_image = { 1555| 20| let flag: u8 = buf.read_be()?; 1556| 20| match flag { 1557| 13| 0 => false, 1558| 0| 1 => true, 1559| | _ => { 1560| 7| return Err(DecodingError::IoError( 1561| 7| std::io::ErrorKind::InvalidData.into(), 1562| 7| )); 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| 13| if matrix_coefficients != 0 { 1570| 0| return Err(DecodingError::IoError( 1571| 0| std::io::ErrorKind::InvalidData.into(), 1572| 0| )); 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| 468| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10parse_clli: 1649| 388| fn parse_clli(&mut self) -> Result<(), DecodingError> { 1650| 388| let info = self.info.as_mut().unwrap(); 1651| 388| if info.content_light_level.is_some() { 1652| 374| return Err(DecodingError::Format( 1653| 374| FormatErrorInner::DuplicateChunk { kind: chunk::cLLI }.into(), 1654| 374| )); 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| 388| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10parse_exif: 1673| 571| fn parse_exif(&mut self) -> Result<(), DecodingError> { 1674| 571| let info = self.info.as_mut().unwrap(); 1675| 571| if info.exif_metadata.is_some() { 1676| 463| return Err(DecodingError::Format( 1677| 463| FormatErrorInner::DuplicateChunk { kind: chunk::eXIf }.into(), 1678| 463| )); 1679| 108| } 1680| | 1681| 108| info.exif_metadata = Some(self.current_chunk.raw_bytes.clone().into()); 1682| 108| Ok(()) 1683| 571| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10parse_fctl: 1167| 276| fn parse_fctl(&mut self) -> Result<(), DecodingError> { 1168| 276| let mut buf = &self.current_chunk.raw_bytes[..]; 1169| 276| let next_seq_no = buf.read_be()?; 1170| | 1171| | // Assuming that fcTL is required before *every* fdAT-sequence 1172| 276| self.current_seq_no = Some(if let Some(seq_no) = self.current_seq_no { 1173| 46| if next_seq_no != seq_no + 1 { 1174| 45| return Err(DecodingError::Format( 1175| 45| FormatErrorInner::ApngOrder { 1176| 45| expected: seq_no + 1, 1177| 45| present: next_seq_no, 1178| 45| } 1179| 45| .into(), 1180| 45| )); 1181| 1| } 1182| 1| next_seq_no 1183| | } else { 1184| 230| if next_seq_no != 0 { 1185| 42| return Err(DecodingError::Format( 1186| 42| FormatErrorInner::ApngOrder { 1187| 42| expected: 0, 1188| 42| present: next_seq_no, 1189| 42| } 1190| 42| .into(), 1191| 42| )); 1192| 188| } 1193| 188| 0 1194| | }); 1195| 189| self.inflater.reset(); 1196| 189| self.ready_for_fdat_chunks = self.have_idat; 1197| 185| let fc = FrameControl { 1198| 189| sequence_number: next_seq_no, 1199| 189| width: buf.read_be()?, 1200| 189| height: buf.read_be()?, 1201| 189| x_offset: buf.read_be()?, 1202| 189| y_offset: buf.read_be()?, 1203| 189| delay_num: buf.read_be()?, 1204| 189| delay_den: buf.read_be()?, 1205| | dispose_op: { 1206| 189| let dispose_op = buf.read_be()?; 1207| 189| match DisposeOp::from_u8(dispose_op) { 1208| 186| Some(dispose_op) => dispose_op, 1209| | None => { 1210| 3| return Err(DecodingError::Format( 1211| 3| FormatErrorInner::InvalidDisposeOp(dispose_op).into(), 1212| 3| )) 1213| | } 1214| | } 1215| | }, 1216| | blend_op: { 1217| 186| let blend_op = buf.read_be()?; 1218| 186| match BlendOp::from_u8(blend_op) { 1219| 185| 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| 185| self.info.as_ref().unwrap().validate(&fc)?; 1229| 113| if !self.have_idat { 1230| 113| self.info.as_ref().unwrap().validate_default_image(&fc)?; 1231| 0| } 1232| 48| self.info.as_mut().unwrap().frame_control = Some(fc); 1233| 48| Ok(()) 1234| 276| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10parse_gama: 1484| 456| fn parse_gama(&mut self) -> Result<(), DecodingError> { 1485| 456| let info = self.info.as_mut().unwrap(); 1486| 456| if self.have_idat { 1487| 0| Err(DecodingError::Format( 1488| 0| FormatErrorInner::AfterIdat { kind: chunk::gAMA }.into(), 1489| 0| )) 1490| 456| } else if info.gama_chunk.is_some() { 1491| 326| Err(DecodingError::Format( 1492| 326| FormatErrorInner::DuplicateChunk { kind: chunk::gAMA }.into(), 1493| 326| )) 1494| | } else { 1495| 130| let mut buf = &self.current_chunk.raw_bytes[..]; 1496| 130| let source_gamma: u32 = buf.read_be()?; 1497| 130| if source_gamma == 0 { 1498| 71| return Err(DecodingError::Format( 1499| 71| FormatErrorInner::BadGammaValue.into(), 1500| 71| )); 1501| 59| } 1502| | 1503| 59| let source_gamma = ScaledFloat::from_scaled(source_gamma); 1504| 59| info.gama_chunk = Some(source_gamma); 1505| 59| Ok(()) 1506| | } 1507| 456| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10parse_iccp: 1685| 3.38k| fn parse_iccp(&mut self) -> Result<(), DecodingError> { 1686| 3.38k| if self.have_idat { 1687| 0| Err(DecodingError::Format( 1688| 0| FormatErrorInner::AfterIdat { kind: chunk::iCCP }.into(), 1689| 0| )) 1690| 3.38k| } else if self.have_iccp { 1691| 625| Err(DecodingError::Format( 1692| 625| FormatErrorInner::DuplicateChunk { kind: chunk::iCCP }.into(), 1693| 625| )) 1694| | } else { 1695| 2.75k| self.have_iccp = true; 1696| 2.75k| let _ = self.parse_iccp_raw(); 1697| 2.75k| Ok(()) 1698| | } 1699| 3.38k| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10parse_ihdr: 1744| 9.93k| fn parse_ihdr(&mut self) -> Result<(), DecodingError> { 1745| 9.93k| if self.info.is_some() { 1746| 2| return Err(DecodingError::Format( 1747| 2| FormatErrorInner::DuplicateChunk { kind: IHDR }.into(), 1748| 2| )); 1749| 9.93k| } 1750| 9.93k| let mut buf = &self.current_chunk.raw_bytes[..]; 1751| 9.93k| let width = buf.read_be()?; 1752| 9.93k| let height = buf.read_be()?; 1753| 9.93k| if width == 0 || height == 0 { 1754| 2| return Err(DecodingError::Format( 1755| 2| FormatErrorInner::InvalidDimensions.into(), 1756| 2| )); 1757| 9.93k| } 1758| 9.93k| let bit_depth = buf.read_be()?; 1759| 9.93k| let bit_depth = match BitDepth::from_u8(bit_depth) { 1760| 9.90k| Some(bits) => bits, 1761| | None => { 1762| 21| return Err(DecodingError::Format( 1763| 21| FormatErrorInner::InvalidBitDepth(bit_depth).into(), 1764| 21| )) 1765| | } 1766| | }; 1767| 9.90k| let color_type = buf.read_be()?; 1768| 9.90k| let color_type = match ColorType::from_u8(color_type) { 1769| 9.90k| Some(color_type) => { 1770| 9.90k| 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.89k| color_type 1780| | } 1781| | } 1782| | None => { 1783| 8| return Err(DecodingError::Format( 1784| 8| FormatErrorInner::InvalidColorType(color_type).into(), 1785| 8| )) 1786| | } 1787| | }; 1788| 9.89k| match buf.read_be()? { 1789| | // compression method 1790| 9.88k| 0u8 => (), 1791| 8| n => { 1792| 8| return Err(DecodingError::Format( 1793| 8| FormatErrorInner::UnknownCompressionMethod(n).into(), 1794| 8| )) 1795| | } 1796| | } 1797| 9.88k| match buf.read_be()? { 1798| | // filter method 1799| 9.88k| 0u8 => (), 1800| 8| n => { 1801| 8| return Err(DecodingError::Format( 1802| 8| FormatErrorInner::UnknownFilterMethod(n).into(), 1803| 8| )) 1804| | } 1805| | } 1806| 9.88k| let interlaced = match buf.read_be()? { 1807| 6.73k| 0u8 => false, 1808| 3.14k| 1 => true, 1809| 7| n => { 1810| 7| return Err(DecodingError::Format( 1811| 7| FormatErrorInner::UnknownInterlaceMethod(n).into(), 1812| 7| )) 1813| | } 1814| | }; 1815| | 1816| 9.87k| self.info = Some(Info { 1817| 9.87k| width, 1818| 9.87k| height, 1819| 9.87k| bit_depth, 1820| 9.87k| color_type, 1821| 9.87k| interlaced, 1822| 9.87k| ..Default::default() 1823| 9.87k| }); 1824| | 1825| 9.87k| Ok(()) 1826| 9.93k| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10parse_itxt: 1876| 16.8k| fn parse_itxt(&mut self) -> Result<(), DecodingError> { 1877| 16.8k| let buf = &self.current_chunk.raw_bytes[..]; 1878| 16.8k| self.limits.reserve_bytes(buf.len())?; 1879| | 1880| 16.8k| let (keyword_slice, value_slice) = Self::split_keyword(buf)?; 1881| | 1882| 15.4k| let compression_flag = *value_slice 1883| 15.4k| .first() 1884| 15.4k| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingCompressionFlag))?; 1885| | 1886| 15.3k| let compression_method = *value_slice 1887| 15.3k| .get(1) 1888| 15.3k| .ok_or_else(|| DecodingError::from(TextDecodingError::InvalidCompressionMethod))?; 1889| | 1890| 15.2k| let second_null_byte_index = value_slice[2..] 1891| 15.2k| .iter() 1892| 15.2k| .position(|&b| b == 0) 1893| 15.2k| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))? 1894| | + 2; 1895| | 1896| 14.8k| let language_tag_slice = &value_slice[2..second_null_byte_index]; 1897| | 1898| 14.8k| let third_null_byte_index = value_slice[second_null_byte_index + 1..] 1899| 14.8k| .iter() 1900| 14.8k| .position(|&b| b == 0) 1901| 14.8k| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))? 1902| 14.3k| + (second_null_byte_index + 1); 1903| | 1904| 14.3k| let translated_keyword_slice = 1905| 14.3k| &value_slice[second_null_byte_index + 1..third_null_byte_index]; 1906| | 1907| 14.3k| let text_slice = &value_slice[third_null_byte_index + 1..]; 1908| | 1909| 14.3k| self.info.as_mut().unwrap().utf8_text.push( 1910| 14.3k| ITXtChunk::decode( 1911| 14.3k| keyword_slice, 1912| 14.3k| compression_flag, 1913| 14.3k| compression_method, 1914| 14.3k| language_tag_slice, 1915| 14.3k| translated_keyword_slice, 1916| 14.3k| text_slice, 1917| | ) 1918| 14.3k| .map_err(DecodingError::from)?, 1919| | ); 1920| | 1921| 11.9k| Ok(()) 1922| 16.8k| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10parse_mdcv: 1591| 453| fn parse_mdcv(&mut self) -> Result<(), DecodingError> { 1592| 453| 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| 453| 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| 79| } else if info.palette.is_some() { 1600| 66| return Err(DecodingError::Format( 1601| 66| FormatErrorInner::AfterPlte { kind: chunk::mDCV }.into(), 1602| 66| )); 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| 453| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10parse_phys: 1410| 732| fn parse_phys(&mut self) -> Result<(), DecodingError> { 1411| 732| let info = self.info.as_mut().unwrap(); 1412| 732| if self.have_idat { 1413| 0| Err(DecodingError::Format( 1414| 0| FormatErrorInner::AfterIdat { kind: chunk::pHYs }.into(), 1415| 0| )) 1416| 732| } else if info.pixel_dims.is_some() { 1417| 368| Err(DecodingError::Format( 1418| 368| FormatErrorInner::DuplicateChunk { kind: chunk::pHYs }.into(), 1419| 368| )) 1420| | } else { 1421| 364| let mut buf = &self.current_chunk.raw_bytes[..]; 1422| 364| let xppu = buf.read_be()?; 1423| 364| let yppu = buf.read_be()?; 1424| 364| let unit = buf.read_be()?; 1425| 364| let unit = match Unit::from_u8(unit) { 1426| 34| Some(unit) => unit, 1427| | None => { 1428| 330| return Err(DecodingError::Format( 1429| 330| FormatErrorInner::InvalidUnit(unit).into(), 1430| 330| )) 1431| | } 1432| | }; 1433| 34| let pixel_dims = PixelDimensions { xppu, yppu, unit }; 1434| 34| info.pixel_dims = Some(pixel_dims); 1435| 34| Ok(()) 1436| | } 1437| 732| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10parse_plte: 1271| 781| fn parse_plte(&mut self) -> Result<(), DecodingError> { 1272| 781| let info = self.info.as_mut().unwrap(); 1273| 781| if info.palette.is_some() { 1274| | // Only one palette is allowed 1275| 4| Err(DecodingError::Format( 1276| 4| FormatErrorInner::DuplicateChunk { kind: chunk::PLTE }.into(), 1277| 4| )) 1278| | } else { 1279| 777| info.palette = Some(Cow::Owned(self.current_chunk.raw_bytes.clone())); 1280| 777| Ok(()) 1281| | } 1282| 781| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10parse_sbit: 1284| 4.32k| fn parse_sbit(&mut self) -> Result<(), DecodingError> { 1285| 4.32k| let info = self.info.as_mut().unwrap(); 1286| 4.32k| if info.palette.is_some() { 1287| 194| return Err(DecodingError::Format( 1288| 194| FormatErrorInner::AfterPlte { kind: chunk::sBIT }.into(), 1289| 194| )); 1290| 4.13k| } 1291| | 1292| 4.13k| if self.have_idat { 1293| 0| return Err(DecodingError::Format( 1294| 0| FormatErrorInner::AfterIdat { kind: chunk::sBIT }.into(), 1295| 0| )); 1296| 4.13k| } 1297| | 1298| 4.13k| if info.sbit.is_some() { 1299| 195| return Err(DecodingError::Format( 1300| 195| FormatErrorInner::DuplicateChunk { kind: chunk::sBIT }.into(), 1301| 195| )); 1302| 3.93k| } 1303| | 1304| 3.93k| 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.93k| let sample_depth = if color_type == ColorType::Indexed { 1307| 3.08k| BitDepth::Eight 1308| | } else { 1309| 852| bit_depth 1310| | }; 1311| 3.93k| let vec = self.current_chunk.raw_bytes.clone(); 1312| 3.93k| let len = vec.len(); 1313| | 1314| | // expected lenth of the chunk 1315| 3.93k| let expected = match color_type { 1316| 792| ColorType::Grayscale => 1, 1317| 3.13k| ColorType::Rgb | ColorType::Indexed => 3, 1318| 3| ColorType::GrayscaleAlpha => 2, 1319| 5| ColorType::Rgba => 4, 1320| | }; 1321| | 1322| | // Check if the sbit chunk size is valid. 1323| 3.93k| if expected != len { 1324| 345| return Err(DecodingError::Format( 1325| 345| FormatErrorInner::InvalidSbitChunkSize { 1326| 345| color_type, 1327| 345| expected, 1328| 345| len, 1329| 345| } 1330| 345| .into(), 1331| 345| )); 1332| 3.59k| } 1333| | 1334| 8.27k| for sbit in &vec { 1335| 8.26k| if *sbit < 1 || *sbit > sample_depth as u8 { 1336| 3.57k| return Err(DecodingError::Format( 1337| 3.57k| FormatErrorInner::InvalidSbit { 1338| 3.57k| sample_depth, 1339| 3.57k| sbit: *sbit, 1340| 3.57k| } 1341| 3.57k| .into(), 1342| 3.57k| )); 1343| 4.68k| } 1344| | } 1345| 16| info.sbit = Some(Cow::Owned(vec)); 1346| 16| Ok(()) 1347| 4.32k| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10parse_srgb: 1509| 457| fn parse_srgb(&mut self) -> Result<(), DecodingError> { 1510| 457| let info = self.info.as_mut().unwrap(); 1511| 457| if self.have_idat { 1512| 0| Err(DecodingError::Format( 1513| 0| FormatErrorInner::AfterIdat { kind: chunk::sRGB }.into(), 1514| 0| )) 1515| 457| } else if info.srgb.is_some() { 1516| 198| Err(DecodingError::Format( 1517| 198| FormatErrorInner::DuplicateChunk { kind: chunk::sRGB }.into(), 1518| 198| )) 1519| | } else { 1520| 259| let mut buf = &self.current_chunk.raw_bytes[..]; 1521| 259| let raw: u8 = buf.read_be()?; // BE is is nonsense for single bytes, but this way the size is checked. 1522| 259| let rendering_intent = crate::SrgbRenderingIntent::from_raw(raw).ok_or_else(|| { 1523| | FormatError::from(FormatErrorInner::InvalidSrgbRenderingIntent(raw)) 1524| 203| })?; 1525| | 1526| | // Set srgb and override source gamma and chromaticities. 1527| 56| info.srgb = Some(rendering_intent); 1528| 56| Ok(()) 1529| | } 1530| 457| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10parse_text: 1841| 8.24k| fn parse_text(&mut self) -> Result<(), DecodingError> { 1842| 8.24k| let buf = &self.current_chunk.raw_bytes[..]; 1843| 8.24k| self.limits.reserve_bytes(buf.len())?; 1844| | 1845| 8.24k| let (keyword_slice, value_slice) = Self::split_keyword(buf)?; 1846| | 1847| 7.02k| self.info 1848| 7.02k| .as_mut() 1849| 7.02k| .unwrap() 1850| 7.02k| .uncompressed_latin1_text 1851| 7.02k| .push(TEXtChunk::decode(keyword_slice, value_slice).map_err(DecodingError::from)?); 1852| | 1853| 7.02k| Ok(()) 1854| 8.24k| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10parse_trns: 1349| 1.67k| fn parse_trns(&mut self) -> Result<(), DecodingError> { 1350| 1.67k| let info = self.info.as_mut().unwrap(); 1351| 1.67k| if info.trns.is_some() { 1352| 505| return Err(DecodingError::Format( 1353| 505| FormatErrorInner::DuplicateChunk { kind: chunk::PLTE }.into(), 1354| 505| )); 1355| 1.16k| } 1356| 1.16k| let (color_type, bit_depth) = { (info.color_type, info.bit_depth as u8) }; 1357| 1.16k| let mut vec = self.current_chunk.raw_bytes.clone(); 1358| 1.16k| let len = vec.len(); 1359| 1.16k| match color_type { 1360| | ColorType::Grayscale => { 1361| 440| if len < 2 { 1362| 238| return Err(DecodingError::Format( 1363| 238| FormatErrorInner::ShortPalette { expected: 2, len }.into(), 1364| 238| )); 1365| 202| } 1366| 202| if bit_depth < 16 { 1367| 125| vec[0] = vec[1]; 1368| 125| vec.truncate(1); 1369| 125| } 1370| 202| info.trns = Some(Cow::Owned(vec)); 1371| 202| Ok(()) 1372| | } 1373| | ColorType::Rgb => { 1374| 234| if len < 6 { 1375| 200| return Err(DecodingError::Format( 1376| 200| FormatErrorInner::ShortPalette { expected: 6, len }.into(), 1377| 200| )); 1378| 34| } 1379| 34| 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| 34| info.trns = Some(Cow::Owned(vec)); 1386| 34| Ok(()) 1387| | } 1388| | ColorType::Indexed => { 1389| | // The transparency chunk must be after the palette chunk and 1390| | // before the data chunk. 1391| 293| if info.palette.is_none() { 1392| 196| return Err(DecodingError::Format( 1393| 196| FormatErrorInner::BeforePlte { kind: chunk::tRNS }.into(), 1394| 196| )); 1395| 97| } else if self.have_idat { 1396| 0| return Err(DecodingError::Format( 1397| 0| FormatErrorInner::OutsidePlteIdat { kind: chunk::tRNS }.into(), 1398| 0| )); 1399| 97| } 1400| | 1401| 97| info.trns = Some(Cow::Owned(vec)); 1402| 97| Ok(()) 1403| | } 1404| 198| c => Err(DecodingError::Format( 1405| 198| FormatErrorInner::ColorWithBadTrns(c).into(), 1406| 198| )), 1407| | } 1408| 1.67k| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder10parse_ztxt: 1856| 68.1k| fn parse_ztxt(&mut self) -> Result<(), DecodingError> { 1857| 68.1k| let buf = &self.current_chunk.raw_bytes[..]; 1858| 68.1k| self.limits.reserve_bytes(buf.len())?; 1859| | 1860| 68.1k| let (keyword_slice, value_slice) = Self::split_keyword(buf)?; 1861| | 1862| 67.3k| let compression_method = *value_slice 1863| 67.3k| .first() 1864| 67.3k| .ok_or_else(|| DecodingError::from(TextDecodingError::InvalidCompressionMethod))?; 1865| | 1866| 67.2k| let text_slice = &value_slice[1..]; 1867| | 1868| 67.2k| self.info.as_mut().unwrap().compressed_latin1_text.push( 1869| 67.2k| ZTXtChunk::decode(keyword_slice, compression_method, text_slice) 1870| 67.2k| .map_err(DecodingError::from)?, 1871| | ); 1872| | 1873| 66.9k| Ok(()) 1874| 68.1k| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder11parse_chunk: 1096| 128k| fn parse_chunk(&mut self, type_str: ChunkType) -> Result { 1097| 128k| let mut parse_result = match type_str { 1098| | // Critical non-data chunks. 1099| 9.93k| IHDR => self.parse_ihdr(), 1100| 781| chunk::PLTE => self.parse_plte(), 1101| 1| chunk::IEND => Ok(()), // TODO: Check chunk size. 1102| | 1103| | // Data chunks handled separately. 1104| 8.34k| chunk::IDAT => Ok(()), 1105| 0| chunk::fdAT => Ok(()), 1106| | 1107| | // Recognized bounded-size ancillary chunks. 1108| 4.32k| chunk::sBIT => self.parse_sbit(), 1109| 1.67k| chunk::tRNS => self.parse_trns(), 1110| 732| chunk::pHYs => self.parse_phys(), 1111| 456| chunk::gAMA => self.parse_gama(), 1112| 868| chunk::acTL => self.parse_actl(), 1113| 276| chunk::fcTL => self.parse_fctl(), 1114| 395| chunk::cHRM => self.parse_chrm(), 1115| 457| chunk::sRGB => self.parse_srgb(), 1116| 468| chunk::cICP => self.parse_cicp(), 1117| 453| chunk::mDCV => self.parse_mdcv(), 1118| 388| chunk::cLLI => self.parse_clli(), 1119| 1.67k| chunk::bKGD => self.parse_bkgd(), 1120| | 1121| | // Ancillary chunks with unbounded size. 1122| 571| chunk::eXIf => self.parse_exif(), 1123| 3.38k| chunk::iCCP => self.parse_iccp(), 1124| 8.24k| chunk::tEXt => self.parse_text(), 1125| 68.1k| chunk::zTXt => self.parse_ztxt(), 1126| 16.8k| 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| 128k| 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.4k| match parse_result { 1150| 109k| Ok(()) => Ok(Decoded::ChunkComplete(type_str)), 1151| | Err(DecodingError::Format(_)) 1152| 19.4k| 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| 19.1k| Ok(Decoded::BadAncillaryChunk(type_str)) 1162| | } 1163| 300| Err(e) => Err(e), 1164| | } 1165| 128k| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder11start_chunk: 1038| 135k| fn start_chunk(&mut self, type_str: ChunkType, length: u32) -> Result { 1039| 123k| let target_length = match type_str { 1040| 9.99k| IHDR => 13..=13, 1041| 784| chunk::PLTE => 3..=768, 1042| 3| chunk::IEND => 0..=0, 1043| 4.57k| chunk::sBIT => 1..=4, 1044| 2.00k| chunk::tRNS => 1..=256, 1045| 1.69k| chunk::pHYs => 9..=9, 1046| 688| chunk::gAMA => 4..=4, 1047| 994| chunk::acTL => 8..=8, 1048| 278| chunk::fcTL => 26..=26, 1049| 590| chunk::cHRM => 32..=32, 1050| 1.02k| chunk::sRGB => 1..=1, 1051| 543| chunk::cICP => 4..=4, 1052| 536| chunk::mDCV => 24..=24, 1053| 454| chunk::cLLI => 8..=8, 1054| 1.72k| chunk::bKGD => 1..=6, 1055| | 1056| | // Unbounded size chunks 1057| 585| chunk::eXIf => 0..=u32::MAX >> 1, // TODO: allow skipping. 1058| 3.40k| chunk::iCCP if !self.decode_options.ignore_iccp_chunk => 0..=u32::MAX >> 1, 1059| 8.26k| chunk::tEXt if !self.decode_options.ignore_text_chunk => 0..=u32::MAX >> 1, 1060| 68.2k| chunk::zTXt if !self.decode_options.ignore_text_chunk => 0..=u32::MAX >> 1, 1061| 16.8k| chunk::iTXt if !self.decode_options.ignore_text_chunk => 0..=u32::MAX >> 1, 1062| | 1063| 0| chunk::IDAT | chunk::fdAT => unreachable!(), 1064| | 1065| 11.9k| _ if is_critical(type_str) => { 1066| 282| return Err(DecodingError::Format( 1067| 282| FormatErrorInner::UnrecognizedCriticalChunk { type_str }.into(), 1068| 282| )); 1069| | } 1070| | _ => { 1071| 11.7k| self.current_chunk.action = ChunkAction::Skip; 1072| 11.7k| return Ok(State::ReadChunkData(type_str)); 1073| | } 1074| | }; 1075| | 1076| 123k| 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| 2.98k| match type_str { 1080| | IHDR | chunk::PLTE | chunk::IEND | chunk::fcTL => { 1081| 50| return Err(DecodingError::Format( 1082| 50| FormatErrorInner::ChunkLengthWrong { kind: type_str }.into(), 1083| 50| )); 1084| | } 1085| 2.93k| _ => { 1086| 2.93k| self.current_chunk.action = ChunkAction::Reject; 1087| 2.93k| } 1088| | } 1089| 120k| } else { 1090| 120k| self.current_chunk.action = ChunkAction::Process; 1091| 120k| } 1092| | 1093| 123k| Ok(State::ReadChunkData(type_str)) 1094| 135k| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder13split_keyword: 1828| 93.2k| fn split_keyword(buf: &[u8]) -> Result<(&[u8], &[u8]), DecodingError> { 1829| 93.2k| let null_byte_index = buf 1830| 93.2k| .iter() 1831| 93.2k| .position(|&b| b == 0) 1832| 93.2k| .ok_or_else(|| DecodingError::from(TextDecodingError::MissingNullSeparator))?; 1833| | 1834| 91.2k| if null_byte_index == 0 || null_byte_index > 79 { 1835| 1.49k| return Err(DecodingError::from(TextDecodingError::InvalidKeywordSize)); 1836| 89.7k| } 1837| | 1838| 89.7k| Ok((&buf[..null_byte_index], &buf[null_byte_index + 1..])) 1839| 93.2k| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder14parse_iccp_raw: 1701| 2.75k| fn parse_iccp_raw(&mut self) -> Result<(), DecodingError> { 1702| 2.75k| let info = self.info.as_mut().unwrap(); 1703| 2.75k| let mut buf = &self.current_chunk.raw_bytes[..]; 1704| | 1705| | // read profile name 1706| 30.2k| for len in 0..=80 { 1707| 30.2k| let raw: u8 = buf.read_be()?; 1708| 30.2k| if (raw == 0 && len == 0) || (raw != 0 && len == 80) { 1709| 2| return Err(DecodingError::from(TextDecodingError::InvalidKeywordSize)); 1710| 30.2k| } 1711| 30.2k| if raw == 0 { 1712| 2.72k| break; 1713| 27.4k| } 1714| | } 1715| | 1716| 2.72k| match buf.read_be()? { 1717| | // compression method 1718| 2.71k| 0u8 => (), 1719| 7| n => { 1720| 7| return Err(DecodingError::Format( 1721| 7| FormatErrorInner::UnknownCompressionMethod(n).into(), 1722| 7| )) 1723| | } 1724| | } 1725| | 1726| 2.71k| match fdeflate::decompress_to_vec_bounded(buf, self.limits.bytes) { 1727| 2.35k| Ok(profile) => { 1728| 2.35k| self.limits.reserve_bytes(profile.len())?; 1729| 2.35k| info.icc_profile = Some(Cow::Owned(profile)); 1730| | } 1731| 355| Err(fdeflate::BoundedDecompressionError::DecompressionError { inner: err }) => { 1732| 355| return Err(DecodingError::Format( 1733| 355| FormatErrorInner::CorruptFlateStream { err }.into(), 1734| 355| )) 1735| | } 1736| | Err(fdeflate::BoundedDecompressionError::OutputTooLarge { .. }) => { 1737| 0| return Err(DecodingError::LimitsExceeded); 1738| | } 1739| | } 1740| | 1741| 2.35k| Ok(()) 1742| 2.75k| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder16new_with_options: 593| 10.1k| pub fn new_with_options(decode_options: DecodeOptions) -> StreamingDecoder { 594| 10.1k| let mut inflater = ZlibStream::new(); 595| 10.1k| inflater.set_ignore_adler32(decode_options.ignore_adler32); 596| | 597| 10.1k| StreamingDecoder { 598| 10.1k| state: Some(State::new_u32(U32ValueKind::Signature1stU32)), 599| 10.1k| current_chunk: ChunkState { 600| 10.1k| type_: ChunkType([0; 4]), 601| 10.1k| crc: Crc32::new(), 602| 10.1k| remaining: 0, 603| 10.1k| raw_bytes: Vec::with_capacity(CHUNK_BUFFER_SIZE), 604| 10.1k| action: ChunkAction::Process, 605| 10.1k| }, 606| 10.1k| inflater, 607| 10.1k| info: None, 608| 10.1k| current_seq_no: None, 609| 10.1k| have_idat: false, 610| 10.1k| have_iccp: false, 611| 10.1k| ready_for_idat_chunks: true, 612| 10.1k| ready_for_fdat_chunks: false, 613| 10.1k| decode_options, 614| 10.1k| limits: Limits { bytes: usize::MAX }, 615| 10.1k| } 616| 10.1k| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder21set_ignore_text_chunk: 635| 10.1k| pub fn set_ignore_text_chunk(&mut self, ignore_text_chunk: bool) { 636| 10.1k| self.decode_options.set_ignore_text_chunk(ignore_text_chunk); 637| 10.1k| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder3new: 589| 10.1k| pub fn new() -> StreamingDecoder { 590| 10.1k| StreamingDecoder::new_with_options(DecodeOptions::default()) 591| 10.1k| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder6update: 680| 975k| pub fn update( 681| 975k| &mut self, 682| 975k| mut buf: &[u8], 683| 975k| mut image_data: Option<&mut UnfilterBuf<'_>>, 684| 975k| ) -> Result<(usize, Decoded), DecodingError> { 685| 975k| if self.state.is_none() { 686| 0| return Err(DecodingError::Parameter( 687| 0| ParameterErrorKind::PolledAfterFatalError.into(), 688| 0| )); 689| 975k| } 690| | 691| 975k| let len = buf.len(); 692| 1.29M| while !buf.is_empty() { 693| 1.29M| let image_data = image_data.as_deref_mut(); 694| | 695| 1.29M| match self.next_state(buf, image_data) { 696| 318k| Ok((bytes, Decoded::Nothing)) => buf = &buf[bytes..], 697| 973k| Ok((bytes, result)) => { 698| 973k| buf = &buf[bytes..]; 699| 973k| return Ok((len - buf.len(), result)); 700| | } 701| 1.57k| Err(err) => { 702| 1.57k| debug_assert!(self.state.is_none()); 703| 1.57k| return Err(err); 704| | } 705| | } 706| | } 707| 796| Ok((len - buf.len(), Decoded::Nothing)) 708| 975k| } _RNvMs9_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_16StreamingDecoder9parse_u32: 833| 463k| fn parse_u32( 834| 463k| &mut self, 835| 463k| kind: U32ValueKind, 836| 463k| u32_be_bytes: &[u8], 837| 463k| image_data: Option<&mut UnfilterBuf<'_>>, 838| 463k| consumed_bytes: usize, 839| 463k| ) -> Result<(usize, Decoded), DecodingError> { 840| 463k| debug_assert_eq!(u32_be_bytes.len(), 4); 841| 463k| let bytes = u32_be_bytes.try_into().unwrap(); 842| 463k| let val = u32::from_be_bytes(bytes); 843| | 844| 463k| match kind { 845| | U32ValueKind::Signature1stU32 => { 846| 10.1k| if bytes == [137, 80, 78, 71] { 847| 10.0k| self.state = Some(State::new_u32(U32ValueKind::Signature2ndU32)); 848| 10.0k| Ok((consumed_bytes, Decoded::Nothing)) 849| | } else { 850| 59| Err(DecodingError::Format( 851| 59| FormatErrorInner::InvalidSignature.into(), 852| 59| )) 853| | } 854| | } 855| | U32ValueKind::Signature2ndU32 => { 856| 10.0k| if bytes == [13, 10, 26, 10] { 857| 10.0k| self.state = Some(State::new_u32(U32ValueKind::Length)); 858| 10.0k| Ok((consumed_bytes, Decoded::Nothing)) 859| | } else { 860| 47| Err(DecodingError::Format( 861| 47| FormatErrorInner::InvalidSignature.into(), 862| 47| )) 863| | } 864| | } 865| | U32ValueKind::Length => { 866| 150k| self.state = Some(State::new_u32(U32ValueKind::Type { length: val })); 867| 150k| Ok((consumed_bytes, Decoded::Nothing)) 868| | } 869| 150k| U32ValueKind::Type { length } => { 870| 150k| let type_str = ChunkType(bytes); 871| 150k| if self.info.is_none() && type_str != IHDR { 872| 50| return Err(DecodingError::Format( 873| 50| FormatErrorInner::ChunkBeforeIhdr { kind: type_str }.into(), 874| 50| )); 875| 150k| } 876| 150k| if type_str != self.current_chunk.type_ 877| 36.7k| && (self.current_chunk.type_ == IDAT || self.current_chunk.type_ == chunk::fdAT) 878| | { 879| 2.57k| let finished = match image_data { 880| 241| Some(image_data) => self.inflater.finish(image_data)?, 881| 2.32k| None => true, 882| | }; 883| | 884| | // We ended up handling IDAT/fdAT data rather than the chunk 885| | // type header atually received. Thus rewind `self.state` to 886| | // what it was before this function was called. 887| 2.39k| self.state = Some(State::U32 { 888| 2.39k| kind, 889| 2.39k| bytes, 890| 2.39k| accumulated_count: 4 - consumed_bytes, 891| 2.39k| }); 892| | 893| 2.39k| if finished { 894| | // We've processed all the image data necessary. Update 895| | // `current_chunk.type_`so this codepath isn't taken 896| | // again next time. 897| 2.35k| self.current_chunk.type_ = type_str; 898| 2.35k| self.ready_for_idat_chunks = false; 899| 2.35k| self.ready_for_fdat_chunks = false; 900| 2.35k| 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| 32| return Ok((0, Decoded::ImageData)); 906| | } 907| 147k| } 908| | 909| 147k| self.current_chunk.type_ = type_str; 910| 147k| if !self.decode_options.ignore_crc { 911| 147k| self.current_chunk.crc.reset(); 912| 147k| self.current_chunk.crc.update(&type_str.0); 913| 147k| } 914| 147k| self.current_chunk.remaining = length; 915| 147k| self.current_chunk.raw_bytes.clear(); 916| | 917| 147k| 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| 12.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| 12.5k| } 944| 12.5k| self.have_idat = true; 945| 12.5k| self.current_chunk.action = ChunkAction::Process; 946| 12.5k| Some(State::ImageData(type_str)) 947| | } 948| 135k| _ => Some(self.start_chunk(type_str, length)?), 949| | }; 950| 147k| Ok((consumed_bytes, Decoded::ChunkBegin(length, type_str))) 951| | } 952| 142k| 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| 142k| let sum = if self.decode_options.ignore_crc { 957| 0| val 958| | } else { 959| 142k| self.current_chunk.crc.clone().finalize() 960| | }; 961| | 962| 142k| if val == sum || CHECKSUM_DISABLED { 963| 142k| 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| 128k| debug_assert!(self.state.is_none()); 968| 128k| let decoded = self.parse_chunk(type_str)?; 969| | 970| 128k| if type_str != IEND { 971| 128k| self.state = Some(State::new_u32(U32ValueKind::Length)); 972| 128k| } 973| 128k| Ok((consumed_bytes, decoded)) 974| | } 975| | ChunkAction::Skip => { 976| 10.8k| self.state = Some(State::new_u32(U32ValueKind::Length)); 977| 10.8k| Ok(( 978| 10.8k| consumed_bytes, 979| 10.8k| Decoded::SkippedAncillaryChunk(self.current_chunk.type_), 980| 10.8k| )) 981| | } 982| | ChunkAction::Reject => { 983| 2.85k| self.state = Some(State::new_u32(U32ValueKind::Length)); 984| 2.85k| 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| 463k| } _RNvNvMs9_NtNtCskrDebHigSPL_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_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_13DecodingErrorINtNtCs6SNw0SRvItZ_4core7convert4FromNtNtNtCsjS9ICikYiHq_3std2io5error5ErrorE4from: 430| 35| fn from(err: io::Error) -> DecodingError { 431| 35| DecodingError::IoError(err) 432| 35| } _RNvXs3_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_13DecodingErrorINtNtCs6SNw0SRvItZ_4core7convert4FromNtB5_11FormatErrorE4from: 436| 203| fn from(err: FormatError) -> DecodingError { 437| 203| DecodingError::Format(err) 438| 203| } _RNvXs4_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_11FormatErrorINtNtCs6SNw0SRvItZ_4core7convert4FromNtB5_16FormatErrorInnerE4from: 442| 27.2M| fn from(inner: FormatErrorInner) -> Self { 443| 27.2M| FormatError { inner } 444| 27.2M| } _RNvXs6_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_13DecodingErrorINtNtCs6SNw0SRvItZ_4core7convert4FromNtNtB9_13text_metadata17TextDecodingErrorE4from: 457| 7.39k| fn from(tbe: TextDecodingError) -> Self { 458| 7.39k| DecodingError::Format(FormatError { 459| 7.39k| inner: FormatErrorInner::BadTextEncoding(tbe), 460| 7.39k| }) 461| 7.39k| } _RNvXs7_NtNtCskrDebHigSPL_3png7decoder6streamNtB5_13DecodeOptionsNtNtCs6SNw0SRvItZ_4core7default7Default7default: 475| 10.1k| fn default() -> Self { 476| 10.1k| Self { 477| 10.1k| ignore_adler32: true, 478| 10.1k| ignore_crc: false, 479| 10.1k| ignore_text_chunk: false, 480| 10.1k| ignore_iccp_chunk: false, 481| 10.1k| skip_ancillary_crc_failures: true, 482| 10.1k| } 483| 10.1k| } _RNvMsa_NtNtCskrDebHigSPL_3png7decoder6streamNtNtB9_6common4Info22validate_default_image: 1962| 113| 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| 113| if fc.x_offset != 0 1972| 85| || fc.y_offset != 0 1973| 80| || fc.width != self.width 1974| 76| || fc.height != self.height 1975| | { 1976| 65| return Err(DecodingError::Format( 1977| 65| FormatErrorInner::BadSubFrameBounds {}.into(), 1978| 65| )); 1979| 48| } 1980| 48| Ok(()) 1981| 113| } _RNvMsa_NtNtCskrDebHigSPL_3png7decoder6streamNtNtB9_6common4Info8validate: 1983| 185| fn validate(&self, fc: &FrameControl) -> Result<(), DecodingError> { 1984| 185| if fc.width == 0 || fc.height == 0 { 1985| 3| return Err(DecodingError::Format( 1986| 3| FormatErrorInner::InvalidDimensions.into(), 1987| 3| )); 1988| 182| } 1989| | 1990| | // Validate mathematically: fc.width + fc.x_offset <= self.width 1991| 182| 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| 182| let in_y_bounds = Some(fc.height) <= self.height.checked_sub(fc.y_offset); 1994| | 1995| 182| if !in_x_bounds || !in_y_bounds { 1996| 69| return Err(DecodingError::Format( 1997| 69| // TODO: do we want to display the bad bounds? 1998| 69| FormatErrorInner::BadSubFrameBounds {}.into(), 1999| 69| )); 2000| 113| } 2001| | 2002| 113| Ok(()) 2003| 185| } _RINvNtNtCskrDebHigSPL_3png7decoder9transform11unpack_bitsNCNvNtB2_7palette16expand_into_rgb80EB6_: 90| 29.3k|fn unpack_bits(input: &[u8], output: &mut [u8], channels: usize, bit_depth: u8, func: F) 91| 29.3k|where 92| 29.3k| F: Fn(u8, &mut [u8]), 93| |{ 94| | // Only [1, 2, 4, 8] are valid bit depths 95| 29.3k| 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| 29.3k| assert!((8 / bit_depth as usize * channels).saturating_mul(input.len()) >= output.len()); 99| | 100| 29.3k| let mut buf_chunks = output.chunks_exact_mut(channels); 101| 29.3k| 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| 29.3k| 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| 29.3k| let mask = ((1u16 << bit_depth) - 1) as u8; 118| | 119| | // These variables are initialized in the loop 120| 29.3k| let mut shift = -1; 121| 29.3k| let mut curr = 0; 122| | 123| 98.3M| for chunk in buf_chunks { 124| 98.3M| if shift < 0 { 125| 12.3M| shift = 8 - bit_depth as i32; 126| 12.3M| curr = *iter.next().expect("input for unpack bits is not empty"); 127| 85.9M| } 128| | 129| 98.3M| let pixel = (curr >> shift) & mask; 130| 98.3M| func(pixel, chunk); 131| | 132| 98.3M| shift -= bit_depth as i32; 133| | } 134| | } 135| 29.3k|} _RINvNtNtCskrDebHigSPL_3png7decoder9transform11unpack_bitsNCNvNtB2_7palette26expand_paletted_into_rgba80EB6_: 90| 7.28k|fn unpack_bits(input: &[u8], output: &mut [u8], channels: usize, bit_depth: u8, func: F) 91| 7.28k|where 92| 7.28k| F: Fn(u8, &mut [u8]), 93| |{ 94| | // Only [1, 2, 4, 8] are valid bit depths 95| 7.28k| assert!(matches!(bit_depth, 1 | 2 | 4 | 8)); 96| | // Check that `input` is capable of producing a buffer as long as `output`: 97| | // number of shift lookups per bit depth * channels * input length 98| 7.28k| assert!((8 / bit_depth as usize * channels).saturating_mul(input.len()) >= output.len()); 99| | 100| 7.28k| let mut buf_chunks = output.chunks_exact_mut(channels); 101| 7.28k| let mut iter = input.iter(); 102| | 103| | // `shift` iterates through the corresponding bit depth sequence: 104| | // 1 => &[7, 6, 5, 4, 3, 2, 1, 0], 105| | // 2 => &[6, 4, 2, 0], 106| | // 4 => &[4, 0], 107| | // 8 => &[0], 108| | // 109| | // `(0..8).step_by(bit_depth.into()).rev()` doesn't always optimize well so 110| | // shifts are calculated instead. (2023-08, Rust 1.71) 111| | 112| 7.28k| if bit_depth == 8 { 113| 41.7k| for (&curr, chunk) in iter.zip(&mut buf_chunks) { 114| 41.7k| func(curr, chunk); 115| 41.7k| } 116| | } else { 117| 2.42k| let mask = ((1u16 << bit_depth) - 1) as u8; 118| | 119| | // These variables are initialized in the loop 120| 2.42k| let mut shift = -1; 121| 2.42k| let mut curr = 0; 122| | 123| 1.17M| for chunk in buf_chunks { 124| 1.17M| if shift < 0 { 125| 158k| shift = 8 - bit_depth as i32; 126| 158k| curr = *iter.next().expect("input for unpack bits is not empty"); 127| 1.01M| } 128| | 129| 1.17M| let pixel = (curr >> shift) & mask; 130| 1.17M| func(pixel, chunk); 131| | 132| 1.17M| shift -= bit_depth as i32; 133| | } 134| | } 135| 7.28k|} _RINvNtNtCskrDebHigSPL_3png7decoder9transform11unpack_bitsNCNvB2_14expand_gray_u80EB6_: 90| 713k|fn unpack_bits(input: &[u8], output: &mut [u8], channels: usize, bit_depth: u8, func: F) 91| 713k|where 92| 713k| F: Fn(u8, &mut [u8]), 93| |{ 94| | // Only [1, 2, 4, 8] are valid bit depths 95| 713k| 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| 713k| assert!((8 / bit_depth as usize * channels).saturating_mul(input.len()) >= output.len()); 99| | 100| 713k| let mut buf_chunks = output.chunks_exact_mut(channels); 101| 713k| 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| 713k| 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| 713k| let mask = ((1u16 << bit_depth) - 1) as u8; 118| | 119| | // These variables are initialized in the loop 120| 713k| let mut shift = -1; 121| 713k| let mut curr = 0; 122| | 123| 658M| for chunk in buf_chunks { 124| 658M| if shift < 0 { 125| 136M| shift = 8 - bit_depth as i32; 126| 136M| curr = *iter.next().expect("input for unpack bits is not empty"); 127| 521M| } 128| | 129| 658M| let pixel = (curr >> shift) & mask; 130| 658M| func(pixel, chunk); 131| | 132| 658M| shift -= bit_depth as i32; 133| | } 134| | } 135| 713k|} _RINvNtNtCskrDebHigSPL_3png7decoder9transform11unpack_bitsNCNvB2_24expand_gray_u8_with_trns0EB6_: 90| 2.86k|fn unpack_bits(input: &[u8], output: &mut [u8], channels: usize, bit_depth: u8, func: F) 91| 2.86k|where 92| 2.86k| F: Fn(u8, &mut [u8]), 93| |{ 94| | // Only [1, 2, 4, 8] are valid bit depths 95| 2.86k| assert!(matches!(bit_depth, 1 | 2 | 4 | 8)); 96| | // Check that `input` is capable of producing a buffer as long as `output`: 97| | // number of shift lookups per bit depth * channels * input length 98| 2.86k| assert!((8 / bit_depth as usize * channels).saturating_mul(input.len()) >= output.len()); 99| | 100| 2.86k| let mut buf_chunks = output.chunks_exact_mut(channels); 101| 2.86k| let mut iter = input.iter(); 102| | 103| | // `shift` iterates through the corresponding bit depth sequence: 104| | // 1 => &[7, 6, 5, 4, 3, 2, 1, 0], 105| | // 2 => &[6, 4, 2, 0], 106| | // 4 => &[4, 0], 107| | // 8 => &[0], 108| | // 109| | // `(0..8).step_by(bit_depth.into()).rev()` doesn't always optimize well so 110| | // shifts are calculated instead. (2023-08, Rust 1.71) 111| | 112| 2.86k| if bit_depth == 8 { 113| 0| for (&curr, chunk) in iter.zip(&mut buf_chunks) { 114| 0| func(curr, chunk); 115| 0| } 116| | } else { 117| 2.86k| let mask = ((1u16 << bit_depth) - 1) as u8; 118| | 119| | // These variables are initialized in the loop 120| 2.86k| let mut shift = -1; 121| 2.86k| let mut curr = 0; 122| | 123| 97.8M| for chunk in buf_chunks { 124| 97.8M| if shift < 0 { 125| 13.2M| shift = 8 - bit_depth as i32; 126| 13.2M| curr = *iter.next().expect("input for unpack bits is not empty"); 127| 84.6M| } 128| | 129| 97.8M| let pixel = (curr >> shift) & mask; 130| 97.8M| func(pixel, chunk); 131| | 132| 97.8M| shift -= bit_depth as i32; 133| | } 134| | } 135| 2.86k|} _RNCNvNtNtCskrDebHigSPL_3png7decoder9transform14expand_gray_u80B7_: 183| 658M| unpack_bits(row, buffer, 1, info.bit_depth as u8, |val, chunk| { 184| 658M| chunk[0] = val * scaling_factor 185| 658M| }); _RNCNvNtNtCskrDebHigSPL_3png7decoder9transform24expand_gray_u8_with_trns0B7_: 191| 97.8M| unpack_bits(row, buffer, 2, info.bit_depth as u8, |pixel, chunk| { 192| 97.8M| chunk[1] = if let Some(trns) = trns { 193| 97.8M| if pixel == trns[0] { 194| 4.99M| 0 195| | } else { 196| 92.8M| 0xFF 197| | } 198| | } else { 199| 0| 0xFF 200| | }; 201| 97.8M| chunk[0] = pixel * scaling_factor 202| 97.8M| }); _RNvNtNtCskrDebHigSPL_3png7decoder9transform14expand_gray_u8: 181| 713k|fn expand_gray_u8(row: &[u8], buffer: &mut [u8], info: &Info) { 182| 713k| let scaling_factor = (255) / ((1u16 << info.bit_depth as u8) - 1) as u8; 183| 713k| unpack_bits(row, buffer, 1, info.bit_depth as u8, |val, chunk| { 184| | chunk[0] = val * scaling_factor 185| | }); 186| 713k|} _RNvNtNtCskrDebHigSPL_3png7decoder9transform16expand_trns_line: 137| 2.23k|fn expand_trns_line(input: &[u8], output: &mut [u8], info: &Info) { 138| 2.23k| let channels = info.color_type.samples(); 139| 2.23k| let trns = info.trns.as_deref(); 140| 37.7M| for (input, output) in input 141| 2.23k| .chunks_exact(channels) 142| 2.23k| .zip(output.chunks_exact_mut(channels + 1)) 143| | { 144| 37.7M| output[..channels].copy_from_slice(input); 145| 37.7M| output[channels] = if Some(input) == trns { 0 } else { 0xFF }; 146| | } 147| 2.23k|} _RNvNtNtCskrDebHigSPL_3png7decoder9transform18expand_trns_line16: 149| 6.55k|fn expand_trns_line16(input: &[u8], output: &mut [u8], info: &Info) { 150| 6.55k| let channels = info.color_type.samples(); 151| 6.55k| let trns = info.trns.as_deref(); 152| 13.8M| for (input, output) in input 153| 6.55k| .chunks_exact(channels * 2) 154| 6.55k| .zip(output.chunks_exact_mut(channels * 2 + 2)) 155| | { 156| 13.8M| output[..channels * 2].copy_from_slice(input); 157| 13.8M| if Some(input) == trns { 158| 0| output[channels * 2] = 0; 159| 0| output[channels * 2 + 1] = 0 160| | } else { 161| 13.8M| output[channels * 2] = 0xFF; 162| 13.8M| output[channels * 2 + 1] = 0xFF 163| | }; 164| | } 165| 6.55k|} _RNvNtNtCskrDebHigSPL_3png7decoder9transform19create_transform_fn: 20| 4.90k|pub fn create_transform_fn( 21| 4.90k| info: &Info, 22| 4.90k| transform: Transformations, 23| 4.90k|) -> Result { 24| 4.90k| let color_type = info.color_type; 25| 4.90k| let bit_depth = info.bit_depth as u8; 26| 4.90k| let trns = info.trns.is_some() || transform.contains(Transformations::ALPHA); 27| 4.90k| let expand = 28| 4.90k| transform.contains(Transformations::EXPAND) || transform.contains(Transformations::ALPHA); 29| 4.90k| let strip16 = bit_depth == 16 && transform.contains(Transformations::STRIP_16); 30| 892| match color_type { 31| 642| ColorType::Indexed if expand => { 32| 642| if info.palette.is_none() { 33| 20| Err(DecodingError::Format( 34| 20| FormatErrorInner::PaletteRequired.into(), 35| 20| )) 36| 622| } 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| 622| Ok(if trns { 47| 86| palette::create_expansion_into_rgba8(info) 48| | } else { 49| 536| palette::create_expansion_into_rgb8(info) 50| | }) 51| | } 52| | } 53| 3.06k| ColorType::Grayscale | ColorType::GrayscaleAlpha if bit_depth < 8 && expand => { 54| 2.07k| Ok(Box::new(if trns { 55| 73| expand_gray_u8_with_trns 56| 2.00k| } else { 57| 2.00k| expand_gray_u8 58| 2.00k| })) 59| | } 60| 995| ColorType::Grayscale | ColorType::Rgb if expand && trns => { 61| 122| Ok(Box::new(if bit_depth == 8 { 62| 45| expand_trns_line 63| 77| } else if strip16 { 64| 0| expand_trns_and_strip_line16 65| 0| } else { 66| 77| assert_eq!(bit_depth, 16); 67| 77| 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| 2.06k| _ => Ok(Box::new(copy_row)), 76| | } 77| 4.90k|} _RNvNtNtCskrDebHigSPL_3png7decoder9transform24expand_gray_u8_with_trns: 188| 2.86k|fn expand_gray_u8_with_trns(row: &[u8], buffer: &mut [u8], info: &Info) { 189| 2.86k| let scaling_factor = (255) / ((1u16 << info.bit_depth as u8) - 1) as u8; 190| 2.86k| let trns = info.trns.as_deref(); 191| 2.86k| unpack_bits(row, buffer, 2, info.bit_depth as u8, |pixel, chunk| { 192| | chunk[1] = if let Some(trns) = trns { 193| | if pixel == trns[0] { 194| | 0 195| | } else { 196| | 0xFF 197| | } 198| | } else { 199| | 0xFF 200| | }; 201| | chunk[0] = pixel * scaling_factor 202| | }); 203| 2.86k|} _RNvNtNtCskrDebHigSPL_3png7decoder9transform8copy_row: 79| 26.4M|fn copy_row(row: &[u8], output_buffer: &mut [u8], _: &Info) { 80| 26.4M| output_buffer.copy_from_slice(row); 81| 26.4M|} _RNCNvNtNtNtCskrDebHigSPL_3png7decoder9transform7palette16expand_into_rgb80B9_: 109| 98.3M| unpack_bits(row, buffer, 3, info.bit_depth as u8, |i, chunk| { 110| 98.3M| let rgba = &rgba_palette[i as usize]; 111| 98.3M| chunk[0] = rgba[0]; 112| 98.3M| chunk[1] = rgba[1]; 113| 98.3M| chunk[2] = rgba[2]; 114| 98.3M| }) _RNCNvNtNtNtCskrDebHigSPL_3png7decoder9transform7palette26create_expansion_into_rgb80B9_: 26| 3.40k| Box::new(move |input, output, _info| expand_8bit_into_rgb8(input, output, &rgba_palette)) _RNCNvNtNtNtCskrDebHigSPL_3png7decoder9transform7palette26create_expansion_into_rgb8s_0B9_: 28| 29.3k| Box::new(move |input, output, info| expand_into_rgb8(input, output, info, &rgba_palette)) _RNCNvNtNtNtCskrDebHigSPL_3png7decoder9transform7palette26expand_paletted_into_rgba80B9_: 123| 1.21M| unpack_bits(row, buffer, 4, info.bit_depth as u8, |i, chunk| { 124| 1.21M| chunk.copy_from_slice(&rgba_palette[i as usize]); 125| 1.21M| }); _RNCNvNtNtNtCskrDebHigSPL_3png7decoder9transform7palette27create_expansion_into_rgba80B9_: 34| 7.28k| Box::new(move |input, output, info| { 35| 7.28k| expand_paletted_into_rgba8(input, output, info, &rgba_palette) 36| 7.28k| }) _RNvNtNtNtCskrDebHigSPL_3png7decoder9transform7palette16expand_into_rgb8: 108| 29.3k|fn expand_into_rgb8(row: &[u8], buffer: &mut [u8], info: &Info, rgba_palette: &[[u8; 4]; 256]) { 109| 29.3k| 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| 29.3k|} _RNvNtNtNtCskrDebHigSPL_3png7decoder9transform7palette19create_rgba_palette: 39| 622|fn create_rgba_palette(info: &Info) -> [[u8; 4]; 256] { 40| 622| let palette = info.palette.as_deref().expect("Caller should verify"); 41| 622| 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| 622| let trns = if trns.len() <= palette.len() / 3 { 51| 596| trns 52| | } else { 53| 26| &[] 54| | }; 55| | 56| | // Default to black, opaque entries. 57| 622| 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| 622| let mut palette_iter = palette; 63| 622| let mut rgba_iter = &mut rgba_palette[..]; 64| 1.93k| while palette_iter.len() >= 4 { 65| 1.31k| // Copying 4 bytes at a time is more efficient than copying 3. 66| 1.31k| // OTOH, this clobbers the alpha value in `rgba_iter[0][3]` - we 67| 1.31k| // need to fix this later. 68| 1.31k| rgba_iter[0].copy_from_slice(&palette_iter[0..4]); 69| 1.31k| 70| 1.31k| palette_iter = &palette_iter[3..]; 71| 1.31k| rgba_iter = &mut rgba_iter[1..]; 72| 1.31k| } 73| 622| if !palette_iter.is_empty() { 74| 622| rgba_iter[0][0..3].copy_from_slice(&palette_iter[0..3]); 75| 622| } 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| 622| for (alpha, rgba) in trns.iter().copied().zip(rgba_palette.iter_mut()) { 82| 343| rgba[3] = alpha; 83| 343| } 84| | 85| | // Unclobber the remaining alpha values. 86| 1.59k| for rgba in rgba_palette[trns.len()..(palette.len() / 3)].iter_mut() { 87| 1.59k| rgba[3] = 0xFF; 88| 1.59k| } 89| | 90| 622| rgba_palette 91| 622|} _RNvNtNtNtCskrDebHigSPL_3png7decoder9transform7palette21expand_8bit_into_rgb8: 93| 3.40k|fn expand_8bit_into_rgb8(mut input: &[u8], mut output: &mut [u8], rgba_palette: &[[u8; 4]; 256]) { 94| 18.2M| while output.len() >= 4 { 95| 18.2M| // Copying 4 bytes at a time is more efficient than 3. 96| 18.2M| let rgba = &rgba_palette[input[0] as usize]; 97| 18.2M| output[0..4].copy_from_slice(rgba); 98| 18.2M| 99| 18.2M| input = &input[1..]; 100| 18.2M| output = &mut output[3..]; 101| 18.2M| } 102| 3.40k| if !output.is_empty() { 103| 3.40k| let rgba = &rgba_palette[input[0] as usize]; 104| 3.40k| output[0..3].copy_from_slice(&rgba[0..3]); 105| 3.40k| } 106| 3.40k|} _RNvNtNtNtCskrDebHigSPL_3png7decoder9transform7palette26create_expansion_into_rgb8: 22| 536|pub fn create_expansion_into_rgb8(info: &Info) -> TransformFn { 23| 536| let rgba_palette = create_rgba_palette(info); 24| | 25| 536| if info.bit_depth == BitDepth::Eight { 26| 60| Box::new(move |input, output, _info| expand_8bit_into_rgb8(input, output, &rgba_palette)) 27| | } else { 28| 476| Box::new(move |input, output, info| expand_into_rgb8(input, output, info, &rgba_palette)) 29| | } 30| 536|} _RNvNtNtNtCskrDebHigSPL_3png7decoder9transform7palette26expand_paletted_into_rgba8: 117| 7.28k|fn expand_paletted_into_rgba8( 118| 7.28k| row: &[u8], 119| 7.28k| buffer: &mut [u8], 120| 7.28k| info: &Info, 121| 7.28k| rgba_palette: &[[u8; 4]; 256], 122| 7.28k|) { 123| 7.28k| unpack_bits(row, buffer, 4, info.bit_depth as u8, |i, chunk| { 124| | chunk.copy_from_slice(&rgba_palette[i as usize]); 125| | }); 126| 7.28k|} _RNvNtNtNtCskrDebHigSPL_3png7decoder9transform7palette27create_expansion_into_rgba8: 32| 86|pub fn create_expansion_into_rgba8(info: &Info) -> TransformFn { 33| 86| let rgba_palette = create_rgba_palette(info); 34| 86| Box::new(move |input, output, info| { 35| | expand_paletted_into_rgba8(input, output, info, &rgba_palette) 36| | }) 37| 86|} _RINvMNtNtCskrDebHigSPL_3png7decoder18unfiltering_bufferNtB3_17UnfilteringBuffer20with_unfilled_bufferNCNvMs4_B5_INtB5_6ReaderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE23next_raw_interlaced_row0INtNtCs6SNw0SRvItZ_4core6result6ResultNtNtB5_12read_decoder25ImageDataCompletionStatusNtNtB5_6stream13DecodingErrorEECs1vRhqpPUfvi_5image: 166| 1.44M| pub fn with_unfilled_buffer(&mut self, f: F) -> T 167| 1.44M| where 168| 1.44M| F: FnOnce(&mut UnfilterBuf<'_>) -> T, 169| | { 170| | // Potentially shift the buffer left to avoid unbounded growth. 171| 1.44M| let discard_size = self.available.min(match &self.prev_row { 172| 1.11M| PrevRow::None | PrevRow::Scratch(_) => self.current_start, 173| 321k| PrevRow::InPlace(prev_start) => *prev_start, 174| | }); 175| 1.44M| 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.58k| && self.filled >= self.data_stream.len() / 2 182| 1.58k| { 183| 1.58k| self.shift_buffer_left(discard_size); 184| 1.43M| } 185| | 186| 1.44M| if self.filled + Self::GROWTH_BYTES > self.data_stream.len() { 187| 596k| self.data_stream.resize(self.filled + Self::GROWTH_BYTES, 0); 188| 844k| } 189| | 190| 1.44M| if self.remaining_bytes < usize::MAX as u64 191| 1.44M| && self.filled.saturating_add(self.remaining_bytes as usize) < self.data_stream.len() 192| 36.8k| { 193| 36.8k| self.data_stream 194| 36.8k| .resize(self.filled + self.remaining_bytes as usize, 0); 195| 1.40M| } 196| | 197| 1.44M| let old_filled = self.filled; 198| 1.44M| let ret = f(&mut UnfilterBuf { 199| 1.44M| buffer: &mut self.data_stream, 200| 1.44M| filled: &mut self.filled, 201| 1.44M| available: &mut self.available, 202| 1.44M| }); 203| 1.44M| assert!(self.filled >= old_filled); 204| 1.44M| self.remaining_bytes -= (self.filled - old_filled) as u64; 205| | 206| 1.44M| if self.remaining_bytes == 0 { 207| 2.67k| self.available = self.filled; 208| 1.43M| } 209| | 210| 1.44M| self.debug_assert_invariants(); 211| 1.44M| ret 212| 1.44M| } _RNCNvMNtNtCskrDebHigSPL_3png7decoder18unfiltering_bufferNtB4_17UnfilteringBuffer3new0B8_: 63| 9.87k| .and_then(|v| v.checked_mul(info.height.min(128) as usize)) _RNCNvMNtNtCskrDebHigSPL_3png7decoder18unfiltering_bufferNtB4_17UnfilteringBuffer3news0_0B8_: 81| 9.87k| .and_then(|v| v.checked_mul(4)) _RNCNvMNtNtCskrDebHigSPL_3png7decoder18unfiltering_bufferNtB4_17UnfilteringBuffer3news1_0B8_: 86| 9.87k| .and_then(|v| checked_next_multiple_of(v, 64)) _RNCNvMNtNtCskrDebHigSPL_3png7decoder18unfiltering_bufferNtB4_17UnfilteringBuffer3news_0B8_: 66| 9.87k| .and_then(|v| checked_next_multiple_of(v, 256)) _RNvMNtNtCskrDebHigSPL_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer11start_frame: 120| 6.76k| pub fn start_frame(&mut self, frame_bytes: u64) { 121| 6.76k| self.data_stream.clear(); 122| 6.76k| self.prev_row = PrevRow::None; 123| 6.76k| self.current_start = 0; 124| 6.76k| self.filled = 0; 125| 6.76k| self.available = 0; 126| 6.76k| self.remaining_bytes = frame_bytes; 127| 6.76k| } _RNvMNtNtCskrDebHigSPL_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer14reset_prev_row: 109| 27.1M| 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| 27.1M| if let PrevRow::Scratch(buf) = &mut self.prev_row { 113| 743k| self.scratch_buffer = std::mem::take(buf); 114| 26.4M| } 115| | 116| 27.1M| self.prev_row = PrevRow::None; 117| 27.1M| self.debug_assert_invariants(); 118| 27.1M| } _RNvMNtNtCskrDebHigSPL_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer15curr_row_filter: 244| 27.1M| fn curr_row_filter(&self) -> Result { 245| 27.1M| let filter = self.data_stream[self.current_start]; 246| 27.1M| RowFilter::from_u8(filter).ok_or(DecodingError::Format( 247| 27.1M| FormatErrorInner::UnknownFilterMethod(filter).into(), 248| 27.1M| )) 249| 27.1M| } _RNvMNtNtCskrDebHigSPL_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer15remaining_bytes: 129| 1.44M| pub fn remaining_bytes(&self) -> u64 { 130| 1.44M| self.remaining_bytes 131| 1.44M| } _RNvMNtNtCskrDebHigSPL_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer17shift_buffer_left: 216| 1.58k| 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.58k| 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.58k| if let Some(16..) = self.data_stream.len().checked_sub(self.filled) { 228| 1.00k| self.data_stream.copy_within(discard_size..self.filled, 0); 229| 1.00k| } else { 230| 582| self.data_stream.copy_within(discard_size.., 0); 231| 582| } 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.58k| self.current_start -= discard_size; 236| 1.58k| self.available -= discard_size; 237| 1.58k| self.filled -= discard_size; 238| 1.58k| match &mut self.prev_row { 239| 100| PrevRow::None | PrevRow::Scratch(_) => (), 240| 1.48k| PrevRow::InPlace(prev_start) => *prev_start -= discard_size, 241| | } 242| 1.58k| } _RNvMNtNtCskrDebHigSPL_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer23debug_assert_invariants: 37| 55.8M| fn debug_assert_invariants(&self) {} _RNvMNtNtCskrDebHigSPL_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer23mutable_len_of_curr_row: 146| 27.8M| pub fn mutable_len_of_curr_row(&self) -> usize { 147| 27.8M| self.available.saturating_sub(self.current_start) 148| 27.8M| } _RNvMNtNtCskrDebHigSPL_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer24readable_len_of_curr_row: 155| 748k| pub fn readable_len_of_curr_row(&self) -> usize { 156| 748k| self.filled - self.current_start 157| 748k| } _RNvMNtNtCskrDebHigSPL_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer26unfilter_curr_row_in_place: 257| 26.4M| pub fn unfilter_curr_row_in_place( 258| 26.4M| &mut self, 259| 26.4M| rowlen: usize, 260| 26.4M| bpp: BytesPerPixel, 261| 26.4M| ) -> Result<(), DecodingError> { 262| 26.4M| 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| 26.4M| debug_assert!(self.mutable_len_of_curr_row() >= rowlen); 267| | 268| 26.4M| let filter = self.curr_row_filter()?; 269| 26.4M| let (prev, row) = self.data_stream.split_at_mut(self.current_start); 270| 26.4M| let prev: &[u8] = self.prev_row.as_slice(prev); 271| 26.4M| let row = &mut row[1..rowlen]; // Skip the `RowFilter` byte. 272| 26.4M| debug_assert!(prev.is_empty() || prev.len() == row.len()); 273| | 274| 26.4M| unfilter(filter, bpp, prev, row); 275| | 276| 26.4M| self.reset_prev_row(); 277| 26.4M| self.prev_row = PrevRow::InPlace(self.current_start + 1); 278| 26.4M| self.current_start += rowlen; 279| 26.4M| self.debug_assert_invariants(); 280| | 281| 26.4M| Ok(()) 282| 26.4M| } _RNvMNtNtCskrDebHigSPL_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer38unfilter_curr_row_using_scratch_buffer: 291| 745k| pub fn unfilter_curr_row_using_scratch_buffer( 292| 745k| &mut self, 293| 745k| rowlen: usize, 294| 745k| bpp: BytesPerPixel, 295| 745k| ) -> Result<(), DecodingError> { 296| 745k| debug_assert!(rowlen >= 2); // 1 byte for `RowFilter` and at least 1 byte of pixel data. 297| 745k| 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| 745k| debug_assert!(self.mutable_len_of_curr_row() < rowlen); 302| | 303| 745k| let filter = self.curr_row_filter()?; 304| | 305| 745k| let mut row = std::mem::take(&mut self.scratch_buffer); 306| 745k| row.resize(rowlen - 1, 0); 307| 745k| row.as_mut_slice() 308| 745k| .copy_from_slice(&self.data_stream[self.current_start + 1..][..rowlen - 1]); 309| | 310| 745k| let prev = self.prev_row(); 311| 745k| debug_assert!(prev.is_empty() || prev.len() == (rowlen - 1)); 312| | 313| 745k| unfilter(filter, bpp, prev, &mut row); 314| | 315| 745k| self.reset_prev_row(); 316| 745k| self.prev_row = PrevRow::Scratch(row); 317| 745k| self.current_start += rowlen; 318| | 319| 745k| self.debug_assert_invariants(); 320| | 321| 745k| Ok(()) 322| 745k| } _RNvMNtNtCskrDebHigSPL_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer3new: 49| 9.87k| 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.87k| let data_stream_capacity = { 54| 9.87k| let max_data = info 55| 9.87k| .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.87k| .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.87k| .and_then(|v| checked_next_multiple_of(v, 256)) 67| 9.87k| .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.87k| max_data.min(128 * 1024) 72| | }; 73| | 74| 9.87k| 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.87k| let rowlen_pot = info 78| 9.87k| .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.87k| .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.87k| .and_then(|v| checked_next_multiple_of(v, 64)) 87| 9.87k| .unwrap_or(isize::MAX as usize); 88| | // But never shift back before we have a number of pages freed. 89| 9.87k| rowlen_pot.max(128 * 1024) 90| | }; 91| | 92| 9.87k| let result = Self { 93| 9.87k| data_stream: Vec::with_capacity(data_stream_capacity), 94| 9.87k| prev_row: PrevRow::None, 95| 9.87k| current_start: 0, 96| 9.87k| filled: 0, 97| 9.87k| available: 0, 98| 9.87k| shift_back_limit, 99| 9.87k| remaining_bytes: u64::MAX, 100| 9.87k| scratch_buffer: Vec::new(), 101| 9.87k| }; 102| | 103| 9.87k| result.debug_assert_invariants(); 104| 9.87k| result 105| 9.87k| } _RNvMNtNtCskrDebHigSPL_3png7decoder18unfiltering_bufferNtB2_17UnfilteringBuffer8prev_row: 134| 27.9M| pub fn prev_row(&self) -> &[u8] { 135| 27.9M| self.prev_row 136| 27.9M| .as_slice(&self.data_stream[..self.current_start]) 137| 27.9M| } _RNvMs_NtNtCskrDebHigSPL_3png7decoder18unfiltering_bufferNtB4_7PrevRow8as_slice: 355| 54.3M| fn as_slice<'a>(&'a self, buf: &'a [u8]) -> &'a [u8] { 356| 54.3M| match self { 357| 8.27k| PrevRow::None => &[], 358| 52.8M| PrevRow::InPlace(prev_start) => &buf[*prev_start..], 359| 1.48M| PrevRow::Scratch(scratch) => scratch.as_slice(), 360| | } 361| 54.3M| } _RNvNtNtCskrDebHigSPL_3png7decoder18unfiltering_buffer24checked_next_multiple_of: 364| 19.7k|fn checked_next_multiple_of(val: usize, factor: usize) -> Option { 365| 19.7k| if factor == 0 { 366| 0| return None; 367| 19.7k| } 368| | 369| 19.7k| let remainder = val % factor; 370| | 371| 19.7k| if remainder > 0 { 372| 18.1k| val.checked_add(factor - remainder) 373| | } else { 374| 1.59k| Some(val) 375| | } 376| 19.7k|} _RNCNvMNtNtCskrDebHigSPL_3png7decoder4zlibNtB4_10ZlibStream6finish0B8_: 162| 1| .map_err(|err| { 163| 1| DecodingError::Format(FormatErrorInner::CorruptFlateStream { err }.into()) 164| 1| })?; _RNCNvMs0_NtNtCskrDebHigSPL_3png7decoder4zlibNtB7_11UnfilterBuf10decompress0Bb_: 233| 606| .map_err(|err| { 234| 606| DecodingError::Format(FormatErrorInner::CorruptFlateStream { err }.into()) 235| 606| })?; _RNvMNtNtCskrDebHigSPL_3png7decoder4zlibNtB2_10ZlibStream10decompress: 109| 680k| pub(crate) fn decompress( 110| 680k| &mut self, 111| 680k| data: &[u8], 112| 680k| image_data: &mut UnfilterBuf<'_>, 113| 680k| ) -> 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| 680k| if self.state.is_done() { 118| 395| return Ok(data.len()); 119| 680k| } 120| | 121| 680k| if !self.started && self.ignore_adler32 { 122| 6.34k| self.state.ignore_adler32(); 123| 674k| } 124| | 125| 680k| let in_consumed = image_data.decompress(&mut self.state, data)?; 126| 679k| self.started = true; 127| | 128| 679k| Ok(in_consumed) 129| 680k| } _RNvMNtNtCskrDebHigSPL_3png7decoder4zlibNtB2_10ZlibStream18set_ignore_adler32: 93| 10.1k| pub(crate) fn set_ignore_adler32(&mut self, flag: bool) -> bool { 94| 10.1k| if !self.started { 95| 10.1k| self.ignore_adler32 = flag; 96| 10.1k| true 97| | } else { 98| 0| false 99| | } 100| 10.1k| } _RNvMNtNtCskrDebHigSPL_3png7decoder4zlibNtB2_10ZlibStream3new: 73| 10.1k| pub(crate) fn new() -> Self { 74| 10.1k| ZlibStream { 75| 10.1k| state: Box::new(Decompressor::new()), 76| 10.1k| started: false, 77| 10.1k| ignore_adler32: true, 78| 10.1k| } 79| 10.1k| } _RNvMNtNtCskrDebHigSPL_3png7decoder4zlibNtB2_10ZlibStream5reset: 81| 189| pub(crate) fn reset(&mut self) { 82| 189| self.started = false; 83| 189| *self.state = Decompressor::new(); 84| 189| } _RNvMNtNtCskrDebHigSPL_3png7decoder4zlibNtB2_10ZlibStream6finish: 138| 241| pub(crate) fn finish( 139| 241| &mut self, 140| 241| image_data: &mut UnfilterBuf<'_>, 141| 241| ) -> Result { 142| 241| if !self.started || self.state.is_done() { 143| 27| return Ok(true); 144| 214| } 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| 214| if *image_data.filled == image_data.buffer.len() { 151| 0| return Ok(true); 152| 214| } 153| | 154| 214| let (_, out_consumed) = self 155| 214| .state 156| 214| .read( 157| 214| &[], 158| 214| &mut image_data.buffer[*image_data.available..], 159| 214| *image_data.filled - *image_data.available, 160| | false, 161| | ) 162| 214| .map_err(|err| { 163| | DecodingError::Format(FormatErrorInner::CorruptFlateStream { err }.into()) 164| 1| })?; 165| 213| *image_data.filled += out_consumed; 166| | 167| 213| if self.state.is_done() { 168| 2| *image_data.available = *image_data.filled; 169| 2| return Ok(true); 170| 211| } 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| 211| if *image_data.filled == image_data.buffer.len() { 176| 32| *image_data.available = 177| 32| (*image_data.available).max(image_data.filled.saturating_sub(LOOKBACK_SIZE)); 178| 32| return Ok(false); 179| 179| } 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| 179| Err(DecodingError::Format( 186| 179| FormatErrorInner::CorruptFlateStream { 187| 179| err: fdeflate::DecompressionError::InsufficientInput, 188| 179| } 189| 179| .into(), 190| 179| )) 191| 241| } _RNvMs0_NtNtCskrDebHigSPL_3png7decoder4zlibNtB5_11UnfilterBuf10decompressB9_: 220| 680k| fn decompress( 221| 680k| &mut self, 222| 680k| decompressor: &mut fdeflate::Decompressor, 223| 680k| input: &[u8], 224| 680k| ) -> Result { 225| 680k| let output_limit = (*self.filled + UnfilteringBuffer::GROWTH_BYTES).min(self.buffer.len()); 226| 680k| let (in_consumed, out_consumed) = decompressor 227| 680k| .read( 228| 680k| input, 229| 680k| &mut self.buffer[*self.available..output_limit], 230| 680k| *self.filled - *self.available, 231| | false, 232| | ) 233| 680k| .map_err(|err| { 234| | DecodingError::Format(FormatErrorInner::CorruptFlateStream { err }.into()) 235| 606| })?; 236| | 237| 679k| *self.filled += out_consumed; 238| 679k| if decompressor.is_done() { 239| 943| *self.available = *self.filled; 240| 678k| } 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| 667k| if new_available > *self.available { 247| 665k| *self.available = new_available; 248| 665k| } 249| 11.7k| } 250| | 251| 679k| Ok(in_consumed) 252| 680k| } _RNCNvNtCskrDebHigSPL_3png6filter8unfilter0B5_: 123| 258M| current.iter_mut().reduce(|&mut prev, curr| { 124| 258M| *curr = curr.wrapping_add(prev); 125| 258M| curr 126| 258M| }); _RNCNvNtCskrDebHigSPL_3png6filter8unfilters_0B5_: 204| 67.7M| current.iter_mut().reduce(|&mut prev, curr| { 205| 67.7M| *curr = curr.wrapping_add(prev / 2); 206| 67.7M| curr 207| 67.7M| }); _RNvMs2_NtCskrDebHigSPL_3png6filterNtB5_9RowFilter7from_u8: 79| 27.1M| pub fn from_u8(n: u8) -> Option { 80| 27.1M| match n { 81| 26.7M| 0 => Some(Self::NoFilter), 82| 120k| 1 => Some(Self::Sub), 83| 125k| 2 => Some(Self::Up), 84| 106k| 3 => Some(Self::Avg), 85| 52.3k| 4 => Some(Self::Paeth), 86| 147| _ => None, 87| | } 88| 27.1M| } _RNvNtCskrDebHigSPL_3png6filter8unfilter: 102| 27.1M|pub(crate) fn unfilter( 103| 27.1M| mut filter: RowFilter, 104| 27.1M| tbpp: BytesPerPixel, 105| 27.1M| previous: &[u8], 106| 27.1M| current: &mut [u8], 107| 27.1M|) { 108| | use self::RowFilter::*; 109| | 110| | // If the previous row is empty, then treat it as if it were filled with zeros. 111| 27.1M| if previous.is_empty() { 112| 8.27k| if filter == Paeth { 113| 712| filter = Sub; 114| 7.55k| } else if filter == Up { 115| 638| filter = NoFilter; 116| 6.92k| } 117| 27.1M| } 118| | 119| 106k| match filter { 120| 26.7M| NoFilter => {} 121| 121k| Sub => match tbpp { 122| | BytesPerPixel::One => { 123| 69.4k| current.iter_mut().reduce(|&mut prev, curr| { 124| | *curr = curr.wrapping_add(prev); 125| | curr 126| | }); 127| | } 128| | BytesPerPixel::Two => { 129| 9.52k| let mut prev = [0; 2]; 130| 149M| for chunk in current.chunks_exact_mut(2) { 131| 149M| let new_chunk = [ 132| 149M| chunk[0].wrapping_add(prev[0]), 133| 149M| chunk[1].wrapping_add(prev[1]), 134| 149M| ]; 135| 149M| *TryInto::<&mut [u8; 2]>::try_into(chunk).unwrap() = new_chunk; 136| 149M| prev = new_chunk; 137| 149M| } 138| | } 139| | BytesPerPixel::Three => { 140| 33.7k| let mut prev = [0; 3]; 141| 192M| for chunk in current.chunks_exact_mut(3) { 142| 192M| let new_chunk = [ 143| 192M| chunk[0].wrapping_add(prev[0]), 144| 192M| chunk[1].wrapping_add(prev[1]), 145| 192M| chunk[2].wrapping_add(prev[2]), 146| 192M| ]; 147| 192M| *TryInto::<&mut [u8; 3]>::try_into(chunk).unwrap() = new_chunk; 148| 192M| prev = new_chunk; 149| 192M| } 150| | } 151| | BytesPerPixel::Four => { 152| 3.39k| let mut prev = [0; 4]; 153| 158M| for chunk in current.chunks_exact_mut(4) { 154| 158M| let new_chunk = [ 155| 158M| chunk[0].wrapping_add(prev[0]), 156| 158M| chunk[1].wrapping_add(prev[1]), 157| 158M| chunk[2].wrapping_add(prev[2]), 158| 158M| chunk[3].wrapping_add(prev[3]), 159| 158M| ]; 160| 158M| *TryInto::<&mut [u8; 4]>::try_into(chunk).unwrap() = new_chunk; 161| 158M| prev = new_chunk; 162| 158M| } 163| | } 164| | BytesPerPixel::Six => { 165| 3.24k| let mut prev = [0; 6]; 166| 12.2M| for chunk in current.chunks_exact_mut(6) { 167| 12.2M| let new_chunk = [ 168| 12.2M| chunk[0].wrapping_add(prev[0]), 169| 12.2M| chunk[1].wrapping_add(prev[1]), 170| 12.2M| chunk[2].wrapping_add(prev[2]), 171| 12.2M| chunk[3].wrapping_add(prev[3]), 172| 12.2M| chunk[4].wrapping_add(prev[4]), 173| 12.2M| chunk[5].wrapping_add(prev[5]), 174| 12.2M| ]; 175| 12.2M| *TryInto::<&mut [u8; 6]>::try_into(chunk).unwrap() = new_chunk; 176| 12.2M| prev = new_chunk; 177| 12.2M| } 178| | } 179| | BytesPerPixel::Eight => { 180| 1.93k| let mut prev = [0; 8]; 181| 4.45M| for chunk in current.chunks_exact_mut(8) { 182| 4.45M| let new_chunk = [ 183| 4.45M| chunk[0].wrapping_add(prev[0]), 184| 4.45M| chunk[1].wrapping_add(prev[1]), 185| 4.45M| chunk[2].wrapping_add(prev[2]), 186| 4.45M| chunk[3].wrapping_add(prev[3]), 187| 4.45M| chunk[4].wrapping_add(prev[4]), 188| 4.45M| chunk[5].wrapping_add(prev[5]), 189| 4.45M| chunk[6].wrapping_add(prev[6]), 190| 4.45M| chunk[7].wrapping_add(prev[7]), 191| 4.45M| ]; 192| 4.45M| *TryInto::<&mut [u8; 8]>::try_into(chunk).unwrap() = new_chunk; 193| 4.45M| prev = new_chunk; 194| 4.45M| } 195| | } 196| | }, 197| | Up => { 198| 257M| for (curr, &above) in current.iter_mut().zip(previous) { 199| 257M| *curr = curr.wrapping_add(above); 200| 257M| } 201| | } 202| 106k| Avg if previous.is_empty() => match tbpp { 203| | BytesPerPixel::One => { 204| 466| current.iter_mut().reduce(|&mut prev, curr| { 205| | *curr = curr.wrapping_add(prev / 2); 206| | curr 207| | }); 208| | } 209| | BytesPerPixel::Two => { 210| 278| let mut prev = [0; 2]; 211| 24.0M| for chunk in current.chunks_exact_mut(2) { 212| 24.0M| let new_chunk = [ 213| 24.0M| chunk[0].wrapping_add(prev[0] / 2), 214| 24.0M| chunk[1].wrapping_add(prev[1] / 2), 215| 24.0M| ]; 216| 24.0M| *TryInto::<&mut [u8; 2]>::try_into(chunk).unwrap() = new_chunk; 217| 24.0M| prev = new_chunk; 218| 24.0M| } 219| | } 220| | BytesPerPixel::Three => { 221| 128| let mut prev = [0; 3]; 222| 34.6M| for chunk in current.chunks_exact_mut(3) { 223| 34.6M| let new_chunk = [ 224| 34.6M| chunk[0].wrapping_add(prev[0] / 2), 225| 34.6M| chunk[1].wrapping_add(prev[1] / 2), 226| 34.6M| chunk[2].wrapping_add(prev[2] / 2), 227| 34.6M| ]; 228| 34.6M| *TryInto::<&mut [u8; 3]>::try_into(chunk).unwrap() = new_chunk; 229| 34.6M| prev = new_chunk; 230| 34.6M| } 231| | } 232| | BytesPerPixel::Four => { 233| 197| let mut prev = [0; 4]; 234| 22.5M| for chunk in current.chunks_exact_mut(4) { 235| 22.5M| let new_chunk = [ 236| 22.5M| chunk[0].wrapping_add(prev[0] / 2), 237| 22.5M| chunk[1].wrapping_add(prev[1] / 2), 238| 22.5M| chunk[2].wrapping_add(prev[2] / 2), 239| 22.5M| chunk[3].wrapping_add(prev[3] / 2), 240| 22.5M| ]; 241| 22.5M| *TryInto::<&mut [u8; 4]>::try_into(chunk).unwrap() = new_chunk; 242| 22.5M| prev = new_chunk; 243| 22.5M| } 244| | } 245| | BytesPerPixel::Six => { 246| 105| let mut prev = [0; 6]; 247| 1.39M| for chunk in current.chunks_exact_mut(6) { 248| 1.39M| let new_chunk = [ 249| 1.39M| chunk[0].wrapping_add(prev[0] / 2), 250| 1.39M| chunk[1].wrapping_add(prev[1] / 2), 251| 1.39M| chunk[2].wrapping_add(prev[2] / 2), 252| 1.39M| chunk[3].wrapping_add(prev[3] / 2), 253| 1.39M| chunk[4].wrapping_add(prev[4] / 2), 254| 1.39M| chunk[5].wrapping_add(prev[5] / 2), 255| 1.39M| ]; 256| 1.39M| *TryInto::<&mut [u8; 6]>::try_into(chunk).unwrap() = new_chunk; 257| 1.39M| prev = new_chunk; 258| 1.39M| } 259| | } 260| | BytesPerPixel::Eight => { 261| 180| let mut prev = [0; 8]; 262| 10.3M| for chunk in current.chunks_exact_mut(8) { 263| 10.3M| let new_chunk = [ 264| 10.3M| chunk[0].wrapping_add(prev[0] / 2), 265| 10.3M| chunk[1].wrapping_add(prev[1] / 2), 266| 10.3M| chunk[2].wrapping_add(prev[2] / 2), 267| 10.3M| chunk[3].wrapping_add(prev[3] / 2), 268| 10.3M| chunk[4].wrapping_add(prev[4] / 2), 269| 10.3M| chunk[5].wrapping_add(prev[5] / 2), 270| 10.3M| chunk[6].wrapping_add(prev[6] / 2), 271| 10.3M| chunk[7].wrapping_add(prev[7] / 2), 272| 10.3M| ]; 273| 10.3M| *TryInto::<&mut [u8; 8]>::try_into(chunk).unwrap() = new_chunk; 274| 10.3M| prev = new_chunk; 275| 10.3M| } 276| | } 277| | }, 278| 104k| Avg => match tbpp { 279| | BytesPerPixel::One => { 280| 60.7k| let mut lprev = [0; 1]; 281| 14.0M| for (chunk, above) in current.chunks_exact_mut(1).zip(previous.chunks_exact(1)) { 282| 14.0M| let new_chunk = 283| 14.0M| [chunk[0].wrapping_add(((above[0] as u16 + lprev[0] as u16) / 2) as u8)]; 284| 14.0M| *TryInto::<&mut [u8; 1]>::try_into(chunk).unwrap() = new_chunk; 285| 14.0M| lprev = new_chunk; 286| 14.0M| } 287| | } 288| | BytesPerPixel::Two => { 289| 9.86k| let mut lprev = [0; 2]; 290| 1.53M| for (chunk, above) in current.chunks_exact_mut(2).zip(previous.chunks_exact(2)) { 291| 1.53M| let new_chunk = [ 292| 1.53M| chunk[0].wrapping_add(((above[0] as u16 + lprev[0] as u16) / 2) as u8), 293| 1.53M| chunk[1].wrapping_add(((above[1] as u16 + lprev[1] as u16) / 2) as u8), 294| 1.53M| ]; 295| 1.53M| *TryInto::<&mut [u8; 2]>::try_into(chunk).unwrap() = new_chunk; 296| 1.53M| lprev = new_chunk; 297| 1.53M| } 298| | } 299| | BytesPerPixel::Three => { 300| 4.80k| let mut lprev = [0; 3]; 301| 64.2M| for (chunk, above) in current.chunks_exact_mut(3).zip(previous.chunks_exact(3)) { 302| 64.2M| let new_chunk = [ 303| 64.2M| chunk[0].wrapping_add(((above[0] as u16 + lprev[0] as u16) / 2) as u8), 304| 64.2M| chunk[1].wrapping_add(((above[1] as u16 + lprev[1] as u16) / 2) as u8), 305| 64.2M| chunk[2].wrapping_add(((above[2] as u16 + lprev[2] as u16) / 2) as u8), 306| 64.2M| ]; 307| 64.2M| *TryInto::<&mut [u8; 3]>::try_into(chunk).unwrap() = new_chunk; 308| 64.2M| lprev = new_chunk; 309| 64.2M| } 310| | } 311| | BytesPerPixel::Four => { 312| 18.1k| let mut lprev = [0; 4]; 313| 35.0M| for (chunk, above) in current.chunks_exact_mut(4).zip(previous.chunks_exact(4)) { 314| 35.0M| let new_chunk = [ 315| 35.0M| chunk[0].wrapping_add(((above[0] as u16 + lprev[0] as u16) / 2) as u8), 316| 35.0M| chunk[1].wrapping_add(((above[1] as u16 + lprev[1] as u16) / 2) as u8), 317| 35.0M| chunk[2].wrapping_add(((above[2] as u16 + lprev[2] as u16) / 2) as u8), 318| 35.0M| chunk[3].wrapping_add(((above[3] as u16 + lprev[3] as u16) / 2) as u8), 319| 35.0M| ]; 320| 35.0M| *TryInto::<&mut [u8; 4]>::try_into(chunk).unwrap() = new_chunk; 321| 35.0M| lprev = new_chunk; 322| 35.0M| } 323| | } 324| | BytesPerPixel::Six => { 325| 1.96k| let mut lprev = [0; 6]; 326| 14.7M| for (chunk, above) in current.chunks_exact_mut(6).zip(previous.chunks_exact(6)) { 327| 14.7M| let new_chunk = [ 328| 14.7M| chunk[0].wrapping_add(((above[0] as u16 + lprev[0] as u16) / 2) as u8), 329| 14.7M| chunk[1].wrapping_add(((above[1] as u16 + lprev[1] as u16) / 2) as u8), 330| 14.7M| chunk[2].wrapping_add(((above[2] as u16 + lprev[2] as u16) / 2) as u8), 331| 14.7M| chunk[3].wrapping_add(((above[3] as u16 + lprev[3] as u16) / 2) as u8), 332| 14.7M| chunk[4].wrapping_add(((above[4] as u16 + lprev[4] as u16) / 2) as u8), 333| 14.7M| chunk[5].wrapping_add(((above[5] as u16 + lprev[5] as u16) / 2) as u8), 334| 14.7M| ]; 335| 14.7M| *TryInto::<&mut [u8; 6]>::try_into(chunk).unwrap() = new_chunk; 336| 14.7M| lprev = new_chunk; 337| 14.7M| } 338| | } 339| | BytesPerPixel::Eight => { 340| 9.12k| let mut lprev = [0; 8]; 341| 29.0M| for (chunk, above) in current.chunks_exact_mut(8).zip(previous.chunks_exact(8)) { 342| 29.0M| let new_chunk = [ 343| 29.0M| chunk[0].wrapping_add(((above[0] as u16 + lprev[0] as u16) / 2) as u8), 344| 29.0M| chunk[1].wrapping_add(((above[1] as u16 + lprev[1] as u16) / 2) as u8), 345| 29.0M| chunk[2].wrapping_add(((above[2] as u16 + lprev[2] as u16) / 2) as u8), 346| 29.0M| chunk[3].wrapping_add(((above[3] as u16 + lprev[3] as u16) / 2) as u8), 347| 29.0M| chunk[4].wrapping_add(((above[4] as u16 + lprev[4] as u16) / 2) as u8), 348| 29.0M| chunk[5].wrapping_add(((above[5] as u16 + lprev[5] as u16) / 2) as u8), 349| 29.0M| chunk[6].wrapping_add(((above[6] as u16 + lprev[6] as u16) / 2) as u8), 350| 29.0M| chunk[7].wrapping_add(((above[7] as u16 + lprev[7] as u16) / 2) as u8), 351| 29.0M| ]; 352| 29.0M| *TryInto::<&mut [u8; 8]>::try_into(chunk).unwrap() = new_chunk; 353| 29.0M| lprev = new_chunk; 354| 29.0M| } 355| | } 356| | }, 357| 51.5k| Paeth => paeth::unfilter(tbpp, previous, current), 358| | } 359| 27.1M|} _RNvNtNtCskrDebHigSPL_3png6filter5paeth17filter_paeth_stbi: 28| 318M|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| 318M| let thresh = c * 3 - (a + b); 38| 318M| let lo = a.min(b); 39| 318M| let hi = a.max(b); 40| 318M| let t0 = if hi <= thresh { lo } else { c }; 41| 318M| let t1 = if thresh <= lo { hi } else { t0 }; 42| 318M| t1 as u8 43| 318M|} _RNvNtNtCskrDebHigSPL_3png6filter5paeth8unfilter: 221| 51.5k|pub(super) fn unfilter(tbpp: BytesPerPixel, previous: &[u8], current: &mut [u8]) { 222| | // Paeth filter pixels: 223| | // C B D 224| | // A X 225| 51.5k| match tbpp { 226| | BytesPerPixel::One => { 227| | const BPP: usize = 1; 228| 40.5k| let mut a_bpp = [0; BPP]; 229| 40.5k| let mut c_bpp = [0; BPP]; 230| | 231| 31.3M| for (c, p) in current 232| 40.5k| .chunks_exact_mut(BPP) 233| 40.5k| .zip(previous.chunks_exact(BPP)) 234| | { 235| 62.6M| for i in 0..BPP { 236| 31.3M| c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i])); 237| 31.3M| } 238| | 239| 31.3M| a_bpp = [c[0] as i16]; 240| 31.3M| c_bpp = [p[0] as i16]; 241| | } 242| | } 243| | BytesPerPixel::Two => { 244| | const BPP: usize = 2; 245| 1.90k| let mut a_bpp = [0; BPP]; 246| 1.90k| let mut c_bpp = [0; BPP]; 247| | 248| 1.13M| for (c, p) in current 249| 1.90k| .chunks_exact_mut(BPP) 250| 1.90k| .zip(previous.chunks_exact(BPP)) 251| | { 252| 3.40M| for i in 0..BPP { 253| 2.26M| c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i])); 254| 2.26M| } 255| | 256| 1.13M| a_bpp = [c[0] as i16, c[1] as i16]; 257| 1.13M| 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.95k| let mut a_bpp = [0; BPP]; 271| 2.95k| let mut c_bpp = [0; BPP]; 272| | 273| 27.0M| for (c, p) in current 274| 2.95k| .chunks_exact_mut(BPP) 275| 2.95k| .zip(previous.chunks_exact(BPP)) 276| | { 277| 108M| for i in 0..BPP { 278| 81.1M| c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i])); 279| 81.1M| } 280| | 281| 27.0M| a_bpp = [c[0] as i16, c[1] as i16, c[2] as i16]; 282| 27.0M| c_bpp = [p[0] as i16, p[1] as i16, p[2] as i16]; 283| | } 284| | } 285| | BytesPerPixel::Four => { 286| | #[cfg(feature = "unstable")] 287| | { 288| | // Results in PR: https://github.com/image-rs/image-png/pull/633 289| | // May be slightly faster on AMD EPYC 7B13. 290| | super::simd::paeth_unfilter_4bpp(current, previous); 291| | return; 292| | } 293| | const BPP: usize = 4; 294| 1.67k| let mut a_bpp = [0; BPP]; 295| 1.67k| let mut c_bpp = [0; BPP]; 296| | 297| 26.5M| for (c, p) in current 298| 1.67k| .chunks_exact_mut(BPP) 299| 1.67k| .zip(previous.chunks_exact(BPP)) 300| | { 301| 132M| for i in 0..BPP { 302| 106M| c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i])); 303| 106M| } 304| | 305| 26.5M| a_bpp = [c[0] as i16, c[1] as i16, c[2] as i16, c[3] as i16]; 306| 26.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.05k| let mut a_bpp = [0; BPP]; 312| 4.05k| let mut c_bpp = [0; BPP]; 313| | 314| 14.6M| for (c, p) in current 315| 4.05k| .chunks_exact_mut(BPP) 316| 4.05k| .zip(previous.chunks_exact(BPP)) 317| | { 318| 102M| for i in 0..BPP { 319| 88.0M| c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i])); 320| 88.0M| } 321| | 322| 14.6M| a_bpp = [ 323| 14.6M| c[0] as i16, 324| 14.6M| c[1] as i16, 325| 14.6M| c[2] as i16, 326| 14.6M| c[3] as i16, 327| 14.6M| c[4] as i16, 328| 14.6M| c[5] as i16, 329| 14.6M| ]; 330| 14.6M| c_bpp = [ 331| 14.6M| p[0] as i16, 332| 14.6M| p[1] as i16, 333| 14.6M| p[2] as i16, 334| 14.6M| p[3] as i16, 335| 14.6M| p[4] as i16, 336| 14.6M| p[5] as i16, 337| 14.6M| ]; 338| | } 339| | } 340| | BytesPerPixel::Eight => { 341| | const BPP: usize = 8; 342| 410| let mut a_bpp = [0; BPP]; 343| 410| let mut c_bpp = [0; BPP]; 344| | 345| 1.23M| for (c, p) in current 346| 410| .chunks_exact_mut(BPP) 347| 410| .zip(previous.chunks_exact(BPP)) 348| | { 349| 11.1M| for i in 0..BPP { 350| 9.89M| c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i])); 351| 9.89M| } 352| | 353| 1.23M| a_bpp = [ 354| 1.23M| c[0] as i16, 355| 1.23M| c[1] as i16, 356| 1.23M| c[2] as i16, 357| 1.23M| c[3] as i16, 358| 1.23M| c[4] as i16, 359| 1.23M| c[5] as i16, 360| 1.23M| c[6] as i16, 361| 1.23M| c[7] as i16, 362| 1.23M| ]; 363| 1.23M| c_bpp = [ 364| 1.23M| p[0] as i16, 365| 1.23M| p[1] as i16, 366| 1.23M| p[2] as i16, 367| 1.23M| p[3] as i16, 368| 1.23M| p[4] as i16, 369| 1.23M| p[5] as i16, 370| 1.23M| p[6] as i16, 371| 1.23M| p[7] as i16, 372| 1.23M| ]; 373| | } 374| | } 375| | } 376| 51.5k|} _RNCNvNtCskrDebHigSPL_3png13text_metadata17decode_iso_8859_10B5_: 158| 1.22M| text.iter().map(|&b| b as char).collect() _RNvMNtCskrDebHigSPL_3png13text_metadataNtB2_9TEXtChunk6decode: 199| 7.02k| pub(crate) fn decode( 200| 7.02k| keyword_slice: &[u8], 201| 7.02k| text_slice: &[u8], 202| 7.02k| ) -> Result { 203| 7.02k| if keyword_slice.is_empty() || keyword_slice.len() > 79 { 204| 0| return Err(TextDecodingError::InvalidKeywordSize); 205| 7.02k| } 206| | 207| 7.02k| Ok(Self { 208| 7.02k| keyword: decode_iso_8859_1(keyword_slice), 209| 7.02k| text: decode_iso_8859_1(text_slice), 210| 7.02k| }) 211| 7.02k| } _RNvMs0_NtCskrDebHigSPL_3png13text_metadataNtB5_9ZTXtChunk26decompress_text_with_limit: 283| 64| pub fn decompress_text_with_limit(&mut self, limit: usize) -> Result<(), DecodingError> { 284| 64| match &self.text { 285| 64| OptCompressed::Compressed(v) => { 286| 64| let uncompressed_raw = match fdeflate::decompress_to_vec_bounded(&v[..], limit) { 287| 28| Ok(s) => s, 288| | Err(BoundedDecompressionError::OutputTooLarge { .. }) => { 289| 0| return Err(DecodingError::from( 290| 0| TextDecodingError::OutOfDecompressionSpace, 291| 0| )); 292| | } 293| | Err(_) => { 294| 36| return Err(DecodingError::from(TextDecodingError::InflationError)); 295| | } 296| | }; 297| 28| self.text = OptCompressed::Uncompressed(decode_iso_8859_1(&uncompressed_raw)); 298| | } 299| 0| OptCompressed::Uncompressed(_) => {} 300| | }; 301| 28| Ok(()) 302| 64| } _RNvMs0_NtCskrDebHigSPL_3png13text_metadataNtB5_9ZTXtChunk6decode: 258| 67.2k| pub(crate) fn decode( 259| 67.2k| keyword_slice: &[u8], 260| 67.2k| compression_method: u8, 261| 67.2k| text_slice: &[u8], 262| 67.2k| ) -> Result { 263| 67.2k| if keyword_slice.is_empty() || keyword_slice.len() > 79 { 264| 0| return Err(TextDecodingError::InvalidKeywordSize); 265| 67.2k| } 266| | 267| 67.2k| if compression_method != 0 { 268| 358| return Err(TextDecodingError::InvalidCompressionMethod); 269| 66.9k| } 270| | 271| 66.9k| Ok(Self { 272| 66.9k| keyword: decode_iso_8859_1(keyword_slice), 273| 66.9k| text: OptCompressed::Compressed(text_slice.to_vec()), 274| 66.9k| }) 275| 67.2k| } _RNvMs0_NtCskrDebHigSPL_3png13text_metadataNtB5_9ZTXtChunk8get_text: 306| 28| pub fn get_text(&self) -> Result { 307| 28| 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| 28| OptCompressed::Uncompressed(s) => Ok(s.clone()), 314| | } 315| 28| } _RNvMs2_NtCskrDebHigSPL_3png13text_metadataNtB5_9ITXtChunk26decompress_text_with_limit: 453| 16| pub fn decompress_text_with_limit(&mut self, limit: usize) -> Result<(), DecodingError> { 454| 16| match &self.text { 455| 8| OptCompressed::Compressed(v) => { 456| 8| 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| 8| 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| 8| OptCompressed::Uncompressed(_) => {} 473| | }; 474| 8| Ok(()) 475| 16| } _RNvMs2_NtCskrDebHigSPL_3png13text_metadataNtB5_9ITXtChunk6decode: 401| 14.3k| pub(crate) fn decode( 402| 14.3k| keyword_slice: &[u8], 403| 14.3k| compression_flag: u8, 404| 14.3k| compression_method: u8, 405| 14.3k| language_tag_slice: &[u8], 406| 14.3k| translated_keyword_slice: &[u8], 407| 14.3k| text_slice: &[u8], 408| 14.3k| ) -> Result { 409| 14.3k| if keyword_slice.is_empty() || keyword_slice.len() > 79 { 410| 0| return Err(TextDecodingError::InvalidKeywordSize); 411| 14.3k| } 412| 14.3k| let keyword = decode_iso_8859_1(keyword_slice); 413| | 414| 14.3k| let compressed = match compression_flag { 415| 11.1k| 0 => false, 416| 2.78k| 1 => true, 417| 410| _ => return Err(TextDecodingError::InvalidCompressionFlag), 418| | }; 419| | 420| 13.9k| if compressed && compression_method != 0 { 421| 219| return Err(TextDecodingError::InvalidCompressionMethod); 422| 13.7k| } 423| | 424| 13.7k| let language_tag = decode_ascii(language_tag_slice)?.to_owned(); 425| | 426| 12.9k| let translated_keyword = std::str::from_utf8(translated_keyword_slice) 427| 12.9k| .map_err(|_| TextDecodingError::Unrepresentable)? 428| 12.8k| .to_string(); 429| 12.8k| let text = if compressed { 430| 2.37k| OptCompressed::Compressed(text_slice.to_vec()) 431| | } else { 432| | OptCompressed::Uncompressed( 433| 10.4k| String::from_utf8(text_slice.to_vec()) 434| 10.4k| .map_err(|_| TextDecodingError::Unrepresentable)?, 435| | ) 436| | }; 437| | 438| 11.9k| Ok(Self { 439| 11.9k| keyword, 440| 11.9k| compressed, 441| 11.9k| language_tag, 442| 11.9k| translated_keyword, 443| 11.9k| text, 444| 11.9k| }) 445| 14.3k| } _RNvMs2_NtCskrDebHigSPL_3png13text_metadataNtB5_9ITXtChunk8get_text: 479| 8| pub fn get_text(&self) -> Result { 480| 8| 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| 8| OptCompressed::Uncompressed(s) => Ok(s.clone()), 488| | } 489| 8| } _RNvNtCskrDebHigSPL_3png13text_metadata12decode_ascii: 177| 13.7k|fn decode_ascii(text: &[u8]) -> Result<&str, TextDecodingError> { 178| 13.7k| 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| 12.9k| Ok(std::str::from_utf8(text).expect("unreachable")) 182| | } else { 183| 808| Err(TextDecodingError::Unrepresentable) 184| | } 185| 13.7k|} _RNvNtCskrDebHigSPL_3png13text_metadata17decode_iso_8859_1: 157| 95.3k|fn decode_iso_8859_1(text: &[u8]) -> String { 158| 95.3k| text.iter().map(|&b| b as char).collect() 159| 95.3k|} _RNvXNtCskrDebHigSPL_3png6traitsRShINtB2_12ReadBytesExthE7read_beB4_: 7| 83.5k| fn read_be(&mut self) -> io::Result<$output_type> { 8| 83.5k| let mut bytes = [0u8; std::mem::size_of::<$output_type>()]; 9| 83.5k| self.read_exact(&mut bytes)?; 10| 83.5k| Ok(<$output_type>::from_be_bytes(bytes)) 11| 83.5k| } _RNvXs0_NtCskrDebHigSPL_3png6traitsRShINtB5_12ReadBytesExtmE7read_beB7_: 7| 23.1k| fn read_be(&mut self) -> io::Result<$output_type> { 8| 23.1k| let mut bytes = [0u8; std::mem::size_of::<$output_type>()]; 9| 23.1k| self.read_exact(&mut bytes)?; 10| 23.1k| Ok(<$output_type>::from_be_bytes(bytes)) 11| 23.1k| } _RNvXs_NtCskrDebHigSPL_3png6traitsRShINtB4_12ReadBytesExttE7read_beB6_: 7| 482| fn read_be(&mut self) -> io::Result<$output_type> { 8| 482| let mut bytes = [0u8; std::mem::size_of::<$output_type>()]; 9| 482| self.read_exact(&mut bytes)?; 10| 482| Ok(<$output_type>::from_be_bytes(bytes)) 11| 482| } _RNvNtNtCs2divbjE383Z_12simd_adler323imp4avx213get_imp_innerB5_: 10| 13.1k|fn get_imp_inner() -> Option { 11| 13.1k| if std::is_x86_feature_detected!("avx2") { 12| 13.1k| Some(imp::update) 13| | } else { 14| 0| None 15| | } 16| 13.1k|} _RNvNtNtCs2divbjE383Z_12simd_adler323imp4avx27get_imp: 4| 13.1k|pub fn get_imp() -> Option { 5| 13.1k| get_imp_inner() 6| 13.1k|} _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp10reduce_add: 143| 1.53M| unsafe fn reduce_add(v: __m256i) -> u32 { 144| 1.53M| let sum = _mm_add_epi32(_mm256_castsi256_si128(v), _mm256_extracti128_si256(v, 1)); 145| 1.53M| let hi = _mm_unpackhi_epi64(sum, sum); 146| | 147| 1.53M| let sum = _mm_add_epi32(hi, sum); 148| 1.53M| let hi = _mm_shuffle_epi32(sum, crate::imp::_MM_SHUFFLE(2, 3, 0, 1)); 149| | 150| 1.53M| let sum = _mm_add_epi32(sum, hi); 151| | 152| 1.53M| _mm_cvtsi128_si32(sum) as _ 153| 1.53M| } _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp10update_impB7_: 57| 131k| unsafe fn update_imp(a: u16, b: u16, data: &[u8]) -> (u16, u16) { 58| 131k| let mut a = a as u32; 59| 131k| let mut b = b as u32; 60| | 61| 131k| let chunks = data.chunks_exact(CHUNK_SIZE); 62| 131k| let remainder = chunks.remainder(); 63| 767k| for chunk in chunks { 64| 635k| update_chunk_block(&mut a, &mut b, chunk); 65| 635k| } 66| | 67| 131k| update_block(&mut a, &mut b, remainder); 68| | 69| 131k| (a as u16, b as u16) 70| 131k| } _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp11get_weights: 156| 766k| unsafe fn get_weights() -> __m256i { 157| 766k| _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| 766k| } _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp12update_blockB7_: 89| 131k| unsafe fn update_block(a: &mut u32, b: &mut u32, chunk: &[u8]) { 90| 131k| 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| 131k| for byte in reduce_add_blocks(a, b, chunk) { 98| 55.2k| *a += *byte as u32; 99| 55.2k| *b += *a; 100| 55.2k| } 101| | 102| 131k| *a %= MOD; 103| 131k| *b %= MOD; 104| 131k| } _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp17reduce_add_blocks: 107| 767k| unsafe fn reduce_add_blocks<'a>(a: &mut u32, b: &mut u32, chunk: &'a [u8]) -> &'a [u8] { 108| 767k| if chunk.len() < BLOCK_SIZE { 109| 199| return chunk; 110| 766k| } 111| | 112| 766k| let blocks = chunk.chunks_exact(BLOCK_SIZE); 113| 766k| let blocks_remainder = blocks.remainder(); 114| | 115| 766k| let one_v = _mm256_set1_epi16(1); 116| 766k| let zero_v = _mm256_setzero_si256(); 117| 766k| let weights = get_weights(); 118| | 119| 766k| let mut p_v = _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, (*a * blocks.len() as u32) as _); 120| 766k| let mut a_v = _mm256_setzero_si256(); 121| 766k| let mut b_v = _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, *b as _); 122| | 123| 131M| for block in blocks { 124| 130M| let block_ptr = block.as_ptr() as *const _; 125| 130M| let block = _mm256_loadu_si256(block_ptr); 126| 130M| 127| 130M| p_v = _mm256_add_epi32(p_v, a_v); 128| 130M| 129| 130M| a_v = _mm256_add_epi32(a_v, _mm256_sad_epu8(block, zero_v)); 130| 130M| let mad = _mm256_maddubs_epi16(block, weights); 131| 130M| b_v = _mm256_add_epi32(b_v, _mm256_madd_epi16(mad, one_v)); 132| 130M| } 133| | 134| 766k| b_v = _mm256_add_epi32(b_v, _mm256_slli_epi32(p_v, 5)); 135| | 136| 766k| *a += reduce_add(a_v); 137| 766k| *b = reduce_add(b_v); 138| | 139| 766k| blocks_remainder 140| 767k| } _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp18update_chunk_blockB7_: 73| 635k| unsafe fn update_chunk_block(a: &mut u32, b: &mut u32, chunk: &[u8]) { 74| 635k| 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| 635k| reduce_add_blocks(a, b, chunk); 83| | 84| 635k| *a %= MOD; 85| 635k| *b %= MOD; 86| 635k| } _RNvNtNtNtCs2divbjE383Z_12simd_adler323imp4avx23imp6update: 51| 131k| pub fn update(a: u16, b: u16, data: &[u8]) -> (u16, u16) { 52| 131k| unsafe { update_imp(a, b, data) } 53| 131k| } _RNvNtNtCs2divbjE383Z_12simd_adler323imp6avx51213get_imp_innerB5_: 44| 13.1k|fn get_imp_inner() -> Option { 45| 13.1k| None 46| 13.1k|} _RNvNtNtCs2divbjE383Z_12simd_adler323imp6avx5127get_imp: 4| 13.1k|pub fn get_imp() -> Option { 5| 13.1k| get_imp_inner() 6| 13.1k|} _RNvNtCs2divbjE383Z_12simd_adler323imp7get_imp: 17| 13.1k|pub fn get_imp() -> Adler32Imp { 18| 13.1k| avx512::get_imp() 19| 13.1k| .or_else(neon::get_imp) 20| 13.1k| .or_else(avx2::get_imp) 21| 13.1k| .or_else(ssse3::get_imp) 22| 13.1k| .or_else(sse2::get_imp) 23| 13.1k| .or_else(wasm::get_imp) 24| 13.1k| .unwrap_or(scalar::update) 25| 13.1k|} _RNvNtNtCs2divbjE383Z_12simd_adler323imp4neon7get_imp: 9| 13.1k|pub fn get_imp() -> Option { 10| 13.1k| None 11| 13.1k|} _RNvMCs2divbjE383Z_12simd_adler32NtB2_7Adler323new: 125| 13.1k| pub fn new() -> Self { 126| 13.1k| Default::default() 127| 13.1k| } _RNvMCs2divbjE383Z_12simd_adler32NtB2_7Adler325write: 149| 131k| pub fn write(&mut self, data: &[u8]) { 150| 131k| let (a, b) = (self.update)(self.a, self.b, data); 151| | 152| 131k| self.a = a; 153| 131k| self.b = b; 154| 131k| } _RNvXs_Cs2divbjE383Z_12simd_adler32NtB4_7Adler32NtNtCs6SNw0SRvItZ_4core7default7Default7default: 195| 13.1k| fn default() -> Self { 196| 13.1k| Self { 197| 13.1k| a: 1, 198| 13.1k| b: 0, 199| 13.1k| update: get_imp(), 200| 13.1k| } 201| 13.1k| } _RNvMs4_NtNtCs1vRhqpPUfvi_5image6codecs3pngNtNtB9_5error10ImageError8from_png: 952| 7.62k| fn from_png(err: png::DecodingError) -> ImageError { 953| | use png::DecodingError::*; 954| 7.62k| match err { 955| 5.74k| IoError(err) => ImageError::IoError(err), 956| | // The input image was not a valid PNG. 957| 1.80k| err @ Format(_) => { 958| 1.80k| ImageError::Decoding(DecodingError::new(ImageFormat::Png.into(), err)) 959| | } 960| | // Other is used when: 961| | // - The decoder is polled for more animation frames despite being done (or not being animated 962| | // in the first place). 963| | // - The output buffer does not have the required size. 964| 0| err @ Parameter(_) => ImageError::Parameter(ParameterError::from_kind( 965| 0| ParameterErrorKind::Generic(err.to_string()), 966| 0| )), 967| | LimitsExceeded => { 968| 74| ImageError::Limits(LimitError::from_kind(LimitErrorKind::InsufficientMemory)) 969| | } 970| | } 971| 7.62k| } _RNCNCNvXs_NtNtCs1vRhqpPUfvi_5image6codecs3pngINtB8_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBc_2io7decoder12ImageDecoder13iptc_metadata00Bc_: 348| 2.63k| .find(|chunk| IPTC_KEYS.iter().any(|key| chunk.keyword.contains(key))) _RNCNCNvXs_NtNtCs1vRhqpPUfvi_5image6codecs3pngINtB8_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBc_2io7decoder12ImageDecoder13iptc_metadatas0_00Bc_: 364| 810| .find(|chunk| IPTC_KEYS.iter().any(|key| chunk.keyword.contains(key))) _RNCNvNtNtCs1vRhqpPUfvi_5image6codecs3png27big_endian_to_native_endian0B7_: 271| 883k| 2 => buf.as_chunks_mut::<2>().0.iter_mut().for_each(|c| { 272| 883k| *c = u16::from_be_bytes(*c).to_ne_bytes(); 273| 883k| }), _RNCNvXs_NtNtCs1vRhqpPUfvi_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder11icc_profile0Ba_: 309| 2.19k| Ok(reader.info().icc_profile.as_ref().map(|x| x.to_vec())) _RNCNvXs_NtNtCs1vRhqpPUfvi_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder12xmp_metadata0Ba_: 325| 789| .find(|chunk| chunk.keyword == XMP_KEY) _RNCNvXs_NtNtCs1vRhqpPUfvi_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder12xmp_metadatas_0Ba_: 333| 8| .map(|text| Some(text.into_bytes())) _RNCNvXs_NtNtCs1vRhqpPUfvi_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder13exif_metadata0Ba_: 314| 54| Ok(reader.info().exif_metadata.as_ref().map(|x| x.to_vec())) _RNCNvXs_NtNtCs1vRhqpPUfvi_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder13iptc_metadata0Ba_: 348| 1.34k| .find(|chunk| IPTC_KEYS.iter().any(|key| chunk.keyword.contains(key))) _RNCNvXs_NtNtCs1vRhqpPUfvi_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder13iptc_metadatas0_0Ba_: 364| 408| .find(|chunk| IPTC_KEYS.iter().any(|key| chunk.keyword.contains(key))) _RNCNvXs_NtNtCs1vRhqpPUfvi_5image6codecs3pngINtB6_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtBa_2io7decoder12ImageDecoder13iptc_metadatas_0Ba_: 356| 28| .map(|text| Some(text.into_bytes())) _RNvMNtNtCs1vRhqpPUfvi_5image6codecs3pngINtB2_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE11with_limitsB6_: 53| 10.1k| pub fn with_limits(r: R, limits: Limits) -> PngDecoder { 54| 10.1k| let max_bytes = usize::try_from(limits.max_alloc.unwrap_or(u64::MAX)).unwrap_or(usize::MAX); 55| 10.1k| let mut decoder = png::Decoder::new_with_limits(r, png::Limits { bytes: max_bytes }); 56| 10.1k| decoder.set_ignore_text_chunk(false); 57| | 58| 10.1k| PngDecoder { 59| 10.1k| decoder: Some(decoder), 60| 10.1k| // We'll replace this once we have a reader. 61| 10.1k| color_type: ColorType::L8, 62| 10.1k| reader: None, 63| 10.1k| limits, 64| 10.1k| } 65| 10.1k| } _RNvMNtNtCs1vRhqpPUfvi_5image6codecs3pngINtB2_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE15color_type_infoB6_: 189| 6.47k| fn color_type_info(info: &png::Info<'_>) -> ExtendedColorType { 190| 6.47k| match (info.color_type, info.bit_depth) { 191| 1.66k| (png::ColorType::Grayscale, png::BitDepth::One) => ExtendedColorType::L1, 192| 205| (png::ColorType::Grayscale, png::BitDepth::Two) => ExtendedColorType::L2, 193| 696| (png::ColorType::Grayscale, png::BitDepth::Four) => ExtendedColorType::L4, 194| 513| (png::ColorType::Grayscale, png::BitDepth::Eight) => ExtendedColorType::L8, 195| 867| (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| 207| (png::ColorType::GrayscaleAlpha, png::BitDepth::Eight) => ExtendedColorType::La8, 200| 114| (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| 641| (png::ColorType::Rgb, png::BitDepth::Eight) => ExtendedColorType::Rgb8, 205| 401| (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| 228| (png::ColorType::Rgba, png::BitDepth::Eight) => ExtendedColorType::Rgba8, 210| 255| (png::ColorType::Rgba, png::BitDepth::Sixteen) => ExtendedColorType::Rgba16, 211| 500| (png::ColorType::Indexed, png::BitDepth::One) => ExtendedColorType::Unknown(1), 212| 48| (png::ColorType::Indexed, png::BitDepth::Two) => ExtendedColorType::Unknown(2), 213| 32| (png::ColorType::Indexed, png::BitDepth::Four) => ExtendedColorType::Unknown(4), 214| 105| (png::ColorType::Indexed, png::BitDepth::Eight) => ExtendedColorType::Unknown(8), 215| 0| (png::ColorType::Indexed, png::BitDepth::Sixteen) => ExtendedColorType::Unknown(16), 216| | } 217| 6.47k| } _RNvMNtNtCs1vRhqpPUfvi_5image6codecs3pngINtB2_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE21text_decompress_limitB6_: 221| 13.4k| fn text_decompress_limit(&mut self) -> usize { 222| 13.4k| let max = png::text_metadata::DECOMPRESSION_LIMIT as u64; 223| 13.4k| self.limits.max_alloc.unwrap_or(max).min(max) as usize 224| 13.4k| } _RNvMNtNtCs1vRhqpPUfvi_5image6codecs3pngINtB2_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE24ensure_reader_and_headerB6_: 67| 56.5k| fn ensure_reader_and_header(&mut self) -> ImageResult<&mut png::Reader> { 68| 56.5k| if self.reader.is_some() { 69| | // We do this for borrow-checking issues, do not borrow self outside the conditional 70| | // branch. So the None/Err case here is not reachable. 71| 46.3k| return self.reader.as_mut().ok_or_else(|| unreachable!()); 72| 10.1k| } 73| | 74| 10.1k| let Some(mut decoder) = self.decoder.take() else { 75| 0| return Err(reader_finished_already()); 76| | }; 77| | 78| 10.1k| self.limits.check_support(&crate::LimitSupport::default())?; 79| | 80| 10.1k| let info = decoder.read_header_info().map_err(ImageError::from_png)?; 81| 9.87k| 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.87k| decoder.set_transformations(png::Transformations::EXPAND); 87| 9.87k| let reader = decoder.read_info().map_err(ImageError::from_png)?; 88| 6.73k| let (color_type, bits) = reader.output_color_type(); 89| | 90| 6.73k| let color_type = match (color_type, bits) { 91| 3.04k| (png::ColorType::Grayscale, png::BitDepth::Eight) => ColorType::L8, 92| 809| (png::ColorType::Grayscale, png::BitDepth::Sixteen) => ColorType::L16, 93| 323| (png::ColorType::GrayscaleAlpha, png::BitDepth::Eight) => ColorType::La8, 94| 191| (png::ColorType::GrayscaleAlpha, png::BitDepth::Sixteen) => ColorType::La16, 95| 1.35k| (png::ColorType::Rgb, png::BitDepth::Eight) => ColorType::Rgb8, 96| 403| (png::ColorType::Rgb, png::BitDepth::Sixteen) => ColorType::Rgb16, 97| 343| (png::ColorType::Rgba, png::BitDepth::Eight) => ColorType::Rgba8, 98| 264| (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.73k| self.color_type = color_type; 145| 6.73k| Ok(self.reader.insert(reader)) 146| 56.5k| } _RNvMNtNtCs1vRhqpPUfvi_5image6codecs3pngINtB2_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE3newB6_: 48| 10.1k| pub fn new(r: R) -> PngDecoder { 49| 10.1k| Self::with_limits(r, Limits::no_limits()) 50| 10.1k| } _RNvXs_NtNtCs1vRhqpPUfvi_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder10read_imageB8_: 372| 6.47k| fn read_image(&mut self, buf: &mut [u8]) -> ImageResult { 373| 6.47k| let layout = self.prepare_image()?; 374| 6.47k| assert_eq!(u64::try_from(buf.len()), Ok(layout.total_bytes())); 375| | 376| 6.47k| let reader = self.ensure_reader_and_header()?; 377| 6.47k| let original_color_type = Self::color_type_info(reader.info()); 378| 6.47k| reader.next_frame(buf).map_err(ImageError::from_png)?; 379| | 380| 2.33k| big_endian_to_native_endian(buf, layout.layout.color); 381| | 382| 2.33k| Ok(DecodedImageAttributes { 383| 2.33k| original_color_type: Some(original_color_type), 384| 2.33k| ..DecodedImageAttributes::default() 385| 2.33k| }) 386| 6.47k| } _RNvXs_NtNtCs1vRhqpPUfvi_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder10set_limitsB8_: 388| 10.1k| fn set_limits(&mut self, limits: Limits) -> ImageResult<()> { 389| 10.1k| limits.check_support(&crate::LimitSupport::default())?; 390| | 391| 10.1k| if let Some(decoder) = &mut self.decoder { 392| 10.1k| decoder.set_limits(png::Limits { 393| 10.1k| bytes: match limits.max_alloc { 394| 0| None => usize::MAX, 395| 10.1k| Some(limit) => limit.try_into().unwrap_or(usize::MAX), 396| | }, 397| | }); 398| | 399| 10.1k| self.limits = limits; 400| 10.1k| Ok(()) 401| | } else { 402| 0| Err(decoding_started_already()) 403| | } 404| 10.1k| } _RNvXs_NtNtCs1vRhqpPUfvi_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder11icc_profileB8_: 307| 6.73k| fn icc_profile(&mut self) -> ImageResult>> { 308| 6.73k| let reader = self.ensure_reader_and_header()?; 309| 6.73k| Ok(reader.info().icc_profile.as_ref().map(|x| x.to_vec())) 310| 6.73k| } _RNvXs_NtNtCs1vRhqpPUfvi_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder12xmp_metadataB8_: 317| 6.73k| fn xmp_metadata(&mut self) -> ImageResult>> { 318| 6.73k| let decompression_limit = self.text_decompress_limit(); 319| 6.73k| let reader = self.ensure_reader_and_header()?; 320| | 321| 6.73k| if let Some(mut itx_chunk) = reader 322| 6.73k| .info() 323| 6.73k| .utf8_text 324| 6.73k| .iter() 325| 6.73k| .find(|chunk| chunk.keyword == XMP_KEY) 326| 6.73k| .cloned() 327| | { 328| 16| itx_chunk 329| 16| .decompress_text_with_limit(decompression_limit) 330| 16| .map_err(ImageError::from_png)?; 331| 8| return itx_chunk 332| 8| .get_text() 333| 8| .map(|text| Some(text.into_bytes())) 334| 8| .map_err(ImageError::from_png); 335| 6.72k| } 336| | 337| 6.72k| Ok(None) 338| 6.73k| } _RNvXs_NtNtCs1vRhqpPUfvi_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder13exif_metadataB8_: 312| 6.73k| fn exif_metadata(&mut self) -> ImageResult>> { 313| 6.73k| let reader = self.ensure_reader_and_header()?; 314| 6.73k| Ok(reader.info().exif_metadata.as_ref().map(|x| x.to_vec())) 315| 6.73k| } _RNvXs_NtNtCs1vRhqpPUfvi_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder13iptc_metadataB8_: 340| 6.73k| fn iptc_metadata(&mut self) -> ImageResult>> { 341| 6.73k| let decompression_limit = self.text_decompress_limit(); 342| 6.73k| let reader = self.ensure_reader_and_header()?; 343| | 344| 6.73k| if let Some(mut text_chunk) = reader 345| 6.73k| .info() 346| 6.73k| .compressed_latin1_text 347| 6.73k| .iter() 348| 6.73k| .find(|chunk| IPTC_KEYS.iter().any(|key| chunk.keyword.contains(key))) 349| 6.73k| .cloned() 350| | { 351| 64| text_chunk 352| 64| .decompress_text_with_limit(decompression_limit) 353| 64| .map_err(ImageError::from_png)?; 354| 28| return text_chunk 355| 28| .get_text() 356| 28| .map(|text| Some(text.into_bytes())) 357| 28| .map_err(ImageError::from_png); 358| 6.67k| } 359| | 360| 6.67k| if let Some(text_chunk) = reader 361| 6.67k| .info() 362| 6.67k| .uncompressed_latin1_text 363| 6.67k| .iter() 364| 6.67k| .find(|chunk| IPTC_KEYS.iter().any(|key| chunk.keyword.contains(key))) 365| 6.67k| .cloned() 366| | { 367| 12| return Ok(Some(text_chunk.text.into_bytes())); 368| 6.66k| } 369| 6.66k| Ok(None) 370| 6.73k| } _RNvXs_NtNtCs1vRhqpPUfvi_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder13prepare_imageB8_: 280| 23.1k| fn prepare_image(&mut self) -> ImageResult { 281| 23.1k| let reader = self.ensure_reader_and_header()?; 282| 19.6k| let (width, height) = reader.info().size(); 283| 19.6k| Ok(DecoderPreparedImage::new(width, height, self.color_type)) 284| 23.1k| } _RNvXs_NtNtCs1vRhqpPUfvi_5image6codecs3pngINtB4_10PngDecoderINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEENtNtNtB8_2io7decoder12ImageDecoder17format_attributesB8_: 286| 11.3k| fn format_attributes(&self) -> FormatAttributes { 287| 11.3k| FormatAttributes { 288| 11.3k| // is any sort of iTXT chunk. 289| 11.3k| // FIXME: we do not collect these in advance. 290| 11.3k| xmp: DecodedMetadataHint::InHeader, 291| 11.3k| // is any sort of iTXT chunk. 292| 11.3k| // FIXME: we do not collect these in advance. 293| 11.3k| iptc: DecodedMetadataHint::InHeader, 294| 11.3k| // see iCCP chunk order. 295| 11.3k| icc: DecodedMetadataHint::InHeader, 296| 11.3k| // see eXIf chunk order. 297| 11.3k| exif: DecodedMetadataHint::InHeader, 298| 11.3k| ..FormatAttributes::default() 299| 11.3k| } 300| 11.3k| } _RNvNtNtCs1vRhqpPUfvi_5image6codecs3png27big_endian_to_native_endian: 266| 2.33k|fn big_endian_to_native_endian(buf: &mut [u8], color: ColorType) { 267| 2.33k| let bytes_per_channel = color.bytes_per_pixel() / color.channel_count(); 268| | 269| 2.33k| match bytes_per_channel { 270| 1.91k| 1 => (), // No reodering necessary for u8 271| 418| 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| 2.33k|} _RNvMNtCs1vRhqpPUfvi_5image5colorNtB2_9ColorType13channel_count: 89| 2.33k| pub fn channel_count(self) -> u8 { 90| 2.33k| let e: ExtendedColorType = self.into(); 91| 2.33k| e.channel_count() 92| 2.33k| } _RNvMNtCs1vRhqpPUfvi_5image5colorNtB2_9ColorType15bytes_per_pixel: 47| 22.0k| pub fn bytes_per_pixel(self) -> u8 { 48| 22.0k| match self { 49| 10.4k| ColorType::L8 => 1, 50| 3.74k| ColorType::L16 | ColorType::La8 => 2, 51| 4.22k| ColorType::Rgb8 => 3, 52| 1.61k| ColorType::Rgba8 | ColorType::La16 | ColorType::L32F => 4, 53| 1.20k| ColorType::Rgb16 => 6, 54| 794| ColorType::Rgba16 | ColorType::La32F => 8, 55| 0| ColorType::Rgb32F => 3 * 4, 56| 0| ColorType::Rgba32F => 4 * 4, 57| | } 58| 22.0k| } _RNvMs_NtCs1vRhqpPUfvi_5image5colorNtB4_17ExtendedColorType13channel_count: 186| 2.33k| pub fn channel_count(self) -> u8 { 187| 2.33k| match self { 188| | ExtendedColorType::A8 189| | | ExtendedColorType::L1 190| | | ExtendedColorType::L2 191| | | ExtendedColorType::L4 192| | | ExtendedColorType::L8 193| | | ExtendedColorType::L16 194| | | ExtendedColorType::L32F 195| 1.83k| | ExtendedColorType::Unknown(_) => 1, 196| | ExtendedColorType::La1 197| | | ExtendedColorType::La2 198| | | ExtendedColorType::La4 199| | | ExtendedColorType::La8 200| | | ExtendedColorType::La16 201| 7| | 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| 438| | 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| 46| | ExtendedColorType::Cmyk16 => 4, 220| | } 221| 2.33k| } _RNvXs0_NtCs1vRhqpPUfvi_5image5colorNtB5_17ExtendedColorTypeINtNtCs6SNw0SRvItZ_4core7convert4FromNtB5_9ColorTypeE4from: 316| 2.33k| fn from(c: ColorType) -> Self { 317| 2.33k| match c { 318| 1.44k| ColorType::L8 => ExtendedColorType::L8, 319| 2| ColorType::La8 => ExtendedColorType::La8, 320| 427| ColorType::Rgb8 => ExtendedColorType::Rgb8, 321| 34| ColorType::Rgba8 => ExtendedColorType::Rgba8, 322| 390| ColorType::L16 => ExtendedColorType::L16, 323| 5| ColorType::La16 => ExtendedColorType::La16, 324| 11| ColorType::Rgb16 => ExtendedColorType::Rgb16, 325| 12| ColorType::Rgba16 => ExtendedColorType::Rgba16, 326| 0| ColorType::L32F => ExtendedColorType::L32F, 327| 0| ColorType::La32F => ExtendedColorType::La32F, 328| 0| ColorType::Rgb32F => ExtendedColorType::Rgb32F, 329| 0| ColorType::Rgba32F => ExtendedColorType::Rgba32F, 330| | } 331| 2.33k| } _RNvMs1_NtCs1vRhqpPUfvi_5image5errorNtB5_14ParameterError9from_kind: 281| 3| pub fn from_kind(kind: ParameterErrorKind) -> Self { 282| 3| ParameterError { 283| 3| kind, 284| 3| underlying: None, 285| 3| } 286| 3| } _RNvMs2_NtCs1vRhqpPUfvi_5image5errorNtB5_10LimitError9from_kind: 298| 341| pub fn from_kind(kind: LimitErrorKind) -> Self { 299| 341| LimitError { kind } 300| 341| } _RNvXs6_NtCs1vRhqpPUfvi_5image5errorNtB5_15ImageFormatHintINtNtCs6SNw0SRvItZ_4core7convert4FromNtNtNtB7_2io6format11ImageFormatE4from: 328| 1.80k| fn from(format: ImageFormat) -> Self { 329| 1.80k| ImageFormatHint::Exact(format) 330| 1.80k| } _RINvMs_NtCs1vRhqpPUfvi_5image5errorNtB5_13DecodingError3newNtNtNtCskrDebHigSPL_3png7decoder6stream13DecodingErrorEB7_: 226| 1.80k| pub fn new(format: ImageFormatHint, err: impl Into>) -> Self { 227| 1.80k| DecodingError { 228| 1.80k| format, 229| 1.80k| underlying: Some(err.into()), 230| 1.80k| } 231| 1.80k| } _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16check_image_fits0Bb_: 635| 427| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_len0Bb_: 640| 427| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_lens_0Bb_: 641| 427| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color3RgbtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16check_image_fits0Bb_: 635| 11| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color3RgbtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_len0Bb_: 640| 11| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color3RgbtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_lens_0Bb_: 641| 11| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4LumahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16check_image_fits0Bb_: 635| 1.44k| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4LumahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_len0Bb_: 640| 1.44k| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4LumahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_lens_0Bb_: 641| 1.44k| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4LumatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16check_image_fits0Bb_: 635| 390| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4LumatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_len0Bb_: 640| 390| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4LumatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_lens_0Bb_: 641| 390| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16check_image_fits0Bb_: 635| 34| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_len0Bb_: 640| 34| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_lens_0Bb_: 641| 34| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4RgbatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16check_image_fits0Bb_: 635| 12| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4RgbatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_len0Bb_: 640| 12| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color4RgbatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_lens_0Bb_: 641| 12| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color5LumaAhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16check_image_fits0Bb_: 635| 2| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color5LumaAhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_len0Bb_: 640| 2| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color5LumaAhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_lens_0Bb_: 641| 2| .and_then(|size| size.checked_mul(height as usize)) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16check_image_fits0Bb_: 635| 5| checked_len.is_some_and(|min_len| min_len <= len) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_len0Bb_: 640| 5| .and_then(|size| size.checked_mul(width as usize)) _RNCNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB7_11ImageBufferINtNtBb_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE16image_buffer_lens_0Bb_: 641| 5| .and_then(|size| size.checked_mul(height as usize)) _RNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16check_image_fitsB9_: 633| 427| fn check_image_fits(width: u32, height: u32, len: usize) -> bool { 634| 427| let checked_len = Self::image_buffer_len(width, height); 635| 427| checked_len.is_some_and(|min_len| min_len <= len) 636| 427| } _RNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE16image_buffer_lenB9_: 638| 427| fn image_buffer_len(width: u32, height: u32) -> Option { 639| 427| Some(

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

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

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

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

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

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

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

::CHANNEL_COUNT as usize) 640| 5| .and_then(|size| size.checked_mul(width as usize)) 641| 5| .and_then(|size| size.checked_mul(height as usize)) 642| 5| } _RNvMsn_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE8from_rawB9_: 511| 5| pub fn from_raw(width: u32, height: u32, buf: Container) -> Option> { 512| 5| if Self::check_image_fits(width, height, buf.len()) { 513| 5| Some(ImageBuffer { 514| 5| data: buf, 515| 5| width, 516| 5| height, 517| 5| color: Cicp::SRGB.into_rgb(), 518| 5| _phantom: PhantomData, 519| 5| }) 520| | } else { 521| 0| None 522| | } 523| 5| } _RNvMsr_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE17set_rgb_primariesB9_: 1076| 430| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 430| self.color.primaries = color; 1078| 430| } _RNvMsr_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE21set_transfer_functionB9_: 1088| 430| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 430| self.color.transfer = tf; 1090| 430| } _RNvMsr_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE17set_rgb_primariesB9_: 1076| 11| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 11| self.color.primaries = color; 1078| 11| } _RNvMsr_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color3RgbtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE21set_transfer_functionB9_: 1088| 11| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 11| self.color.transfer = tf; 1090| 11| } _RNvMsr_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4LumahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE17set_rgb_primariesB9_: 1076| 1.44k| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 1.44k| self.color.primaries = color; 1078| 1.44k| } _RNvMsr_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4LumahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE21set_transfer_functionB9_: 1088| 1.44k| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 1.44k| self.color.transfer = tf; 1090| 1.44k| } _RNvMsr_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4LumatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE17set_rgb_primariesB9_: 1076| 390| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 390| self.color.primaries = color; 1078| 390| } _RNvMsr_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4LumatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE21set_transfer_functionB9_: 1088| 390| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 390| self.color.transfer = tf; 1090| 390| } _RNvMsr_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE17set_rgb_primariesB9_: 1076| 34| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 34| self.color.primaries = color; 1078| 34| } _RNvMsr_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE21set_transfer_functionB9_: 1088| 34| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 34| self.color.transfer = tf; 1090| 34| } _RNvMsr_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE17set_rgb_primariesB9_: 1076| 12| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 12| self.color.primaries = color; 1078| 12| } _RNvMsr_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbatEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE21set_transfer_functionB9_: 1088| 12| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 12| self.color.transfer = tf; 1090| 12| } _RNvMsr_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE17set_rgb_primariesB9_: 1076| 2| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 2| self.color.primaries = color; 1078| 2| } _RNvMsr_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAhEINtNtCshDtJu3Ru83O_5alloc3vec3VechEE21set_transfer_functionB9_: 1088| 2| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 2| self.color.transfer = tf; 1090| 2| } _RNvMsr_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE17set_rgb_primariesB9_: 1076| 5| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 1077| 5| self.color.primaries = color; 1078| 5| } _RNvMsr_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color5LumaAtEINtNtCshDtJu3Ru83O_5alloc3vec3VectEE21set_transfer_functionB9_: 1088| 5| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 1089| 5| self.color.transfer = tf; 1090| 5| } _RNvXst_NtNtCs1vRhqpPUfvi_5image6images6bufferINtB5_11ImageBufferINtNtB9_5color4RgbahEINtNtCshDtJu3Ru83O_5alloc3vec3VechEENtNtCs6SNw0SRvItZ_4core7default7Default7defaultB9_: 1189| 10.1k| fn default() -> Self { 1190| 10.1k| Self { 1191| 10.1k| width: 0, 1192| 10.1k| height: 0, 1193| 10.1k| _phantom: PhantomData, 1194| 10.1k| color: Cicp::SRGB.into_rgb(), 1195| 10.1k| data: Default::default(), 1196| 10.1k| } 1197| 10.1k| } _RNvNtNtCs1vRhqpPUfvi_5image6images8dynimage28load_from_memory_with_format: 1959| 10.1k|pub fn load_from_memory_with_format(buf: &[u8], format: ImageFormat) -> ImageResult { 1960| | // Note: this function (and `load_from_memory`) were supposed to be generic over `AsRef<[u8]>` 1961| | // so that we do not monomorphize copies of all our decoders unless some downsteam crate 1962| | // actually calls one of these functions. See https://github.com/image-rs/image/pull/2470. 1963| | // 1964| | // However the type inference break of this is apparently quite large in the ecosystem so for 1965| | // now they are unfortunately not. See https://github.com/image-rs/image/issues/2585. 1966| 10.1k| let b = io::Cursor::new(buf); 1967| 10.1k| free_functions::load(b, format) 1968| 10.1k|} _RNvMs_NtNtCs1vRhqpPUfvi_5image6images8dynimageNtB4_12DynamicImage10decode_raw: 280| 6.47k| pub(crate) fn decode_raw( 281| 6.47k| &mut self, 282| 6.47k| decoder: &mut dyn ImageDecoder, 283| 6.47k| layout: DecoderPreparedImage, 284| 6.47k| ) -> ImageResult { 285| 6.47k| decoder_to_image(self, decoder, layout) 286| 6.47k| } _RNvMs_NtNtCs1vRhqpPUfvi_5image6images8dynimageNtB4_12DynamicImage17set_rgb_primaries: 929| 2.33k| pub fn set_rgb_primaries(&mut self, color: CicpColorPrimaries) { 930| 2.33k| dynamic_map!(self, ref mut p, p.set_rgb_primaries(color)); 931| 2.33k| } _RNvMs_NtNtCs1vRhqpPUfvi_5image6images8dynimageNtB4_12DynamicImage21set_transfer_function: 939| 2.33k| pub fn set_transfer_function(&mut self, tf: CicpTransferCharacteristics) { 940| 2.33k| dynamic_map!(self, ref mut p, p.set_transfer_function(tf)); 941| 2.33k| } _RNvNtNtCs1vRhqpPUfvi_5image6images8dynimage16decoder_to_image: 1793| 6.47k|pub(crate) fn decoder_to_image( 1794| 6.47k| image: &mut DynamicImage, 1795| 6.47k| decoder: &mut dyn ImageDecoder, 1796| 6.47k| layout: DecoderPreparedImage, 1797| 6.47k|) -> ImageResult { 1798| | let crate::ImageLayout { 1799| 6.47k| width: w, 1800| 6.47k| height: h, 1801| 6.47k| color: color_type, 1802| | .. 1803| 6.47k| } = layout.layout; 1804| | 1805| | let attr; 1806| | 1807| 6.47k| *image = match color_type { 1808| | ColorType::Rgb8 => { 1809| | let buf; 1810| 1.22k| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1811| 427| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgb8) 1812| | } 1813| | 1814| | ColorType::Rgba8 => { 1815| | let buf; 1816| 333| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1817| 34| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgba8) 1818| | } 1819| | 1820| | ColorType::L8 => { 1821| | let buf; 1822| 2.96k| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1823| 1.44k| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLuma8) 1824| | } 1825| | 1826| | ColorType::La8 => { 1827| | let buf; 1828| 318| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1829| 2| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLumaA8) 1830| | } 1831| | 1832| | ColorType::Rgb16 => { 1833| | let buf; 1834| 397| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1835| 11| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgb16) 1836| | } 1837| | 1838| | ColorType::Rgba16 => { 1839| | let buf; 1840| 259| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1841| 12| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgba16) 1842| | } 1843| | 1844| | ColorType::Rgb32F => { 1845| | let buf; 1846| 0| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1847| 0| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgb32F) 1848| | } 1849| | 1850| | ColorType::Rgba32F => { 1851| | let buf; 1852| 0| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1853| 0| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgba32F) 1854| | } 1855| | 1856| | ColorType::L16 => { 1857| | let buf; 1858| 794| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1859| 390| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLuma16) 1860| | } 1861| | 1862| | ColorType::La16 => { 1863| | let buf; 1864| 187| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1865| 5| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLumaA16) 1866| | } 1867| | 1868| | ColorType::L32F => { 1869| | let buf; 1870| 0| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1871| 0| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLuma32F) 1872| | } 1873| | 1874| | ColorType::La32F => { 1875| | let buf; 1876| 0| (buf, attr) = free_functions::decoder_to_vec(decoder)?; 1877| 0| ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLumaA32F) 1878| | } 1879| | } 1880| 2.33k| .ok_or_else(|| { 1881| | ImageError::Parameter(ParameterError::from_kind( 1882| | ParameterErrorKind::DimensionMismatch, 1883| | )) 1884| 0| })?; 1885| | 1886| | // Presume SRGB for now. This is the one we convert into in some decoders and the one that is 1887| | // most widely used in the wild. FIXME: add an API to decoder to indicate the color space as a 1888| | // CICP directly or through interpreting the ICC information. 1889| 2.33k| image.set_rgb_primaries(Cicp::SRGB.primaries); 1890| 2.33k| image.set_transfer_function(Cicp::SRGB.transfer); 1891| | 1892| 2.33k| Ok(attr) 1893| 6.47k|} _RNvXse_NtNtCs1vRhqpPUfvi_5image6images8dynimageNtB5_12DynamicImageNtNtCs6SNw0SRvItZ_4core7default7Default7default: 1785| 10.1k| fn default() -> Self { 1786| 10.1k| Self::ImageRgba8(Default::default()) 1787| 10.1k| } _RNvMs1_NtCs1vRhqpPUfvi_5image2ioNtB5_20DecoderPreparedImage11total_bytes: 146| 19.6k| pub fn total_bytes(&self) -> u64 { 147| 19.6k| self.layout.total_bytes() 148| 19.6k| } _RNvMs1_NtCs1vRhqpPUfvi_5image2ioNtB5_20DecoderPreparedImage3new: 132| 19.6k| pub fn new(w: u32, h: u32, color: crate::ColorType) -> DecoderPreparedImage { 133| 19.6k| DecoderPreparedImage { 134| 19.6k| layout: ImageLayout::new(w, h, color), 135| 19.6k| } 136| 19.6k| } _RNvMs_NtCs1vRhqpPUfvi_5image2ioNtB4_11ImageLayout11total_bytes: 91| 19.6k| pub fn total_bytes(&self) -> u64 { 92| 19.6k| let ImageLayout { width, height, .. } = *self; 93| 19.6k| let total_pixels = u64::from(width) * u64::from(height); 94| 19.6k| let bytes_per_pixel = u64::from(self.color.bytes_per_pixel()); 95| 19.6k| total_pixels.saturating_mul(bytes_per_pixel) 96| 19.6k| } _RNvMs_NtCs1vRhqpPUfvi_5image2ioNtB4_11ImageLayout3new: 60| 19.6k| pub fn new(w: u32, h: u32, color: crate::ColorType) -> ImageLayout { 61| 19.6k| ImageLayout { 62| 19.6k| color, 63| 19.6k| width: w, 64| 19.6k| height: h, 65| 19.6k| } 66| 19.6k| } _RNvXs_NtNtCs1vRhqpPUfvi_5image2io7decoderINtNtCshDtJu3Ru83O_5alloc5boxed3BoxDNtB4_12ImageDecoderEL_EB1d_10set_limitsB8_: 318| 10.1k| fn set_limits(&mut self, limits: crate::Limits) -> ImageResult<()> { 319| 10.1k| (**self).set_limits(limits) 320| 10.1k| } _RNvXs_NtNtCs1vRhqpPUfvi_5image2io7decoderINtNtCshDtJu3Ru83O_5alloc5boxed3BoxDNtB4_12ImageDecoderEL_EB1d_13prepare_imageB8_: 297| 10.1k| fn prepare_image(&mut self) -> ImageResult { 298| 10.1k| (**self).prepare_image() 299| 10.1k| } _RNvXs_NtNtCs1vRhqpPUfvi_5image2io7decoderINtNtCshDtJu3Ru83O_5alloc5boxed3BoxDNtB4_12ImageDecoderEL_EB1d_17format_attributesB8_: 294| 6.73k| fn format_attributes(&self) -> FormatAttributes { 295| 6.73k| (**self).format_attributes() 296| 6.73k| } _RINvNtNtCs1vRhqpPUfvi_5image2io14free_functions4loadINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEECsi3bDR6OqnXm_17fuzzer_script_png: 22| 10.1k|pub fn load(r: R, format: ImageFormat) -> ImageResult { 23| 10.1k| let mut reader = ImageReaderOptions::new(r); 24| 10.1k| reader.set_format(format); 25| 10.1k| reader.decode() 26| 10.1k|} _RINvNtNtCs1vRhqpPUfvi_5image2io14free_functions14decoder_to_vechDNtNtB4_7decoder12ImageDecoderEL_EB6_: 170| 4.83k|pub(crate) fn decoder_to_vec( 171| 4.83k| decoder: &mut (impl ImageDecoder + ?Sized), 172| 4.83k|) -> ImageResult<(Vec, DecodedImageAttributes)> 173| 4.83k|where 174| 4.83k| T: crate::traits::Primitive + bytemuck::Pod, 175| |{ 176| 4.83k| let total_bytes = usize::try_from(decoder.prepare_image()?.total_bytes()); 177| 4.83k| 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.83k| } 182| | 183| 4.83k| let mut buf = vec![num_traits::Zero::zero(); total_bytes.unwrap() / size_of::()]; 184| 4.83k| let attr = decoder.read_image(bytemuck::cast_slice_mut(buf.as_mut_slice()))?; 185| 1.91k| Ok((buf, attr)) 186| 4.83k|} _RINvNtNtCs1vRhqpPUfvi_5image2io14free_functions14decoder_to_vectDNtNtB4_7decoder12ImageDecoderEL_EB6_: 170| 1.63k|pub(crate) fn decoder_to_vec( 171| 1.63k| decoder: &mut (impl ImageDecoder + ?Sized), 172| 1.63k|) -> ImageResult<(Vec, DecodedImageAttributes)> 173| 1.63k|where 174| 1.63k| T: crate::traits::Primitive + bytemuck::Pod, 175| |{ 176| 1.63k| let total_bytes = usize::try_from(decoder.prepare_image()?.total_bytes()); 177| 1.63k| 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.63k| } 182| | 183| 1.63k| let mut buf = vec![num_traits::Zero::zero(); total_bytes.unwrap() / size_of::()]; 184| 1.63k| let attr = decoder.read_image(bytemuck::cast_slice_mut(buf.as_mut_slice()))?; 185| 418| Ok((buf, attr)) 186| 1.63k|} _RNvMNtNtCs1vRhqpPUfvi_5image2io17image_reader_typeINtB2_18ImageReaderOptionsINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE10set_formatCsi3bDR6OqnXm_17fuzzer_script_png: 139| 10.1k| pub fn set_format(&mut self, format: ImageFormat) { 140| 10.1k| self.format = Some(Format::BuiltIn(format)); 141| 10.1k| } _RNCNvMs3_NtNtCs1vRhqpPUfvi_5image2io17image_reader_typeNtB7_20DecodedImageMetadata13apply_metdata0Bb_: 937| 42| orientation = exif.and_then(|chunk| Orientation::from_exif_chunk(&chunk)); _RNvMNtNtCs1vRhqpPUfvi_5image2io17image_reader_typeINtB2_18ImageReaderOptionsINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE11into_readerB6_: 257| 10.1k| pub fn into_reader(mut self) -> ImageResult> { 258| 10.1k| let format = self.require_format()?; 259| 10.1k| let decoder = Self::make_decoder(format, self.inner, self.spec_compliance)?; 260| 10.1k| let mut reader = ImageReader::from_decoder(decoder); 261| 10.1k| reader.set_limits(self.limits)?; 262| 10.1k| Ok(reader) 263| 10.1k| } _RNvMNtNtCs1vRhqpPUfvi_5image2io17image_reader_typeINtB2_18ImageReaderOptionsINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE12make_decoderB6_: 176| 10.1k| fn make_decoder( 177| 10.1k| format: Format, 178| 10.1k| reader: R, 179| 10.1k| spec_compliance: SpecCompliance, 180| 10.1k| ) -> ImageResult> { 181| | #[allow(unused)] 182| | use crate::codecs::*; 183| | 184| 10.1k| let format = match format { 185| 10.1k| 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| 10.1k| Ok(match format { 200| | #[cfg(feature = "avif-native")] 201| | ImageFormat::Avif => Box::new(avif::AvifDecoder::new(reader)?), 202| | #[cfg(feature = "png")] 203| 10.1k| 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| 10.1k| } _RNvMNtNtCs1vRhqpPUfvi_5image2io17image_reader_typeINtB2_18ImageReaderOptionsINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE14require_formatB6_: 344| 10.1k| fn require_format(&mut self) -> ImageResult { 345| 10.1k| 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| 10.1k| } _RNvMNtNtCs1vRhqpPUfvi_5image2io17image_reader_typeINtB2_18ImageReaderOptionsINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE3newB6_: 107| 10.1k| pub fn new(buffered_reader: R) -> Self { 108| 10.1k| ImageReaderOptions { 109| 10.1k| inner: buffered_reader, 110| 10.1k| format: None, 111| 10.1k| limits: Limits::default(), 112| 10.1k| spec_compliance: SpecCompliance::default(), 113| 10.1k| } 114| 10.1k| } _RNvMNtNtCs1vRhqpPUfvi_5image2io17image_reader_typeINtB2_18ImageReaderOptionsINtNtNtCsjS9ICikYiHq_3std2io6cursor6CursorRShEE6decodeB6_: 339| 10.1k| pub fn decode(self) -> ImageResult { 340| 10.1k| let (image, _meta) = self.into_reader()?.decode()?; 341| 2.33k| Ok(image) 342| 10.1k| } _RNvMs0_NtNtCs1vRhqpPUfvi_5image2io17image_reader_typeNtB5_13MetadataBlock11is_not_none: 433| 26.9k| fn is_not_none(&self) -> bool { 434| 26.9k| !matches!(self, MetadataBlock::None) 435| 26.9k| } _RNvMs0_NtNtCs1vRhqpPUfvi_5image2io17image_reader_typeNtB5_13MetadataBlock3get: 437| 4.66k| fn get(&mut self) -> ImageResult>> { 438| 4.66k| match self { 439| 2.45k| MetadataBlock::None => Ok(None), 440| 2.20k| 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| 4.66k| } _RNvMs2_NtNtCs1vRhqpPUfvi_5image2io17image_reader_typeNtB5_11ImageReader10set_limits: 801| 10.1k| pub fn set_limits(&mut self, mut limits: Limits) -> ImageResult<()> { 802| 10.1k| if let Some(max_alloc) = &mut limits.max_alloc { 803| 10.1k| // We'll take half for ourselves, half to the decoder. 804| 10.1k| *max_alloc /= 2; 805| 10.1k| } 806| | 807| 10.1k| self.inner.set_limits(limits.clone())?; 808| 10.1k| self.limits = limits; 809| 10.1k| Ok(()) 810| 10.1k| } _RNvMs2_NtNtCs1vRhqpPUfvi_5image2io17image_reader_typeNtB5_11ImageReader12from_decoder: 790| 10.1k| pub fn from_decoder(boxed: Box) -> Self { 791| 10.1k| ImageReader { 792| 10.1k| inner: boxed, 793| 10.1k| settings: ImageReaderSettings::default(), 794| 10.1k| limits: Limits::default(), 795| 10.1k| last_attributes: Default::default(), 796| 10.1k| metadata_buffers: MetadataBuffers::default(), 797| 10.1k| } 798| 10.1k| } _RNvMs2_NtNtCs1vRhqpPUfvi_5image2io17image_reader_typeNtB5_11ImageReader18decode_to_dynimage: 541| 10.1k| pub(crate) fn decode_to_dynimage( 542| 10.1k| &mut self, 543| 10.1k| image: &mut DynamicImage, 544| 10.1k| ) -> ImageResult> { 545| 10.1k| let layout = self.inner.prepare_image()?; 546| 6.73k| self.fill_header_metadata_if_any(); 547| | 548| | // This is technically redundant but it's also cheap. 549| 6.73k| 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.73k| self.limits.reserve(layout.total_bytes())?; 553| | 554| | // Retrieve the raw image data as indicated by the layout. 555| 6.47k| self.last_attributes = image.decode_raw(self.inner.as_mut(), layout)?; 556| | 557| 2.33k| let mut meta = DecodedImageMetadata { 558| 2.33k| inner: self.inner.as_mut(), 559| 2.33k| attributes: &mut self.last_attributes, 560| 2.33k| metadata_buffers: &mut self.metadata_buffers, 561| 2.33k| }; 562| | 563| 2.33k| meta.apply_metdata(&self.settings, image)?; 564| | 565| 2.33k| Ok(meta) 566| 10.1k| } _RNvMs2_NtNtCs1vRhqpPUfvi_5image2io17image_reader_typeNtB5_11ImageReader27fill_header_metadata_if_any: 658| 6.73k| 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.73k| let first_meta_retrieved = self.metadata_buffers.first_meta_retrieved; 664| 6.73k| let format_attrs = self.inner.format_attributes(); 665| | 666| 6.73k| let attributes = [ 667| 6.73k| ( 668| 6.73k| format_attrs.exif, 669| 6.73k| &mut self.metadata_buffers.exif, 670| 6.73k| ::exif_metadata as MetadataFn, 671| 6.73k| ), 672| 6.73k| ( 673| 6.73k| format_attrs.icc, 674| 6.73k| &mut self.metadata_buffers.icc, 675| 6.73k| ::icc_profile as MetadataFn, 676| 6.73k| ), 677| 6.73k| ( 678| 6.73k| format_attrs.xmp, 679| 6.73k| &mut self.metadata_buffers.xmp, 680| 6.73k| ::xmp_metadata as MetadataFn, 681| 6.73k| ), 682| 6.73k| ( 683| 6.73k| format_attrs.iptc, 684| 6.73k| &mut self.metadata_buffers.iptc, 685| 6.73k| ::iptc_metadata as MetadataFn, 686| 6.73k| ), 687| 6.73k| ]; 688| | 689| 33.6k| for (hint, buffer, getter) in attributes { 690| 26.9k| let should_buffer_now = match hint { 691| 26.9k| DecodedMetadataHint::InHeader => !first_meta_retrieved, 692| 0| DecodedMetadataHint::PerImage => true, 693| 0| DecodedMetadataHint::Unsupported | DecodedMetadataHint::None => false, 694| | }; 695| | 696| 26.9k| if !should_buffer_now { 697| 0| continue; 698| 26.9k| } 699| | 700| | // We might have already tried this and succeeded. Expect the same result as last time 701| | // but avoids the allocation associated with that. A repeated `None` should be cheap, 702| | // most probably. This holds for variants that retrieve it once. 703| 26.9k| if matches!(hint, DecodedMetadataHint::InHeader) && buffer.is_not_none() { 704| 0| continue; 705| 26.9k| } 706| | 707| 26.9k| match getter(self.inner.as_mut()) { 708| 24.6k| Ok(None) => *buffer = MetadataBlock::None, 709| 2.30k| Ok(Some(metadata)) => *buffer = MetadataBlock::Ok(metadata), 710| 44| Err(err) => { 711| 44| *buffer = MetadataBlock::Err(err); 712| 44| } 713| | } 714| | } 715| | 716| | // Note: on error we do not set this flag. You can try again. 717| 6.73k| self.metadata_buffers.first_meta_retrieved = true; 718| 6.73k| } _RNvMs2_NtNtCs1vRhqpPUfvi_5image2io17image_reader_typeNtB5_11ImageReader6decode: 511| 10.1k| pub fn decode(&mut self) -> ImageResult<(DynamicImage, DecodedImageMetadata<'_>)> { 512| 10.1k| let mut empty = DynamicImage::default(); 513| 10.1k| let meta = self.decode_to_dynimage(&mut empty)?; 514| 2.33k| Ok((empty, meta)) 515| 10.1k| } _RNvMs3_NtNtCs1vRhqpPUfvi_5image2io17image_reader_typeNtB5_20DecodedImageMetadata11icc_profile: 875| 2.33k| pub fn icc_profile(&mut self) -> ImageResult>> { 876| 2.33k| Self::access_block_with( 877| 2.33k| &mut self.metadata_buffers.icc, 878| 2.33k| self.inner.format_attributes().icc, 879| 2.33k| self.inner, 880| 2.33k| ::icc_profile, 881| | ) 882| 2.33k| } _RNvMs3_NtNtCs1vRhqpPUfvi_5image2io17image_reader_typeNtB5_20DecodedImageMetadata13apply_metdata: 904| 2.33k| fn apply_metdata( 905| 2.33k| &mut self, 906| 2.33k| settings: &ImageReaderSettings, 907| 2.33k| image: &mut DynamicImage, 908| 2.33k| ) -> Result<(), ImageError> { 909| | // Run all the metadata extraction which we may need. 910| 2.33k| let icc = self.icc_profile()?; 911| 2.33k| 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| 2.33k| if let Some(icc) = icc { 918| 2.16k| 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| 3| 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| 3| } else { 925| 3| image.set_rgb_primaries(crate::metadata::CicpColorPrimaries::Unspecified); 926| 3| image.set_transfer_function( 927| 3| crate::metadata::CicpTransferCharacteristics::Unspecified, 928| 3| ); 929| 3| } 930| 2.16k| } 931| 167| } 932| | 933| 2.33k| let mut orientation = self.attributes.orientation; 934| | 935| | // Determine which orientation to use. 936| 2.33k| if orientation.is_none() { 937| 2.33k| orientation = exif.and_then(|chunk| Orientation::from_exif_chunk(&chunk)); 938| 0| } 939| | 940| 2.33k| self.attributes.orientation = orientation; 941| | 942| 2.33k| if settings.apply_orientation { 943| 2.33k| if let Some(orient) = orientation { 944| 0| image.apply_orientation(orient); 945| 2.33k| } 946| 0| } 947| | 948| 2.33k| Ok(()) 949| 2.33k| } _RNvMs3_NtNtCs1vRhqpPUfvi_5image2io17image_reader_typeNtB5_20DecodedImageMetadata13exif_metadata: 865| 2.33k| pub fn exif_metadata(&mut self) -> ImageResult>> { 866| 2.33k| Self::access_block_with( 867| 2.33k| &mut self.metadata_buffers.exif, 868| 2.33k| self.inner.format_attributes().exif, 869| 2.33k| self.inner, 870| 2.33k| ::exif_metadata, 871| | ) 872| 2.33k| } _RNvMs3_NtNtCs1vRhqpPUfvi_5image2io17image_reader_typeNtB5_20DecodedImageMetadata17access_block_with: 951| 4.66k| fn access_block_with<'l>( 952| 4.66k| block: &mut MetadataBlock, 953| 4.66k| meta: DecodedMetadataHint, 954| 4.66k| decoder: &mut (dyn ImageDecoder + 'l), 955| 4.66k| access: fn(&'_ mut (dyn ImageDecoder + 'l)) -> ImageResult>>, 956| 4.66k| ) -> ImageResult>> { 957| 4.66k| match meta { 958| | DecodedMetadataHint::InHeader => { 959| 4.66k| if matches!(block, MetadataBlock::ErrorTaken) { 960| | // We can retry this, prefer rechecking from the source. 961| 0| access(decoder) 962| | } else { 963| 4.66k| 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| 4.66k| } _RNvXs1_NtNtCs1vRhqpPUfvi_5image2io17image_reader_typeNtB5_19ImageReaderSettingsNtNtCs6SNw0SRvItZ_4core7default7Default7default: 476| 10.1k| fn default() -> Self { 477| 10.1k| ImageReaderSettings { 478| 10.1k| apply_orientation: true, 479| 10.1k| } 480| 10.1k| } _RNvMs_NtNtCs1vRhqpPUfvi_5image2io6limitsNtB4_6Limits13check_support: 70| 20.3k| pub fn check_support(&self, _supported: &LimitSupport) -> ImageResult<()> { 71| 20.3k| Ok(()) 72| 20.3k| } _RNvMs_NtNtCs1vRhqpPUfvi_5image2io6limitsNtB4_6Limits16check_dimensions: 83| 16.6k| pub fn check_dimensions(&self, width: u32, height: u32) -> ImageResult<()> { 84| 16.6k| if let Some(max_width) = self.max_image_width { 85| 0| if width > max_width { 86| 0| return Err(ImageError::Limits(error::LimitError::from_kind( 87| 0| error::LimitErrorKind::DimensionError, 88| 0| ))); 89| 0| } 90| 16.6k| } 91| | 92| 16.6k| if let Some(max_height) = self.max_image_height { 93| 0| if height > max_height { 94| 0| return Err(ImageError::Limits(error::LimitError::from_kind( 95| 0| error::LimitErrorKind::DimensionError, 96| 0| ))); 97| 0| } 98| 16.6k| } 99| | 100| 16.6k| Ok(()) 101| 16.6k| } _RNvMs_NtNtCs1vRhqpPUfvi_5image2io6limitsNtB4_6Limits23check_layout_dimensions: 74| 6.73k| pub(crate) fn check_layout_dimensions( 75| 6.73k| &self, 76| 6.73k| layout: &crate::io::DecoderPreparedImage, 77| 6.73k| ) -> ImageResult<()> { 78| 6.73k| self.check_dimensions(layout.layout.width, layout.layout.height) 79| 6.73k| } _RNvMs_NtNtCs1vRhqpPUfvi_5image2io6limitsNtB4_6Limits7reserve: 105| 6.73k| pub fn reserve(&mut self, amount: u64) -> ImageResult<()> { 106| 6.73k| if let Some(max_alloc) = self.max_alloc.as_mut() { 107| 6.73k| if *max_alloc < amount { 108| 267| return Err(ImageError::Limits(error::LimitError::from_kind( 109| 267| error::LimitErrorKind::InsufficientMemory, 110| 267| ))); 111| 6.47k| } 112| | 113| 6.47k| *max_alloc -= amount; 114| 0| } 115| | 116| 6.47k| Ok(()) 117| 6.73k| } _RNvMs_NtNtCs1vRhqpPUfvi_5image2io6limitsNtB4_6Limits9no_limits: 61| 10.1k| pub fn no_limits() -> Limits { 62| 10.1k| Limits { 63| 10.1k| max_image_width: None, 64| 10.1k| max_image_height: None, 65| 10.1k| max_alloc: None, 66| 10.1k| } 67| 10.1k| } _RNvXNtNtCs1vRhqpPUfvi_5image2io6limitsNtB2_6LimitsNtNtCs6SNw0SRvItZ_4core7default7Default7default: 49| 20.3k| fn default() -> Limits { 50| 20.3k| Limits { 51| 20.3k| max_image_width: None, 52| 20.3k| max_image_height: None, 53| 20.3k| max_alloc: Some(512 * 1024 * 1024), 54| 20.3k| } 55| 20.3k| } _RNvMNtCs1vRhqpPUfvi_5image8metadataNtB2_11Orientation15from_exif_chunk: 95| 42| pub fn from_exif_chunk(chunk: &[u8]) -> Option { 96| 42| Self::from_exif_chunk_inner(chunk).map(|res| res.0) 97| 42| } _RNvMNtCs1vRhqpPUfvi_5image8metadataNtB2_11Orientation21from_exif_chunk_inner: 126| 42| fn from_exif_chunk_inner(chunk: &[u8]) -> Option<(Self, u64, ExifEndian)> { 127| 42| let mut reader = Cursor::new(chunk); 128| | 129| 42| let mut magic = [0; 4]; 130| 42| reader.read_exact(&mut magic).ok()?; 131| | 132| 41| match magic { 133| | [0x49, 0x49, 42, 0] => { 134| 27| return Self::locate_orientation_entry::(&mut reader) 135| 27| .map(|(orient, offset)| (orient, offset, ExifEndian::Little)); 136| | } 137| | [0x4d, 0x4d, 0, 42] => { 138| 0| return Self::locate_orientation_entry::(&mut reader) 139| 0| .map(|(orient, offset)| (orient, offset, ExifEndian::Big)); 140| | } 141| 14| _ => {} 142| | } 143| 14| None 144| 42| } _RNvNtCs1vRhqpPUfvi_5image8metadata12cms_provider: 22| 2.16k|pub(crate) fn cms_provider() -> &'static dyn CmsProvider { 23| 2.16k| &moxcms::Moxcms 24| 2.16k|} _RINvMNtCs1vRhqpPUfvi_5image8metadataNtB3_11Orientation24locate_orientation_entryNtCs7zV65YDL4Pm_14byteorder_lite12LittleEndianEB5_: 147| 27| fn locate_orientation_entry(reader: &mut Cursor<&[u8]>) -> Option<(Self, u64)> 148| 27| where 149| 27| B: byteorder_lite::ByteOrder, 150| | { 151| 27| let ifd_offset = reader.read_u32::().ok()?; 152| 27| reader.set_position(u64::from(ifd_offset)); 153| 27| let entries = reader.read_u16::().ok()?; 154| 26| for _ in 0..entries { 155| 278| let tag = reader.read_u16::().ok()?; 156| 271| let format = reader.read_u16::().ok()?; 157| 262| let count = reader.read_u32::().ok()?; 158| 257| let value = reader.read_u16::().ok()?; 159| 256| let _padding = reader.read_u16::().ok()?; 160| 254| 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| 254| } 165| | } 166| | // If we reached this point without returning early, there was no orientation 167| 2| None 168| 27| } _RNvMs7_NtNtCs1vRhqpPUfvi_5image8metadata4cicpNtB5_4Cicp12try_into_rgb: 1215| 3| pub(crate) fn try_into_rgb(self) -> Result { 1216| 3| if Cicp::from(self.into_rgb()) != self { 1217| 3| Err(ImageError::Parameter(ParameterError::from_kind( 1218| 3| ParameterErrorKind::RgbCicpRequired(self), 1219| 3| ))) 1220| | } else { 1221| 0| Ok(self.into_rgb()) 1222| | } 1223| 3| } _RNvMs7_NtNtCs1vRhqpPUfvi_5image8metadata4cicpNtB5_4Cicp8into_rgb: 1201| 12.5k| pub(crate) const fn into_rgb(self) -> CicpRgb { 1202| 12.5k| CicpRgb { 1203| 12.5k| primaries: self.primaries, 1204| 12.5k| transfer: self.transfer, 1205| 12.5k| // NOTE: if we add support for constant luminance (through the CMS having support for 1206| 12.5k| // the Luma->YCbCr->Rgb expansion natively or otherwise) then consider if we should 1207| 12.5k| // track here whether the matrix was `Identity` or `ChromaticityDerivedNonConstant` so 1208| 12.5k| // that the `ImageBuffer::color_space()` function roundtrips the value. It may be 1209| 12.5k| // important to know whether the non-constant chromaticity was an invention by `image` 1210| 12.5k| // or part of the file. The colorimetry is the same either way. 1211| 12.5k| luminance: DerivedLuminance::NonConstant, 1212| 12.5k| } 1213| 12.5k| } _RNvXs9_NtNtCs1vRhqpPUfvi_5image8metadata4cicpNtB5_4CicpINtNtCs6SNw0SRvItZ_4core7convert4FromNtB5_7CicpRgbE4from: 1281| 3| fn from(cicp: CicpRgb) -> Self { 1282| 3| Cicp { 1283| 3| primaries: cicp.primaries, 1284| 3| transfer: cicp.transfer, 1285| 3| matrix: CicpMatrixCoefficients::Identity, 1286| 3| full_range: CicpVideoFullRangeFlag::FullRange, 1287| 3| } 1288| 3| } _RNvXNtNtCs1vRhqpPUfvi_5image8metadata6moxcmsNtB2_6MoxcmsNtB4_11CmsProvider9parse_icc: 85| 2.16k| fn parse_icc(&self, icc: &[u8]) -> Option { 86| 2.16k| let profile = moxcms::ColorProfile::new_from_slice(icc).ok()?; 87| 747| 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| 3| primaries: match cicp.color_primaries { 95| 0| Mcp::Bt709 => CicpColorPrimaries::SRgb, 96| 3| 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| 3| transfer: match cicp.transfer_characteristics { 109| 0| Mtc::Bt709 => CicpTransferCharacteristics::Bt709, 110| 3| 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| 3| matrix: match cicp.matrix_coefficients { 128| 3| 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| 3| full_range: match cicp.full_range { 146| 3| false => CicpVideoFullRangeFlag::NarrowRange, 147| 0| true => CicpVideoFullRangeFlag::FullRange, 148| | }, 149| | }) 150| 2.16k| }