use crate::convert::TryToUsize;
use crate::error::FormatError;
use crate::source::{BytesSource, FileSource};
pub const HDF5_SIGNATURE: [u8; 8] = [0x89, b'H', b'D', b'F', b'\r', b'\n', 0x1A, b'\n'];
pub fn find_signature_in<S: FileSource + ?Sized>(source: &S) -> Result<u64, FormatError> {
let len = source.len();
let mut sig = [0u8; 8];
if len >= 8 {
source.read_at(0, &mut sig)?;
if sig == HDF5_SIGNATURE {
return Ok(0);
}
}
let mut offset = 512u64;
while offset + 8 <= len {
source.read_at(offset, &mut sig)?;
if sig == HDF5_SIGNATURE {
return Ok(offset);
}
offset *= 2;
}
Err(FormatError::SignatureNotFound)
}
pub fn find_signature(data: &[u8]) -> Result<usize, FormatError> {
find_signature_in(&BytesSource::new(data)).and_then(|off| off.to_usize())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn signature_at_offset_0() {
let mut data = vec![0u8; 64];
data[..8].copy_from_slice(&HDF5_SIGNATURE);
assert_eq!(find_signature(&data), Ok(0));
}
#[test]
fn signature_at_offset_512() {
let mut data = vec![0u8; 1024];
data[512..520].copy_from_slice(&HDF5_SIGNATURE);
assert_eq!(find_signature(&data), Ok(512));
}
#[test]
fn signature_at_offset_1024() {
let mut data = vec![0u8; 2048];
data[1024..1032].copy_from_slice(&HDF5_SIGNATURE);
assert_eq!(find_signature(&data), Ok(1024));
}
#[test]
fn signature_at_offset_2048() {
let mut data = vec![0u8; 4096];
data[2048..2056].copy_from_slice(&HDF5_SIGNATURE);
assert_eq!(find_signature(&data), Ok(2048));
}
#[test]
fn signature_not_found() {
let data = vec![0u8; 8192];
assert_eq!(find_signature(&data), Err(FormatError::SignatureNotFound));
}
#[test]
fn signature_not_found_empty() {
assert_eq!(find_signature(&[]), Err(FormatError::SignatureNotFound));
}
#[test]
fn signature_not_found_too_short() {
assert_eq!(
find_signature(&[0x89, b'H', b'D']),
Err(FormatError::SignatureNotFound)
);
}
#[test]
fn signature_at_non_power_of_two_not_found() {
let mut data = vec![0u8; 1024];
data[100..108].copy_from_slice(&HDF5_SIGNATURE);
assert_eq!(find_signature(&data), Err(FormatError::SignatureNotFound));
}
#[test]
fn signature_prefers_earliest() {
let mut data = vec![0u8; 1024];
data[..8].copy_from_slice(&HDF5_SIGNATURE);
data[512..520].copy_from_slice(&HDF5_SIGNATURE);
assert_eq!(find_signature(&data), Ok(0));
}
#[cfg(feature = "std")]
#[test]
fn signature_found_over_a_streaming_source() {
use crate::source::ReadSeekSource;
let mut data = vec![0u8; 1024];
data[512..520].copy_from_slice(&HDF5_SIGNATURE);
let src = ReadSeekSource::new(std::io::Cursor::new(data)).unwrap();
assert_eq!(find_signature_in(&src), Ok(512));
}
}