ps2mc 0.1.0

A Rust library for reading, extracting, and rewriting PlayStation 2 memory card images.
Documentation
use super::error::Ps2mcError;

/// 编译期计算:计算一个字节的奇偶性 (奇数个1返回1,偶数个返回0)
const fn calculate_parity(mut byte: u8) -> u8 {
    byte ^= byte >> 1;
    byte ^= byte >> 2;
    byte ^= byte >> 4;
    byte & 1
}

/// 编译期生成:256字节的奇偶性查找表
const PARITY_TABLE: [u8; 256] = {
    let mut table = [0; 256];
    let mut b = 0;
    while b < 256 {
        table[b] = calculate_parity(b as u8);
        b += 1;
    }
    table
};

/// 编译期生成:256字节的列奇偶校验掩码表
const COLUMN_PARITY_MASKS: [u8; 256] = {
    let mut table = [0; 256];
    let cpmasks = [0x55, 0x33, 0x0F, 0x00, 0xAA, 0xCC, 0xF0];
    let mut b = 0;
    while b < 256 {
        let mut mask = 0;
        let mut i = 0;
        while i < 7 {
            let bit = calculate_parity((b as u8) & cpmasks[i]);
            mask |= bit << i;
            i += 1;
        }
        table[b] = mask;
        b += 1;
    }
    table
};

/// 为 128 字节的数据块计算 3 字节的 PS2 标准 ECC 校验码。
pub fn calculate(data: &[u8]) -> Result<[u8; 3], Ps2mcError> {
    if data.len() != 128 {
        return Err(Ps2mcError::UnexpectedEof {
            context: "ecc block",
            expected: 128,
            actual: data.len(),
        });
    }

    let mut cp = 0x77;
    let mut lp0 = 0x7F;
    let mut lp1 = 0x7F;

    for (i, &b) in data.iter().enumerate() {
        let idx = b as usize;

        // 1. 计算列校验 (直接查编译期做好的表)
        cp ^= COLUMN_PARITY_MASKS[idx];

        // 2. 计算行校验
        if PARITY_TABLE[idx] == 1 {
            // Rust 的 !(i as u8) 对应 Python 的 ~i
            lp0 ^= !(i as u8);
            lp1 ^= i as u8;
        }
    }

    // 返回固定的 3 字节数组
    Ok([cp, lp0 & 0x7F, lp1 & 0x7F])
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_ecc_empty_block() {
        let data = [0u8; 128];
        let ecc = calculate(&data).unwrap();
        // 全0数据的标准 PS2 ECC 应该是 [0x77, 0x7F, 0x7F]
        assert_eq!(ecc, [0x77, 0x7F, 0x7F]);
    }
}