gen3_charset/
lib.rs

1use std::{
2    fmt::{self, Display},
3    marker::PhantomData,
4};
5
6#[allow(unused)]
7mod intl {
8
9    /// Reference [Pokemon Gen 3 charset](https://bulbapedia.bulbagarden.net/wiki/Character_encoding_(Generation_III))
10    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    /// Reference [Pokemon Gen 3 charset](https://bulbapedia.bulbagarden.net/wiki/Character_encoding_(Generation_III))
62    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}