1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use BinRead;
use Cursor;
use SqpackFile;
/// SQPK `E` command body: grow a `.dat` file by writing empty-block markers
/// into a previously unallocated region.
///
/// `ExpandData` and [`SqpkDeleteData`](super::SqpkDeleteData) produce the same
/// on-disk result — both write a `SqPack` empty-block header at `block_offset`
/// followed by zeroed bytes for the full block range. The semantic difference is
/// in the patch's intent:
///
/// - `E` (`ExpandData`) extends the file into space that did not previously exist,
/// growing the archive. It typically precedes a series of `A` (`AddData`) writes
/// into that newly allocated space.
/// - `D` (`DeleteData`) clears existing live blocks, logically freeing them.
///
/// The apply implementation (`src/apply/sqpk.rs`) handles both commands with
/// the same `write_empty_block` helper.
///
/// ## Wire format (all big-endian)
///
/// ```text
/// ┌────────────────────────────────────────────────────────────────────┐
/// │ <padding> : [u8; 3] (reserved, always zero) │ bytes 0–2
/// │ main_id : u16 BE │ bytes 3–4
/// │ sub_id : u16 BE │ bytes 5–6
/// │ file_id : u32 BE │ bytes 7–10
/// │ block_offset_raw : u32 BE multiply by 128 to get byte offset │ bytes 11–14
/// │ block_count : u32 BE number of 128-byte blocks to allocate │ bytes 15–18
/// │ <reserved> : u32 (always zero) │ bytes 19–22
/// └────────────────────────────────────────────────────────────────────┘
/// ```
///
/// `block_offset_raw` is in **128-byte `SqPack` block units** and is multiplied
/// by 128 (`<< 7`) during parsing. `block_count` is a direct block count (not
/// a byte count) and is stored as-is.
///
/// The total byte range affected by this command is `block_count * 128` bytes
/// starting at `block_offset`.
///
/// ## Reference
///
/// See `SqpkExpandData.cs` in the `XIVLauncher` reference implementation.
///
/// # Errors
///
/// Parsing returns [`crate::ZiPatchError::BinrwError`] if the body is too
/// short to contain all required fields.
pub