11//! Sample code unpacking and normalization helpers.
22
33use num_traits:: ToPrimitive ;
4+ use pdf_utils:: BitReader ;
45
56use crate :: { error:: DecodeError , layout:: SampleLayout } ;
67
@@ -161,7 +162,7 @@ fn decode_contiguous_samples(
161162 }
162163 _ => 0 ,
163164 } ) ,
164- _ => decode_packed_samples ( data, bits_per_sample, sample_count, 0 ) ,
165+ _ => decode_packed_samples ( data, bits_per_sample, sample_count) ,
165166 }
166167}
167168
@@ -217,7 +218,6 @@ fn decode_row_aligned_samples(
217218 row_data,
218219 bits_per_sample,
219220 samples_per_row,
220- 0 ,
221221 ) ?) ;
222222 }
223223 }
@@ -245,39 +245,27 @@ fn decode_packed_samples(
245245 data : & [ u8 ] ,
246246 bits_per_sample : usize ,
247247 sample_count : usize ,
248- initial_bit_offset : usize ,
249248) -> Result < Vec < u32 > , DecodeError > {
250249 let total_bits = sample_count. saturating_mul ( bits_per_sample) ;
251- let required_bits = initial_bit_offset. saturating_add ( total_bits) ;
252- let required_bytes = required_bits. div_ceil ( 8 ) ;
250+ let required_bytes = total_bits. div_ceil ( 8 ) ;
253251 ensure_len ( data, required_bytes) ?;
252+ let bit_width = u8:: try_from ( bits_per_sample)
253+ . map_err ( |_| DecodeError :: InvalidBitsPerSample { bits_per_sample } ) ?;
254254
255+ let mut reader = BitReader :: new ( data) ;
255256 let mut out = Vec :: with_capacity ( sample_count) ;
256- let mut bit_offset = initial_bit_offset;
257257 for _ in 0 ..sample_count {
258- out. push ( read_bits ( data, bit_offset, bits_per_sample) ) ;
259- bit_offset = bit_offset. saturating_add ( bits_per_sample) ;
258+ let sample = reader
259+ . read_bits_u32 ( bit_width)
260+ . ok_or ( DecodeError :: InsufficientData {
261+ expected_bytes : required_bytes,
262+ actual_bytes : data. len ( ) ,
263+ } ) ?;
264+ out. push ( sample) ;
260265 }
261266 Ok ( out)
262267}
263268
264- /// Reads one packed sample value from the input bit stream.
265- fn read_bits ( data : & [ u8 ] , bit_offset : usize , bits_per_sample : usize ) -> u32 {
266- let mut value = 0u32 ;
267-
268- for bit_index in 0 ..bits_per_sample {
269- let absolute_bit = bit_offset. saturating_add ( bit_index) ;
270- let byte_index = absolute_bit / 8 ;
271- let bit_in_byte = absolute_bit % 8 ;
272- let byte = data. get ( byte_index) . copied ( ) . unwrap_or_default ( ) ;
273- let bit = ( byte >> ( 7usize . saturating_sub ( bit_in_byte) ) ) & 1 ;
274- value <<= 1 ;
275- value |= u32:: from ( bit) ;
276- }
277-
278- value
279- }
280-
281269#[ cfg( test) ]
282270#[ allow( clippy:: unwrap_used, clippy:: expect_used) ]
283271mod tests {
@@ -295,6 +283,25 @@ mod tests {
295283 assert_eq ! ( samples, vec![ 1 , 0 , 1 , 1 , 0 , 0 , 1 , 0 ] ) ;
296284 }
297285
286+ #[ test]
287+ fn decode_contiguous_2_and_4_bit_samples ( ) {
288+ let two_bit_samples = decode_sample_codes (
289+ & [ 0b00_01_10_11 ] ,
290+ 2 ,
291+ SampleLayout :: Contiguous { sample_count : 4 } ,
292+ )
293+ . unwrap ( ) ;
294+ let four_bit_samples = decode_sample_codes (
295+ & [ 0x1F , 0xA0 ] ,
296+ 4 ,
297+ SampleLayout :: Contiguous { sample_count : 3 } ,
298+ )
299+ . unwrap ( ) ;
300+
301+ assert_eq ! ( two_bit_samples, vec![ 0 , 1 , 2 , 3 ] ) ;
302+ assert_eq ! ( four_bit_samples, vec![ 1 , 15 , 10 ] ) ;
303+ }
304+
298305 #[ test]
299306 fn decode_contiguous_12_bit_samples ( ) {
300307 let samples = decode_sample_codes (
@@ -483,6 +490,20 @@ mod tests {
483490 ) ) ;
484491 }
485492
493+ #[ test]
494+ fn decode_reports_truncated_packed_data ( ) {
495+ let err = decode_sample_codes ( & [ 0xFF ] , 12 , SampleLayout :: Contiguous { sample_count : 1 } )
496+ . expect_err ( "12-bit sample requires two bytes" ) ;
497+
498+ assert ! ( matches!(
499+ err,
500+ DecodeError :: InsufficientData {
501+ expected_bytes: 2 ,
502+ actual_bytes: 1
503+ }
504+ ) ) ;
505+ }
506+
486507 #[ test]
487508 fn decode_normalizes_samples ( ) {
488509 let samples = decode_normalized_samples ( & [ 0x00 , 0xFF ] , 8 , 2 ) . unwrap ( ) ;
0 commit comments