Fix silent wrong data and libhdf5 interop found by the HDF5 audit #11
@@ -988,10 +988,14 @@ fn zstd_decompress(_data: &[u8], _expected_bytes: usize) -> Result<Vec<u8>, Form
|
|||||||
Err(FormatError::UnsupportedFilter(FILTER_ZSTD))
|
Err(FormatError::UnsupportedFilter(FILTER_ZSTD))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compress data with zstd.
|
/// Compress data with zstd as one frame whose header records the content
|
||||||
|
/// size. The registered HDF5 Zstandard filter (`H5Zzstd.c`, used by
|
||||||
|
/// libhdf5 + hdf5plugin) sizes its output buffer from
|
||||||
|
/// `ZSTD_getFrameContentSize` and fails on a frame without it, which is what
|
||||||
|
/// the streaming encoder (`zstd::encode_all`) produced.
|
||||||
#[cfg(feature = "zstd")]
|
#[cfg(feature = "zstd")]
|
||||||
fn zstd_compress(data: &[u8], level: u32) -> Result<Vec<u8>, FormatError> {
|
fn zstd_compress(data: &[u8], level: u32) -> Result<Vec<u8>, FormatError> {
|
||||||
zstd::encode_all(data, level as i32)
|
zstd::bulk::compress(data, level as i32)
|
||||||
.map_err(|e| FormatError::CompressionError(format!("zstd: {e}")))
|
.map_err(|e| FormatError::CompressionError(format!("zstd: {e}")))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1710,6 +1714,23 @@ mod tests {
|
|||||||
|
|
||||||
// --- Zstd tests ---
|
// --- Zstd tests ---
|
||||||
|
|
||||||
|
/// libhdf5's zstd plugin needs the frame content size to size its
|
||||||
|
/// output; frames without it fail to decode there.
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "zstd")]
|
||||||
|
fn zstd_frames_record_content_size() {
|
||||||
|
for n in [0usize, 1, 200, 100_000] {
|
||||||
|
let data: Vec<u8> = (0..n).map(|i| (i % 7) as u8).collect();
|
||||||
|
let c = zstd_compress(&data, 3).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
zstd::zstd_safe::get_frame_content_size(&c).unwrap(),
|
||||||
|
Some(n as u64),
|
||||||
|
"{n} bytes"
|
||||||
|
);
|
||||||
|
assert_eq!(zstd_decompress(&c, n).unwrap(), data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "zstd")]
|
#[cfg(feature = "zstd")]
|
||||||
fn zstd_compress_decompress_roundtrip() {
|
fn zstd_compress_decompress_roundtrip() {
|
||||||
|
|||||||
@@ -985,3 +985,16 @@ fn hdf5plugin_reads_our_lz4() {
|
|||||||
});
|
});
|
||||||
assert_eq!(got, data);
|
assert_eq!(got, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// libhdf5's Zstandard plugin must decode what we write (it could not while
|
||||||
|
/// our frames lacked the content size).
|
||||||
|
#[cfg(feature = "zstd")]
|
||||||
|
#[test]
|
||||||
|
#[ignore = "requires Python h5py + hdf5plugin"]
|
||||||
|
fn hdf5plugin_reads_our_zstd() {
|
||||||
|
let data: Vec<f64> = (0..1000).map(|i| (i % 37) as f64 * 0.5).collect();
|
||||||
|
let got = hdf5plugin_roundtrip("zstd", &data, |ds| {
|
||||||
|
ds.with_zstd(3);
|
||||||
|
});
|
||||||
|
assert_eq!(got, data);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user