use std::collections::HashMap;
use crate::error::Result;
pub fn read_handles(data: &[u8]) -> Result<HashMap<u64, i64>> {
let mut handle_map: HashMap<u64, i64> = HashMap::new();
let mut pos: usize = 0;
while pos + 2 <= data.len() {
let size = ((data[pos] as usize) << 8) | (data[pos + 1] as usize);
pos += 2;
if size <= 2 || size > 2048 {
break;
}
let data_bytes = size - 2;
let chunk_end = (pos + data_bytes).min(data.len());
let mut last_handle: u64 = 0;
let mut last_offset: i64 = 0;
while pos < chunk_end {
let (handle_delta, bytes_read) = read_mc(&data[pos..]);
pos += bytes_read;
let (offset_delta, bytes_read) = read_smc(&data[pos..]);
pos += bytes_read;
last_handle = last_handle.wrapping_add(handle_delta);
last_offset = last_offset.wrapping_add(offset_delta);
handle_map.insert(last_handle, last_offset);
}
if pos + 2 <= data.len() {
pos += 2;
}
}
Ok(handle_map)
}
fn read_mc(data: &[u8]) -> (u64, usize) {
let mut value: u64 = 0;
let mut shift: u32 = 0;
let mut i: usize = 0;
loop {
if i >= data.len() {
break;
}
let b = data[i];
i += 1;
value |= ((b & 0x7F) as u64) << shift;
if (b & 0x80) == 0 {
break;
}
shift += 7;
}
(value, i)
}
fn read_smc(data: &[u8]) -> (i64, usize) {
let mut value: u64 = 0;
let mut shift: u32 = 0;
let mut i: usize = 0;
let mut last_byte: u8 = 0;
loop {
if i >= data.len() {
break;
}
let b = data[i];
i += 1;
last_byte = b;
if (b & 0x80) == 0 {
value |= ((b & 0x3F) as u64) << shift;
break;
} else {
value |= ((b & 0x7F) as u64) << shift;
shift += 7;
}
}
let signed_value = value as i64;
if (last_byte & 0x40) != 0 {
(-signed_value, i)
} else {
(signed_value, i)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mc_encoding() {
let (val, len) = read_mc(&[0x05]);
assert_eq!(val, 5);
assert_eq!(len, 1);
let (val, len) = read_mc(&[0xC8, 0x01]);
assert_eq!(val, 200);
assert_eq!(len, 2);
}
#[test]
fn test_smc_encoding() {
let (val, _) = read_smc(&[0x24]);
assert_eq!(val, 36);
let (val, _) = read_smc(&[0x64]);
assert_eq!(val, -36);
let (val, len) = read_smc(&[0xE4, 0x00]);
assert_eq!(val, 100);
assert_eq!(len, 2);
}
#[test]
fn test_handle_reader_basic() {
let mut chunk_data = Vec::new();
chunk_data.push(0x05); chunk_data.push(0xE4); chunk_data.push(0x00);
chunk_data.push(0x03); chunk_data.push(0x32);
let mut data = Vec::new();
let size = (2 + chunk_data.len()) as u16;
data.push((size >> 8) as u8);
data.push((size & 0xFF) as u8);
data.extend_from_slice(&chunk_data);
data.push(0x00); data.push(0x00);
let handles = read_handles(&data).unwrap();
assert_eq!(handles.len(), 2);
assert_eq!(handles[&5_u64], 100_i64);
assert_eq!(handles[&8_u64], 150_i64); }
}