Mercurial > touhou
annotate formats/src/th06/t6rp.rs @ 794:8c2ef2d503c9 default tip
formats: Implement T6RP in Rust
This has been tested against demo00.rpy shipped in CM.DAT.
| author | Link Mauve <linkmauve@linkmauve.fr> |
|---|---|
| date | Tue, 02 Jun 2026 16:39:21 +0200 |
| parents | |
| children |
| 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 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
41 unknown: u32, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
42 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
43 /// The list of keys pressed during this level. |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
44 pub keys: Vec<(u32, u16, u16)>, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
45 } |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
46 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
47 /// The unencrypted part of a replay. |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
48 #[derive(Debug, Clone)] |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
49 pub struct Header { |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
50 /// The version, only 1.02 is supported so far. |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
51 pub version: u16, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
52 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
53 /// 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
|
54 pub character: u8, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
55 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
56 /// The rank picked by the player, 0 = Easy, 4 = Extra. |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
57 pub rank: u8, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
58 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
59 /// The checksum of the encrypted part of this replay. |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
60 pub checksum: u32, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
61 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
62 unknown1: u8, |
|
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 unknown2: 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 /// The encryption key for the rest of this replay. |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
67 pub key: u8, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
68 } |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
69 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
70 /// The encrypted part of a replay. |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
71 #[derive(Debug, Clone)] |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
72 pub struct T6rp { |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
73 unknown3: u8, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
74 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
75 /// The date at which this replay got recorded. |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
76 pub date: [u8; 9], |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
77 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
78 /// The name of the player. |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
79 pub name: [u8; 9], |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
80 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
81 unknown4: u16, |
|
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 /// The score at the end of this replay. |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
84 pub score: u32, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
85 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
86 unknown5: 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 /// How much slowdown has been experienced while recording this replay. |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
89 pub slowdown: f32, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
90 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
91 unknown6: u32, |
|
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 /// 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
|
94 pub levels: [Option<Level>; 7], |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
95 } |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
96 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
97 // 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
|
98 // newtype for the decrypted data to have verify() and parse(). |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
99 impl T6rp { |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
100 /// 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
|
101 pub fn parse_header(input: &[u8]) -> IResult<&[u8], Header> { |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
102 let (encrypted, (_, version, character, rank, checksum, unknown1, unknown2, key)) = ( |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
103 tag(&b"T6RP"[..]), |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
104 le_u16, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
105 le_u8, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
106 le_u8, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
107 le_u32, |
|
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_u8, |
|
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 ) |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
112 .parse(input)?; |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
113 Ok(( |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
114 encrypted, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
115 Header { |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
116 version, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
117 character, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
118 rank, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
119 checksum, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
120 unknown1, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
121 unknown2, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
122 key, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
123 }, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
124 )) |
|
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 /// 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
|
128 pub fn decrypt(key: u8, encrypted: &[u8]) -> Vec<u8> { |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
129 let mut decrypted = Vec::with_capacity(encrypted.len()); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
130 for (i, c) in encrypted.iter().enumerate() { |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
131 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
|
132 } |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
133 decrypted |
|
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 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
136 /// Verify decrypted data against the header’s checksum. |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
137 pub fn verify(key: u8, checksum: u32, data: &[u8]) -> bool { |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
138 let real_sum = data |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
139 .iter() |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
140 .map(|c| *c as u32) |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
141 .sum::<u32>() |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
142 .wrapping_add(0x3f000318) |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
143 .wrapping_add(key as u32); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
144 checksum == real_sum |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
145 } |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
146 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
147 /// Parse a slice of bytes into a `T6rp` struct. |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
148 pub fn from_slice(input: &[u8]) -> IResult<&[u8], T6rp> { |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
149 let ( |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
150 _, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
151 (unknown3, date, name, unknown4, score, unknown5, slowdown, unknown6, stage_offsets), |
|
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 le_u8, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
154 count(le_u8, 9), |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
155 count(le_u8, 9), |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
156 le_u16, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
157 le_u32, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
158 le_u32, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
159 le_f32, |
|
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 count(le_u32, 7), |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
162 ) |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
163 .parse(input)?; |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
164 let date = date.try_into().unwrap(); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
165 let name = name.try_into().unwrap(); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
166 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
167 let mut levels = [const { None }; 7]; |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
168 for (index, offset) in stage_offsets.into_iter().enumerate() { |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
169 if offset == 0 { |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
170 continue; |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
171 } |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
172 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
173 let data = &input[offset as usize - 15..]; |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
174 let ( |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
175 mut data, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
176 (score, random_seed, point_items, power, lives, bombs, difficulty, unknown), |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
177 ) = (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
|
178 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
179 let mut keys = Vec::new(); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
180 loop { |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
181 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
|
182 data = data2; |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
183 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
184 if time == 9999999 { |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
185 break; |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
186 } |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
187 keys.push((time, keystate, unknown)); |
|
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 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
190 levels[index] = Some(Level { |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
191 score, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
192 random_seed, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
193 point_items, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
194 power, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
195 lives, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
196 bombs, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
197 difficulty, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
198 unknown, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
199 keys, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
200 }); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
201 } |
|
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 Ok(( |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
204 b"", |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
205 T6rp { |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
206 unknown3, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
207 date, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
208 name, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
209 unknown4, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
210 score, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
211 unknown5, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
212 slowdown, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
213 unknown6, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
214 levels, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
215 }, |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
216 )) |
|
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 #[cfg(test)] |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
221 mod tests { |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
222 use super::*; |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
223 use std::fs::File; |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
224 use std::io::{self, Read}; |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
225 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
226 #[test] |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
227 fn t6rp() { |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
228 let file = File::open("EoSD/CM.bak/demo00.rpy").unwrap(); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
229 let mut file = io::BufReader::new(file); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
230 let mut buf = Vec::new(); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
231 file.read_to_end(&mut buf).unwrap(); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
232 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
233 let (encrypted, header) = T6rp::parse_header(&buf).unwrap(); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
234 assert_eq!(header.version, 0x0102); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
235 assert_eq!(header.character, 0); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
236 assert_eq!(header.rank, 3); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
237 assert_eq!(header.checksum, 0x3f03188d); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
238 assert_eq!(header.key, 0x9d); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
239 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
240 let data = T6rp::decrypt(header.key, &encrypted); |
|
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 assert!(T6rp::verify(header.key, header.checksum, &data)); |
|
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 let (_, t6rp) = T6rp::from_slice(&data).unwrap(); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
245 assert_eq!(t6rp.date, *b"08/21/02\0"); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
246 assert_eq!(t6rp.name, *b"A \0"); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
247 assert_eq!(t6rp.score, 7837690); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
248 assert_eq!(t6rp.slowdown, 0.62111616); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
249 |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
250 let level4 = t6rp.levels[4 - 1].as_ref().unwrap(); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
251 assert_eq!(level4.score, 7837690); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
252 assert_eq!(level4.random_seed, 0xbf81); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
253 assert_eq!(level4.point_items, 0); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
254 assert_eq!(level4.power, 128); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
255 assert_eq!(level4.lives, 2); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
256 assert_eq!(level4.bombs, 3); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
257 assert_eq!(level4.difficulty, 16); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
258 assert_eq!(level4.keys.len(), 322); |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
259 } |
|
8c2ef2d503c9
formats: Implement T6RP in Rust
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff
changeset
|
260 } |
