1use std::{
2 fmt::{self, Display},
3 marker::PhantomData,
4};
5
6#[allow(unused)]
7mod intl {
8
9 pub const CHARSET_TABLE: [[&str; 16]; 16] = [
11 [
12 " ", "À", "Á", "Â", "Ç", "È", "É", "Ê", "Ë", "Ì", " ", "Î", "Ï", "Ò", "Ó", "Ô",
13 ],
14 [
15 "Œ", "Ù", "Ú", "Û", "Ñ", "ß", "à", "á", " ", "ç", "è", "é", "ê", "ë", "ì", " ",
16 ],
17 [
18 "î", "ï", "ò", "ó", "ô", "œ", "ù", "ú", "û", "ñ", "º", "ª", " ", "&", "+", " ",
19 ],
20 [
21 " ", " ", " ", " ", "Lv", "=", ";", " ", " ", " ", " ", " ", " ", " ", " ", " ",
22 ],
23 [" "; 16],
24 [
25 "▯", "¿", "¡", "PK", "MN", "PO", "Ké", " ", " ", " ", "Í", "%", "(", ")", " ", " ",
26 ],
27 [
28 " ", " ", " ", " ", " ", " ", " ", " ", "â", " ", " ", " ", " ", " ", " ", "í",
29 ],
30 [
31 " ", " ", " ", " ", " ", " ", " ", " ", " ", "⬆", "⬇", "⬅", "➡", "*", "*", "*",
32 ],
33 [
34 "*", "*", "*", "*", "ᵉ", "<", ">", " ", " ", " ", " ", " ", " ", " ", " ", " ",
35 ],
36 [" "; 16],
37 [
38 "ʳᵉ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", ".", "-", "・",
39 ],
40 [
41 "...", "“", "”", "‘", "’", "♂", "♀", " ", ",", "×", "/", "A", "B", "C", "D", "E",
42 ],
43 [
44 "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
45 ],
46 [
47 "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
48 ],
49 [
50 "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "▶",
51 ],
52 [
53 ":", "Ä", "Ö", "Ü", "ä", "ö", "ü", " ", " ", " ", "", "", "", "", "", "",
54 ],
55 ];
56}
57
58#[allow(unused)]
59mod jpn {
60
61 pub const CHARSET_TABLE: [[&str; 16]; 16] = [
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 "ペ", "ポ",
102 ],
103 [
104 "ッ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "!", "?", "。", "ー", "・",
105 ],
106 [
107 "..", "『", "』", "「", "」", "♂", "♀", "円", ".", "×", "/", "A", "B", "C", "D", "E",
108 ],
109 [
110 "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
111 ],
112 [
113 "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
114 ],
115 [
116 "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "▶",
117 ],
118 [
119 ":", "Ä", "Ö", "Ü", "ä", "ö", "ü", "⬆", "⬇", "⬅", "", "", "", "", "", "",
120 ],
121 ];
122}
123
124#[repr(u8)]
125#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
126pub enum PokeLanguage {
127 Japanese = 1,
128 English = 2,
129 French = 3,
130 Italian = 4,
131 German = 5,
132 Korean = 6,
133 Spanish = 7,
134}
135
136impl Default for PokeLanguage {
137 fn default() -> Self {
138 PokeLanguage::English
139 }
140}
141
142#[derive(Debug)]
143pub struct Intl;
144
145#[derive(Debug)]
146pub struct Jpn;
147
148pub trait HasCharTable {
149 const CHAR_TABLE: [[&'static str; 16]; 16];
150}
151
152impl HasCharTable for Intl {
153 const CHAR_TABLE: [[&'static str; 16]; 16] = intl::CHARSET_TABLE;
154}
155
156impl HasCharTable for Jpn {
157 const CHAR_TABLE: [[&'static str; 16]; 16] = jpn::CHARSET_TABLE;
158}
159
160#[repr(transparent)]
161#[derive(Debug, Clone, Copy)]
162pub struct PkStrFFI<T: HasCharTable, const N: usize>(PkString<T, [u8; N]>);
163
164#[repr(C)]
165#[derive(Debug, Copy, Clone)]
166pub struct PkString<T: HasCharTable, U> {
167 raw_data: U,
168 phantom: PhantomData<T>,
169}
170
171impl<T: HasCharTable, U> From<U> for PkString<T, U> {
172 fn from(data: U) -> Self {
173 Self {
174 raw_data: data,
175 phantom: PhantomData::default(),
176 }
177 }
178}
179
180impl<T, const N: usize> Display for PkStrFFI<T, N>
181where
182 T: HasCharTable,
183{
184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185 let s = String::from(&self.0);
186 f.write_str(&s)
187 }
188}
189
190impl<T, U> Display for PkString<T, U>
191where
192 T: HasCharTable,
193 U: AsRef<[u8]>,
194{
195 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196 let s = String::from(self);
197 f.write_str(&s)
198 }
199}
200
201impl<T, const N: usize> From<[u8; N]> for PkStrFFI<T, N>
202where
203 T: HasCharTable,
204{
205 fn from(data: [u8; N]) -> Self {
206 Self(PkString::from(data))
207 }
208}
209
210impl<T, const N: usize> From<PkStrFFI<T, N>> for String
211where
212 T: HasCharTable,
213{
214 fn from(data: PkStrFFI<T, N>) -> Self {
215 String::from(data.0)
216 }
217}
218
219impl<T, U> From<PkString<T, U>> for String
220where
221 T: HasCharTable,
222 U: AsRef<[u8]>,
223{
224 fn from(data: PkString<T, U>) -> Self {
225 let mut s = String::with_capacity(data.raw_data.as_ref().len());
226 for c in data.raw_data.as_ref() {
227 let c = *c;
228 if c == 255 {
229 break;
230 }
231 let high = (c & 0x0F) as usize;
232 let low = (c >> 4) as usize;
233 s.push_str(T::CHAR_TABLE[low][high]);
234 }
235 s
236 }
237}
238
239impl<'a, T, U> From<&'a PkString<T, U>> for String
240where
241 T: HasCharTable,
242 U: AsRef<[u8]>,
243{
244 fn from(data: &'a PkString<T, U>) -> Self {
245 let mut s = String::with_capacity(data.raw_data.as_ref().len());
246 for c in data.raw_data.as_ref() {
247 let c = *c;
248 if c == 255 {
249 break;
250 }
251 let high = (c & 0x0F) as usize;
252 let low = (c >> 4) as usize;
253 s.push_str(T::CHAR_TABLE[low][high]);
254 }
255 s
256 }
257}
258
259mod test {
260 use crate::{Jpn, PkStrFFI};
261
262 use super::{Intl, PkString};
263 use std::mem::size_of;
264
265 #[test]
266 fn test_sz() {
267 assert_eq!(size_of::<PkStrFFI<Intl, 7>>(), size_of::<[u8; 7]>());
268 assert_eq!(size_of::<PkString<Intl, [u8; 7]>>(), size_of::<[u8; 7]>())
269 }
270
271 #[test]
272 fn parse_pkstring_intl() {
273 let bytes = [0xBCu8, 0xCF, 0xBE, 0xC3, 0xFF, 0xFF, 0xFF];
274 let s = PkString::<Intl, [u8; 7]>::from(bytes);
275 assert_eq!(&format!("{}", s), "BUDI");
276 println!("{}", s);
277 println!("{:?}", s);
278 }
279
280 #[test]
281 fn parse_pkstring_jpn() {
282 let bytes = [112u8, 142, 139, 123, 83, 255, 0, 8, 76, 125];
283 let s = PkString::<Jpn, [u8; 10]>::from(bytes);
284 assert_eq!(&format!("{}", s), "ミズゴロウ");
285 println!("{}", s);
286 println!("{:?}", s);
287 }
288
289 #[test]
290 fn parse_pkstrffi_intl() {
291 let bytes = [0xBCu8, 0xCF, 0xBE, 0xC3, 0xFF, 0xFF, 0xFF];
292 let s = PkStrFFI::<Intl, 7>::from(bytes);
293 assert_eq!(&format!("{}", s), "BUDI");
294 println!("{}", s);
295 println!("{:?}", s);
296 }
297
298 #[test]
299 fn parse_pkstrffi_jpn() {
300 let bytes = [112u8, 142, 139, 123, 83, 255, 0, 8, 76, 125];
301 let s = PkStrFFI::<Jpn, 10>::from(bytes);
302 assert_eq!(&format!("{}", s), "ミズゴロウ");
303 println!("{}", s);
304 println!("{:?}", s);
305 }
306
307 #[test]
308 fn parse_pkstrffi_transmute() {
309 use std::mem::transmute;
310
311 let bytes = [0xBCu8, 0xCF, 0xBE, 0xC3, 0xFF, 0xFF, 0xFF];
312 let s = unsafe { transmute::<_, PkStrFFI<Intl, 7>>(bytes) };
313 assert_eq!(&format!("{}", s), "BUDI");
314 println!("{}", s);
315 println!("{:?}", s);
316 }
317}