lzokay_native/
lib.rs

1//! # LZ👌in Rust
2//!
3//! A pure rust port of [lzokay](https://github.com/jackoalan/lzokay), which is a C++ implementation of the [LZO compression format](http://www.oberhumer.com/opensource/lzo/).
4//!
5//! ## Examples
6//!
7//! ### Compressing raw data
8//! ```rust
9//! use std::fs::File;
10//!
11//! fn main () -> Result<(), lzokay_native::Error> {
12//!     let data = include_bytes!("../test-data/uncompressed/alice29.txt");
13//!     let compressed = lzokay_native::compress(data);
14//!
15//!     Ok(())
16//! }
17//! ```
18//!
19//! ### Multiple compressions without repeated (de-)allocations
20//! By using a [`Dict`] and [`compress_with_dict`] you can avoid repeat allocation/deallocation
21//! of the work memory used by the compressor:
22//!
23//! ```rust
24//! use std::fs::File;
25//!
26//! fn main () -> Result<(), lzokay_native::Error> {
27//!     let mut dict = lzokay_native::Dict::new();
28//!
29//!     let data1 = include_bytes!("../test-data/uncompressed/alice29.txt");
30//!     let compressed1 = lzokay_native::compress_with_dict(data1, &mut dict)?;
31//!
32//!     let data2 = include_bytes!("../test-data/uncompressed/asyoulik.txt");
33//!     let compressed2 = lzokay_native::compress_with_dict(data2, &mut dict)?;
34//!     
35//!     Ok(())
36//! }
37//! ```
38//!
39//! ### Decompressing a file
40//! ```rust
41//! use std::fs::File;
42//!
43//! fn main () -> Result<(), lzokay_native::Error> {
44//!     let file_path = "./test-data/compressed/fields.c.lzo";
45//!     
46//!     let mut file = File::open(file_path)?; // file implements std::io::Read
47//!     let decompressed = lzokay_native::decompress(&mut file, None);
48//!
49//!     Ok(())
50//! }
51//! ```
52//!
53//! ### Decompressing raw data
54//! ```rust
55//! use std::fs::File;
56//!
57//! fn main () -> Result<(), lzokay_native::Error> {
58//!     let data = include_bytes!("../test-data/compressed/fields.c.lzo");
59//!     let decompressed = lzokay_native::decompress_all(data, None);
60//!
61//!     Ok(())
62//! }
63//! ```
64
65#![warn(missing_docs)]
66#![warn(clippy::cargo)]
67#![warn(clippy::pedantic)]
68#![warn(clippy::nursery)]
69#![warn(clippy::unwrap_used)]
70#![warn(clippy::expect_used)]
71#![allow(clippy::module_name_repetitions)]
72#![allow(clippy::multiple_crate_versions)]
73#![cfg_attr(docsrs, feature(doc_auto_cfg))]
74#![allow(clippy::cast_possible_truncation)]
75#![allow(clippy::cast_possible_wrap)]
76#![allow(clippy::cast_sign_loss)]
77
78#[cfg(feature = "compress")]
79mod compress;
80#[cfg(feature = "compress")]
81pub use compress::*;
82
83#[cfg(feature = "decompress")]
84mod decompress;
85#[cfg(feature = "decompress")]
86pub use decompress::*;
87
88mod util;
89
90pub use util::Error;
91
92#[cfg(test)]
93mod tests {
94    use std::fs;
95    #[cfg(any(feature = "decompress", feature = "compress"))]
96    use std::io::Cursor;
97
98    #[cfg(any(feature = "decompress", feature = "compress"))]
99    use sha1::Digest;
100    #[cfg(any(feature = "decompress", feature = "compress"))]
101    use sha1::Sha1;
102
103    #[test]
104    #[ignore]
105    fn generated_test_data() {
106        let files = fs::read_dir("./test-data/uncompressed").unwrap();
107
108        let mut lzo = minilzo_rs::LZO::init().unwrap();
109
110        for file in files {
111            let data = fs::read(file.as_ref().unwrap().path()).unwrap();
112
113            let compressed_data = lzo.compress(&data).unwrap();
114
115            let mut output_path = "./test-data/compressed/".to_owned();
116            output_path.push_str(file.unwrap().file_name().to_str().unwrap());
117            output_path.push_str(".lzo");
118            fs::write(output_path, compressed_data).unwrap();
119        }
120    }
121
122    #[cfg(feature = "compress")]
123    #[test]
124    fn compress_decompress_test() {
125        let files = fs::read_dir("./test-data/uncompressed").unwrap();
126
127        for file in files {
128            let data = fs::read(file.unwrap().path()).unwrap();
129
130            let mut sha = Sha1::new();
131            sha.update(data.clone());
132            let uncomp_data_sha = sha.finalize();
133
134            let data_compressed = crate::compress::compress(&data).unwrap();
135
136            let data_uncompressed =
137                crate::decompress::decompress(&mut Cursor::new(data_compressed), None).unwrap();
138
139            sha = Sha1::new();
140            sha.update(data_uncompressed);
141            let comp_data_sha = sha.finalize();
142            assert_eq!(uncomp_data_sha, comp_data_sha);
143        }
144    }
145
146    #[cfg(feature = "decompress")]
147    #[test]
148    fn decompress_test() {
149        let files = fs::read_dir("./test-data/compressed").unwrap();
150
151        for file in files {
152            let data = fs::read(file.as_ref().unwrap().path()).unwrap();
153
154            let data_uncompressed =
155                crate::decompress::decompress(&mut Cursor::new(data), None).unwrap();
156
157            let mut sha = Sha1::new();
158            sha.update(data_uncompressed);
159            let uncomp_data_sha = sha.finalize();
160
161            let file_name = file
162                .unwrap()
163                .path()
164                .file_stem()
165                .unwrap()
166                .to_str()
167                .unwrap()
168                .to_owned();
169
170            let mut input_path = "./test-data/uncompressed/".to_owned();
171            input_path.push_str(&file_name);
172
173            let comp_data = fs::read(input_path).unwrap();
174            sha = Sha1::new();
175            sha.update(comp_data);
176            let comp_data_sha = sha.finalize();
177
178            assert_eq!(uncomp_data_sha, comp_data_sha);
179        }
180    }
181
182    #[cfg(feature = "compress")]
183    #[test]
184    fn check_lzo_decompress_compatibility() {
185        let files = fs::read_dir("./test-data/uncompressed").unwrap();
186
187        let lzo = minilzo_rs::LZO::init().unwrap();
188
189        for file in files {
190            let data = fs::read(file.unwrap().path()).unwrap();
191            let data_len = data.len();
192
193            let mut sha = Sha1::new();
194            sha.update(data.clone());
195            let uncomp_data_sha = sha.finalize();
196
197            let data_compressed = crate::compress::compress(&data).unwrap();
198
199            let data_uncompressed = lzo.decompress_safe(&data_compressed, data_len).unwrap();
200
201            sha = Sha1::new();
202            sha.update(data_uncompressed);
203            let comp_data_sha = sha.finalize();
204            assert_eq!(uncomp_data_sha, comp_data_sha);
205        }
206    }
207
208    #[cfg(feature = "decompress")]
209    #[test]
210    fn decompress_test_small() {
211        let compressed = fs::read("./test-data/compressed/pic_small.png.lzo").unwrap();
212
213        // let size =
214        //     decompress::decompress_stream(&mut Cursor::new(compressed.clone()), Some(442780))
215        //         .unwrap();
216
217        let size2 = crate::decompress::decompress(&mut Cursor::new(compressed), None).unwrap();
218        fs::write("./test-data/output/pic_small.out.png", size2).unwrap();
219    }
220}