pmd_code_table/
code_to_text.rs1use std::{collections::BTreeMap, string::FromUtf16Error};
2use thiserror::Error;
3use crate::CodeTableEntryFile;
4
5#[derive(Debug, Error)]
7pub enum CodeToTextError {
8 #[error("The final character of this line is not a valid UTF-16 character. It end with the 16bit code point {1} (partially decoded string: {0:?}). The encoding of the input is likely invalid.")]
9 FinalInvalid(String, u16),
10 #[error("Can't decode the pair of the two number {2} and {3} as a valid UTF-16 character. The input file is likely corrupted (partially decoded string: {1:?})")]
11 CantDecodeUtf16(#[source] FromUtf16Error, String, u16, u16),
12 #[error("There are missing character at the end of the string to decode the value of a placeholder. The input file is likely corrupted")]
13 FinalNotLongEnoughtForData
14}
15
16pub struct CodeToText<'a> {
17 pub(crate) code_to_text: BTreeMap<u16, &'a CodeTableEntryFile>
18}
19
20impl<'a> CodeToText<'a> {
21 pub fn decode(&'a self, text: &[u16]) -> Result<String, CodeToTextError> {
22 let mut iterator = text.iter().map(|x| *x);
23
24 let mut result = String::new();
25
26 while let Some(point) = iterator.next() {
27 struct EncodedData<'a> {
28 entry: &'a CodeTableEntryFile,
29 encoded_value: u32,
30 }
31
32 let data: Option<EncodedData> = if let Some(entry) = self.code_to_text.get(&point) {
33 Some(EncodedData {
34 entry: *entry,
35 encoded_value: 0
36 })
37 } else if let Some(entry) = self.code_to_text.get(&(point & 0xFF00)) {
38 Some(EncodedData {
39 entry: *entry,
40 encoded_value: (point & 0x00FF) as u32 })
42 } else {
43 None
44 };
45
46 if let Some(mut data) = data {
47 let encoded_value_string = if data.entry.flags != 0 {
48 if data.entry.lenght > 0 {
49 data.encoded_value = 0;
50 for j in 0..data.entry.lenght {
51 let this_encoded_char = iterator.next().map_or_else(|| Err(CodeToTextError::FinalNotLongEnoughtForData), Ok)?;
52 data.encoded_value |= (this_encoded_char as u32) << j*16;
53 }
54 };
55
56 data.encoded_value.to_string()
57 } else {
58 String::new()
59 };
60
61 result.push('[');
62 result.push_str(&data.entry.string);
63 result.push_str(&encoded_value_string);
64 result.push(']');
65 } else {
66 if point == '[' as u16 {
67 result.push_str("\\[");
68 } else if point == '\\' as u16 {
69 result.push_str("\\\\");
70 } else {
71 if let Some(point_as_char) = char::from_u32(point as u32) {
72 result.push(point_as_char);
73 } else if let Some(next_point) = iterator.next() {
74 let decoded_string = String::from_utf16(&[point, next_point]).map_err(|err| CodeToTextError::CantDecodeUtf16(err, result.clone(), point, next_point))?;
75 result.push_str(&decoded_string);
76 } else {
77 return Err(CodeToTextError::FinalInvalid(result, point))
78 }
79 }
80 }
81 };
82
83 Ok(result)
84 }
85}