libbz2_rs_sys/
compress.rs

1#![forbid(unsafe_code)]
2
3use crate::blocksort::block_sort;
4use crate::bzlib::{EState, BZ_MAX_SELECTORS, BZ_N_GROUPS, BZ_N_ITERS, BZ_RUNA, BZ_RUNB};
5use crate::{assert_h, debug_log, debug_logln, huffman};
6
7pub(crate) struct EWriter {
8    pub num_z: u32,
9    bs_live: i32,
10    bs_buff: u32,
11}
12
13pub(crate) struct LiveWriter<'a> {
14    zbits: &'a mut [u8],
15    writer: &'a mut EWriter,
16    num_z: u32,
17    bs_live: i32,
18    bs_buff: u32,
19}
20
21impl Drop for LiveWriter<'_> {
22    fn drop(&mut self) {
23        self.writer.num_z = self.num_z;
24        self.writer.bs_buff = self.bs_buff;
25        self.writer.bs_live = self.bs_live;
26    }
27}
28
29impl<'a> LiveWriter<'a> {
30    fn new(writer: &'a mut EWriter, zbits: &'a mut [u8]) -> Self {
31        Self {
32            num_z: writer.num_z,
33            bs_live: writer.bs_live,
34            bs_buff: writer.bs_buff,
35            zbits,
36            writer,
37        }
38    }
39
40    fn initialize(&mut self) {
41        self.bs_live = 0;
42        self.bs_buff = 0;
43    }
44
45    #[inline]
46    fn finish(&mut self) {
47        while self.bs_live > 0 {
48            self.zbits[self.num_z as usize] = (self.bs_buff >> 24) as u8;
49            self.num_z += 1;
50            self.bs_buff <<= 8;
51            self.bs_live -= 8;
52        }
53    }
54
55    #[inline]
56    fn flush_whole_bytes(&mut self) {
57        let range = self.num_z as usize..self.num_z as usize + 4;
58        if let Some(dst) = self.zbits.get_mut(range) {
59            dst.copy_from_slice(&self.bs_buff.to_be_bytes());
60            let bits_written = self.bs_live & !7;
61            self.bs_buff <<= bits_written;
62            self.bs_live -= bits_written;
63            self.num_z += (bits_written / 8) as u32;
64        }
65
66        while self.bs_live >= 8 {
67            self.zbits[self.num_z as usize] = (self.bs_buff >> 24) as u8;
68            self.num_z += 1;
69            self.bs_buff <<= 8;
70            self.bs_live -= 8;
71        }
72    }
73
74    fn write(&mut self, n: u8, v: u32) {
75        self.flush_whole_bytes();
76
77        self.bs_buff |= v << (32 - self.bs_live - i32::from(n));
78        self.bs_live += i32::from(n);
79    }
80
81    fn write_u8(&mut self, c: u8) {
82        self.write(8, c as u32);
83    }
84
85    fn write_u32(&mut self, u: u32) {
86        let [a, b, c, d] = u.to_le_bytes();
87
88        self.write(8, d as u32);
89        self.write(8, c as u32);
90        self.write(8, b as u32);
91        self.write(8, a as u32);
92    }
93}
94
95fn make_maps_e(s: &mut EState) {
96    s.nInUse = 0;
97    for (i, in_use) in s.inUse.iter().enumerate() {
98        if *in_use {
99            s.unseqToSeq[i] = s.nInUse as u8;
100            s.nInUse += 1;
101        }
102    }
103}
104
105fn generate_mtf_values(s: &mut EState) {
106    /*
107       After sorting (eg, here),
108          s.arr1 [ 0 .. s->nblock-1 ] holds sorted order,
109          and
110          s.arr2 [ 0 .. s->nblock-1 ]
111          holds the original block data.
112
113       The first thing to do is generate the MTF values,
114       and put them in
115          s.arr1 [ 0 .. s->nblock-1 ].
116       Because there are strictly fewer or equal MTF values
117       than block values, ptr values in this area are overwritten
118       with MTF values only when they are no longer needed.
119
120       The final compressed bitstream is generated into the
121       area starting at
122          (UChar*) (&((UChar*)s->arr2)[s->nblock])
123
124       These storage aliases are set up in bzCompressInit(),
125       except for the last one, which is arranged in
126       compressBlock().
127    */
128
129    make_maps_e(s);
130    let EOB = s.nInUse + 1;
131
132    s.mtfFreq[..=EOB as usize].fill(0);
133
134    let mut wr = 0;
135    let mut zPend = 0;
136
137    let mut yy: [u8; 256] = [0; 256];
138    for i in 0..s.nInUse {
139        yy[i as usize] = i as u8;
140    }
141
142    for i in 0..s.nblock {
143        debug_assert!(wr <= i, "generateMTFValues(1)");
144        let mut j = s.arr1.ptr()[i as usize].wrapping_sub(1) as i32;
145        if j < 0 {
146            j += s.nblock;
147        }
148        let ll_i: u8 = s.unseqToSeq[s.arr2.block(s.nblock as usize)[j as usize] as usize];
149        debug_assert!((ll_i as i32) < s.nInUse, "generateMTFValues(2a)");
150
151        if yy[0] == ll_i {
152            zPend += 1;
153        } else {
154            if zPend > 0 {
155                zPend -= 1;
156                loop {
157                    if zPend & 1 != 0 {
158                        s.arr1.mtfv()[wr as usize] = 1;
159                        wr += 1;
160                        s.mtfFreq[1] += 1;
161                    } else {
162                        s.arr1.mtfv()[wr as usize] = 0;
163                        wr += 1;
164                        s.mtfFreq[0] += 1;
165                    }
166                    if zPend < 2 {
167                        break;
168                    }
169                    zPend = (zPend - 2) / 2;
170                }
171                zPend = 0;
172            }
173
174            {
175                let mut rtmp: u8;
176                rtmp = yy[1];
177                yy[1] = yy[0];
178                j = 1;
179                while ll_i != rtmp {
180                    j += 1;
181                    core::mem::swap(&mut rtmp, &mut yy[j as usize]);
182                }
183                yy[0] = rtmp;
184                s.arr1.mtfv()[wr as usize] = (j + 1) as u16;
185                wr += 1;
186                s.mtfFreq[(j + 1) as usize] += 1;
187            }
188        }
189    }
190
191    if zPend > 0 {
192        zPend -= 1;
193        loop {
194            if zPend & 1 != 0 {
195                s.arr1.mtfv()[wr as usize] = BZ_RUNB;
196                wr += 1;
197                s.mtfFreq[BZ_RUNB as usize] += 1;
198            } else {
199                s.arr1.mtfv()[wr as usize] = BZ_RUNA;
200                wr += 1;
201                s.mtfFreq[BZ_RUNA as usize] += 1;
202            }
203            if zPend < 2 {
204                break;
205            }
206            zPend = (zPend - 2) / 2;
207        }
208    }
209
210    s.arr1.mtfv()[wr as usize] = EOB as u16;
211    wr += 1;
212    s.mtfFreq[EOB as usize] += 1;
213
214    s.nMTF = wr;
215}
216
217fn send_mtf_values(s: &mut EState) {
218    const BZ_LESSER_ICOST: u8 = 0;
219    const BZ_GREATER_ICOST: u8 = 15;
220
221    let mut gs: i32;
222    let mut ge: i32;
223    let mut totc: i32;
224    let mut bt: i32;
225    let mut bc: i32;
226    let mut nSelectors: usize = 0;
227    let mut selCtr: usize;
228    let mut nBytes: i32;
229
230    /*--
231    s.len: [[u8; BZ_MAX_ALPHA_SIZE]; BZ_N_GROUPS];
232    is a global because the decoder also needs it.
233
234    s.code: [[i32; BZ_MAX_ALPHA_SIZE]; BZ_N_GROUPS];
235    s.rfreq: [[i32; BZ_MAX_ALPHA_SIZE]; BZ_N_GROUPS];
236
237    are also globals only used in this proc.
238    Made global to keep stack frame size small.
239    --*/
240
241    let mtfv = s.arr1.mtfv();
242
243    if s.verbosity >= 3 {
244        debug_logln!(
245            "      {} in block, {} after MTF & 1-2 coding, {}+2 syms in use",
246            s.nblock,
247            s.nMTF,
248            s.nInUse,
249        );
250    }
251
252    let alphaSize = usize::try_from(s.nInUse + 2).unwrap_or(0);
253
254    for t in s.len.iter_mut() {
255        t[..alphaSize].fill(BZ_GREATER_ICOST);
256    }
257
258    /*--- Decide how many coding tables to use ---*/
259    assert_h!(s.nMTF > 0, 3001);
260    let nGroups: usize = match s.nMTF {
261        0..200 => 2,
262        200..600 => 3,
263        600..1200 => 4,
264        1200..2400 => 5,
265        _ => 6,
266    };
267
268    let mut cost: [u16; 6] = [0; 6];
269    let cost = &mut cost[..nGroups];
270
271    let mut fave: [i32; 6] = [0; 6];
272    let fave = &mut fave[..nGroups];
273
274    /*--- Generate an initial set of coding tables ---*/
275    {
276        let mut tFreq: i32;
277        let mut aFreq: i32;
278
279        let mut nPart = nGroups;
280        let mut remF = s.nMTF;
281        let mut gs = 0i32;
282
283        while nPart > 0 {
284            tFreq = remF / nPart as i32;
285            ge = gs - 1;
286            aFreq = 0;
287            while aFreq < tFreq && ge < alphaSize as i32 - 1 {
288                ge += 1;
289                aFreq += s.mtfFreq[ge as usize];
290            }
291            if ge > gs && nPart != nGroups && nPart != 1 && (nGroups - nPart) % 2 == 1 {
292                aFreq -= s.mtfFreq[ge as usize];
293                ge -= 1;
294            }
295
296            if s.verbosity >= 3 {
297                debug_logln!(
298                    "      initial group {}, [{} .. {}], has {} syms ({:4.1}%)",
299                    nPart,
300                    gs,
301                    ge,
302                    aFreq,
303                    100.0f64 * aFreq as f64 / s.nMTF as f64,
304                );
305            }
306
307            for v in 0..alphaSize {
308                s.len[nPart - 1][v] = if (gs..=ge).contains(&(v as i32)) {
309                    BZ_LESSER_ICOST
310                } else {
311                    BZ_GREATER_ICOST
312                };
313            }
314            nPart -= 1;
315            gs = ge + 1;
316            remF -= aFreq;
317        }
318    }
319
320    /*---
321       Iterate up to BZ_N_ITERS times to improve the tables.
322    ---*/
323    for iter in 0..BZ_N_ITERS {
324        fave.fill(0);
325
326        for t in 0..nGroups {
327            s.rfreq[t][..alphaSize].fill(0);
328        }
329
330        /*---
331          Set up an auxiliary length table which is used to fast-track
332          the common case (nGroups == 6).
333        ---*/
334        if nGroups == 6 {
335            for v in 0..alphaSize {
336                s.len_pack[v][0] = ((s.len[1][v] as u32) << 16) | (s.len[0][v] as u32);
337                s.len_pack[v][1] = ((s.len[3][v] as u32) << 16) | (s.len[2][v] as u32);
338                s.len_pack[v][2] = ((s.len[5][v] as u32) << 16) | (s.len[4][v] as u32);
339            }
340        }
341
342        nSelectors = 0;
343        totc = 0;
344        gs = 0;
345        loop {
346            /*--- Set group start & end marks. --*/
347            if gs >= s.nMTF {
348                break;
349            }
350            ge = gs + 50 - 1;
351            if ge >= s.nMTF {
352                ge = s.nMTF - 1;
353            }
354
355            /*--
356               Calculate the cost of this group as coded
357               by each of the coding tables.
358            --*/
359            cost.fill(0);
360
361            if nGroups == 6 && 50 == ge - gs + 1 {
362                let mut cost01: u32 = 0;
363                let mut cost23: u32 = 0;
364                let mut cost45: u32 = 0;
365
366                for chunk in mtfv[gs as usize..][..50].chunks_exact(10) {
367                    for icv in chunk {
368                        let [a, b, c, _] = s.len_pack[usize::from(*icv)];
369                        cost01 = cost01.wrapping_add(a);
370                        cost23 = cost23.wrapping_add(b);
371                        cost45 = cost45.wrapping_add(c);
372                    }
373                }
374
375                cost[0] = (cost01 & 0xffff) as u16;
376                cost[1] = (cost01 >> 16) as u16;
377                cost[2] = (cost23 & 0xffff) as u16;
378                cost[3] = (cost23 >> 16) as u16;
379                cost[4] = (cost45 & 0xffff) as u16;
380                cost[5] = (cost45 >> 16) as u16;
381            } else {
382                /*--- slow version which correctly handles all situations ---*/
383                for i in gs..=ge {
384                    let icv_0: u16 = mtfv[i as usize];
385
386                    for (t, c) in cost.iter_mut().enumerate() {
387                        *c = (*c as i32 + s.len[t][icv_0 as usize] as i32) as u16;
388                    }
389                }
390            }
391
392            /*--
393               Find the coding table which is best for this group,
394               and record its identity in the selector table.
395            --*/
396            bc = 999999999;
397            bt = -1;
398            for (t, &c) in cost.iter().enumerate() {
399                if (c as i32) < bc {
400                    bc = c as i32;
401                    bt = t as i32;
402                }
403            }
404            totc += bc;
405            fave[bt as usize] += 1;
406            s.selector[nSelectors] = bt as u8;
407            nSelectors += 1;
408
409            if nGroups == 6 && 50 == ge - gs + 1 {
410                for chunk in mtfv[gs as usize..][..50].chunks_exact(10) {
411                    for &mtfv_i in chunk {
412                        s.rfreq[bt as usize][usize::from(mtfv_i)] += 1;
413                    }
414                }
415            } else {
416                for i in gs..=ge {
417                    s.rfreq[bt as usize][mtfv[i as usize] as usize] += 1;
418                }
419            }
420
421            gs = ge + 1;
422        }
423
424        if s.verbosity >= 3 {
425            debug_log!(
426                "      pass {}: size is {}, grp uses are ",
427                iter + 1,
428                totc / 8,
429            );
430            for f in fave.iter() {
431                debug_log!("{} ", f);
432            }
433            debug_logln!();
434        }
435
436        /*--
437          Recompute the tables based on the accumulated frequencies.
438        --*/
439        /* maxLen was changed from 20 to 17 in bzip2-1.0.3.  See
440        comment in huffman.c for details. */
441        for t in 0..nGroups {
442            huffman::make_code_lengths(&mut s.len[t], &s.rfreq[t], alphaSize, 17);
443        }
444    }
445
446    assert_h!(nGroups < 8, 3002);
447    assert_h!(nSelectors < 32768, 3003);
448    assert_h!(nSelectors <= usize::from(BZ_MAX_SELECTORS), 3003);
449
450    /*--- Compute MTF values for the selectors. ---*/
451    {
452        let mut pos: [u8; BZ_N_GROUPS] = [0, 1, 2, 3, 4, 5];
453
454        let mut tmp2: u8;
455        let mut tmp: u8;
456
457        for (i, &ll_i) in s.selector[..nSelectors].iter().enumerate() {
458            let mut j = 0;
459            tmp = pos[j as usize];
460            while ll_i != tmp {
461                j += 1;
462                tmp2 = tmp;
463                tmp = pos[j as usize];
464                pos[j as usize] = tmp2;
465            }
466            pos[0] = tmp;
467            s.selectorMtf[i] = j as u8;
468        }
469    }
470
471    /*--- Assign actual codes for the tables. --*/
472    for (t, len) in s.len[..nGroups].iter().enumerate() {
473        let len = &len[..alphaSize];
474
475        let mut minLen = 32;
476        let mut maxLen = 0;
477
478        for &l in len {
479            maxLen = Ord::max(maxLen, l);
480            minLen = Ord::min(minLen, l);
481        }
482
483        assert_h!(maxLen <= 17, 3004);
484        assert_h!(minLen >= 1, 3005);
485
486        huffman::assign_codes(&mut s.code[t], len, minLen, maxLen);
487    }
488
489    /*--- Transmit the mapping table. ---*/
490    let mut writer = LiveWriter::new(&mut s.writer, s.arr2.zbits(s.nblock as usize));
491
492    {
493        let inUse16: [bool; 16] =
494            core::array::from_fn(|i| s.inUse[i * 16..][..16].iter().any(|x| *x));
495
496        nBytes = writer.num_z as i32;
497        for in_use in inUse16 {
498            writer.write(1, in_use as u32);
499        }
500        for (i, any_in_use) in inUse16.iter().enumerate() {
501            if *any_in_use {
502                for j in 0..16 {
503                    writer.write(1, s.inUse[i * 16 + j] as u32);
504                }
505            }
506        }
507        if s.verbosity >= 3 {
508            debug_log!("      bytes: mapping {}, ", writer.num_z as i32 - nBytes,);
509        }
510    }
511
512    /*--- Now the selectors. ---*/
513    nBytes = writer.num_z as i32;
514    writer.write(3, nGroups as u32);
515    writer.write(15, nSelectors as u32);
516
517    for i in 0..nSelectors {
518        for _ in 0..s.selectorMtf[i] {
519            writer.write(1, 1);
520        }
521        writer.write(1, 0);
522    }
523    if s.verbosity >= 3 {
524        debug_log!("selectors {}, ", writer.num_z as i32 - nBytes);
525    }
526
527    /*--- Now the coding tables. ---*/
528    nBytes = writer.num_z as i32;
529
530    for t in 0..nGroups {
531        let mut curr = s.len[t][0];
532        writer.write(5, curr as u32);
533        for i in 0..alphaSize {
534            while curr < s.len[t][i] {
535                writer.write(2, 2);
536                curr += 1;
537            }
538            while curr > s.len[t][i] {
539                writer.write(2, 3);
540                curr -= 1;
541            }
542            writer.write(1, 0);
543        }
544    }
545    if s.verbosity >= 3 {
546        debug_log!("code lengths {}, ", writer.num_z as i32 - nBytes);
547    }
548
549    /*--- And finally, the block data proper ---*/
550    nBytes = writer.num_z as i32;
551    selCtr = 0;
552    gs = 0;
553    loop {
554        if gs >= s.nMTF {
555            break;
556        }
557        ge = gs + 50 - 1;
558        if ge >= s.nMTF {
559            ge = s.nMTF - 1;
560        }
561        assert_h!((s.selector[selCtr] as usize) < nGroups, 3006);
562        if nGroups == 6 && 50 == ge - gs + 1 {
563            /*--- fast track the common case ---*/
564
565            let s_len_sel_selCtr = s.len[s.selector[selCtr] as usize];
566            let s_code_sel_selCtr = s.code[s.selector[selCtr] as usize];
567
568            for chunk in mtfv[gs as usize..][..50].chunks_exact(10) {
569                for &mtfv_i in chunk {
570                    writer.write(
571                        s_len_sel_selCtr[usize::from(mtfv_i)],
572                        s_code_sel_selCtr[usize::from(mtfv_i)],
573                    );
574                }
575            }
576        } else {
577            /*--- slow version which correctly handles all situations ---*/
578            for i in gs..=ge {
579                writer.write(
580                    s.len[s.selector[selCtr] as usize][mtfv[i as usize] as usize],
581                    s.code[s.selector[selCtr] as usize][mtfv[i as usize] as usize],
582                );
583            }
584        }
585        gs = ge + 1;
586        selCtr += 1;
587    }
588    assert_h!(selCtr == nSelectors, 3007);
589
590    if s.verbosity >= 3 {
591        debug_logln!("codes {}", writer.num_z as i32 - nBytes);
592    }
593}
594
595pub(crate) fn compress_block(s: &mut EState, is_last_block: bool) {
596    if s.nblock > 0 {
597        s.blockCRC = !s.blockCRC;
598        s.combinedCRC = s.combinedCRC.rotate_left(1);
599        s.combinedCRC ^= s.blockCRC;
600        if s.blockNo > 1 {
601            s.writer.num_z = 0;
602        }
603
604        if s.verbosity >= 2 {
605            debug_logln!(
606                "    block {}: crc = 0x{:08x}, combined CRC = 0x{:08x}, size = {}",
607                s.blockNo,
608                s.blockCRC,
609                s.combinedCRC,
610                s.nblock,
611            );
612        }
613
614        block_sort(s);
615    }
616
617    {
618        /*-- If this is the first block, create the stream header. --*/
619        if s.blockNo == 1 {
620            let mut writer = LiveWriter::new(&mut s.writer, s.arr2.zbits(s.nblock as usize));
621
622            writer.initialize();
623            writer.write_u8(b'B');
624            writer.write_u8(b'Z');
625            writer.write_u8(b'h');
626            writer.write_u8(b'0' + s.blockSize100k as u8);
627        }
628
629        if s.nblock > 0 {
630            let mut writer = LiveWriter::new(&mut s.writer, s.arr2.zbits(s.nblock as usize));
631
632            writer.write_u8(0x31);
633            writer.write_u8(0x41);
634            writer.write_u8(0x59);
635            writer.write_u8(0x26);
636            writer.write_u8(0x53);
637            writer.write_u8(0x59);
638
639            /*-- Now the block's CRC, so it is in a known place. --*/
640            writer.write_u32(s.blockCRC);
641
642            /*--
643               Now a single bit indicating (non-)randomisation.
644               As of version 0.9.5, we use a better sorting algorithm
645               which makes randomisation unnecessary.  So always set
646               the randomised bit to 'no'.  Of course, the decoder
647               still needs to be able to handle randomised blocks
648               so as to maintain backwards compatibility with
649               older versions of bzip2.
650            --*/
651            writer.write(1, 0);
652
653            writer.write(24, s.origPtr as u32);
654
655            drop(writer);
656
657            generate_mtf_values(s);
658
659            send_mtf_values(s);
660        }
661    }
662
663    /*-- If this is the last block, add the stream trailer. --*/
664    if is_last_block {
665        let mut writer = LiveWriter::new(&mut s.writer, s.arr2.zbits(s.nblock as usize));
666
667        writer.write_u8(0x17);
668        writer.write_u8(0x72);
669        writer.write_u8(0x45);
670        writer.write_u8(0x38);
671        writer.write_u8(0x50);
672        writer.write_u8(0x90);
673        writer.write_u32(s.combinedCRC);
674
675        if s.verbosity >= 2 {
676            debug_log!("    final combined CRC = 0x{:08x}\n   ", s.combinedCRC);
677        }
678
679        writer.finish();
680    }
681}