zipatch-rs 1.0.0

Parser for FFXIV ZiPatch patch files
Documentation
use binrw::BinRead;
use std::io::Cursor;

use super::SqpackFile;

/// SQPK `D` command body: overwrite a contiguous block range with empty-block markers.
#[derive(BinRead, Debug, Clone, PartialEq, Eq)]
#[br(big)]
pub struct SqpkDeleteData {
    /// `SqPack` file the deletion targets.
    #[br(pad_before = 3)]
    pub target_file: SqpackFile,
    /// Start offset of the affected range (raw `u32` shifted left 7 bits).
    #[br(map = |raw: u32| (raw as u64) << 7)]
    pub block_offset: u64,
    /// Number of 128-byte blocks to clear (not shifted).
    #[br(pad_after = 4)]
    pub block_count: u32,
}

pub(crate) fn parse(body: &[u8]) -> crate::Result<SqpkDeleteData> {
    Ok(SqpkDeleteData::read_be(&mut Cursor::new(body))?)
}

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

    #[test]
    fn parses_delete_data() {
        let mut body = Vec::new();
        body.extend_from_slice(&[0u8; 3]); // alignment
        body.extend_from_slice(&4u16.to_be_bytes()); // main_id
        body.extend_from_slice(&5u16.to_be_bytes()); // sub_id
        body.extend_from_slice(&6u32.to_be_bytes()); // file_id
        body.extend_from_slice(&2u32.to_be_bytes()); // block_offset raw → 2 << 7 = 256
        body.extend_from_slice(&7u32.to_be_bytes()); // block_count (no shift)
        body.extend_from_slice(&[0u8; 4]); // reserved

        let cmd = parse(&body).unwrap();
        assert_eq!(cmd.target_file.main_id, 4);
        assert_eq!(cmd.block_offset, 256);
        assert_eq!(cmd.block_count, 7);
    }
}