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 as *mut u8) };
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 as *mut u8) };
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: i32 = 2;
447pub(crate) const BZ_N_QSORT: i32 = 12;
448pub(crate) const BZ_N_SHELL: i32 = 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 rNToGo: i32,
625 pub rTPos: i32,
626 pub bsBuff: u64,
627 pub bsLive: i32,
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))]
763pub unsafe extern "C" fn BZ2_bzCompressInit(
764 strm: *mut bz_stream,
765 blockSize100k: c_int,
766 verbosity: c_int,
767 workFactor: c_int,
768) -> c_int {
769 let Some(strm) = (unsafe { BzStream::from_ptr(strm) }) else {
770 return ReturnCode::BZ_PARAM_ERROR as c_int;
771 };
772 BZ2_bzCompressInitHelp(strm, blockSize100k, verbosity, workFactor) as c_int
773}
774
775pub(crate) fn BZ2_bzCompressInitHelp(
776 strm: &mut BzStream<EState>,
777 blockSize100k: c_int,
778 verbosity: c_int,
779 mut workFactor: c_int,
780) -> ReturnCode {
781 if !(1..=9).contains(&blockSize100k) || !(0..=250).contains(&workFactor) {
782 return ReturnCode::BZ_PARAM_ERROR;
783 }
784
785 if workFactor == 0 {
786 workFactor = 30;
787 }
788
789 let Some(allocator) = configure_allocator(strm) else {
791 return ReturnCode::BZ_PARAM_ERROR;
792 };
793
794 let Some(s) = allocator.allocate_zeroed::<EState>(1) else {
795 return ReturnCode::BZ_MEM_ERROR;
796 };
797
798 unsafe { (*s).strm_addr = strm as *const _ as usize }; let n = 100000 * blockSize100k;
803
804 let arr1_len = n as usize;
805 let arr1 = Arr1::alloc(&allocator, arr1_len);
806
807 let arr2_len = n as usize + (2 + 12 + 18 + 2);
808 let arr2 = Arr2::alloc(&allocator, arr2_len);
809
810 let ftab = Ftab::alloc(&allocator);
811
812 match (arr1, arr2, ftab) {
813 (Some(arr1), Some(arr2), Some(ftab)) => unsafe {
814 (*s).arr1 = arr1;
815 (*s).arr2 = arr2;
816 (*s).ftab = ftab;
817 },
818 (arr1, arr2, ftab) => {
819 if let Some(mut arr1) = arr1 {
820 unsafe { arr1.dealloc(&allocator) };
821 }
822
823 if let Some(mut arr2) = arr2 {
824 unsafe { arr2.dealloc(&allocator) };
825 }
826
827 if let Some(mut ftab) = ftab {
828 unsafe { ftab.dealloc(&allocator) };
829 }
830
831 unsafe { allocator.deallocate(s, 1) };
832
833 return ReturnCode::BZ_MEM_ERROR;
834 }
835 };
836
837 strm.state = s;
838
839 let s = unsafe { &mut *s };
845
846 s.blockNo = 0;
847 s.state = State::Output;
848 s.mode = Mode::Running;
849 s.combinedCRC = 0;
850 s.blockSize100k = blockSize100k;
851 s.nblockMAX = 100000 * blockSize100k - 19;
852 s.verbosity = verbosity;
853 s.workFactor = workFactor;
854
855 strm.total_in_lo32 = 0;
856 strm.total_in_hi32 = 0;
857 strm.total_out_lo32 = 0;
858 strm.total_out_hi32 = 0;
859
860 init_rl(s);
861 prepare_new_block(s);
862
863 ReturnCode::BZ_OK
864}
865
866macro_rules! BZ_UPDATE_CRC {
867 ($crcVar:expr, $cha:expr) => {
868 let index = ($crcVar >> 24) ^ ($cha as core::ffi::c_uint);
869 $crcVar = ($crcVar << 8) ^ BZ2_CRC32TABLE[index as usize];
870 };
871}
872
873fn add_pair_to_block(s: &mut EState) {
874 let ch: u8 = s.state_in_ch as u8;
875
876 for _ in 0..s.state_in_len {
877 BZ_UPDATE_CRC!(s.blockCRC, ch);
878 }
879
880 let block = s.arr2.raw_block();
881 s.inUse[s.state_in_ch as usize] = true;
882 match s.state_in_len {
883 1 => {
884 block[s.nblock as usize..][..1].fill(ch);
885 s.nblock += 1;
886 }
887 2 => {
888 block[s.nblock as usize..][..2].fill(ch);
889 s.nblock += 2;
890 }
891 3 => {
892 block[s.nblock as usize..][..3].fill(ch);
893 s.nblock += 3;
894 }
895 _ => {
896 s.inUse[(s.state_in_len - 4) as usize] = true;
897
898 block[s.nblock as usize..][..4].fill(ch);
899 s.nblock += 4;
900
901 block[s.nblock as usize] = (s.state_in_len - 4) as u8;
902 s.nblock += 1;
903 }
904 };
905}
906
907fn flush_rl(s: &mut EState) {
908 if s.state_in_ch < 256 {
909 add_pair_to_block(s);
910 }
911 init_rl(s);
912}
913
914macro_rules! ADD_CHAR_TO_BLOCK {
915 ($zs:expr, $zchh0:expr) => {
916 let zchh: u32 = $zchh0 as u32;
917
918 if zchh != $zs.state_in_ch && $zs.state_in_len == 1 {
919 let ch: u8 = $zs.state_in_ch as u8;
922 BZ_UPDATE_CRC!($zs.blockCRC, ch);
923 $zs.inUse[$zs.state_in_ch as usize] = true;
924 $zs.arr2.raw_block()[$zs.nblock as usize] = ch;
925 $zs.nblock += 1;
926 $zs.nblock;
927 $zs.state_in_ch = zchh;
928 } else if zchh != $zs.state_in_ch || $zs.state_in_len == 255 {
929 if $zs.state_in_ch < 256 {
932 add_pair_to_block($zs);
933 }
934 $zs.state_in_ch = zchh;
935 $zs.state_in_len = 1;
936 } else {
937 $zs.state_in_len += 1;
938 }
939 };
940}
941
942fn copy_input_until_stop(strm: &mut BzStream<EState>, s: &mut EState) -> bool {
943 let mut progress_in = false;
944
945 match s.mode {
946 Mode::Running => loop {
947 if s.nblock >= s.nblockMAX {
948 break;
949 }
950 if let Some(b) = strm.read_byte() {
951 progress_in = true;
952 ADD_CHAR_TO_BLOCK!(s, b as u32);
953 } else {
954 break;
955 }
956 },
957 Mode::Idle | Mode::Flushing | Mode::Finishing => loop {
958 if s.nblock >= s.nblockMAX {
959 break;
960 }
961 if s.avail_in_expect == 0 {
962 break;
963 }
964 if let Some(b) = strm.read_byte() {
965 progress_in = true;
966 ADD_CHAR_TO_BLOCK!(s, b as u32);
967 } else {
968 break;
969 }
970 s.avail_in_expect -= 1;
971 },
972 }
973 progress_in
974}
975
976fn copy_output_until_stop(strm: &mut BzStream<EState>, s: &mut EState) -> bool {
977 let mut progress_out = false;
978
979 let zbits = &mut s.arr2.raw_block()[s.nblock as usize..];
980
981 loop {
982 if s.state_out_pos >= s.writer.num_z as i32 {
983 break;
984 }
985 if !strm.write_byte(zbits[s.state_out_pos as usize]) {
986 break;
987 }
988 progress_out = true;
989 s.state_out_pos += 1;
990 }
991 progress_out
992}
993
994fn handle_compress(strm: &mut BzStream<EState>, s: &mut EState) -> bool {
995 let mut progress_in = false;
996 let mut progress_out = false;
997
998 loop {
999 if let State::Input = s.state {
1000 progress_out |= copy_output_until_stop(strm, s);
1001 if s.state_out_pos < s.writer.num_z as i32 {
1002 break;
1003 }
1004 if matches!(s.mode, Mode::Finishing) && s.avail_in_expect == 0 && isempty_rl(s) {
1005 break;
1006 }
1007 prepare_new_block(s);
1008 s.state = State::Output;
1009 if matches!(s.mode, Mode::Flushing) && s.avail_in_expect == 0 && isempty_rl(s) {
1010 break;
1011 }
1012 }
1013 if let State::Input = s.state {
1014 continue;
1015 }
1016 progress_in |= copy_input_until_stop(strm, s);
1017 if !matches!(s.mode, Mode::Running) && s.avail_in_expect == 0 {
1018 flush_rl(s);
1019 let is_last_block = matches!(s.mode, Mode::Finishing);
1020 compress_block(s, is_last_block);
1021 s.state = State::Input;
1022 } else if s.nblock >= s.nblockMAX {
1023 compress_block(s, false);
1024 s.state = State::Input;
1025 } else if strm.avail_in == 0 {
1026 break;
1027 }
1028 }
1029
1030 progress_in || progress_out
1031}
1032
1033pub(crate) enum Action {
1034 Run = 0,
1035 Flush = 1,
1036 Finish = 2,
1037}
1038
1039impl TryFrom<i32> for Action {
1040 type Error = ();
1041
1042 fn try_from(value: i32) -> Result<Self, Self::Error> {
1043 match value {
1044 0 => Ok(Self::Run),
1045 1 => Ok(Self::Flush),
1046 2 => Ok(Self::Finish),
1047 _ => Err(()),
1048 }
1049 }
1050}
1051
1052#[cfg_attr(feature = "export-symbols", export_name = prefix!(BZ2_bzCompress))]
1081pub unsafe extern "C" fn BZ2_bzCompress(strm: *mut bz_stream, action: c_int) -> c_int {
1082 let Some(strm) = (unsafe { BzStream::from_ptr(strm) }) else {
1083 return ReturnCode::BZ_PARAM_ERROR as c_int;
1084 };
1085
1086 BZ2_bzCompressHelp(strm, action) as c_int
1087}
1088
1089pub(crate) fn BZ2_bzCompressHelp(strm: &mut BzStream<EState>, action: i32) -> ReturnCode {
1090 let Some(s) = (unsafe { strm.state.as_mut() }) else {
1091 return ReturnCode::BZ_PARAM_ERROR;
1092 };
1093
1094 if s.strm_addr != strm as *mut _ as usize {
1096 return ReturnCode::BZ_PARAM_ERROR;
1097 }
1098
1099 compress_loop(strm, s, action)
1100}
1101
1102fn compress_loop(strm: &mut BzStream<EState>, s: &mut EState, action: i32) -> ReturnCode {
1103 loop {
1104 match s.mode {
1105 Mode::Idle => return ReturnCode::BZ_SEQUENCE_ERROR,
1106 Mode::Running => match Action::try_from(action) {
1107 Ok(Action::Run) => {
1108 let progress = handle_compress(strm, s);
1109 return if progress {
1110 ReturnCode::BZ_RUN_OK
1111 } else {
1112 ReturnCode::BZ_PARAM_ERROR
1113 };
1114 }
1115 Ok(Action::Flush) => {
1116 s.avail_in_expect = strm.avail_in;
1117 s.mode = Mode::Flushing;
1118 }
1119 Ok(Action::Finish) => {
1120 s.avail_in_expect = strm.avail_in;
1121 s.mode = Mode::Finishing;
1122 }
1123 Err(()) => {
1124 return ReturnCode::BZ_PARAM_ERROR;
1125 }
1126 },
1127 Mode::Flushing => {
1128 let Ok(Action::Flush) = Action::try_from(action) else {
1129 return ReturnCode::BZ_SEQUENCE_ERROR;
1130 };
1131 if s.avail_in_expect != strm.avail_in {
1132 return ReturnCode::BZ_SEQUENCE_ERROR;
1133 }
1134 handle_compress(strm, s);
1135 if s.avail_in_expect > 0
1136 || !isempty_rl(s)
1137 || s.state_out_pos < s.writer.num_z as i32
1138 {
1139 return ReturnCode::BZ_FLUSH_OK;
1140 }
1141 s.mode = Mode::Running;
1142 return ReturnCode::BZ_RUN_OK;
1143 }
1144 Mode::Finishing => {
1145 let Ok(Action::Finish) = Action::try_from(action) else {
1146 return ReturnCode::BZ_SEQUENCE_ERROR;
1148 };
1149 if s.avail_in_expect != strm.avail_in {
1150 return ReturnCode::BZ_SEQUENCE_ERROR;
1152 }
1153 let progress = handle_compress(strm, s);
1154 if !progress {
1155 return ReturnCode::BZ_SEQUENCE_ERROR;
1156 }
1157 if s.avail_in_expect > 0
1158 || !isempty_rl(s)
1159 || s.state_out_pos < s.writer.num_z as i32
1160 {
1161 return ReturnCode::BZ_FINISH_OK;
1162 }
1163 s.mode = Mode::Idle;
1164 return ReturnCode::BZ_STREAM_END;
1165 }
1166 }
1167 }
1168}
1169
1170#[cfg_attr(feature = "export-symbols", export_name = prefix!(BZ2_bzCompressEnd))]
1186pub unsafe extern "C" fn BZ2_bzCompressEnd(strm: *mut bz_stream) -> c_int {
1187 let Some(strm) = (unsafe { BzStream::from_ptr(strm) }) else {
1188 return ReturnCode::BZ_PARAM_ERROR as c_int;
1189 };
1190 BZ2_bzCompressEndHelp(strm)
1191}
1192
1193fn BZ2_bzCompressEndHelp(strm: &mut BzStream<EState>) -> c_int {
1194 let Some(s) = (unsafe { strm.state.as_mut() }) else {
1195 return ReturnCode::BZ_PARAM_ERROR as c_int;
1196 };
1197
1198 if s.strm_addr != strm as *mut _ as usize {
1200 return ReturnCode::BZ_PARAM_ERROR as c_int;
1201 }
1202
1203 let Some(allocator) = strm.allocator() else {
1204 return ReturnCode::BZ_PARAM_ERROR as c_int;
1205 };
1206
1207 unsafe {
1208 s.arr1.dealloc(&allocator);
1209 s.arr2.dealloc(&allocator);
1210 s.ftab.dealloc(&allocator);
1211 }
1212
1213 unsafe {
1214 allocator.deallocate(strm.state.cast::<EState>(), 1);
1215 }
1216 strm.state = ptr::null_mut::<EState>();
1217
1218 ReturnCode::BZ_OK as c_int
1219}
1220
1221pub(crate) enum DecompressMode {
1222 Small,
1223 Fast,
1224}
1225
1226#[cfg_attr(feature = "export-symbols", export_name = prefix!(BZ2_bzDecompressInit))]
1247pub unsafe extern "C" fn BZ2_bzDecompressInit(
1248 strm: *mut bz_stream,
1249 verbosity: c_int,
1250 small: c_int,
1251) -> c_int {
1252 let Some(strm) = (unsafe { BzStream::from_ptr(strm) }) else {
1253 return ReturnCode::BZ_PARAM_ERROR as c_int;
1254 };
1255 BZ2_bzDecompressInitHelp(strm, verbosity, small) as c_int
1256}
1257
1258pub(crate) fn BZ2_bzDecompressInitHelp(
1259 strm: &mut BzStream<DState>,
1260 verbosity: c_int,
1261 small: c_int,
1262) -> ReturnCode {
1263 let decompress_mode = match small {
1264 0 => DecompressMode::Fast,
1265 1 => DecompressMode::Small,
1266 _ => return ReturnCode::BZ_PARAM_ERROR,
1267 };
1268 if !(0..=4).contains(&verbosity) {
1269 return ReturnCode::BZ_PARAM_ERROR;
1270 }
1271
1272 let Some(allocator) = configure_allocator(strm) else {
1274 return ReturnCode::BZ_PARAM_ERROR;
1275 };
1276
1277 let Some(s) = allocator.allocate_zeroed::<DState>(1) else {
1278 return ReturnCode::BZ_MEM_ERROR;
1279 };
1280
1281 unsafe { (*s).strm_addr = strm as *const _ as usize }; unsafe {
1286 (*s).state = decompress::State::BZ_X_MAGIC_1;
1287 (*s).bsLive = 0;
1288 (*s).bsBuff = 0;
1289 (*s).calculatedCombinedCRC = 0;
1290 }
1291
1292 unsafe {
1293 (*s).smallDecompress = decompress_mode;
1294 (*s).ll4 = DSlice::new();
1295 (*s).ll16 = DSlice::new();
1296 (*s).tt = DSlice::new();
1297 (*s).currBlockNo = 0;
1298 (*s).verbosity = verbosity;
1299 }
1300
1301 strm.state = s;
1302
1303 strm.total_in_lo32 = 0;
1304 strm.total_in_hi32 = 0;
1305 strm.total_out_lo32 = 0;
1306 strm.total_out_hi32 = 0;
1307
1308 ReturnCode::BZ_OK
1309}
1310
1311macro_rules! BZ_RAND_MASK {
1312 ($s:expr) => {
1313 ($s.rNToGo == 1) as u8
1314 };
1315}
1316
1317macro_rules! BZ_RAND_UPD_MASK {
1318 ($s:expr) => {
1319 if ($s.rNToGo == 0) {
1320 $s.rNToGo = $crate::randtable::BZ2_RNUMS[$s.rTPos as usize];
1321 $s.rTPos += 1;
1322 if ($s.rTPos == 512) {
1323 $s.rTPos = 0
1324 };
1325 }
1326 $s.rNToGo -= 1;
1327 };
1328}
1329
1330pub(crate) use BZ_RAND_UPD_MASK;
1331
1332macro_rules! BZ_GET_FAST {
1333 ($s:expr) => {
1334 match $s.tt.as_slice().get($s.tPos as usize) {
1335 None => return true,
1336 Some(&bits) => {
1337 $s.tPos = bits;
1338 let tmp = ($s.tPos & 0xff) as u8;
1339 $s.tPos >>= 8;
1340 tmp
1341 }
1342 }
1343 };
1344}
1345
1346fn un_rle_obuf_to_output_fast(strm: &mut BzStream<DState>, s: &mut DState) -> bool {
1347 let mut k1: u8;
1348 if s.blockRandomised {
1349 loop {
1350 loop {
1352 if s.state_out_len == 0 {
1353 if strm.avail_out == 0 {
1354 return false;
1355 } else {
1356 break;
1357 }
1358 }
1359 if !strm.write_byte(s.state_out_ch) {
1360 return false;
1361 }
1362 BZ_UPDATE_CRC!(s.calculatedBlockCRC, s.state_out_ch);
1363 s.state_out_len -= 1;
1364 }
1365
1366 if s.nblock_used == s.save.nblock as i32 + 1 {
1368 return false;
1369 }
1370
1371 if s.nblock_used > s.save.nblock as i32 + 1 {
1373 return true;
1374 }
1375
1376 s.state_out_ch = s.k0;
1377
1378 s.state_out_len = 1;
1379 k1 = BZ_GET_FAST!(s);
1380 BZ_RAND_UPD_MASK!(s);
1381 k1 ^= BZ_RAND_MASK!(s);
1382 s.nblock_used += 1;
1383 if s.nblock_used == s.save.nblock as i32 + 1 {
1384 continue;
1385 };
1386 if k1 != s.k0 {
1387 s.k0 = k1;
1388 continue;
1389 };
1390
1391 s.state_out_len = 2;
1392 k1 = BZ_GET_FAST!(s);
1393 BZ_RAND_UPD_MASK!(s);
1394 k1 ^= BZ_RAND_MASK!(s);
1395 s.nblock_used += 1;
1396 if s.nblock_used == s.save.nblock as i32 + 1 {
1397 continue;
1398 };
1399 if k1 != s.k0 {
1400 s.k0 = k1;
1401 continue;
1402 };
1403
1404 s.state_out_len = 3;
1405 k1 = BZ_GET_FAST!(s);
1406 BZ_RAND_UPD_MASK!(s);
1407 k1 ^= BZ_RAND_MASK!(s);
1408 s.nblock_used += 1;
1409 if s.nblock_used == s.save.nblock as i32 + 1 {
1410 continue;
1411 };
1412 if k1 != s.k0 {
1413 s.k0 = k1;
1414 continue;
1415 };
1416
1417 k1 = BZ_GET_FAST!(s);
1418 BZ_RAND_UPD_MASK!(s);
1419 k1 ^= BZ_RAND_MASK!(s);
1420 s.nblock_used += 1;
1421 s.state_out_len = k1 as u32 + 4;
1422 s.k0 = BZ_GET_FAST!(s);
1423 BZ_RAND_UPD_MASK!(s);
1424 s.k0 ^= BZ_RAND_MASK!(s);
1425 s.nblock_used += 1;
1426 }
1427 } else {
1428 let mut c_calculatedBlockCRC: u32 = s.calculatedBlockCRC;
1430 let mut c_state_out_ch: u8 = s.state_out_ch;
1431 let mut c_state_out_len: u32 = s.state_out_len;
1432 let mut c_nblock_used: i32 = s.nblock_used;
1433 let mut c_k0: u8 = s.k0;
1434 let mut c_tPos: u32 = s.tPos;
1435 let mut cs_next_out: *mut c_char = strm.next_out;
1436 let mut cs_avail_out: c_uint = strm.avail_out;
1437 let ro_blockSize100k: u8 = s.blockSize100k;
1438 let avail_out_INIT: u32 = cs_avail_out;
1441 let s_save_nblockPP: i32 = s.save.nblock as i32 + 1;
1442
1443 let tt = &s.tt.as_slice()[..100000usize.wrapping_mul(usize::from(ro_blockSize100k))];
1444
1445 macro_rules! BZ_GET_FAST_C {
1446 ($c_tPos:expr) => {
1447 match tt.get($c_tPos as usize) {
1448 None => {
1449 return true;
1451 }
1452 Some(&v) => (v >> 8, (v & 0xff) as u8),
1453 }
1454 };
1455 }
1456
1457 'return_notr: loop {
1458 macro_rules! write_one_byte {
1459 ($byte:expr) => {
1460 if cs_avail_out == 0 {
1461 c_state_out_len = 1;
1462 break 'return_notr;
1463 } else {
1464 unsafe { *(cs_next_out as *mut u8) = $byte };
1465 BZ_UPDATE_CRC!(c_calculatedBlockCRC, $byte);
1466 cs_next_out = unsafe { cs_next_out.add(1) };
1467 cs_avail_out -= 1;
1468 }
1469 };
1470 }
1471
1472 if c_state_out_len > 0 {
1473 let bound = Ord::min(cs_avail_out, c_state_out_len);
1474
1475 unsafe {
1476 core::ptr::write_bytes(cs_next_out as *mut u8, c_state_out_ch, bound as usize);
1477 cs_next_out = cs_next_out.add(bound as usize);
1478 };
1479
1480 for _ in 0..bound {
1481 BZ_UPDATE_CRC!(c_calculatedBlockCRC, c_state_out_ch);
1482 }
1483
1484 cs_avail_out -= bound;
1485 c_state_out_len -= bound;
1486
1487 if cs_avail_out == 0 {
1488 break 'return_notr;
1489 }
1490 }
1491
1492 loop {
1493 if c_nblock_used > s_save_nblockPP {
1495 return true;
1496 }
1497
1498 if c_nblock_used == s_save_nblockPP {
1500 c_state_out_len = 0;
1501 break 'return_notr;
1502 }
1503
1504 c_state_out_ch = c_k0;
1505 (c_tPos, k1) = BZ_GET_FAST_C!(c_tPos);
1506 c_nblock_used += 1;
1507
1508 if k1 != c_k0 {
1509 c_k0 = k1;
1510 write_one_byte!(c_state_out_ch);
1511 continue;
1512 }
1513
1514 if c_nblock_used == s_save_nblockPP {
1515 write_one_byte!(c_state_out_ch);
1516 continue;
1517 }
1518
1519 c_state_out_len = 2;
1520 (c_tPos, k1) = BZ_GET_FAST_C!(c_tPos);
1521 c_nblock_used += 1;
1522
1523 if c_nblock_used == s_save_nblockPP {
1524 continue 'return_notr;
1525 }
1526
1527 if k1 != c_k0 {
1528 c_k0 = k1;
1529 continue 'return_notr;
1530 }
1531
1532 c_state_out_len = 3;
1533 (c_tPos, k1) = BZ_GET_FAST_C!(c_tPos);
1534 c_nblock_used += 1;
1535
1536 if c_nblock_used == s_save_nblockPP {
1537 continue 'return_notr;
1538 }
1539
1540 if k1 != c_k0 {
1541 c_k0 = k1;
1542 continue 'return_notr;
1543 }
1544
1545 (c_tPos, k1) = BZ_GET_FAST_C!(c_tPos);
1546 c_nblock_used += 1;
1547 c_state_out_len = k1 as u32 + 4;
1548 (c_tPos, c_k0) = BZ_GET_FAST_C!(c_tPos);
1549 c_nblock_used += 1;
1550
1551 continue 'return_notr;
1552 }
1553 }
1554
1555 let total_out_lo32_old: c_uint = strm.total_out_lo32;
1557 strm.total_out_lo32 =
1558 (strm.total_out_lo32).wrapping_add(avail_out_INIT.wrapping_sub(cs_avail_out));
1559 if strm.total_out_lo32 < total_out_lo32_old {
1560 strm.total_out_hi32 = (strm.total_out_hi32).wrapping_add(1);
1561 }
1562 s.calculatedBlockCRC = c_calculatedBlockCRC;
1563 s.state_out_ch = c_state_out_ch;
1564 s.state_out_len = c_state_out_len;
1565 s.nblock_used = c_nblock_used;
1566 s.k0 = c_k0;
1567 s.tPos = c_tPos;
1568 strm.next_out = cs_next_out;
1569 strm.avail_out = cs_avail_out;
1570 }
1572
1573 false
1574}
1575
1576#[inline]
1577pub(crate) fn index_into_f(index: u32, cftab: &[u32; 257]) -> u8 {
1578 let mut nb = 0u16;
1579 let mut na = 256;
1580 loop {
1581 let mid = (nb + na) >> 1;
1582 if index >= cftab[mid as usize] {
1583 nb = mid;
1584 } else {
1585 na = mid;
1586 }
1587 if na - nb == 1 {
1588 break;
1589 }
1590 }
1591
1592 debug_assert!(u8::try_from(nb).is_ok());
1594 nb as u8
1595}
1596
1597macro_rules! GET_LL4 {
1598 ($s:expr, $i:expr) => {
1599 $s.ll4.as_slice()[($s.tPos >> 1) as usize] as u32 >> ($s.tPos << 2 & 0x4) & 0xf
1600 };
1601}
1602
1603macro_rules! BZ_GET_SMALL {
1604 ($s:expr) => {
1605 match $s.ll16.as_slice().get($s.tPos as usize) {
1606 None => return true,
1607 Some(&low_bits) => {
1608 let high_bits = GET_LL4!($s, $s.tPos);
1609 let tmp = index_into_f($s.tPos, &$s.cftab);
1610 $s.tPos = u32::from(low_bits) | high_bits << 16;
1611 tmp
1612 }
1613 }
1614 };
1615}
1616
1617fn un_rle_obuf_to_output_small(strm: &mut BzStream<DState>, s: &mut DState) -> bool {
1618 let mut k1: u8;
1619 if s.blockRandomised {
1620 loop {
1621 loop {
1623 if s.state_out_len == 0 {
1624 match strm.avail_out {
1625 0 => return false,
1626 _ => break,
1627 }
1628 }
1629 if !strm.write_byte(s.state_out_ch) {
1630 return false;
1631 }
1632 BZ_UPDATE_CRC!(s.calculatedBlockCRC, s.state_out_ch);
1633 s.state_out_len -= 1;
1634 }
1635
1636 if s.nblock_used == s.save.nblock as i32 + 1 {
1638 return false;
1639 }
1640
1641 if s.nblock_used > s.save.nblock as i32 + 1 {
1643 return true;
1644 }
1645
1646 s.state_out_ch = s.k0;
1647
1648 s.state_out_len = 1;
1649 k1 = BZ_GET_SMALL!(s);
1650 BZ_RAND_UPD_MASK!(s);
1651 k1 ^= BZ_RAND_MASK!(s);
1652 s.nblock_used += 1;
1653 if s.nblock_used == s.save.nblock as i32 + 1 {
1654 continue;
1655 };
1656 if k1 != s.k0 {
1657 s.k0 = k1;
1658 continue;
1659 };
1660
1661 s.state_out_len = 2;
1662 k1 = BZ_GET_SMALL!(s);
1663 BZ_RAND_UPD_MASK!(s);
1664 k1 ^= BZ_RAND_MASK!(s);
1665 s.nblock_used += 1;
1666 if s.nblock_used == s.save.nblock as i32 + 1 {
1667 continue;
1668 }
1669 if k1 != s.k0 {
1670 s.k0 = k1;
1671 continue;
1672 };
1673
1674 s.state_out_len = 3;
1675 k1 = BZ_GET_SMALL!(s);
1676 BZ_RAND_UPD_MASK!(s);
1677 k1 ^= BZ_RAND_MASK!(s);
1678 s.nblock_used += 1;
1679 if s.nblock_used == s.save.nblock as i32 + 1 {
1680 continue;
1681 }
1682 if k1 != s.k0 {
1683 s.k0 = k1;
1684 continue;
1685 };
1686
1687 k1 = BZ_GET_SMALL!(s);
1688 BZ_RAND_UPD_MASK!(s);
1689 k1 ^= BZ_RAND_MASK!(s);
1690 s.nblock_used += 1;
1691 s.state_out_len = k1 as u32 + 4;
1692 s.k0 = BZ_GET_SMALL!(s);
1693 BZ_RAND_UPD_MASK!(s);
1694 s.k0 ^= BZ_RAND_MASK!(s);
1695 s.nblock_used += 1;
1696 }
1697 } else {
1698 loop {
1699 loop {
1700 if s.state_out_len == 0 {
1701 if strm.avail_out == 0 {
1702 return false;
1703 } else {
1704 break;
1705 }
1706 }
1707 if !strm.write_byte(s.state_out_ch) {
1708 return false;
1709 }
1710 BZ_UPDATE_CRC!(s.calculatedBlockCRC, s.state_out_ch);
1711 s.state_out_len -= 1;
1712 }
1713 if s.nblock_used == s.save.nblock as i32 + 1 {
1714 return false;
1715 }
1716 if s.nblock_used > s.save.nblock as i32 + 1 {
1717 return true;
1718 }
1719
1720 s.state_out_len = 1;
1721 s.state_out_ch = s.k0;
1722 k1 = BZ_GET_SMALL!(s);
1723 s.nblock_used += 1;
1724 if s.nblock_used == s.save.nblock as i32 + 1 {
1725 continue;
1726 }
1727 if k1 != s.k0 {
1728 s.k0 = k1;
1729 continue;
1730 };
1731
1732 s.state_out_len = 2;
1733 k1 = BZ_GET_SMALL!(s);
1734 s.nblock_used += 1;
1735 if s.nblock_used == s.save.nblock as i32 + 1 {
1736 continue;
1737 }
1738 if k1 != s.k0 {
1739 s.k0 = k1;
1740 continue;
1741 };
1742
1743 s.state_out_len = 3;
1744 k1 = BZ_GET_SMALL!(s);
1745 s.nblock_used += 1;
1746 if s.nblock_used == s.save.nblock as i32 + 1 {
1747 continue;
1748 }
1749 if k1 != s.k0 {
1750 s.k0 = k1;
1751 continue;
1752 };
1753
1754 k1 = BZ_GET_SMALL!(s);
1755 s.nblock_used += 1;
1756 s.state_out_len = k1 as u32 + 4;
1757 s.k0 = BZ_GET_SMALL!(s);
1758 s.nblock_used += 1;
1759 }
1760 }
1761}
1762
1763#[cfg_attr(feature = "export-symbols", export_name = prefix!(BZ2_bzDecompress))]
1790pub unsafe extern "C" fn BZ2_bzDecompress(strm: *mut bz_stream) -> c_int {
1791 let Some(strm) = (unsafe { BzStream::from_ptr(strm) }) else {
1792 return ReturnCode::BZ_PARAM_ERROR as c_int;
1793 };
1794
1795 BZ2_bzDecompressHelp(strm) as c_int
1796}
1797
1798pub(crate) fn BZ2_bzDecompressHelp(strm: &mut BzStream<DState>) -> ReturnCode {
1799 let Some(s) = (unsafe { strm.state.as_mut() }) else {
1800 return ReturnCode::BZ_PARAM_ERROR;
1801 };
1802
1803 if s.strm_addr != strm as *mut _ as usize {
1805 return ReturnCode::BZ_PARAM_ERROR;
1806 }
1807
1808 let Some(allocator) = strm.allocator() else {
1809 return ReturnCode::BZ_PARAM_ERROR;
1810 };
1811
1812 loop {
1813 match s.state {
1814 decompress::State::BZ_X_IDLE => {
1815 return ReturnCode::BZ_SEQUENCE_ERROR;
1816 }
1817 decompress::State::BZ_X_OUTPUT => {
1818 let corrupt = match s.smallDecompress {
1819 DecompressMode::Small => un_rle_obuf_to_output_small(strm, s),
1820 DecompressMode::Fast => un_rle_obuf_to_output_fast(strm, s),
1821 };
1822
1823 if corrupt {
1824 return ReturnCode::BZ_DATA_ERROR;
1825 }
1826
1827 if s.nblock_used == s.save.nblock as i32 + 1 && s.state_out_len == 0 {
1828 s.calculatedBlockCRC = !s.calculatedBlockCRC;
1829 if s.verbosity >= 3 {
1830 debug_log!(
1831 " {{{:#08x}, {:#08x}}}",
1832 s.storedBlockCRC,
1833 s.calculatedBlockCRC,
1834 );
1835 }
1836 if s.verbosity >= 2 {
1837 debug_log!("]");
1838 }
1839 #[cfg(not(feature = "__internal-fuzz-disable-checksum"))]
1840 if s.calculatedBlockCRC != s.storedBlockCRC {
1841 return ReturnCode::BZ_DATA_ERROR;
1842 }
1843 s.calculatedCombinedCRC = s.calculatedCombinedCRC.rotate_left(1);
1844 s.calculatedCombinedCRC ^= s.calculatedBlockCRC;
1845 s.state = decompress::State::BZ_X_BLKHDR_1;
1846
1847 continue;
1848 } else {
1849 return ReturnCode::BZ_OK;
1850 }
1851 }
1852 _ => match decompress(strm, s, &allocator) {
1853 ReturnCode::BZ_STREAM_END => {
1854 if s.verbosity >= 3 {
1855 debug_log!(
1856 "\n combined CRCs: stored = {:#08x}, computed = {:#08x}",
1857 s.storedCombinedCRC,
1858 s.calculatedCombinedCRC,
1859 );
1860 }
1861 #[cfg(not(feature = "__internal-fuzz-disable-checksum"))]
1862 if s.calculatedCombinedCRC != s.storedCombinedCRC {
1863 return ReturnCode::BZ_DATA_ERROR;
1864 }
1865 return ReturnCode::BZ_STREAM_END;
1866 }
1867 return_code => match s.state {
1868 decompress::State::BZ_X_OUTPUT => continue,
1869 _ => return return_code,
1870 },
1871 },
1872 }
1873 }
1874}
1875
1876#[cfg_attr(feature = "export-symbols", export_name = prefix!(BZ2_bzDecompressEnd))]
1892pub unsafe extern "C" fn BZ2_bzDecompressEnd(strm: *mut bz_stream) -> c_int {
1893 let Some(strm) = (unsafe { BzStream::from_ptr(strm) }) else {
1894 return ReturnCode::BZ_PARAM_ERROR as c_int;
1895 };
1896 BZ2_bzDecompressEndHelp(strm) as c_int
1897}
1898
1899fn BZ2_bzDecompressEndHelp(strm: &mut BzStream<DState>) -> ReturnCode {
1900 let Some(s) = (unsafe { strm.state.as_mut() }) else {
1901 return ReturnCode::BZ_PARAM_ERROR;
1902 };
1903
1904 if s.strm_addr != strm as *mut _ as usize {
1906 return ReturnCode::BZ_PARAM_ERROR;
1907 }
1908
1909 let Some(allocator) = strm.allocator() else {
1910 return ReturnCode::BZ_PARAM_ERROR;
1911 };
1912
1913 unsafe {
1914 s.tt.dealloc(&allocator);
1915 s.ll16.dealloc(&allocator);
1916 s.ll4.dealloc(&allocator);
1917 }
1918
1919 unsafe { allocator.deallocate(strm.state, 1) };
1920 strm.state = ptr::null_mut::<DState>();
1921
1922 ReturnCode::BZ_OK
1923}
1924
1925#[cfg_attr(feature = "export-symbols", export_name = prefix!(BZ2_bzBuffToBuffCompress))]
1963pub unsafe extern "C" fn BZ2_bzBuffToBuffCompress(
1964 dest: *mut c_char,
1965 destLen: *mut c_uint,
1966 source: *mut c_char,
1967 sourceLen: c_uint,
1968 blockSize100k: c_int,
1969 verbosity: c_int,
1970 workFactor: c_int,
1971) -> c_int {
1972 if dest.is_null() || source.is_null() {
1973 return ReturnCode::BZ_PARAM_ERROR as c_int;
1974 }
1975
1976 let Some(destLen) = (unsafe { destLen.as_mut() }) else {
1977 return ReturnCode::BZ_PARAM_ERROR as c_int;
1978 };
1979
1980 match unsafe {
1981 BZ2_bzBuffToBuffCompressHelp(
1982 dest,
1983 *destLen,
1984 source,
1985 sourceLen,
1986 blockSize100k,
1987 verbosity,
1988 workFactor,
1989 )
1990 } {
1991 Ok(written) => {
1992 *destLen -= written;
1993 ReturnCode::BZ_OK as c_int
1994 }
1995 Err(err) => err as c_int,
1996 }
1997}
1998
1999unsafe fn BZ2_bzBuffToBuffCompressHelp(
2000 dest: *mut c_char,
2001 destLen: c_uint,
2002 source: *mut c_char,
2003 sourceLen: c_uint,
2004 blockSize100k: c_int,
2005 verbosity: c_int,
2006 workFactor: c_int,
2007) -> Result<c_uint, ReturnCode> {
2008 let mut strm = BzStream::zeroed();
2009
2010 match BZ2_bzCompressInitHelp(&mut strm, blockSize100k, verbosity, workFactor) {
2011 ReturnCode::BZ_OK => {}
2012 ret => return Err(ret),
2013 }
2014
2015 strm.next_in = source;
2016 strm.next_out = dest;
2017 strm.avail_in = sourceLen;
2018 strm.avail_out = destLen;
2019
2020 match BZ2_bzCompressHelp(&mut strm, Action::Finish as i32) {
2021 ReturnCode::BZ_FINISH_OK => {
2022 BZ2_bzCompressEndHelp(&mut strm);
2023 Err(ReturnCode::BZ_OUTBUFF_FULL)
2024 }
2025 ReturnCode::BZ_STREAM_END => {
2026 BZ2_bzCompressEndHelp(&mut strm);
2027 Ok(strm.avail_out)
2028 }
2029 error => {
2030 BZ2_bzCompressEndHelp(&mut strm);
2031 Err(error)
2032 }
2033 }
2034}
2035
2036#[cfg_attr(feature = "export-symbols", export_name = prefix!(BZ2_bzBuffToBuffDecompress))]
2078pub unsafe extern "C" fn BZ2_bzBuffToBuffDecompress(
2079 dest: *mut c_char,
2080 destLen: *mut c_uint,
2081 source: *mut c_char,
2082 sourceLen: c_uint,
2083 small: c_int,
2084 verbosity: c_int,
2085) -> c_int {
2086 if dest.is_null() || destLen.is_null() || source.is_null() {
2087 return ReturnCode::BZ_PARAM_ERROR as c_int;
2088 }
2089
2090 let Some(destLen) = (unsafe { destLen.as_mut() }) else {
2091 return ReturnCode::BZ_PARAM_ERROR as c_int;
2092 };
2093
2094 match unsafe {
2095 BZ2_bzBuffToBuffDecompressHelp(dest, *destLen, source, sourceLen, small, verbosity)
2096 } {
2097 Ok(written) => {
2098 *destLen -= written;
2099 ReturnCode::BZ_OK as c_int
2100 }
2101 Err(err) => err as c_int,
2102 }
2103}
2104
2105unsafe fn BZ2_bzBuffToBuffDecompressHelp(
2106 dest: *mut c_char,
2107 destLen: c_uint,
2108 source: *mut c_char,
2109 sourceLen: c_uint,
2110 small: c_int,
2111 verbosity: c_int,
2112) -> Result<c_uint, ReturnCode> {
2113 let mut strm = BzStream::zeroed();
2114
2115 match BZ2_bzDecompressInitHelp(&mut strm, verbosity, small) {
2116 ReturnCode::BZ_OK => {}
2117 ret => return Err(ret),
2118 }
2119
2120 strm.next_in = source;
2121 strm.next_out = dest;
2122 strm.avail_in = sourceLen;
2123 strm.avail_out = destLen;
2124
2125 match BZ2_bzDecompressHelp(&mut strm) {
2126 ReturnCode::BZ_OK => {
2127 BZ2_bzDecompressEndHelp(&mut strm);
2128 match strm.avail_out {
2129 0 => Err(ReturnCode::BZ_OUTBUFF_FULL),
2130 _ => Err(ReturnCode::BZ_UNEXPECTED_EOF),
2131 }
2132 }
2133 ReturnCode::BZ_STREAM_END => {
2134 BZ2_bzDecompressEndHelp(&mut strm);
2135 Ok(strm.avail_out)
2136 }
2137 error => {
2138 BZ2_bzDecompressEndHelp(&mut strm);
2139 Err(error)
2140 }
2141 }
2142}