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
158
159
use std::ptr;
use std::slice;
use lazy_static::lazy_static;
use hdf5_sys::h5p::{H5Pget_chunk, H5Pget_filter_by_id2, H5Pmodify_filter};
use hdf5_sys::h5t::H5Tget_size;
use hdf5_sys::h5z::{H5Z_class2_t, H5Z_filter_t, H5Zregister, H5Z_CLASS_T_VERS, H5Z_FLAG_REVERSE};
use crate::globals::{H5E_CALLBACK, H5E_PLIST};
use crate::internal_prelude::*;
use lzf_sys::{lzf_compress, lzf_decompress, LZF_VERSION};
const LZF_FILTER_NAME: &[u8] = b"lzf\0";
pub const LZF_FILTER_ID: H5Z_filter_t = 32000;
const LZF_FILTER_VERSION: c_uint = 4;
const LZF_FILTER_INFO: H5Z_class2_t = H5Z_class2_t {
version: H5Z_CLASS_T_VERS as _,
id: LZF_FILTER_ID,
encoder_present: 1,
decoder_present: 1,
name: LZF_FILTER_NAME.as_ptr().cast(),
can_apply: None,
set_local: Some(set_local_lzf),
filter: Some(filter_lzf),
};
lazy_static! {
static ref LZF_INIT: Result<(), &'static str> = {
let ret = unsafe { H5Zregister((&LZF_FILTER_INFO as *const H5Z_class2_t).cast()) };
if H5ErrorCode::is_err_code(ret) {
return Err("Can't register LZF filter");
}
Ok(())
};
}
pub fn register_lzf() -> Result<(), &'static str> {
(*LZF_INIT).clone()
}
extern "C" fn set_local_lzf(dcpl_id: hid_t, type_id: hid_t, _space_id: hid_t) -> herr_t {
const MAX_NDIMS: usize = 32;
let mut flags: c_uint = 0;
let mut nelmts: size_t = 0;
let mut values: Vec<c_uint> = vec![0; 8];
let ret = unsafe {
H5Pget_filter_by_id2(
dcpl_id,
LZF_FILTER_ID,
&mut flags as *mut _,
&mut nelmts as *mut _,
values.as_mut_ptr(),
0,
ptr::null_mut(),
ptr::null_mut(),
)
};
if ret < 0 {
return -1;
}
nelmts = nelmts.max(3);
if values[0] == 0 {
values[0] = LZF_FILTER_VERSION;
}
if values[1] == 0 {
values[1] = LZF_VERSION;
}
let mut chunkdims: Vec<hsize_t> = vec![0; MAX_NDIMS];
let ndims: c_int = unsafe { H5Pget_chunk(dcpl_id, MAX_NDIMS as _, chunkdims.as_mut_ptr()) };
if ndims < 0 {
return -1;
}
if ndims > MAX_NDIMS as _ {
h5err!("Chunk rank exceeds limit", H5E_PLIST, H5E_CALLBACK);
return -1;
}
let mut bufsize: size_t = unsafe { H5Tget_size(type_id) };
if bufsize == 0 {
return -1;
}
for &chunkdim in chunkdims[..(ndims as usize)].iter() {
bufsize *= chunkdim as size_t;
}
values[2] = bufsize as _;
let r = unsafe { H5Pmodify_filter(dcpl_id, LZF_FILTER_ID, flags, nelmts, values.as_ptr()) };
if r < 0 {
-1
} else {
1
}
}
extern "C" fn filter_lzf(
flags: c_uint, cd_nelmts: size_t, cd_values: *const c_uint, nbytes: size_t,
buf_size: *mut size_t, buf: *mut *mut c_void,
) -> size_t {
if flags & H5Z_FLAG_REVERSE == 0 {
unsafe { filter_lzf_compress(nbytes, buf_size, buf) }
} else {
unsafe { filter_lzf_decompress(cd_nelmts, cd_values, nbytes, buf_size, buf) }
}
}
unsafe fn filter_lzf_compress(
nbytes: size_t, buf_size: *mut size_t, buf: *mut *mut c_void,
) -> size_t {
let outbuf_size = *buf_size;
let outbuf = libc::malloc(outbuf_size);
if outbuf.is_null() {
h5err!("Can't allocate compression buffer", H5E_PLIST, H5E_CALLBACK);
return 0;
}
let status = lzf_compress(*buf, nbytes as _, outbuf, outbuf_size as _);
if status == 0 {
libc::free(outbuf);
} else {
libc::free(*buf);
*buf = outbuf;
}
status as _
}
unsafe fn filter_lzf_decompress(
cd_nelmts: size_t, cd_values: *const c_uint, nbytes: size_t, buf_size: *mut size_t,
buf: *mut *mut c_void,
) -> size_t {
let cdata = slice::from_raw_parts(cd_values, cd_nelmts as _);
let mut outbuf_size = if cd_nelmts >= 3 && cdata[2] != 0 { cdata[2] as _ } else { *buf_size };
let mut outbuf: *mut c_void;
let mut status: c_uint;
loop {
outbuf = libc::malloc(outbuf_size);
if outbuf.is_null() {
h5err!("Can't allocate decompression buffer", H5E_PLIST, H5E_CALLBACK);
return 0;
}
status = lzf_decompress(*buf, nbytes as _, outbuf, outbuf_size as _);
if status != 0 {
break;
}
libc::free(outbuf);
let e = errno::errno().0;
if e == 7 {
outbuf_size += *buf_size;
continue;
} else if e == 22 {
h5err!("Invalid data for LZF decompression", H5E_PLIST, H5E_CALLBACK);
} else {
h5err!("Unknown LZF decompression error", H5E_PLIST, H5E_CALLBACK);
}
return 0;
}
libc::free(*buf);
*buf = outbuf;
*buf_size = outbuf_size as _;
status as _
}