libbz2_rs_sys/
lib.rs

1#![no_std]
2#![allow(non_snake_case)]
3#![allow(clippy::too_many_arguments)]
4#![deny(unreachable_pub)]
5#![deny(unsafe_op_in_unsafe_fn)]
6
7//! A drop-in compatible rust implementation of bzip2
8
9#[cfg(feature = "std")]
10extern crate std;
11
12use core::ffi::c_int;
13#[cfg(not(feature = "std"))]
14use core::sync::atomic::{AtomicI32, Ordering};
15
16mod allocator;
17mod blocksort;
18mod bzlib;
19mod compress;
20mod crctable;
21mod decompress;
22#[cfg(feature = "stdio")]
23mod high_level;
24mod huffman;
25mod randtable;
26
27pub(crate) use bzlib::{Action, ReturnCode};
28
29pub const BZ_OK: c_int = ReturnCode::BZ_OK as c_int;
30pub const BZ_RUN_OK: c_int = ReturnCode::BZ_RUN_OK as c_int;
31pub const BZ_FLUSH_OK: c_int = ReturnCode::BZ_FLUSH_OK as c_int;
32pub const BZ_FINISH_OK: c_int = ReturnCode::BZ_FINISH_OK as c_int;
33pub const BZ_STREAM_END: c_int = ReturnCode::BZ_STREAM_END as c_int;
34pub const BZ_SEQUENCE_ERROR: c_int = ReturnCode::BZ_SEQUENCE_ERROR as c_int;
35pub const BZ_PARAM_ERROR: c_int = ReturnCode::BZ_PARAM_ERROR as c_int;
36pub const BZ_MEM_ERROR: c_int = ReturnCode::BZ_MEM_ERROR as c_int;
37pub const BZ_DATA_ERROR: c_int = ReturnCode::BZ_DATA_ERROR as c_int;
38pub const BZ_DATA_ERROR_MAGIC: c_int = ReturnCode::BZ_DATA_ERROR_MAGIC as c_int;
39pub const BZ_IO_ERROR: c_int = ReturnCode::BZ_IO_ERROR as c_int;
40pub const BZ_UNEXPECTED_EOF: c_int = ReturnCode::BZ_UNEXPECTED_EOF as c_int;
41pub const BZ_OUTBUFF_FULL: c_int = ReturnCode::BZ_OUTBUFF_FULL as c_int;
42pub const BZ_CONFIG_ERROR: c_int = ReturnCode::BZ_CONFIG_ERROR as c_int;
43
44pub const BZ_RUN: c_int = Action::Run as c_int;
45pub const BZ_FLUSH: c_int = Action::Flush as c_int;
46pub const BZ_FINISH: c_int = Action::Finish as c_int;
47
48pub const BZ_MAX_UNUSED: c_int = bzlib::BZ_MAX_UNUSED_U32 as c_int;
49
50// types
51pub use bzlib::bz_stream;
52#[cfg(feature = "stdio")]
53pub use bzlib::BZFILE;
54
55// the low-level interface
56pub use bzlib::{BZ2_bzCompress, BZ2_bzCompressEnd, BZ2_bzCompressInit};
57pub use bzlib::{BZ2_bzDecompress, BZ2_bzDecompressEnd, BZ2_bzDecompressInit};
58
59// utility functions
60pub use bzlib::{BZ2_bzBuffToBuffCompress, BZ2_bzBuffToBuffDecompress};
61
62// the high-level interface
63#[cfg(feature = "stdio")]
64pub use bzlib::{BZ2_bzRead, BZ2_bzReadClose, BZ2_bzReadGetUnused, BZ2_bzReadOpen};
65#[cfg(feature = "stdio")]
66pub use bzlib::{BZ2_bzWrite, BZ2_bzWriteClose, BZ2_bzWriteClose64, BZ2_bzWriteOpen};
67
68// zlib compatibility functions
69#[cfg(feature = "stdio")]
70pub use bzlib::{
71    BZ2_bzclose, BZ2_bzdopen, BZ2_bzerror, BZ2_bzflush, BZ2_bzlibVersion, BZ2_bzopen, BZ2_bzread,
72    BZ2_bzwrite,
73};
74
75// --- version number logic
76
77macro_rules! libbz2_rs_sys_version {
78    () => {
79        concat!("1.1.0-libbz2-rs-sys-", env!("CARGO_PKG_VERSION"))
80    };
81}
82
83pub(crate) use libbz2_rs_sys_version;
84
85// --- debug logs
86
87#[cfg(all(not(feature = "std"), feature = "stdio"))]
88pub(crate) struct StderrWritter;
89
90#[cfg(all(not(feature = "std"), feature = "stdio"))]
91impl core::fmt::Write for StderrWritter {
92    fn write_str(&mut self, s: &str) -> core::fmt::Result {
93        use core::ffi::c_void;
94        use libc::write;
95
96        unsafe { write(2, s.as_ptr() as *const c_void, s.len() as _) };
97
98        Ok(())
99    }
100}
101
102macro_rules! debug_log {
103    ($($arg:tt)*) => {
104        #[cfg(feature = "std")]
105        std::eprint!($($arg)*);
106        #[cfg(all(not(feature = "std"), feature = "stdio"))]
107        {
108            use core::fmt::Write;
109            let _ = write!($crate::StderrWritter, $($arg)*);
110        }
111    };
112}
113
114macro_rules! debug_logln {
115    ($($arg:tt)*) => {
116        #[cfg(feature = "std")]
117        std::eprintln!($($arg)*);
118        #[cfg(all(not(feature = "std"), feature = "stdio"))]
119        {
120            use core::fmt::Write;
121            let _ = writeln!($crate::StderrWritter, $($arg)*);
122        }
123    };
124}
125
126pub(crate) use debug_log;
127pub(crate) use debug_logln;
128
129// --- assert failure logic
130
131macro_rules! assert_h {
132    ($condition:expr, $errcode:expr) => {
133        if !$condition {
134            $crate::handle_assert_failure($errcode)
135        }
136    };
137}
138
139#[cfg(not(feature = "std"))]
140#[doc(hidden)]
141pub static ASSERT_CODE: AtomicI32 = AtomicI32::new(-1);
142
143#[cold]
144fn handle_assert_failure(errcode: c_int) -> ! {
145    #[cfg(feature = "std")]
146    std::eprint!("{}", AssertFail(errcode));
147    #[cfg(feature = "std")]
148    std::process::exit(3);
149
150    // Stash the assertion code for the panic handler in the cdylib to pass to bz_internal_error.
151    // Using relaxed ordering as this will be accessed on the same thread.
152    #[cfg(not(feature = "std"))]
153    #[allow(clippy::unnecessary_cast)]
154    ASSERT_CODE.store(errcode as i32, Ordering::Relaxed);
155    #[cfg(not(feature = "std"))]
156    panic!("{}", AssertFail(errcode));
157}
158
159use assert_h;
160
161struct AssertFail(i32);
162
163impl core::fmt::Display for AssertFail {
164    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
165        write!(
166            f,
167            concat!(
168                "\n",
169                "\n",
170                "libbzip2-rs: internal error number {}.\n",
171                "This is a bug in libbzip2-rs, {}.\n",
172                "Please report it at: https://github.com/trifectatechfoundation/libbzip2-rs/issues\n",
173                "If this happened when you were using some program which uses\n",
174                "libbzip2-rs as a component, you should also report this bug to\n",
175                "the author(s) of that program.\n",
176                "Please make an effort to report this bug;\n",
177                "timely and accurate bug reports eventually lead to higher\n",
178                "quality software.  Thanks.\n",
179                "\n"
180            ),
181            self.0,
182            libbz2_rs_sys_version!(),
183        )?;
184
185        if self.0 == 1007 {
186            write!(
187                f,
188                concat!(
189                    "\n",
190                    "*** A special note about internal error number 1007 ***\n",
191                    "\n",
192                    "Experience suggests that a common cause of i.e. 1007\n",
193                    "is unreliable memory or other hardware.  The 1007 assertion\n",
194                    "just happens to cross-check the results of huge numbers of\n",
195                    "memory reads/writes, and so acts (unintendedly) as a stress\n",
196                    "test of your memory system.\n",
197                    "\n",
198                    "I suggest the following: try compressing the file again,\n",
199                    "possibly monitoring progress in detail with the -vv flag.\n",
200                    "\n",
201                    "* If the error cannot be reproduced, and/or happens at different\n",
202                    "  points in compression, you may have a flaky memory system.\n",
203                    "  Try a memory-test program.  I have used Memtest86\n",
204                    "  (www.memtest86.com).  At the time of writing it is free (GPLd).\n",
205                    "  Memtest86 tests memory much more thorougly than your BIOSs\n",
206                    "  power-on test, and may find failures that the BIOS doesn't.\n",
207                    "\n",
208                    "* If the error can be repeatably reproduced, this is a bug in\n",
209                    "  bzip2, and I would very much like to hear about it.  Please\n",
210                    "  let me know, and, ideally, save a copy of the file causing the\n",
211                    "  problem -- without which I will be unable to investigate it.\n",
212                    "\n"
213                )
214            )?;
215        }
216
217        Ok(())
218    }
219}
220
221#[cfg(test)]
222mod test {
223    extern crate alloc;
224
225    use super::*;
226
227    use alloc::string::String;
228
229    #[test]
230    fn print_assert_fail_coverage() {
231        use core::fmt::Write;
232        write!(&mut String::new(), "{}", AssertFail(1007)).unwrap();
233    }
234}