use super::super::nam_json::WeightsLayout;
use super::error::NambError;
pub fn crc32_ieee_update(mut crc: u32, data: &[u8]) -> u32 {
for &byte in data {
crc ^= byte as u32;
for _ in 0..8 {
let mask = (crc & 1).wrapping_neg();
crc = (crc >> 1) ^ (0xEDB88320u32 & mask);
}
}
crc
}
pub fn crc32_ieee(data: &[u8]) -> u32 {
crc32_ieee_update(0xFFFFFFFFu32, data) ^ 0xFFFFFFFFu32
}
pub fn check_crc(
data: &[u8],
version: u16,
weights_offset: usize,
expected: u32,
) -> Result<(), NambError> {
let calculated = if version >= 2 {
let crc = crc32_ieee_update(0xFFFFFFFFu32, &data[..24]);
let crc = crc32_ieee_update(crc, &data[28..]);
crc ^ 0xFFFFFFFFu32
} else {
crc32_ieee(&data[weights_offset..])
};
if calculated != expected {
return Err(NambError::CrcMismatch {
got: calculated,
expected,
});
}
Ok(())
}
pub const FLAG_HAS_CRC32: u8 = 0x01;
#[repr(C, packed)]
#[derive(Debug, Clone, Copy)]
pub struct NambHeader {
pub magic: u32,
pub version: u16,
pub layout_type: u8,
pub flags: u8,
pub reserved_v2: [u8; 4],
pub weights_offset: u32,
pub reserved1: [u32; 2],
pub crc32: u32,
pub reserved2: u32,
pub version_str: [u8; 32],
pub sample_rate: f32,
pub input_level_dbu: f32,
pub output_level_dbu: f32,
pub reserved3: [u32; 1],
}
impl NambHeader {
pub fn validate(&self) -> Result<(), NambError> {
let magic = self.magic;
let version = self.version;
if magic != 0x4E414D42 {
return Err(NambError::InvalidMagic(magic));
}
if version != 1 && version != 2 {
return Err(NambError::InvalidVersion(version));
}
Ok(())
}
pub fn get_layout(&self) -> WeightsLayout {
let version = self.version;
if version < 2 {
return WeightsLayout::Original;
}
match self.layout_type {
1 => WeightsLayout::GateMajorLstm,
2 => WeightsLayout::Interleaved4WaveNet,
_ => WeightsLayout::Original,
}
}
}