1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use std::io::{self, Read};
use ll;
struct DecoderContext {
c: ll::ZBUFFDecompressionContext,
}
impl DecoderContext {
fn new() -> Self {
DecoderContext { c: unsafe { ll::ZBUFF_createDCtx() } }
}
}
impl Drop for DecoderContext {
fn drop(&mut self) {
let code = unsafe { ll::ZBUFF_freeDCtx(self.c) };
ll::parse_code(code).unwrap();
}
}
/// A decoder that decompress input data from another `Read`.
pub struct Decoder<R: Read> {
// input reader (compressed data)
reader: R,
// input buffer
buffer: Vec<u8>,
// we already read everything in the buffer up to that point
offset: usize,
// decompression context
context: DecoderContext,
}
impl<R: Read> Decoder<R> {
/// Creates a new decoder.
pub fn new(reader: R) -> io::Result<Self> {
let context = DecoderContext::new();
try!(ll::parse_code(unsafe { ll::ZBUFF_decompressInit(context.c) }));
Decoder::with_context(reader, context)
}
/// Creates a new decoder, using an existing dictionary.
///
/// The dictionary must be the same as the one used during compression.
pub fn with_dictionary(reader: R, dictionary: &[u8]) -> io::Result<Self> {
let context = DecoderContext::new();
try!(ll::parse_code(unsafe {
ll::ZBUFF_decompressInitDictionary(context.c,
dictionary.as_ptr(),
dictionary.len())
}));
Decoder::with_context(reader, context)
}
fn with_context(reader: R, context: DecoderContext) -> io::Result<Self> {
let buffer_size = unsafe { ll::ZBUFF_recommendedDInSize() };
Ok(Decoder {
reader: reader,
buffer: Vec::with_capacity(buffer_size),
offset: 0,
context: context,
})
}
/// Recommendation for the size of the output buffer.
pub fn recommended_output_size() -> usize {
unsafe { ll::ZBUFF_recommendedDOutSize() }
}
}
impl<R: Read> Read for Decoder<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let mut written = 0;
while written != buf.len() {
if self.offset == self.buffer.len() {
// We need moar data!
// Make a nice clean buffer
let buffer_size = self.buffer.capacity();
unsafe {
self.buffer.set_len(buffer_size);
}
// And FILL IT!
self.offset = 0;
let read = try!(self.reader.read(&mut self.buffer));
unsafe {
self.buffer.set_len(read);
}
// If we can't read anything, no need to try and decompress it.
// Just break the loop.
if read == 0 {
break;
}
}
let mut out_size = buf.len() - written;
let mut in_size = self.buffer.len() - self.offset;
unsafe {
let code =
ll::ZBUFF_decompressContinue(self.context.c,
buf[written..].as_mut_ptr(),
&mut out_size,
self.buffer[self.offset..]
.as_ptr(),
&mut in_size);
let _ = try!(ll::parse_code(code));
}
written += out_size;
self.offset += in_size;
}
Ok(written)
}
}