@@ -408,6 +408,89 @@ fn dflt_rle_block(
408408 (o, pre + shft(pos) + post)
409409}
410410
411+ ///|
412+ fn is_periodic(dat : FixedArray [Byte ], len : Int , period : Int ) -> Bool {
413+ if period <= 0 || period >= len {
414+ return false
415+ }
416+ for i in period..<len {
417+ if dat[i] != dat[i - period] {
418+ return false
419+ }
420+ }
421+ true
422+ }
423+
424+ ///|
425+ fn detect_period(dat : FixedArray [Byte ], len : Int ) -> Int {
426+ let periods : FixedArray [Int ] = [2, 4, 8, 16, 32, 64, 128, 256, 512]
427+ for i in 0..<periods.length() {
428+ let p = periods[i]
429+ if p * 2 <= len && is_periodic(dat, len, p) {
430+ return p
431+ }
432+ }
433+ 0
434+ }
435+
436+ ///|
437+ fn dflt_periodic_block(
438+ dat : FixedArray [Byte ],
439+ period : Int ,
440+ pre : Int ,
441+ post : Int ,
442+ st : DeflateState ,
443+ crc_state? : CRC32State? = None ,
444+ adler_state? : AdlerState? = None ,
445+ ) -> (FixedArray [Byte ], Int ) {
446+ let s = if st.z != 0 { st.z } else { dat.length() }
447+ let o_size = sat_add(sat_add(pre, s), sat_add(16, post))
448+ let mut o = FixedArray ::make(o_size, b'\x00')
449+ let syms_size = period + (s - period) / 258 + 4
450+ let syms : FixedArray [Int ] = FixedArray ::make(syms_size, 0)
451+ let lf : FixedArray [Int ] = FixedArray ::make(288, 0)
452+ let df : FixedArray [Int ] = FixedArray ::make(32, 0)
453+ let mut li = 0
454+ for i in 0..<period {
455+ let b = dat[i].to_int()
456+ syms[li] = b
457+ li += 1
458+ lf[b] += 1
459+ }
460+ let dc = revfd[period]
461+ let mut rem = s - period
462+ while rem >= 3 {
463+ let l = if rem > 258 { 258 } else { rem }
464+ let lc = revfl[l]
465+ syms[li] = 268435456 | (lc << 18) | dc
466+ li += 1
467+ lf[257 + (lc & 31)] += 1
468+ df[dc & 31] += 1
469+ rem -= l
470+ }
471+ let mut tail = s - rem
472+ while rem > 0 {
473+ let b = dat[tail].to_int()
474+ syms[li] = b
475+ li += 1
476+ lf[b] += 1
477+ tail += 1
478+ rem -= 1
479+ }
480+ o = ensure_out(o, out_capacity_need(pre, 0, s, post))
481+ let pos = wblk(dat, o, st.l, syms, lf, df, 0, li, 0, s, pre * 8) - pre * 8
482+ match crc_state {
483+ Some (cs) => cs.push_range(dat, 0, s)
484+ None => ()
485+ }
486+ match adler_state {
487+ Some (a_s) => a_s.push_range(dat, 0, s)
488+ None => ()
489+ }
490+ st.i = s
491+ (o, pre + shft(pos) + post)
492+ }
493+
411494///|
412495/// Ensure output buffer has enough capacity, growing if needed
413496fn ensure_out(o : FixedArray [Byte ], need : Int ) -> FixedArray [Byte ] {
@@ -465,6 +548,20 @@ fn dflt(
465548 if !is_compressible(dat, 0, s) {
466549 return dflt(dat, 0, plvl, pre, post, st, crc_state~, adler_state~)
467550 }
551+ if s >= 1024 && st.w == 0 && st.i == 0 && st.r == 0 {
552+ let period = detect_period(dat, s)
553+ if period != 0 {
554+ return dflt_periodic_block(
555+ dat,
556+ period,
557+ pre,
558+ post,
559+ st,
560+ crc_state~,
561+ adler_state~,
562+ )
563+ }
564+ }
468565 if pos != 0 {
469566 o[w_start] = (st.r >> 3).to_byte()
470567 }
0 commit comments