1use core::ffi::{c_char, c_int, c_uint, c_void};
2use core::mem::offset_of;
3use core::{mem, ptr};
4
5use crate::allocator::Allocator;
6use crate::compress::compress_block;
7use crate::crctable::BZ2_CRC32TABLE;
8use crate::debug_log;
9use crate::decompress::{self, decompress};
10#[cfg(feature = "stdio")]
11use crate::libbz2_rs_sys_version;
12
13#[cfg(feature = "stdio")]
14pub use crate::high_level::*;
15
16pub(crate) const BZ_MAX_ALPHA_SIZE: usize = 258;
17pub(crate) const BZ_MAX_CODE_LEN: usize = 23;
18
19pub(crate) const BZ_N_GROUPS: usize = 6;
20pub(crate) const BZ_N_ITERS: usize = 4;
21
22pub(crate) const BZ_G_SIZE: usize = 50;
23pub(crate) const BZ_MAX_SELECTORS: u16 = {
24 let tmp = 2 + (900000 / BZ_G_SIZE);
25 assert!(tmp >> 16 == 0);
26 tmp as u16
27};
28
29pub(crate) const BZ_RUNA: u16 = 0;
30pub(crate) const BZ_RUNB: u16 = 1;
31
32pub(crate) const BZ_MAX_UNUSED_U32: u32 = 5000;
33
34#[cfg(doc)]
35use crate::{
36 BZ_CONFIG_ERROR, BZ_DATA_ERROR, BZ_DATA_ERROR_MAGIC, BZ_FINISH, BZ_FINISH_OK, BZ_FLUSH,
37 BZ_FLUSH_OK, BZ_IO_ERROR, BZ_MEM_ERROR, BZ_OK, BZ_OUTBUFF_FULL, BZ_PARAM_ERROR, BZ_RUN,
38 BZ_RUN_OK, BZ_SEQUENCE_ERROR, BZ_STREAM_END, BZ_UNEXPECTED_EOF,
39};
40
41#[cfg(feature = "custom-prefix")]
42macro_rules! prefix {
43 ($name:expr) => {
44 concat!(env!("LIBBZ2_RS_SYS_PREFIX"), stringify!($name))
45 };
46}
47
48const _PRE_ONE_DOT_O: () = assert!(env!("CARGO_PKG_VERSION_MAJOR").as_bytes()[0] == b'0');
51
52#[cfg(feature = "semver-prefix")]
53macro_rules! prefix {
54 ($name:expr) => {
55 concat!(
56 "LIBBZ2_RS_SYS_v",
57 env!("CARGO_PKG_VERSION_MAJOR"),
58 ".",
59 env!("CARGO_PKG_VERSION_MINOR"),
60 ".x_",
61 stringify!($name)
62 )
63 };
64}
65
66#[cfg(all(
67 not(feature = "custom-prefix"),
68 not(feature = "semver-prefix"),
69 not(any(test, feature = "testing-prefix"))
70))]
71macro_rules! prefix {
72 ($name:expr) => {
73 stringify!($name)
74 };
75}
76
77#[cfg(all(
78 not(feature = "custom-prefix"),
79 not(feature = "semver-prefix"),
80 any(test, feature = "testing-prefix")
81))]
82macro_rules! prefix {
83 ($name:expr) => {
84 concat!("LIBBZ2_RS_SYS_TEST_", stringify!($name))
85 };
86}
87
88pub(crate) use prefix;
89
90#[doc = libbz2_rs_sys_version!()]
96#[cfg_attr(feature = "export-symbols", export_name = prefix!(BZ2_bzlibVersion))]
101#[cfg(feature = "stdio")]
102pub const extern "C" fn BZ2_bzlibVersion() -> *const core::ffi::c_char {
103 const LIBBZ2_RS_SYS_VERSION: &str = concat!(libbz2_rs_sys_version!(), "\0");
104 LIBBZ2_RS_SYS_VERSION.as_ptr().cast::<core::ffi::c_char>()
105}
106
107type AllocFunc = unsafe extern "C" fn(*mut c_void, c_int, c_int) -> *mut c_void;
108type FreeFunc = unsafe extern "C" fn(*mut c_void, *mut c_void) -> ();
109
110#[allow(non_camel_case_types)]
146#[repr(C)]
147pub struct bz_stream {
148 pub next_in: *const c_char,
149 pub avail_in: c_uint,
150 pub total_in_lo32: c_uint,
151 pub total_in_hi32: c_uint,
152 pub next_out: *mut c_char,
153 pub avail_out: c_uint,
154 pub total_out_lo32: c_uint,
155 pub total_out_hi32: c_uint,
156 pub state: *mut c_void,
157 pub bzalloc: Option<AllocFunc>,
158 pub bzfree: Option<FreeFunc>,
159 pub opaque: *mut c_void,
160}
161
162pub(crate) use stream::*;
163mod stream {
164 use super::*;
165
166 #[repr(C)]
167 pub(crate) struct BzStream<S: StreamState> {
168 pub next_in: *const c_char,
169 pub avail_in: c_uint,
170 pub total_in_lo32: c_uint,
171 pub total_in_hi32: c_uint,
172 pub next_out: *mut c_char,
173 pub avail_out: c_uint,
174 pub total_out_lo32: c_uint,
175 pub total_out_hi32: c_uint,
176 pub state: *mut S,
177 pub bzalloc: Option<AllocFunc>,
178 pub bzfree: Option<FreeFunc>,
179 pub opaque: *mut c_void,
180 }
181
182 macro_rules! check_layout {
183 ($($field:ident,)*) => {
184 const _: () = {
185 $(assert!(offset_of!(bz_stream, $field) == offset_of!(BzStream<DState>, $field));)*
186 $(assert!(offset_of!(bz_stream, $field) == offset_of!(BzStream<EState>, $field));)*
187 };
188 };
189}
190
191 check_layout!(
192 next_in,
193 avail_in,
194 total_in_lo32,
195 total_in_hi32,
196 next_out,
197 avail_out,
198 total_out_lo32,
199 total_out_hi32,
200 state,
201 bzalloc,
202 bzfree,
203 opaque,
204 );
205
206 pub(crate) trait StreamState {}
207
208 impl StreamState for EState {}
209 impl StreamState for DState {}
210
211 impl bz_stream {
212 pub const fn zeroed() -> Self {
213 Self {
214 next_in: ptr::null_mut::<c_char>(),
215 avail_in: 0,
216 total_in_lo32: 0,
217 total_in_hi32: 0,
218 next_out: ptr::null_mut::<c_char>(),
219 avail_out: 0,
220 total_out_lo32: 0,
221 total_out_hi32: 0,
222 state: ptr::null_mut::<c_void>(),
223 bzalloc: None,
224 bzfree: None,
225 opaque: ptr::null_mut::<c_void>(),
226 }
227 }
228 }
229
230 impl<S: StreamState> BzStream<S> {
231 pub(crate) const fn zeroed() -> Self {
232 Self {
233 next_in: ptr::null_mut::<c_char>(),
234 avail_in: 0,
235 total_in_lo32: 0,
236 total_in_hi32: 0,
237 next_out: ptr::null_mut::<c_char>(),
238 avail_out: 0,
239 total_out_lo32: 0,
240 total_out_hi32: 0,
241 state: ptr::null_mut::<S>(),
242 bzalloc: None,
243 bzfree: None,
244 opaque: ptr::null_mut::<c_void>(),
245 }
246 }
247
248 pub(crate) unsafe fn from_mut(s: &mut bz_stream) -> &mut Self {
254 unsafe { mem::transmute(s) }
255 }
256
257 pub(crate) unsafe fn from_ptr<'a>(p: *mut bz_stream) -> Option<&'a mut Self> {
263 unsafe { p.cast::<Self>().as_mut() }
264 }
265
266 pub(super) fn allocator(&self) -> Option<Allocator> {
267 unsafe { Allocator::from_bz_stream(self) }
268 }
269
270 #[must_use]
274 #[inline(always)]
275 pub(crate) fn pull_u64(
276 &mut self,
277 mut bit_buffer: u64,
278 bits_used: i32,
279 ) -> Option<(u64, i32)> {
280 debug_assert!(bits_used <= 56);
282
283 if self.avail_in < 8 {
284 return None;
285 }
286
287 let read = u64::from_be_bytes(unsafe { self.next_in.cast::<[u8; 8]>().read() });
289
290 let increment_bits = (63 - bits_used) & !7;
294
295 bit_buffer = (bit_buffer << increment_bits) | (read >> (64 - increment_bits));
297
298 let increment_bytes = increment_bits / 8;
300 self.next_in = unsafe { (self.next_in).add(increment_bytes as usize) };
301 self.avail_in -= increment_bytes as u32;
302
303 Some((bit_buffer, bits_used + increment_bits))
306 }
307
308 #[must_use]
312 #[inline(always)]
313 pub(crate) fn pull_u8(
314 &mut self,
315 mut bit_buffer: u64,
316 bits_used: i32,
317 ) -> Option<(u64, i32)> {
318 debug_assert!(bits_used <= 56);
320
321 if self.avail_in == 0 || bits_used > 56 {
322 return None;
323 }
324
325 let read = unsafe { self.next_in.cast::<u8>().read() };
326 bit_buffer <<= 8;
327 bit_buffer |= u64::from(read);
328
329 self.next_in = unsafe { (self.next_in).offset(1) };
330 self.avail_in -= 1;
331
332 Some((bit_buffer, bits_used + 8))
335 }
336
337 #[must_use]
338 pub(crate) fn read_byte(&mut self) -> Option<u8> {
339 if self.avail_in == 0 {
340 return None;
341 }
342 let b = unsafe { self.next_in.cast::<u8>().read() };
343 self.next_in = unsafe { (self.next_in).offset(1) };
344 self.avail_in -= 1;
345 self.total_in_lo32 = (self.total_in_lo32).wrapping_add(1);
346 if self.total_in_lo32 == 0 {
347 self.total_in_hi32 = (self.total_in_hi32).wrapping_add(1);
348 }
349 Some(b)
350 }
351
352 #[must_use]
353 pub(super) fn write_byte(&mut self, byte: u8) -> bool {
354 if self.avail_out == 0 {
355 return false;
356 }
357 unsafe {
358 *self.next_out = byte as c_char;
359 }
360 self.avail_out -= 1;
361 self.next_out = unsafe { (self.next_out).offset(1) };
362 self.total_out_lo32 = (self.total_out_lo32).wrapping_add(1);
363 if self.total_out_lo32 == 0 {
364 self.total_out_hi32 = (self.total_out_hi32).wrapping_add(1);
365 }
366 true
367 }
368 }
369
370 pub(super) fn configure_allocator<S: StreamState>(strm: &mut BzStream<S>) -> Option<Allocator> {
371 match (strm.bzalloc, strm.bzfree) {
372 (Some(allocate), Some(deallocate)) => {
373 Some(Allocator::custom(allocate, deallocate, strm.opaque))
374 }
375 (None, None) => {
376 let allocator = Allocator::DEFAULT?;
377 let (bzalloc, bzfree) = Allocator::default_function_pointers()?;
378
379 strm.bzalloc = Some(bzalloc);
380 strm.bzfree = Some(bzfree);
381
382 Some(allocator)
383 }
384 #[cfg(any(feature = "rust-allocator", not(feature = "c-allocator")))]
389 _ => None,
390
391 #[cfg(all(feature = "c-allocator", not(feature = "rust-allocator")))]
392 _ => {
393 let (default_bzalloc, default_bzfree) = crate::allocator::c_allocator::ALLOCATOR;
400
401 let bzalloc = strm.bzalloc.get_or_insert(default_bzalloc);
402 let bzfree = strm.bzfree.get_or_insert(default_bzfree);
403
404 Some(Allocator::custom(*bzalloc, *bzfree, strm.opaque))
405 }
406 }
407 }
408}
409
410#[repr(i32)]
411#[derive(Debug, Clone, Copy, PartialEq, Eq)]
412#[allow(non_camel_case_types)]
413pub(crate) enum ReturnCode {
414 BZ_OK = 0,
415 BZ_RUN_OK = 1,
416 BZ_FLUSH_OK = 2,
417 BZ_FINISH_OK = 3,
418 BZ_STREAM_END = 4,
419 BZ_SEQUENCE_ERROR = -1,
420 BZ_PARAM_ERROR = -2,
421 BZ_MEM_ERROR = -3,
422 BZ_DATA_ERROR = -4,
423 BZ_DATA_ERROR_MAGIC = -5,
424 BZ_IO_ERROR = -6,
425 BZ_UNEXPECTED_EOF = -7,
426 BZ_OUTBUFF_FULL = -8,
427 BZ_CONFIG_ERROR = -9,
428}
429
430#[repr(u8)]
431#[derive(Copy, Clone)]
432pub(crate) enum Mode {
433 Idle,
434 Running,
435 Flushing,
436 Finishing,
437}
438
439#[repr(u8)]
440#[derive(Copy, Clone)]
441pub(crate) enum State {
442 Output,
443 Input,
444}
445
446pub(crate) const BZ_N_RADIX: u32 = 2;
447pub(crate) const BZ_N_QSORT: u32 = 12;
448pub(crate) const BZ_N_SHELL: u32 = 18;
449pub(crate) const BZ_N_OVERSHOOT: usize = (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) as usize;
450
451pub(crate) const FTAB_LEN: usize = u16::MAX as usize + 2;
452
453pub(crate) struct EState {
454 pub strm_addr: usize, pub mode: Mode,
456 pub state: State,
457 pub avail_in_expect: u32,
458 pub arr1: Arr1,
459 pub arr2: Arr2,
460 pub ftab: Ftab,
461 pub origPtr: i32,
462 pub writer: crate::compress::EWriter,
463 pub workFactor: i32,
464 pub state_in_ch: u32,
465 pub state_in_len: i32,
466 pub nblock: i32,
467 pub nblockMAX: i32,
468 pub state_out_pos: i32,
469 pub nInUse: i32,
470 pub inUse: [bool; 256],
471 pub unseqToSeq: [u8; 256],
472 pub blockCRC: u32,
473 pub combinedCRC: u32,
474 pub verbosity: i32,
475 pub blockNo: i32,
476 pub blockSize100k: i32,
477 pub nMTF: i32,
478 pub mtfFreq: [i32; 258],
479 pub selector: [u8; 18002],
480 pub selectorMtf: [u8; 18002],
481 pub len: [[u8; BZ_MAX_ALPHA_SIZE]; BZ_N_GROUPS],
482 pub code: [[u32; 258]; 6],
483 pub rfreq: [[i32; 258]; 6],
484 pub len_pack: [[u32; 4]; 258],
485}
486
487pub(crate) fn dangling<T>() -> *mut T {
489 ptr::null_mut::<T>().wrapping_add(mem::align_of::<T>())
490}
491
492pub(crate) struct Arr1 {
493 ptr: *mut u32,
494 len: usize,
495}
496
497impl Arr1 {
498 fn alloc(allocator: &Allocator, len: usize) -> Option<Self> {
499 let ptr = allocator.allocate_zeroed(len)?;
500 Some(Self { ptr, len })
501 }
502
503 unsafe fn dealloc(&mut self, allocator: &Allocator) {
504 let this = mem::replace(
505 self,
506 Self {
507 ptr: dangling(),
508 len: 0,
509 },
510 );
511 if this.len != 0 {
512 unsafe { allocator.deallocate(this.ptr, this.len) }
513 }
514 }
515
516 pub(crate) fn mtfv(&mut self) -> &mut [u16] {
517 unsafe { core::slice::from_raw_parts_mut(self.ptr.cast(), self.len * 2) }
518 }
519
520 pub(crate) fn ptr(&mut self) -> &mut [u32] {
521 unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
522 }
523}
524
525pub(crate) struct Arr2 {
526 ptr: *mut u32,
527 len: usize,
528}
529
530impl Arr2 {
531 fn alloc(allocator: &Allocator, len: usize) -> Option<Self> {
532 let ptr = allocator.allocate_zeroed(len)?;
533 Some(Self { ptr, len })
534 }
535
536 unsafe fn dealloc(&mut self, allocator: &Allocator) {
537 let this = mem::replace(
538 self,
539 Self {
540 ptr: dangling(),
541 len: 0,
542 },
543 );
544 if this.len != 0 {
545 unsafe { allocator.deallocate(this.ptr, this.len) }
546 }
547 }
548
549 pub(crate) fn eclass(&mut self) -> &mut [u32] {
550 unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
551 }
552
553 pub(crate) fn zbits(&mut self, nblock: usize) -> &mut [u8] {
554 assert!(nblock <= 4 * self.len);
555 unsafe {
556 core::slice::from_raw_parts_mut(
557 self.ptr.cast::<u8>().add(nblock),
558 self.len * 4 - nblock,
559 )
560 }
561 }
562
563 pub(crate) fn raw_block(&mut self) -> &mut [u8] {
564 unsafe { core::slice::from_raw_parts_mut(self.ptr.cast(), self.len * 4) }
565 }
566
567 pub(crate) fn block(&mut self, nblock: usize) -> &mut [u8] {
568 assert!(nblock <= 4 * self.len);
569 unsafe { core::slice::from_raw_parts_mut(self.ptr.cast(), nblock) }
570 }
571
572 pub(crate) fn block_and_quadrant(&mut self, nblock: usize) -> (&mut [u8], &mut [u16]) {
573 let len = nblock + BZ_N_OVERSHOOT;
574 assert!(3 * len.next_multiple_of(2) <= 4 * self.len);
575
576 let block = unsafe { core::slice::from_raw_parts_mut(self.ptr.cast(), len) };
577
578 let start_byte = len.next_multiple_of(2);
579 let quadrant: *mut u16 = unsafe { self.ptr.cast::<u16>().byte_add(start_byte) };
580 let quadrant = unsafe { core::slice::from_raw_parts_mut(quadrant, len) };
581 quadrant.fill(0);
582
583 (block, quadrant)
584 }
585}
586
587pub(crate) struct Ftab {
588 ptr: *mut u32,
589}
590
591impl Ftab {
592 fn alloc(allocator: &Allocator) -> Option<Self> {
593 let ptr = allocator.allocate_zeroed(FTAB_LEN)?;
594 Some(Self { ptr })
595 }
596
597 unsafe fn dealloc(&mut self, allocator: &Allocator) {
598 let this = mem::replace(
599 self,
600 Self {
601 ptr: ptr::null_mut(),
602 },
603 );
604 if !this.ptr.is_null() {
605 unsafe { allocator.deallocate(this.ptr, FTAB_LEN) }
606 }
607 }
608
609 pub(crate) fn ftab(&mut self) -> &mut [u32; FTAB_LEN] {
610 unsafe { self.ptr.cast::<[u32; FTAB_LEN]>().as_mut().unwrap() }
612 }
613}
614
615#[repr(C)]
616pub(crate) struct DState {
617 pub strm_addr: usize, pub state: decompress::State,
619 pub state_out_len: u32,
620 pub state_out_ch: u8,
621 pub blockRandomised: bool,
622 pub blockSize100k: u8,
623 pub k0: u8,
624 pub bsBuff: u64,
625 pub bsLive: i32,
626 pub rNToGo: u16,
627 pub rTPos: u16,
628 pub smallDecompress: DecompressMode,
629 pub currBlockNo: i32,
630 pub verbosity: i32,
631 pub origPtr: i32,
632 pub tPos: u32,
633 pub nblock_used: i32,
634 pub unzftab: [u32; 256],
635 pub cftab: [u32; 257],
636 pub cftabCopy: [u32; 257],
637 pub tt: DSlice<u32>,
638 pub ll16: DSlice<u16>,
639 pub ll4: DSlice<u8>,
640 pub storedBlockCRC: u32,
641 pub storedCombinedCRC: u32,
642 pub calculatedBlockCRC: u32,
643 pub calculatedCombinedCRC: u32,
644 pub nInUse: u16,
645 pub inUse: [bool; 256],
646 pub inUse16: [bool; 16],
647 pub seqToUnseq: [u8; 256],
648 pub mtfa: [u8; 4096],
649 pub mtfbase: [u16; 16],
650 pub selector: [u8; 18002],
651 pub selectorMtf: [u8; 18002],
652 pub len: [[u8; 258]; 6],
653 pub limit: [[i32; 258]; 6],
654 pub base: [[i32; 258]; 6],
655 pub perm: [[u16; 258]; 6],
656 pub minLens: [u8; 6],
657 pub save: SaveArea,
658}
659
660#[derive(Default)]
661#[repr(C)]
662pub(crate) struct SaveArea {
663 pub i: i32,
664 pub j: i32,
665 pub alphaSize: u16,
666 pub EOB: u16,
667 pub groupNo: i32,
668 pub nblock: u32,
669 pub es: u32,
670 pub zvec: i32,
671 pub nextSym: u16,
672 pub nSelectors: u16,
673 pub groupPos: u8,
674 pub zn: u8,
675 pub nGroups: u8,
676 pub t: u8,
677 pub curr: u8,
678 pub nblockMAX100k: u8,
679 pub logN: u8, pub zj: bool,
681 pub gMinlen: u8,
682 pub gSel: u8,
683}
684
685pub(crate) struct DSlice<T> {
686 ptr: *mut T,
687 len: usize,
688}
689
690impl<T> DSlice<T> {
691 fn new() -> Self {
692 Self {
693 ptr: dangling(),
694 len: 0,
695 }
696 }
697
698 pub(crate) fn alloc(allocator: &Allocator, len: usize) -> Option<Self> {
699 let ptr = allocator.allocate_zeroed::<T>(len)?;
700 Some(Self { ptr, len })
701 }
702
703 pub(crate) unsafe fn dealloc(&mut self, allocator: &Allocator) {
704 let this = mem::replace(self, Self::new());
705 if this.len != 0 {
706 unsafe { allocator.deallocate(this.ptr, this.len) }
707 }
708 }
709
710 pub(crate) fn as_slice(&self) -> &[T] {
711 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
712 }
713
714 pub(crate) fn as_mut_slice(&mut self) -> &mut [T] {
715 unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
716 }
717}
718
719const _C_INT_SIZE: () = assert!(core::mem::size_of::<core::ffi::c_int>() == 4);
720const _C_SHORT_SIZE: () = assert!(core::mem::size_of::<core::ffi::c_short>() == 2);
721const _C_CHAR_SIZE: () = assert!(core::mem::size_of::<core::ffi::c_char>() == 1);
722
723fn prepare_new_block(s: &mut EState) {
724 s.nblock = 0;
725 s.writer.num_z = 0;
726 s.state_out_pos = 0;
727 s.blockCRC = 0xffffffff;
728 s.inUse.fill(false);
729 s.blockNo += 1;
730}
731
732fn init_rl(s: &mut EState) {
733 s.state_in_ch = 256 as c_int as u32;
734 s.state_in_len = 0 as c_int;
735}
736
737fn isempty_rl(s: &mut EState) -> bool {
738 !(s.state_in_ch < 256 && s.state_in_len > 0)
739}
740
741#[cfg_attr(feature = "export-symbols", export_name = prefix!(BZ2_bzCompressInit))]
766pub unsafe extern "C" fn BZ2_bzCompressInit(
767 strm: *mut bz_stream,
768 blockSize100k: c_int,
769 verbosity: c_int,
770 workFactor: c_int,
771) -> c_int {
772 let Some(strm) = (unsafe { BzStream::from_ptr(strm) }) else {
773 return ReturnCode::BZ_PARAM_ERROR as c_int;
774 };
775 BZ2_bzCompressInitHelp(strm, blockSize100k, verbosity, workFactor) as c_int
776}
777
778pub(crate) fn BZ2_bzCompressInitHelp(
779 strm: &mut BzStream<EState>,
780 blockSize100k: c_int,
781 verbosity: c_int,
782 mut workFactor: c_int,
783) -> ReturnCode {
784 if !(1..=9).contains(&blockSize100k) || !(0..=250).contains(&workFactor) {
785 return ReturnCode::BZ_PARAM_ERROR;
786 }
787
788 if workFactor == 0 {
789 workFactor = 30;
790 }
791
792 let Some(allocator) = configure_allocator(strm) else {
794 return ReturnCode::BZ_PARAM_ERROR;
795 };
796
797 let Some(s) = allocator.allocate_zeroed::<EState>(1) else {
798 return ReturnCode::BZ_MEM_ERROR;
799 };
800
801 unsafe { (*s).strm_addr = strm as *const _ as usize }; let n = 100000 * blockSize100k;
806
807 let arr1_len = n as usize;
808 let arr1 = Arr1::alloc(&allocator, arr1_len);
809
810 let arr2_len = n as usize + BZ_N_OVERSHOOT;
811 let arr2 = Arr2::alloc(&allocator, arr2_len);
812
813 let ftab = Ftab::alloc(&allocator);
814
815 match (arr1, arr2, ftab) {
816 (Some(arr1), Some(arr2), Some(ftab)) => unsafe {
817 (*s).arr1 = arr1;
818 (*s).arr2 = arr2;
819 (*s).ftab = ftab;
820 },
821 (arr1, arr2, ftab) => {
822 if let Some(mut arr1) = arr1 {
823 unsafe { arr1.dealloc(&allocator) };
824 }
825
826 if let Some(mut arr2) = arr2 {
827 unsafe { arr2.dealloc(&allocator) };
828 }
829
830 if let Some(mut ftab) = ftab {
831 unsafe { ftab.dealloc(&allocator) };
832 }
833
834 unsafe { allocator.deallocate(s, 1) };
835
836 return ReturnCode::BZ_MEM_ERROR;
837 }
838 };
839
840 strm.state = s;
841
842 let s = unsafe { &mut *s };
848
849 s.blockNo = 0;
850 s.state = State::Output;
851 s.mode = Mode::Running;
852 s.combinedCRC = 0;
853 s.blockSize100k = blockSize100k;
854 s.nblockMAX = 100000 * blockSize100k - 19;
855 s.verbosity = verbosity;
856 s.workFactor = workFactor;
857
858 strm.total_in_lo32 = 0;
859 strm.total_in_hi32 = 0;
860 strm.total_out_lo32 = 0;
861 strm.total_out_hi32 = 0;
862
863 init_rl(s);
864 prepare_new_block(s);
865
866 ReturnCode::BZ_OK
867}
868
869macro_rules! BZ_UPDATE_CRC {
870 ($crcVar:expr, $cha:expr) => {
871 let index = ($crcVar >> 24) ^ ($cha as core::ffi::c_uint);
872 $crcVar = ($crcVar << 8) ^ BZ2_CRC32TABLE[index as usize];
873 };
874}
875
876fn add_pair_to_block(s: &mut EState) {
877 let ch: u8 = s.state_in_ch as u8;
878
879 for _ in 0..s.state_in_len {
880 BZ_UPDATE_CRC!(s.blockCRC, ch);
881 }
882
883 let block = s.arr2.raw_block();
884 s.inUse[s.state_in_ch as usize] = true;
885 match s.state_in_len {
886 1 => {
887 block[s.nblock as usize..][..1].fill(ch);
888 s.nblock += 1;
889 }
890 2 => {
891 block[s.nblock as usize..][..2].fill(ch);
892 s.nblock += 2;
893 }
894 3 => {
895 block[s.nblock as usize..][..3].fill(ch);
896 s.nblock += 3;
897 }
898 _ => {
899 s.inUse[(s.state_in_len - 4) as usize] = true;
900
901 block[s.nblock as usize..][..4].fill(ch);
902 s.nblock += 4;
903
904 block[s.nblock as usize] = (s.state_in_len - 4) as u8;
905 s.nblock += 1;
906 }
907 };
908}
909
910fn flush_rl(s: &mut EState) {
911 if s.state_in_ch < 256 {
912 add_pair_to_block(s);
913 }
914 init_rl(s);
915}
916
917macro_rules! ADD_CHAR_TO_BLOCK {
918 ($zs:expr, $zchh0:expr) => {
919 let zchh: u32 = $zchh0 as u32;
920
921 if zchh != $zs.state_in_ch && $zs.state_in_len == 1 {
922 let ch: u8 = $zs.state_in_ch as u8;
925 BZ_UPDATE_CRC!($zs.blockCRC, ch);
926 $zs.inUse[$zs.state_in_ch as usize] = true;
927 $zs.arr2.raw_block()[$zs.nblock as usize] = ch;
928 $zs.nblock += 1;
929 $zs.nblock;
930 $zs.state_in_ch = zchh;
931 } else if zchh != $zs.state_in_ch || $zs.state_in_len == 255 {
932 if $zs.state_in_ch < 256 {
935 add_pair_to_block($zs);
936 }
937 $zs.state_in_ch = zchh;
938 $zs.state_in_len = 1;
939 } else {
940 $zs.state_in_len += 1;
941 }
942 };
943}
944
945fn copy_input_until_stop(strm: &mut BzStream<EState>, s: &mut EState) -> bool {
946 let mut progress_in = false;
947
948 match s.mode {
949 Mode::Running => loop {
950 if s.nblock >= s.nblockMAX {
951 break;
952 }
953 if let Some(b) = strm.read_byte() {
954 progress_in = true;
955 ADD_CHAR_TO_BLOCK!(s, b as u32);
956 } else {
957 break;
958 }
959 },
960 Mode::Idle | Mode::Flushing | Mode::Finishing => loop {
961 if s.nblock >= s.nblockMAX {
962 break;
963 }
964 if s.avail_in_expect == 0 {
965 break;
966 }
967 if let Some(b) = strm.read_byte() {
968 progress_in = true;
969 ADD_CHAR_TO_BLOCK!(s, b as u32);
970 } else {
971 break;
972 }
973 s.avail_in_expect -= 1;
974 },
975 }
976 progress_in
977}
978
979fn copy_output_until_stop(strm: &mut BzStream<EState>, s: &mut EState) -> bool {
980 let mut progress_out = false;
981
982 let zbits = &mut s.arr2.raw_block()[s.nblock as usize..];
983
984 loop {
985 if s.state_out_pos >= s.writer.num_z as i32 {
986 break;
987 }
988 if !strm.write_byte(zbits[s.state_out_pos as usize]) {
989 break;
990 }
991 progress_out = true;
992 s.state_out_pos += 1;
993 }
994 progress_out
995}
996
997fn handle_compress(strm: &mut BzStream<EState>, s: &mut EState) -> bool {
998 let mut progress_in = false;
999 let mut progress_out = false;
1000
1001 loop {
1002 if let State::Input = s.state {
1003 progress_out |= copy_output_until_stop(strm, s);
1004 if s.state_out_pos < s.writer.num_z as i32 {
1005 break;
1006 }
1007 if matches!(s.mode, Mode::Finishing) && s.avail_in_expect == 0 && isempty_rl(s) {
1008 break;
1009 }
1010 prepare_new_block(s);
1011 s.state = State::Output;
1012 if matches!(s.mode, Mode::Flushing) && s.avail_in_expect == 0 && isempty_rl(s) {
1013 break;
1014 }
1015 }
1016 if let State::Input = s.state {
1017 continue;
1018 }
1019 progress_in |= copy_input_until_stop(strm, s);
1020 if !matches!(s.mode, Mode::Running) && s.avail_in_expect == 0 {
1021 flush_rl(s);
1022 let is_last_block = matches!(s.mode, Mode::Finishing);
1023 compress_block(s, is_last_block);
1024 s.state = State::Input;
1025 } else if s.nblock >= s.nblockMAX {
1026 compress_block(s, false);
1027 s.state = State::Input;
1028 } else if strm.avail_in == 0 {
1029 break;
1030 }
1031 }
1032
1033 progress_in || progress_out
1034}
1035
1036pub(crate) enum Action {
1037 Run = 0,
1038 Flush = 1,
1039 Finish = 2,
1040}
1041
1042impl TryFrom<i32> for Action {
1043 type Error = ();
1044
1045 fn try_from(value: i32) -> Result<Self, Self::Error> {
1046 match value {
1047 0 => Ok(Self::Run),
1048 1 => Ok(Self::Flush),
1049 2 => Ok(Self::Finish),
1050 _ => Err(()),
1051 }
1052 }
1053}
1054
1055#[cfg_attr(feature = "export-symbols", export_name = prefix!(BZ2_bzCompress))]
1084pub unsafe extern "C" fn BZ2_bzCompress(strm: *mut bz_stream, action: c_int) -> c_int {
1085 let Some(strm) = (unsafe { BzStream::from_ptr(strm) }) else {
1086 return ReturnCode::BZ_PARAM_ERROR as c_int;
1087 };
1088
1089 BZ2_bzCompressHelp(strm, action) as c_int
1090}
1091
1092pub(crate) fn BZ2_bzCompressHelp(strm: &mut BzStream<EState>, action: i32) -> ReturnCode {
1093 let Some(s) = (unsafe { strm.state.as_mut() }) else {
1094 return ReturnCode::BZ_PARAM_ERROR;
1095 };
1096
1097 if s.strm_addr != strm as *mut _ as usize {
1099 return ReturnCode::BZ_PARAM_ERROR;
1100 }
1101
1102 compress_loop(strm, s, action)
1103}
1104
1105fn compress_loop(strm: &mut BzStream<EState>, s: &mut EState, action: i32) -> ReturnCode {
1106 loop {
1107 match s.mode {
1108 Mode::Idle => return ReturnCode::BZ_SEQUENCE_ERROR,
1109 Mode::Running => match Action::try_from(action) {
1110 Ok(Action::Run) => {
1111 let progress = handle_compress(strm, s);
1112 return if progress {
1113 ReturnCode::BZ_RUN_OK
1114 } else {
1115 ReturnCode::BZ_PARAM_ERROR
1116 };
1117 }
1118 Ok(Action::Flush) => {
1119 s.avail_in_expect = strm.avail_in;
1120 s.mode = Mode::Flushing;
1121 }
1122 Ok(Action::Finish) => {
1123 s.avail_in_expect = strm.avail_in;
1124 s.mode = Mode::Finishing;
1125 }
1126 Err(()) => {
1127 return ReturnCode::BZ_PARAM_ERROR;
1128 }
1129 },
1130 Mode::Flushing => {
1131 let Ok(Action::Flush) = Action::try_from(action) else {
1132 return ReturnCode::BZ_SEQUENCE_ERROR;
1133 };
1134 if s.avail_in_expect != strm.avail_in {
1135 return ReturnCode::BZ_SEQUENCE_ERROR;
1136 }
1137 handle_compress(strm, s);
1138 if s.avail_in_expect > 0
1139 || !isempty_rl(s)
1140 || s.state_out_pos < s.writer.num_z as i32
1141 {
1142 return ReturnCode::BZ_FLUSH_OK;
1143 }
1144 s.mode = Mode::Running;
1145 return ReturnCode::BZ_RUN_OK;
1146 }
1147 Mode::Finishing => {
1148 let Ok(Action::Finish) = Action::try_from(action) else {
1149 return ReturnCode::BZ_SEQUENCE_ERROR;
1151 };
1152 if s.avail_in_expect != strm.avail_in {
1153 return ReturnCode::BZ_SEQUENCE_ERROR;
1155 }
1156 let progress = handle_compress(strm, s);
1157 if !progress {
1158 return ReturnCode::BZ_SEQUENCE_ERROR;
1159 }
1160 if s.avail_in_expect > 0
1161 || !isempty_rl(s)
1162 || s.state_out_pos < s.writer.num_z as i32
1163 {
1164 return ReturnCode::BZ_FINISH_OK;
1165 }
1166 s.mode = Mode::Idle;
1167 return ReturnCode::BZ_STREAM_END;
1168 }
1169 }
1170 }
1171}
1172
1173#[cfg_attr(feature = "export-symbols", export_name = prefix!(BZ2_bzCompressEnd))]
1189pub unsafe extern "C" fn BZ2_bzCompressEnd(strm: *mut bz_stream) -> c_int {
1190 let Some(strm) = (unsafe { BzStream::from_ptr(strm) }) else {
1191 return ReturnCode::BZ_PARAM_ERROR as c_int;
1192 };
1193 BZ2_bzCompressEndHelp(strm)
1194}
1195
1196fn BZ2_bzCompressEndHelp(strm: &mut BzStream<EState>) -> c_int {
1197 let Some(s) = (unsafe { strm.state.as_mut() }) else {
1198 return ReturnCode::BZ_PARAM_ERROR as c_int;
1199 };
1200
1201 if s.strm_addr != strm as *mut _ as usize {
1203 return ReturnCode::BZ_PARAM_ERROR as c_int;
1204 }
1205
1206 let Some(allocator) = strm.allocator() else {
1207 return ReturnCode::BZ_PARAM_ERROR as c_int;
1208 };
1209
1210 unsafe {
1211 s.arr1.dealloc(&allocator);
1212 s.arr2.dealloc(&allocator);
1213 s.ftab.dealloc(&allocator);
1214 }
1215
1216 unsafe {
1217 allocator.deallocate(strm.state.cast::<EState>(), 1);
1218 }
1219 strm.state = ptr::null_mut::<EState>();
1220
1221 ReturnCode::BZ_OK as c_int
1222}
1223
1224pub(crate) enum DecompressMode {
1225 Small,
1226 Fast,
1227}
1228
1229#[cfg_attr(feature = "export-symbols", export_name = prefix!(BZ2_bzDecompressInit))]
1250pub unsafe extern "C" fn BZ2_bzDecompressInit(
1251 strm: *mut bz_stream,
1252 verbosity: c_int,
1253 small: c_int,
1254) -> c_int {
1255 let Some(strm) = (unsafe { BzStream::from_ptr(strm) }) else {
1256 return ReturnCode::BZ_PARAM_ERROR as c_int;
1257 };
1258 BZ2_bzDecompressInitHelp(strm, verbosity, small) as c_int
1259}
1260
1261pub(crate) fn BZ2_bzDecompressInitHelp(
1262 strm: &mut BzStream<DState>,
1263 verbosity: c_int,
1264 small: c_int,
1265) -> ReturnCode {
1266 let decompress_mode = match small {
1267 0 => DecompressMode::Fast,
1268 1 => DecompressMode::Small,
1269 _ => return ReturnCode::BZ_PARAM_ERROR,
1270 };
1271 if !(0..=4).contains(&verbosity) {
1272 return ReturnCode::BZ_PARAM_ERROR;
1273 }
1274
1275 let Some(allocator) = configure_allocator(strm) else {
1277 return ReturnCode::BZ_PARAM_ERROR;
1278 };
1279
1280 let Some(s) = allocator.allocate_zeroed::<DState>(1) else {
1281 return ReturnCode::BZ_MEM_ERROR;
1282 };
1283
1284 unsafe { (*s).strm_addr = strm as *const _ as usize }; unsafe {
1289 (*s).state = decompress::State::BZ_X_MAGIC_1;
1290 (*s).bsLive = 0;
1291 (*s).bsBuff = 0;
1292 (*s).calculatedCombinedCRC = 0;
1293 }
1294
1295 unsafe {
1296 (*s).smallDecompress = decompress_mode;
1297 (*s).ll4 = DSlice::new();
1298 (*s).ll16 = DSlice::new();
1299 (*s).tt = DSlice::new();
1300 (*s).currBlockNo = 0;
1301 (*s).verbosity = verbosity;
1302 }
1303
1304 strm.state = s;
1305
1306 strm.total_in_lo32 = 0;
1307 strm.total_in_hi32 = 0;
1308 strm.total_out_lo32 = 0;
1309 strm.total_out_hi32 = 0;
1310
1311 ReturnCode::BZ_OK
1312}
1313
1314macro_rules! BZ_RAND_MASK {
1315 ($s:expr) => {
1316 ($s.rNToGo == 1) as u8
1317 };
1318}
1319
1320macro_rules! BZ_RAND_UPD_MASK {
1321 ($s:expr) => {
1322 if ($s.rNToGo == 0) {
1323 $s.rNToGo = $crate::randtable::BZ2_RNUMS[$s.rTPos as usize];
1324 $s.rTPos += 1;
1325 if ($s.rTPos == 512) {
1326 $s.rTPos = 0
1327 };
1328 }
1329 $s.rNToGo -= 1;
1330 };
1331}
1332
1333pub(crate) use BZ_RAND_UPD_MASK;
1334
1335macro_rules! BZ_GET_FAST {
1336 ($s:expr) => {
1337 match $s.tt.as_slice().get($s.tPos as usize) {
1338 None => return true,
1339 Some(&bits) => {
1340 $s.tPos = bits;
1341 let tmp = ($s.tPos & 0xff) as u8;
1342 $s.tPos >>= 8;
1343 tmp
1344 }
1345 }
1346 };
1347}
1348
1349fn un_rle_obuf_to_output_fast(strm: &mut BzStream<DState>, s: &mut DState) -> bool {
1350 let mut k1: u8;
1351 if s.blockRandomised {
1352 loop {
1353 loop {
1355 if s.state_out_len == 0 {
1356 if strm.avail_out == 0 {
1357 return false;
1358 } else {
1359 break;
1360 }
1361 }
1362 if !strm.write_byte(s.state_out_ch) {
1363 return false;
1364 }
1365 BZ_UPDATE_CRC!(s.calculatedBlockCRC, s.state_out_ch);
1366 s.state_out_len -= 1;
1367 }
1368
1369 if s.nblock_used == s.save.nblock as i32 + 1 {
1371 return false;
1372 }
1373
1374 if s.nblock_used > s.save.nblock as i32 + 1 {
1376 return true;
1377 }
1378
1379 s.state_out_ch = s.k0;
1380
1381 s.state_out_len = 1;
1382 k1 = BZ_GET_FAST!(s);
1383 BZ_RAND_UPD_MASK!(s);
1384 k1 ^= BZ_RAND_MASK!(s);
1385 s.nblock_used += 1;
1386 if s.nblock_used == s.save.nblock as i32 + 1 {
1387 continue;
1388 };
1389 if k1 != s.k0 {
1390 s.k0 = k1;
1391 continue;
1392 };
1393
1394 s.state_out_len = 2;
1395 k1 = BZ_GET_FAST!(s);
1396 BZ_RAND_UPD_MASK!(s);
1397 k1 ^= BZ_RAND_MASK!(s);
1398 s.nblock_used += 1;
1399 if s.nblock_used == s.save.nblock as i32 + 1 {
1400 continue;
1401 };
1402 if k1 != s.k0 {
1403 s.k0 = k1;
1404 continue;
1405 };
1406
1407 s.state_out_len = 3;
1408 k1 = BZ_GET_FAST!(s);
1409 BZ_RAND_UPD_MASK!(s);
1410 k1 ^= BZ_RAND_MASK!(s);
1411 s.nblock_used += 1;
1412 if s.nblock_used == s.save.nblock as i32 + 1 {
1413 continue;
1414 };
1415 if k1 != s.k0 {
1416 s.k0 = k1;
1417 continue;
1418 };
1419
1420 k1 = BZ_GET_FAST!(s);
1421 BZ_RAND_UPD_MASK!(s);
1422 k1 ^= BZ_RAND_MASK!(s);
1423 s.nblock_used += 1;
1424 s.state_out_len = k1 as u32 + 4;
1425 s.k0 = BZ_GET_FAST!(s);
1426 BZ_RAND_UPD_MASK!(s);
1427 s.k0 ^= BZ_RAND_MASK!(s);
1428 s.nblock_used += 1;
1429 }
1430 } else {
1431 let mut c_calculatedBlockCRC: u32 = s.calculatedBlockCRC;
1433 let mut c_state_out_ch: u8 = s.state_out_ch;
1434 let mut c_state_out_len: u32 = s.state_out_len;
1435 let mut c_nblock_used: i32 = s.nblock_used;
1436 let mut c_k0: u8 = s.k0;
1437 let mut c_tPos: u32 = s.tPos;
1438 let mut cs_next_out: *mut c_char = strm.next_out;
1439 let mut cs_avail_out: c_uint = strm.avail_out;
1440 let ro_blockSize100k: u8 = s.blockSize100k;
1441 let avail_out_INIT: u32 = cs_avail_out;
1444 let s_save_nblockPP: i32 = s.save.nblock as i32 + 1;
1445
1446 let tt = &s.tt.as_slice()[..100000usize.wrapping_mul(usize::from(ro_blockSize100k))];
1447
1448 macro_rules! BZ_GET_FAST_C {
1449 ($c_tPos:expr) => {
1450 match tt.get($c_tPos as usize) {
1451 None => {
1452 return true;
1454 }
1455 Some(&v) => (v >> 8, (v & 0xff) as u8),
1456 }
1457 };
1458 }
1459
1460 'return_notr: loop {
1461 macro_rules! write_one_byte {
1462 ($byte:expr) => {
1463 if cs_avail_out == 0 {
1464 c_state_out_len = 1;
1465 break 'return_notr;
1466 } else {
1467 unsafe { *(cs_next_out as *mut u8) = $byte };
1468 BZ_UPDATE_CRC!(c_calculatedBlockCRC, $byte);
1469 cs_next_out = unsafe { cs_next_out.add(1) };
1470 cs_avail_out -= 1;
1471 }
1472 };
1473 }
1474
1475 if c_state_out_len > 0 {
1476 let bound = Ord::min(cs_avail_out, c_state_out_len);
1477
1478 unsafe {
1479 core::ptr::write_bytes(cs_next_out as *mut u8, c_state_out_ch, bound as usize);
1480 cs_next_out = cs_next_out.add(bound as usize);
1481 };
1482
1483 for _ in 0..bound {
1484 BZ_UPDATE_CRC!(c_calculatedBlockCRC, c_state_out_ch);
1485 }
1486
1487 cs_avail_out -= bound;
1488 c_state_out_len -= bound;
1489
1490 if cs_avail_out == 0 {
1491 break 'return_notr;
1492 }
1493 }
1494
1495 loop {
1496 if c_nblock_used > s_save_nblockPP {
1498 return true;
1499 }
1500
1501 if c_nblock_used == s_save_nblockPP {
1503 c_state_out_len = 0;
1504 break 'return_notr;
1505 }
1506
1507 c_state_out_ch = c_k0;
1508 (c_tPos, k1) = BZ_GET_FAST_C!(c_tPos);
1509 c_nblock_used += 1;
1510
1511 if k1 != c_k0 {
1512 c_k0 = k1;
1513 write_one_byte!(c_state_out_ch);
1514 continue;
1515 }
1516
1517 if c_nblock_used == s_save_nblockPP {
1518 write_one_byte!(c_state_out_ch);
1519 continue;
1520 }
1521
1522 c_state_out_len = 2;
1523 (c_tPos, k1) = BZ_GET_FAST_C!(c_tPos);
1524 c_nblock_used += 1;
1525
1526 if c_nblock_used == s_save_nblockPP {
1527 continue 'return_notr;
1528 }
1529
1530 if k1 != c_k0 {
1531 c_k0 = k1;
1532 continue 'return_notr;
1533 }
1534
1535 c_state_out_len = 3;
1536 (c_tPos, k1) = BZ_GET_FAST_C!(c_tPos);
1537 c_nblock_used += 1;
1538
1539 if c_nblock_used == s_save_nblockPP {
1540 continue 'return_notr;
1541 }
1542
1543 if k1 != c_k0 {
1544 c_k0 = k1;
1545 continue 'return_notr;
1546 }
1547
1548 (c_tPos, k1) = BZ_GET_FAST_C!(c_tPos);
1549 c_nblock_used += 1;
1550 c_state_out_len = k1 as u32 + 4;
1551 (c_tPos, c_k0) = BZ_GET_FAST_C!(c_tPos);
1552 c_nblock_used += 1;
1553
1554 continue 'return_notr;
1555 }
1556 }
1557
1558 let total_out_lo32_old: c_uint = strm.total_out_lo32;
1560 strm.total_out_lo32 =
1561 (strm.total_out_lo32).wrapping_add(avail_out_INIT.wrapping_sub(cs_avail_out));
1562 if strm.total_out_lo32 < total_out_lo32_old {
1563 strm.total_out_hi32 = (strm.total_out_hi32).wrapping_add(1);
1564 }
1565 s.calculatedBlockCRC = c_calculatedBlockCRC;
1566 s.state_out_ch = c_state_out_ch;
1567 s.state_out_len = c_state_out_len;
1568 s.nblock_used = c_nblock_used;
1569 s.k0 = c_k0;
1570 s.tPos = c_tPos;
1571 strm.next_out = cs_next_out;
1572 strm.avail_out = cs_avail_out;
1573 }
1575
1576 false
1577}
1578
1579#[inline]
1580pub(crate) fn index_into_f(index: u32, cftab: &[u32; 257]) -> u8 {
1581 let mut nb = 0u16;
1582 let mut na = 256;
1583 loop {
1584 let mid = (nb + na) >> 1;
1585 if index >= cftab[mid as usize] {
1586 nb = mid;
1587 } else {
1588 na = mid;
1589 }
1590 if na - nb == 1 {
1591 break;
1592 }
1593 }
1594
1595 debug_assert!(u8::try_from(nb).is_ok());
1597 nb as u8
1598}
1599
1600macro_rules! GET_LL4 {
1601 ($s:expr, $i:expr) => {
1602 $s.ll4.as_slice()[($s.tPos >> 1) as usize] as u32 >> ($i << 2 & 0x4) & 0xf
1603 };
1604}
1605
1606macro_rules! BZ_GET_SMALL {
1607 ($s:expr) => {
1608 match $s.ll16.as_slice().get($s.tPos as usize) {
1609 None => return true,
1610 Some(&low_bits) => {
1611 let high_bits = GET_LL4!($s, $s.tPos);
1612 let tmp = index_into_f($s.tPos, &$s.cftab);
1613 $s.tPos = u32::from(low_bits) | high_bits << 16;
1614 tmp
1615 }
1616 }
1617 };
1618}
1619
1620fn un_rle_obuf_to_output_small(strm: &mut BzStream<DState>, s: &mut DState) -> bool {
1621 let mut k1: u8;
1622 if s.blockRandomised {
1623 loop {
1624 loop {
1626 if s.state_out_len == 0 {
1627 match strm.avail_out {
1628 0 => return false,
1629 _ => break,
1630 }
1631 }
1632 if !strm.write_byte(s.state_out_ch) {
1633 return false;
1634 }
1635 BZ_UPDATE_CRC!(s.calculatedBlockCRC, s.state_out_ch);
1636 s.state_out_len -= 1;
1637 }
1638
1639 if s.nblock_used == s.save.nblock as i32 + 1 {
1641 return false;
1642 }
1643
1644 if s.nblock_used > s.save.nblock as i32 + 1 {
1646 return true;
1647 }
1648
1649 s.state_out_ch = s.k0;
1650
1651 s.state_out_len = 1;
1652 k1 = BZ_GET_SMALL!(s);
1653 BZ_RAND_UPD_MASK!(s);
1654 k1 ^= BZ_RAND_MASK!(s);
1655 s.nblock_used += 1;
1656 if s.nblock_used == s.save.nblock as i32 + 1 {
1657 continue;
1658 };
1659 if k1 != s.k0 {
1660 s.k0 = k1;
1661 continue;
1662 };
1663
1664 s.state_out_len = 2;
1665 k1 = BZ_GET_SMALL!(s);
1666 BZ_RAND_UPD_MASK!(s);
1667 k1 ^= BZ_RAND_MASK!(s);
1668 s.nblock_used += 1;
1669 if s.nblock_used == s.save.nblock as i32 + 1 {
1670 continue;
1671 }
1672 if k1 != s.k0 {
1673 s.k0 = k1;
1674 continue;
1675 };
1676
1677 s.state_out_len = 3;
1678 k1 = BZ_GET_SMALL!(s);
1679 BZ_RAND_UPD_MASK!(s);
1680 k1 ^= BZ_RAND_MASK!(s);
1681 s.nblock_used += 1;
1682 if s.nblock_used == s.save.nblock as i32 + 1 {
1683 continue;
1684 }
1685 if k1 != s.k0 {
1686 s.k0 = k1;
1687 continue;
1688 };
1689
1690 k1 = BZ_GET_SMALL!(s);
1691 BZ_RAND_UPD_MASK!(s);
1692 k1 ^= BZ_RAND_MASK!(s);
1693 s.nblock_used += 1;
1694 s.state_out_len = k1 as u32 + 4;
1695 s.k0 = BZ_GET_SMALL!(s);
1696 BZ_RAND_UPD_MASK!(s);
1697 s.k0 ^= BZ_RAND_MASK!(s);
1698 s.nblock_used += 1;
1699 }
1700 } else {
1701 loop {
1702 loop {
1703 if s.state_out_len == 0 {
1704 if strm.avail_out == 0 {
1705 return false;
1706 } else {
1707 break;
1708 }
1709 }
1710 if !strm.write_byte(s.state_out_ch) {
1711 return false;
1712 }
1713 BZ_UPDATE_CRC!(s.calculatedBlockCRC, s.state_out_ch);
1714 s.state_out_len -= 1;
1715 }
1716 if s.nblock_used == s.save.nblock as i32 + 1 {
1717 return false;
1718 }
1719 if s.nblock_used > s.save.nblock as i32 + 1 {
1720 return true;
1721 }
1722
1723 s.state_out_len = 1;
1724 s.state_out_ch = s.k0;
1725 k1 = BZ_GET_SMALL!(s);
1726 s.nblock_used += 1;
1727 if s.nblock_used == s.save.nblock as i32 + 1 {
1728 continue;
1729 }
1730 if k1 != s.k0 {
1731 s.k0 = k1;
1732 continue;
1733 };
1734
1735 s.state_out_len = 2;
1736 k1 = BZ_GET_SMALL!(s);
1737 s.nblock_used += 1;
1738 if s.nblock_used == s.save.nblock as i32 + 1 {
1739 continue;
1740 }
1741 if k1 != s.k0 {
1742 s.k0 = k1;
1743 continue;
1744 };
1745
1746 s.state_out_len = 3;
1747 k1 = BZ_GET_SMALL!(s);
1748 s.nblock_used += 1;
1749 if s.nblock_used == s.save.nblock as i32 + 1 {
1750 continue;
1751 }
1752 if k1 != s.k0 {
1753 s.k0 = k1;
1754 continue;
1755 };
1756
1757 k1 = BZ_GET_SMALL!(s);
1758 s.nblock_used += 1;
1759 s.state_out_len = k1 as u32 + 4;
1760 s.k0 = BZ_GET_SMALL!(s);
1761 s.nblock_used += 1;
1762 }
1763 }
1764}
1765
1766#[cfg_attr(feature = "export-symbols", export_name = prefix!(BZ2_bzDecompress))]
1796pub unsafe extern "C" fn BZ2_bzDecompress(strm: *mut bz_stream) -> c_int {
1797 let Some(strm) = (unsafe { BzStream::from_ptr(strm) }) else {
1798 return ReturnCode::BZ_PARAM_ERROR as c_int;
1799 };
1800
1801 BZ2_bzDecompressHelp(strm) as c_int
1802}
1803
1804pub(crate) fn BZ2_bzDecompressHelp(strm: &mut BzStream<DState>) -> ReturnCode {
1805 let Some(s) = (unsafe { strm.state.as_mut() }) else {
1806 return ReturnCode::BZ_PARAM_ERROR;
1807 };
1808
1809 if s.strm_addr != strm as *mut _ as usize {
1811 return ReturnCode::BZ_PARAM_ERROR;
1812 }
1813
1814 let Some(allocator) = strm.allocator() else {
1815 return ReturnCode::BZ_PARAM_ERROR;
1816 };
1817
1818 loop {
1819 match s.state {
1820 decompress::State::BZ_X_IDLE => {
1821 return ReturnCode::BZ_SEQUENCE_ERROR;
1822 }
1823 decompress::State::BZ_X_OUTPUT => {
1824 let corrupt = match s.smallDecompress {
1825 DecompressMode::Small => un_rle_obuf_to_output_small(strm, s),
1826 DecompressMode::Fast => un_rle_obuf_to_output_fast(strm, s),
1827 };
1828
1829 if corrupt {
1830 return ReturnCode::BZ_DATA_ERROR;
1831 }
1832
1833 if s.nblock_used == s.save.nblock as i32 + 1 && s.state_out_len == 0 {
1834 s.calculatedBlockCRC = !s.calculatedBlockCRC;
1835 if s.verbosity >= 3 {
1836 debug_log!(
1837 " {{{:#08x}, {:#08x}}}",
1838 s.storedBlockCRC,
1839 s.calculatedBlockCRC,
1840 );
1841 }
1842 if s.verbosity >= 2 {
1843 debug_log!("]");
1844 }
1845 #[cfg(not(feature = "__internal-fuzz-disable-checksum"))]
1846 if s.calculatedBlockCRC != s.storedBlockCRC {
1847 return ReturnCode::BZ_DATA_ERROR;
1848 }
1849 s.calculatedCombinedCRC = s.calculatedCombinedCRC.rotate_left(1);
1850 s.calculatedCombinedCRC ^= s.calculatedBlockCRC;
1851 s.state = decompress::State::BZ_X_BLKHDR_1;
1852
1853 continue;
1854 } else {
1855 return ReturnCode::BZ_OK;
1856 }
1857 }
1858 _ => match decompress(strm, s, &allocator) {
1859 ReturnCode::BZ_STREAM_END => {
1860 if s.verbosity >= 3 {
1861 debug_log!(
1862 "\n combined CRCs: stored = {:#08x}, computed = {:#08x}",
1863 s.storedCombinedCRC,
1864 s.calculatedCombinedCRC,
1865 );
1866 }
1867 #[cfg(not(feature = "__internal-fuzz-disable-checksum"))]
1868 if s.calculatedCombinedCRC != s.storedCombinedCRC {
1869 return ReturnCode::BZ_DATA_ERROR;
1870 }
1871 return ReturnCode::BZ_STREAM_END;
1872 }
1873 return_code => match s.state {
1874 decompress::State::BZ_X_OUTPUT => continue,
1875 _ => return return_code,
1876 },
1877 },
1878 }
1879 }
1880}
1881
1882#[cfg_attr(feature = "export-symbols", export_name = prefix!(BZ2_bzDecompressEnd))]
1898pub unsafe extern "C" fn BZ2_bzDecompressEnd(strm: *mut bz_stream) -> c_int {
1899 let Some(strm) = (unsafe { BzStream::from_ptr(strm) }) else {
1900 return ReturnCode::BZ_PARAM_ERROR as c_int;
1901 };
1902 BZ2_bzDecompressEndHelp(strm) as c_int
1903}
1904
1905fn BZ2_bzDecompressEndHelp(strm: &mut BzStream<DState>) -> ReturnCode {
1906 let Some(s) = (unsafe { strm.state.as_mut() }) else {
1907 return ReturnCode::BZ_PARAM_ERROR;
1908 };
1909
1910 if s.strm_addr != strm as *mut _ as usize {
1912 return ReturnCode::BZ_PARAM_ERROR;
1913 }
1914
1915 let Some(allocator) = strm.allocator() else {
1916 return ReturnCode::BZ_PARAM_ERROR;
1917 };
1918
1919 unsafe {
1920 s.tt.dealloc(&allocator);
1921 s.ll16.dealloc(&allocator);
1922 s.ll4.dealloc(&allocator);
1923 }
1924
1925 unsafe { allocator.deallocate(strm.state, 1) };
1926 strm.state = ptr::null_mut::<DState>();
1927
1928 ReturnCode::BZ_OK
1929}
1930
1931#[cfg_attr(feature = "export-symbols", export_name = prefix!(BZ2_bzBuffToBuffCompress))]
1969pub unsafe extern "C" fn BZ2_bzBuffToBuffCompress(
1970 dest: *mut c_char,
1971 destLen: *mut c_uint,
1972 source: *mut c_char,
1973 sourceLen: c_uint,
1974 blockSize100k: c_int,
1975 verbosity: c_int,
1976 workFactor: c_int,
1977) -> c_int {
1978 if dest.is_null() || source.is_null() {
1979 return ReturnCode::BZ_PARAM_ERROR as c_int;
1980 }
1981
1982 if !(0..=4).contains(&verbosity) {
1983 return ReturnCode::BZ_PARAM_ERROR as c_int;
1984 }
1985
1986 let Some(destLen) = (unsafe { destLen.as_mut() }) else {
1987 return ReturnCode::BZ_PARAM_ERROR as c_int;
1988 };
1989
1990 match unsafe {
1991 BZ2_bzBuffToBuffCompressHelp(
1992 dest,
1993 *destLen,
1994 source,
1995 sourceLen,
1996 blockSize100k,
1997 verbosity,
1998 workFactor,
1999 )
2000 } {
2001 Ok(written) => {
2002 *destLen -= written;
2003 ReturnCode::BZ_OK as c_int
2004 }
2005 Err(err) => err as c_int,
2006 }
2007}
2008
2009unsafe fn BZ2_bzBuffToBuffCompressHelp(
2010 dest: *mut c_char,
2011 destLen: c_uint,
2012 source: *mut c_char,
2013 sourceLen: c_uint,
2014 blockSize100k: c_int,
2015 verbosity: c_int,
2016 workFactor: c_int,
2017) -> Result<c_uint, ReturnCode> {
2018 let mut strm = BzStream::zeroed();
2019
2020 match BZ2_bzCompressInitHelp(&mut strm, blockSize100k, verbosity, workFactor) {
2021 ReturnCode::BZ_OK => {}
2022 ret => return Err(ret),
2023 }
2024
2025 strm.next_in = source;
2026 strm.next_out = dest;
2027 strm.avail_in = sourceLen;
2028 strm.avail_out = destLen;
2029
2030 match BZ2_bzCompressHelp(&mut strm, Action::Finish as i32) {
2031 ReturnCode::BZ_FINISH_OK => {
2032 BZ2_bzCompressEndHelp(&mut strm);
2033 Err(ReturnCode::BZ_OUTBUFF_FULL)
2034 }
2035 ReturnCode::BZ_STREAM_END => {
2036 BZ2_bzCompressEndHelp(&mut strm);
2037 Ok(strm.avail_out)
2038 }
2039 error => {
2040 BZ2_bzCompressEndHelp(&mut strm);
2041 Err(error)
2042 }
2043 }
2044}
2045
2046#[cfg_attr(feature = "export-symbols", export_name = prefix!(BZ2_bzBuffToBuffDecompress))]
2088pub unsafe extern "C" fn BZ2_bzBuffToBuffDecompress(
2089 dest: *mut c_char,
2090 destLen: *mut c_uint,
2091 source: *mut c_char,
2092 sourceLen: c_uint,
2093 small: c_int,
2094 verbosity: c_int,
2095) -> c_int {
2096 if dest.is_null() || source.is_null() {
2097 return ReturnCode::BZ_PARAM_ERROR as c_int;
2098 }
2099
2100 let Some(destLen) = (unsafe { destLen.as_mut() }) else {
2101 return ReturnCode::BZ_PARAM_ERROR as c_int;
2102 };
2103
2104 match unsafe {
2105 BZ2_bzBuffToBuffDecompressHelp(dest, *destLen, source, sourceLen, small, verbosity)
2106 } {
2107 Ok(written) => {
2108 *destLen -= written;
2109 ReturnCode::BZ_OK as c_int
2110 }
2111 Err(err) => err as c_int,
2112 }
2113}
2114
2115unsafe fn BZ2_bzBuffToBuffDecompressHelp(
2116 dest: *mut c_char,
2117 destLen: c_uint,
2118 source: *mut c_char,
2119 sourceLen: c_uint,
2120 small: c_int,
2121 verbosity: c_int,
2122) -> Result<c_uint, ReturnCode> {
2123 let mut strm = BzStream::zeroed();
2124
2125 match BZ2_bzDecompressInitHelp(&mut strm, verbosity, small) {
2126 ReturnCode::BZ_OK => {}
2127 ret => return Err(ret),
2128 }
2129
2130 strm.next_in = source;
2131 strm.next_out = dest;
2132 strm.avail_in = sourceLen;
2133 strm.avail_out = destLen;
2134
2135 match BZ2_bzDecompressHelp(&mut strm) {
2136 ReturnCode::BZ_OK => {
2137 BZ2_bzDecompressEndHelp(&mut strm);
2138 match strm.avail_out {
2139 0 => Err(ReturnCode::BZ_OUTBUFF_FULL),
2140 _ => Err(ReturnCode::BZ_UNEXPECTED_EOF),
2141 }
2142 }
2143 ReturnCode::BZ_STREAM_END => {
2144 BZ2_bzDecompressEndHelp(&mut strm);
2145 Ok(strm.avail_out)
2146 }
2147 error => {
2148 BZ2_bzDecompressEndHelp(&mut strm);
2149 Err(error)
2150 }
2151 }
2152}