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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
use std::fmt;
use libc::{c_char, c_int, size_t};
const SNAPPY_OK: c_int = 0;
const SNAPPY_INVALID_INPUT: c_int = 1;
const SNAPPY_BUFFER_TOO_SMALL: c_int = 2;
#[link(name = "snappy")]
extern {
fn snappy_compress(
input: *const c_char,
input_len: size_t,
compressed: *mut c_char,
compressed_len: *mut size_t
) -> c_int;
fn snappy_max_compressed_length(source_len: size_t) -> size_t;
fn snappy_uncompress(
compressed: *const c_char,
compressed_len: size_t,
uncompressed: *mut c_char,
uncompressed_len: *mut size_t,
) -> c_int;
fn snappy_uncompressed_length(
compressed: *const c_char,
compressed_len: size_t,
result: *mut size_t,
) -> c_int;
fn snappy_validate_compressed_buffer(
compressed: *const c_char,
compressed_len: size_t,
) -> c_int;
}
#[derive(Debug)]
pub struct InvalidInput;
impl fmt::Display for InvalidInput {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Attempted snappy decompression with invalid input")
}
}
pub fn max_compressed_len(len: usize) -> usize {
unsafe { snappy_max_compressed_length(len as size_t) as usize }
}
pub fn decompressed_len(compressed: &[u8]) -> Result<usize, InvalidInput> {
let mut size: size_t = 0;
let len = compressed.len() as size_t;
let status = unsafe { snappy_uncompressed_length(compressed.as_ptr() as *const c_char, len, &mut size) };
if status == SNAPPY_INVALID_INPUT {
Err(InvalidInput)
} else {
Ok(size)
}
}
pub fn compress(input: &[u8]) -> Vec<u8> {
let mut buf = Vec::new();
compress_into(input, &mut buf);
buf
}
pub fn compress_into(input: &[u8], output: &mut Vec<u8>) -> usize {
let mut len = max_compressed_len(input.len());
if output.len() < len {
output.resize(len, 0);
}
let status = unsafe {
snappy_compress(
input.as_ptr() as *const c_char,
input.len() as size_t,
output.as_mut_ptr() as *mut c_char,
&mut len as &mut size_t,
)
};
match status {
SNAPPY_OK => len,
SNAPPY_INVALID_INPUT => panic!("snappy compression has no concept of invalid input"),
SNAPPY_BUFFER_TOO_SMALL => panic!("buffer cannot be too small, the capacity was just ensured."),
_ => panic!("snappy returned unspecified status"),
}
}
pub fn decompress(input: &[u8]) -> Result<Vec<u8>, InvalidInput> {
let mut v = Vec::new();
decompress_into(input, &mut v).map(|_| v)
}
pub fn decompress_into(input: &[u8], output: &mut Vec<u8>) -> Result<usize, InvalidInput> {
let mut len = decompressed_len(input)?;
if output.len() < len {
output.resize(len, 0);
}
let status = unsafe {
snappy_uncompress(
input.as_ptr() as *const c_char,
input.len() as size_t,
output.as_mut_ptr() as *mut c_char,
&mut len as &mut size_t,
)
};
match status {
SNAPPY_OK => Ok(len as usize),
SNAPPY_INVALID_INPUT => Err(InvalidInput),
SNAPPY_BUFFER_TOO_SMALL => panic!("buffer cannot be too small, size was just set to large enough."),
_ => panic!("snappy returned unspecified status"),
}
}
pub fn validate_compressed_buffer(input: &[u8]) -> bool {
let status = unsafe { snappy_validate_compressed_buffer(input.as_ptr() as *const c_char, input.len() as size_t )};
status == SNAPPY_OK
}