annotate formats/src/th06/t6rp.rs @ 795:2d60a14f4816 default tip

python: Rewrite the main entrypoint in Rust This lets us progressively replace Python modules with Rust ones. Currently missing features include: - Saving replays - Networking code for cooperative mode - Reading a configuration file for options - Maybe more. But the base game is working, so yay!
author Link Mauve <linkmauve@linkmauve.fr>
date Tue, 02 Jun 2026 19:06:16 +0200
parents 8c2ef2d503c9
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
794
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
1 //! Touhou 6 Replay (T6RP) format support.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
2 //!
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
3 //! This module provides classes for handling the Touhou 6 Replay file format.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
4 //! The T6RP file format is an encrypted format describing different aspects of
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
5 //! a game of EoSD. Since the EoSD engine is entirely deterministic, a small
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
6 //! replay file is sufficient to unfold a full game.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
7
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
8 use std::convert::TryInto;
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
9
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
10 use nom::{
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
11 bytes::complete::tag,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
12 multi::count,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
13 number::complete::{le_f32, le_i8, le_u16, le_u32, le_u8},
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
14 IResult, Parser,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
15 };
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
16
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
17 /// A single level of a replay.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
18 #[derive(Debug, Clone, Default)]
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
19 pub struct Level {
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
20 /// The score before starting the level.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
21 pub score: u32,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
22
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
23 /// The seed initializing the PRNG.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
24 pub random_seed: u16,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
25
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
26 /// The amount of point items collected before starting this level.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
27 pub point_items: u16,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
28
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
29 /// The power level at the beginning of the level.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
30 pub power: u8,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
31
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
32 /// How many lives are remaining before starting this level.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
33 pub lives: i8,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
34
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
35 /// How many bombs are remaining before starting this level.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
36 pub bombs: i8,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
37
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
38 /// The hidden difficulty at the beginning of this level.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
39 pub difficulty: u8,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
40
795
2d60a14f4816 python: Rewrite the main entrypoint in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents: 794
diff changeset
41 /// XXX
2d60a14f4816 python: Rewrite the main entrypoint in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents: 794
diff changeset
42 // TODO: Make non-pub.
2d60a14f4816 python: Rewrite the main entrypoint in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents: 794
diff changeset
43 pub unknown: u32,
794
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
44
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
45 /// The list of keys pressed during this level.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
46 pub keys: Vec<(u32, u16, u16)>,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
47 }
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
48
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
49 /// The unencrypted part of a replay.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
50 #[derive(Debug, Clone)]
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
51 pub struct Header {
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
52 /// The version, only 1.02 is supported so far.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
53 pub version: u16,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
54
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
55 /// The character picked by the player, 0 = Reimu A, 3 = Marisa B.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
56 pub character: u8,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
57
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
58 /// The rank picked by the player, 0 = Easy, 4 = Extra.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
59 pub rank: u8,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
60
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
61 /// The checksum of the encrypted part of this replay.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
62 pub checksum: u32,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
63
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
64 unknown1: u8,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
65
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
66 unknown2: u8,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
67
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
68 /// The encryption key for the rest of this replay.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
69 pub key: u8,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
70 }
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
71
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
72 /// The encrypted part of a replay.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
73 #[derive(Debug, Clone)]
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
74 pub struct T6rp {
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
75 unknown3: u8,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
76
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
77 /// The date at which this replay got recorded.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
78 pub date: [u8; 9],
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
79
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
80 /// The name of the player.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
81 pub name: [u8; 9],
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
82
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
83 unknown4: u16,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
84
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
85 /// The score at the end of this replay.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
86 pub score: u32,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
87
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
88 unknown5: u32,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
89
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
90 /// How much slowdown has been experienced while recording this replay.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
91 pub slowdown: f32,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
92
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
93 unknown6: u32,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
94
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
95 /// Each of the stages that got recorded, only 0..=6 or 7 can be set.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
96 pub levels: [Option<Level>; 7],
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
97 }
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
98
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
99 // TODO: Add a newtype for `encrypted`, to provide the decrypt() method on it and then another
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
100 // newtype for the decrypted data to have verify() and parse().
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
101 impl T6rp {
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
102 /// Parse a slice of bytes into a `Header` struct, which is the unencrypted part of T6RP.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
103 pub fn parse_header(input: &[u8]) -> IResult<&[u8], Header> {
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
104 let (encrypted, (_, version, character, rank, checksum, unknown1, unknown2, key)) = (
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
105 tag(&b"T6RP"[..]),
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
106 le_u16,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
107 le_u8,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
108 le_u8,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
109 le_u32,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
110 le_u8,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
111 le_u8,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
112 le_u8,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
113 )
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
114 .parse(input)?;
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
115 Ok((
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
116 encrypted,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
117 Header {
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
118 version,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
119 character,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
120 rank,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
121 checksum,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
122 unknown1,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
123 unknown2,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
124 key,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
125 },
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
126 ))
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
127 }
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
128
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
129 /// Decrypt the contents of the replay with the header’s key.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
130 pub fn decrypt(key: u8, encrypted: &[u8]) -> Vec<u8> {
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
131 let mut decrypted = Vec::with_capacity(encrypted.len());
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
132 for (i, c) in encrypted.iter().enumerate() {
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
133 decrypted.push(c.wrapping_sub(key).wrapping_sub((7 * i) as u8));
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
134 }
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
135 decrypted
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
136 }
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
137
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
138 /// Verify decrypted data against the header’s checksum.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
139 pub fn verify(key: u8, checksum: u32, data: &[u8]) -> bool {
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
140 let real_sum = data
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
141 .iter()
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
142 .map(|c| *c as u32)
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
143 .sum::<u32>()
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
144 .wrapping_add(0x3f000318)
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
145 .wrapping_add(key as u32);
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
146 checksum == real_sum
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
147 }
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
148
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
149 /// Parse a slice of bytes into a `T6rp` struct.
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
150 pub fn from_slice(input: &[u8]) -> IResult<&[u8], T6rp> {
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
151 let (
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
152 _,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
153 (unknown3, date, name, unknown4, score, unknown5, slowdown, unknown6, stage_offsets),
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
154 ) = (
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
155 le_u8,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
156 count(le_u8, 9),
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
157 count(le_u8, 9),
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
158 le_u16,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
159 le_u32,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
160 le_u32,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
161 le_f32,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
162 le_u32,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
163 count(le_u32, 7),
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
164 )
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
165 .parse(input)?;
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
166 let date = date.try_into().unwrap();
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
167 let name = name.try_into().unwrap();
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
168
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
169 let mut levels = [const { None }; 7];
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
170 for (index, offset) in stage_offsets.into_iter().enumerate() {
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
171 if offset == 0 {
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
172 continue;
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
173 }
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
174
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
175 let data = &input[offset as usize - 15..];
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
176 let (
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
177 mut data,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
178 (score, random_seed, point_items, power, lives, bombs, difficulty, unknown),
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
179 ) = (le_u32, le_u16, le_u16, le_u8, le_i8, le_i8, le_u8, le_u32).parse(data)?;
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
180
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
181 let mut keys = Vec::new();
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
182 loop {
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
183 let (data2, (time, keystate, unknown)) = (le_u32, le_u16, le_u16).parse(data)?;
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
184 data = data2;
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
185
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
186 if time == 9999999 {
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
187 break;
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
188 }
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
189 keys.push((time, keystate, unknown));
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
190 }
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
191
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
192 levels[index] = Some(Level {
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
193 score,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
194 random_seed,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
195 point_items,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
196 power,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
197 lives,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
198 bombs,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
199 difficulty,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
200 unknown,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
201 keys,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
202 });
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
203 }
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
204
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
205 Ok((
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
206 b"",
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
207 T6rp {
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
208 unknown3,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
209 date,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
210 name,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
211 unknown4,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
212 score,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
213 unknown5,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
214 slowdown,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
215 unknown6,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
216 levels,
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
217 },
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
218 ))
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
219 }
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
220 }
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
221
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
222 #[cfg(test)]
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
223 mod tests {
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
224 use super::*;
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
225 use std::fs::File;
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
226 use std::io::{self, Read};
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
227
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
228 #[test]
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
229 fn t6rp() {
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
230 let file = File::open("EoSD/CM.bak/demo00.rpy").unwrap();
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
231 let mut file = io::BufReader::new(file);
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
232 let mut buf = Vec::new();
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
233 file.read_to_end(&mut buf).unwrap();
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
234
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
235 let (encrypted, header) = T6rp::parse_header(&buf).unwrap();
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
236 assert_eq!(header.version, 0x0102);
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
237 assert_eq!(header.character, 0);
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
238 assert_eq!(header.rank, 3);
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
239 assert_eq!(header.checksum, 0x3f03188d);
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
240 assert_eq!(header.key, 0x9d);
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
241
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
242 let data = T6rp::decrypt(header.key, &encrypted);
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
243
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
244 assert!(T6rp::verify(header.key, header.checksum, &data));
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
245
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
246 let (_, t6rp) = T6rp::from_slice(&data).unwrap();
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
247 assert_eq!(t6rp.date, *b"08/21/02\0");
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
248 assert_eq!(t6rp.name, *b"A \0");
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
249 assert_eq!(t6rp.score, 7837690);
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
250 assert_eq!(t6rp.slowdown, 0.62111616);
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
251
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
252 let level4 = t6rp.levels[4 - 1].as_ref().unwrap();
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
253 assert_eq!(level4.score, 7837690);
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
254 assert_eq!(level4.random_seed, 0xbf81);
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
255 assert_eq!(level4.point_items, 0);
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
256 assert_eq!(level4.power, 128);
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
257 assert_eq!(level4.lives, 2);
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
258 assert_eq!(level4.bombs, 3);
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
259 assert_eq!(level4.difficulty, 16);
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
260 assert_eq!(level4.keys.len(), 322);
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
261 }
8c2ef2d503c9 formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
262 }