use srum_core::IdMapEntry;
use crate::SrumError;
const ESE_KEY_LEN: usize = 7;
const COL_ID_INDEX_OFF: usize = 5;
const COL_TAGGED_OFF: usize = 10;
const TAGGED_DESCRIPTOR_LEN: usize = 5;
pub fn decode_id_map_entry(data: &[u8], page: u32, tag: usize) -> Result<IdMapEntry, SrumError> {
if data.len() < 2 {
return Err(SrumError::DecodeError {
page,
tag,
detail: format!("id-map record too short: {}", data.len()),
});
}
let cb_pfx = u16::from_le_bytes([data[0], data[1]]) as usize;
if cb_pfx > ESE_KEY_LEN {
return Err(SrumError::DecodeError {
page,
tag,
detail: format!("id-map cb_pfx={cb_pfx} exceeds KEY_LEN={ESE_KEY_LEN}"),
});
}
let col_start = 2 + (ESE_KEY_LEN - cb_pfx);
if data.len() < col_start + 2 || data[col_start] != 0x02 || data[col_start + 1] != 0x7f {
return Err(SrumError::DecodeError {
page,
tag,
detail: format!(
"id-map record missing ESE header marker at col_start={col_start}: len={}",
data.len()
),
});
}
let id_off = col_start + COL_ID_INDEX_OFF;
if data.len() < id_off + 4 {
return Err(SrumError::DecodeError {
page,
tag,
detail: format!(
"real ESE id-map too short for IdIndex: len={}, need >= {}",
data.len(),
id_off + 4
),
});
}
let id = i32::from_le_bytes([
data[id_off],
data[id_off + 1],
data[id_off + 2],
data[id_off + 3],
]);
let blob_start = col_start + COL_TAGGED_OFF + TAGGED_DESCRIPTOR_LEN;
let name = if data.len() > blob_start {
let blob = &data[blob_start..];
let blob = if blob.len() >= 2 && blob[blob.len() - 2] == 0 && blob[blob.len() - 1] == 0 {
&blob[..blob.len() - 2]
} else {
blob
};
let utf16: Vec<u16> = blob
.chunks_exact(2)
.map(|b| u16::from_le_bytes([b[0], b[1]]))
.collect();
char::decode_utf16(utf16)
.map(|r| r.unwrap_or(char::REPLACEMENT_CHARACTER))
.collect()
} else {
String::new()
};
Ok(IdMapEntry { id, name })
}