@@ -206,6 +206,13 @@ pub enum CompressionStrategy {
206
206
Fixed = 4 ,
207
207
}
208
208
209
+ impl From < CompressionStrategy > for i32 {
210
+ #[ inline( always) ]
211
+ fn from ( value : CompressionStrategy ) -> Self {
212
+ value as i32
213
+ }
214
+ }
215
+
209
216
/// A list of deflate flush types.
210
217
#[ derive( Debug , Copy , Clone , PartialEq , Eq , Hash ) ]
211
218
pub enum TDEFLFlush {
@@ -299,10 +306,15 @@ pub(crate) const MAX_MATCH_LEN: usize = 258;
299
306
const DEFAULT_FLAGS : u32 = NUM_PROBES [ 4 ] | TDEFL_WRITE_ZLIB_HEADER ;
300
307
301
308
mod zlib {
309
+ use super :: TDEFL_RLE_MATCHES ;
310
+
302
311
const DEFAULT_CM : u8 = 8 ;
303
312
const DEFAULT_CINFO : u8 = 7 << 4 ;
304
313
const _DEFAULT_FDICT: u8 = 0 ;
305
314
const DEFAULT_CMF : u8 = DEFAULT_CM | DEFAULT_CINFO ;
315
+ // CMF used for RLE (technically it uses a window size of 0 but the lowest that can
316
+ // be specified in the header corresponds to a window size of 1 << (0 + 8) aka 256.
317
+ const MIN_CMF : u8 = DEFAULT_CM | 0 ;
306
318
/// The 16-bit value consisting of CMF and FLG must be divisible by this to be valid.
307
319
const FCHECK_DIVISOR : u8 = 31 ;
308
320
@@ -324,7 +336,9 @@ mod zlib {
324
336
use super :: NUM_PROBES ;
325
337
326
338
let num_probes = flags & ( super :: MAX_PROBES_MASK as u32 ) ;
327
- if flags & super :: TDEFL_GREEDY_PARSING_FLAG != 0 {
339
+ if ( flags & super :: TDEFL_GREEDY_PARSING_FLAG != 0 )
340
+ || ( flags & super :: TDEFL_RLE_MATCHES != 0 )
341
+ {
328
342
if num_probes <= 1 {
329
343
0
330
344
} else {
@@ -337,18 +351,26 @@ mod zlib {
337
351
}
338
352
}
339
353
354
+ const fn cmf_from_flags ( flags : u32 ) -> u8 {
355
+ if flags & TDEFL_RLE_MATCHES == 0 {
356
+ DEFAULT_CMF
357
+ } else {
358
+ MIN_CMF
359
+ }
360
+ }
361
+
340
362
/// Get the zlib header for the level using the default window size and no
341
363
/// dictionary.
342
- fn header_from_level ( level : u8 ) -> [ u8 ; 2 ] {
343
- let cmf = DEFAULT_CMF ;
364
+ fn header_from_level ( level : u8 , flags : u32 ) -> [ u8 ; 2 ] {
365
+ let cmf = cmf_from_flags ( flags ) ;
344
366
[ cmf, add_fcheck ( cmf, level << 6 ) ]
345
367
}
346
368
347
369
/// Create a zlib header from the given compression flags.
348
370
/// Only level is considered.
349
371
pub fn header_from_flags ( flags : u32 ) -> [ u8 ; 2 ] {
350
372
let level = zlib_level_from_flags ( flags) ;
351
- header_from_level ( level)
373
+ header_from_level ( level, flags )
352
374
}
353
375
354
376
#[ cfg( test) ]
@@ -381,7 +403,7 @@ mod zlib {
381
403
382
404
#[ test]
383
405
fn test_header ( ) {
384
- let header = super :: header_from_level ( 3 ) ;
406
+ let header = super :: header_from_level ( 3 , 0 ) ;
385
407
assert_eq ! (
386
408
( ( usize :: from( header[ 0 ] ) * 256 ) + usize :: from( header[ 1 ] ) ) % 31 ,
387
409
0
@@ -776,7 +798,7 @@ const HUFF_CODES_TABLE: usize = 2;
776
798
/// Status of RLE encoding of huffman code lengths.
777
799
struct Rle {
778
800
pub z_count : u32 ,
779
- pub repeat_count : u32 ,
801
+ pub repeat_count : u16 ,
780
802
pub prev_code_size : u8 ,
781
803
}
782
804
@@ -792,7 +814,7 @@ impl Rle {
792
814
if self . repeat_count != 0 {
793
815
if self . repeat_count < 3 {
794
816
counts[ self . prev_code_size as usize ] =
795
- counts[ self . prev_code_size as usize ] . wrapping_add ( self . repeat_count as u16 ) ;
817
+ counts[ self . prev_code_size as usize ] . wrapping_add ( self . repeat_count ) ;
796
818
let code = self . prev_code_size ;
797
819
write ( & [ code, code, code] [ ..self . repeat_count as usize ] ) ?;
798
820
} else {
@@ -2466,4 +2488,45 @@ mod test {
2466
2488
let decoded = decompress_to_vec ( & encoded[ ..] ) . unwrap ( ) ;
2467
2489
assert_eq ! ( & decoded[ ..] , & slice[ ..] ) ;
2468
2490
}
2491
+
2492
+ #[ test]
2493
+ fn zlib_window_bits ( ) {
2494
+ use crate :: inflate:: stream:: { inflate, InflateState } ;
2495
+ use crate :: DataFormat ;
2496
+ use alloc:: boxed:: Box ;
2497
+ let slice = [
2498
+ 1 , 2 , 3 , 4 , 1 , 2 , 3 , 1 , 2 , 3 , 1 , 2 , 6 , 1 , 2 , 3 , 1 , 2 , 3 , 2 , 3 , 1 , 2 , 3 , 35 , 22 , 22 , 2 ,
2499
+ 6 , 2 , 6 ,
2500
+ ] ;
2501
+ let mut encoded = vec ! [ ] ;
2502
+ let flags = create_comp_flags_from_zip_params ( 2 , 1 , CompressionStrategy :: RLE . into ( ) ) ;
2503
+ let mut d = CompressorOxide :: new ( flags) ;
2504
+ let ( status, in_consumed) =
2505
+ compress_to_output ( & mut d, & slice, TDEFLFlush :: Finish , |out : & [ u8 ] | {
2506
+ encoded. extend_from_slice ( out) ;
2507
+ true
2508
+ } ) ;
2509
+
2510
+ assert_eq ! ( status, TDEFLStatus :: Done ) ;
2511
+ assert_eq ! ( in_consumed, slice. len( ) ) ;
2512
+
2513
+ let mut output = vec ! [ 0 ; slice. len( ) ] ;
2514
+
2515
+ let mut decompressor = Box :: new ( InflateState :: new ( DataFormat :: Zlib ) ) ;
2516
+
2517
+ let mut out_slice = output. as_mut_slice ( ) ;
2518
+ // Feed 1 byte at a time and no back buffer to test that RLE encoding has been used.
2519
+ for i in 0 ..encoded. len ( ) {
2520
+ let result = inflate (
2521
+ & mut decompressor,
2522
+ & encoded[ i..i + 1 ] ,
2523
+ out_slice,
2524
+ crate :: MZFlush :: None ,
2525
+ ) ;
2526
+ out_slice = & mut out_slice[ result. bytes_written ..] ;
2527
+ }
2528
+ let cmf = decompressor. decompressor ( ) . zlib_header ( ) . 0 ;
2529
+ assert_eq ! ( cmf, 8 ) ;
2530
+ assert_eq ! ( output, slice)
2531
+ }
2469
2532
}
0 commit comments