]> git.lizzy.rs Git - rust.git/blob - src/libextra/flate.rs
c974148ee1241f07e23b305180b679901ff77e9f
[rust.git] / src / libextra / flate.rs
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 /*!
12
13 Simple compression
14
15 */
16
17 #[allow(missing_doc)];
18
19 use std::libc::{c_void, size_t, c_int};
20 use std::libc;
21 use std::vec;
22
23 pub mod rustrt {
24     use std::libc::{c_int, c_void, size_t};
25
26     #[link_name = "rustrt"]
27     extern {
28         pub fn tdefl_compress_mem_to_heap(psrc_buf: *const c_void,
29                                           src_buf_len: size_t,
30                                           pout_len: *mut size_t,
31                                           flags: c_int)
32                                           -> *c_void;
33
34         pub fn tinfl_decompress_mem_to_heap(psrc_buf: *const c_void,
35                                             src_buf_len: size_t,
36                                             pout_len: *mut size_t,
37                                             flags: c_int)
38                                             -> *c_void;
39     }
40 }
41
42 static LZ_NONE : c_int = 0x0;   // Huffman-coding only.
43 static LZ_FAST : c_int = 0x1;   // LZ with only one probe
44 static LZ_NORM : c_int = 0x80;  // LZ with 128 probes, "normal"
45 static LZ_BEST : c_int = 0xfff; // LZ with 4095 probes, "best"
46 static TINFL_FLAG_PARSE_ZLIB_HEADER : c_int = 0x1; // parse zlib header and adler32 checksum
47 static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum
48
49 fn deflate_bytes_(bytes: &[u8], flags: c_int) -> ~[u8] {
50     do bytes.as_imm_buf |b, len| {
51         unsafe {
52             let mut outsz : size_t = 0;
53             let res =
54                 rustrt::tdefl_compress_mem_to_heap(b as *c_void,
55                                                    len as size_t,
56                                                    &mut outsz,
57                                                    flags);
58             assert!(res as int != 0);
59             let out = vec::raw::from_buf_raw(res as *u8,
60                                              outsz as uint);
61             libc::free(res);
62             out
63         }
64     }
65 }
66
67 pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] {
68     deflate_bytes_(bytes, LZ_NORM)
69 }
70
71 pub fn deflate_bytes_zlib(bytes: &[u8]) -> ~[u8] {
72     deflate_bytes_(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER)
73 }
74
75 fn inflate_bytes_(bytes: &[u8], flags: c_int) -> ~[u8] {
76     do bytes.as_imm_buf |b, len| {
77         unsafe {
78             let mut outsz : size_t = 0;
79             let res =
80                 rustrt::tinfl_decompress_mem_to_heap(b as *c_void,
81                                                      len as size_t,
82                                                      &mut outsz,
83                                                      flags);
84             assert!(res as int != 0);
85             let out = vec::raw::from_buf_raw(res as *u8,
86                                             outsz as uint);
87             libc::free(res);
88             out
89         }
90     }
91 }
92
93 pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] {
94     inflate_bytes_(bytes, 0)
95 }
96
97 pub fn inflate_bytes_zlib(bytes: &[u8]) -> ~[u8] {
98     inflate_bytes_(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER)
99 }
100
101 #[cfg(test)]
102 mod tests {
103     use super::*;
104     use std::rand;
105     use std::rand::RngUtil;
106
107     #[test]
108     fn test_flate_round_trip() {
109         let mut r = rand::rng();
110         let mut words = ~[];
111         do 20.times {
112             let range = r.gen_uint_range(1, 10);
113             words.push(r.gen_bytes(range));
114         }
115         do 20.times {
116             let mut input = ~[];
117             do 2000.times {
118                 input.push_all(r.choose(words));
119             }
120             debug!("de/inflate of %u bytes of random word-sequences",
121                    input.len());
122             let cmp = deflate_bytes(input);
123             let out = inflate_bytes(cmp);
124             debug!("%u bytes deflated to %u (%.1f%% size)",
125                    input.len(), cmp.len(),
126                    100.0 * ((cmp.len() as float) / (input.len() as float)));
127             assert_eq!(input, out);
128         }
129     }
130
131     #[test]
132     fn test_zlib_flate() {
133         let bytes = ~[1, 2, 3, 4, 5];
134         let deflated = deflate_bytes(bytes);
135         let inflated = inflate_bytes(deflated);
136         assert_eq!(inflated, bytes);
137     }
138 }