1use binread::{BinRead, BinReaderExt, FilePtr32, NullWideString};
6use pmd_sir0::{Sir0, Sir0Error};
7use std::{
8 collections::{BTreeMap, HashMap},
9 io::{self, Read, Seek, SeekFrom},
10};
11use thiserror::Error;
12
13mod code_to_text;
14pub use code_to_text::{CodeToText, CodeToTextError};
15
16mod text_to_code;
17pub use text_to_code::{TextToCode, TextToCodeError};
18
19#[derive(BinRead, Debug)]
21#[br(little)]
22pub struct CodeTableEntryFile {
23 #[br(parse_with = FilePtr32::parse, try_map = |x: NullWideString| x.into_string_lossless())]
24 pub string: String,
25 pub value: u16,
26 pub flags: u16,
27 pub lenght: u16,
28 pub unk: u16,
29}
30
31#[derive(Default)]
33pub struct CodeTable {
34 entries: Vec<CodeTableEntryFile>,
35}
36
37#[derive(Error, Debug)]
39pub enum CodeTableDecodeError {
40 #[error("can't decode the Sir0 file")]
41 CantDecodeSir0(#[from] Sir0Error),
42 #[error("the sir0 container only have {0} pointer, but it should have at least 5 pointer")]
43 NotEnoughtPointer(usize),
44 #[error("The offset of the pointer n°{0} can't be obtained")]
45 CantGetOffsetForPointer(usize),
46 #[error("Can't read (maybe a part) of the Sir0 file. This may be caused by an invalid file")]
47 IOError(#[from] io::Error),
48 #[error("Can't decode/read an entry of the code_table.bin file")]
49 CantReadEntry(#[source] binread::Error),
50}
51
52impl CodeTable {
55 pub fn new_from_file<F: Read + Seek>(file: F) -> Result<Self, CodeTableDecodeError> {
57 let mut result = Self::default();
58 let mut sir0 = Sir0::new(file)?;
59 if sir0.offsets_len() < 5 {
60 return Err(CodeTableDecodeError::NotEnoughtPointer(sir0.offsets_len()));
61 };
62
63 for pointer_id in 3..sir0.offsets_len() - 2 {
64 let pointer = *sir0.offsets_get(pointer_id).map_or_else(
65 || Err(CodeTableDecodeError::CantGetOffsetForPointer(pointer_id)),
66 Ok,
67 )?;
68 let sir0_file = sir0.get_file();
69 sir0_file.seek(SeekFrom::Start(pointer))?;
70 let entry: CodeTableEntryFile = sir0_file
71 .read_le()
72 .map_or_else(|err| Err(CodeTableDecodeError::CantReadEntry(err)), Ok)?;
73 result.entries.push(entry);
74 }
75
76 Ok(result)
77 }
78
79 pub fn add_missing(&mut self) {
82 self.entries.push(CodeTableEntryFile {
83 string: "rubi:base".to_string(),
84 value: 0xcf00,
85 flags: 0,
86 lenght: 0,
87 unk: 0,
88 });
89 self.entries.push(CodeTableEntryFile {
90 string: "rubi:over".to_string(),
91 value: 0xcf02,
92 flags: 0,
93 lenght: 0,
94 unk: 0
95 });
96 self.entries.push(CodeTableEntryFile {
97 string: "rubi:end".to_string(),
98 value: 0xcfff,
99 flags: 0,
100 lenght: 0,
101 unk: 0
102 });
103 }
104
105 pub fn generate_code_to_text(&self) -> CodeToText {
107 let mut code_to_text = BTreeMap::new();
108 for entry in self.entries.iter() {
109 code_to_text.insert(entry.value, entry);
110 };
111
112 CodeToText {
113 code_to_text
114 }
115 }
116
117 pub fn generate_text_to_code(
121 &self,
122 ) -> TextToCode {
123 let mut text_to_code = HashMap::new();
124 for entry in self.entries.iter() {
125 text_to_code.insert(&entry.string, entry);
126 }
127
128 TextToCode {
129 text_to_code
130 }
131 }
132
133 pub fn entries(&self) -> &Vec<CodeTableEntryFile> {
135 &self.entries
136 }
137}