pmd_code_table/
text_to_code.rs1use std::{collections::HashMap, num::ParseIntError};
2
3use thiserror::Error;
4
5use crate::CodeTableEntryFile;
6
7#[derive(Debug, Error)]
8pub enum TextToCodeError {
9 #[error("The character '{0:?}' has been escaped, but it doesn't need to. If you want to display \\, you need to write \\\\.")]
10 UselessEscape(char),
11 #[error("The final character of the string is an unescaped \\. If you want to display \\, add another \\ at the end of that string.")]
12 UnfinishedEscape,
13 #[error("The string end with an unfinished placeholder. [ start an escape sequence if they aren't preceded with \\ (this \\ isn't displayed), and a ] close it.")]
14 UnclosedPlaceholder,
15 #[error("The string contain an empty placeholder []. If you want to display [], write \\[] instead (to escape the [)")]
16 EmptyPlaceholder,
17 #[error("The string contain a placeholder containing too much part (a part in a placeholder is separated with :). The various part of the placeholder are : {0:?}")]
18 PlaceholderTooMuchPart(Vec<String>),
19 #[error("The placeholder {0:?} is unrecognized")]
20 UnknownPlaceholder(String),
21 #[error("The value \"{1:?}\" for the placeholder \"{2:?}\" is neither an hardcoded one, nor a base 10 string (or it may be a base 10 number, but superior to 2^32 - 1)")]
22 InvalidValue(#[source] ParseIntError, String, String),
23 #[error("The placeholder {1:?} has the associated value {0:?}, thought it should less or equal to 255 (hard value for this placeholder type")]
24 CantEncodedParameterEmbeddedData(u32, String)
25}
26
27pub struct TextToCode<'a> {
28 pub(crate) text_to_code: HashMap<&'a String, &'a CodeTableEntryFile>,
29}
30
31impl<'a> TextToCode<'a> {
32 pub fn encode(&self, text: &str) -> Result<Vec<u16>, TextToCodeError> {
33 let mut buffer = [0; 2];
34 let mut result: Vec<u16> = Vec::new();
35
36 let mut iterator = text.chars();
37 while let Some(chara) = iterator.next() {
38 if chara == '[' {
39 let mut placeholder = Vec::new();
40 let mut placeholder_current_string = String::with_capacity(10);
41 loop {
42 if let Some(placeholder_char) = iterator.next() {
43 if placeholder_char == ']' {
44 placeholder.push(placeholder_current_string.clone());
45 break;
46 } else if placeholder_char == ':' {
47 placeholder_current_string.push(':');
48 placeholder.push(placeholder_current_string.clone());
49 placeholder_current_string = String::with_capacity(10);
50 } else {
51 placeholder_current_string.push(placeholder_char)
52 }
53 } else {
54 return Err(TextToCodeError::UnclosedPlaceholder);
55 }
56 }
57 let (directive, value) = match placeholder.len() {
58 0 => return Err(TextToCodeError::EmptyPlaceholder),
59 1 => (placeholder[0].clone(), None),
60 2 => (placeholder[0].clone(), Some(placeholder[1].clone())),
61 _ => return Err(TextToCodeError::PlaceholderTooMuchPart(placeholder)),
62 };
63
64 let complete_placeholder = if let Some(ref value) = value {
65 format!("{}{}", directive, value)
66 } else {
67 directive.clone()
68 };
69
70 if let Some(placeholder_char) = self.text_to_code.get(&complete_placeholder) {
71 result.push(placeholder_char.value);
72 } else if let Some(value) = value.clone() {
73 let entry = *self.text_to_code.get(&directive).map_or_else(|| Err(TextToCodeError::UnknownPlaceholder(directive.clone())), Ok)?;
74 let value_number = u32::from_str_radix(&value, 10).map_err(|err| TextToCodeError::InvalidValue(err, value.clone(), directive.clone()))?;
75 if entry.lenght == 0 {
76 if value_number > 255 {
77 return Err(TextToCodeError::CantEncodedParameterEmbeddedData(value_number, entry.string.clone()))
78 };
79 result.push(entry.value + value_number as u16);
80 } else {
81 result.push(entry.value + (value_number % 256).saturating_sub(1) as u16);
82 let mut remaining = value_number;
83 loop {
84 if remaining == 0 {
85 break
86 }
87 let this_part = remaining & 0x0000FFFF;
88 remaining = remaining >> 16;
89 result.push(this_part as u16);
90 }
91 }
92 } else {
93 return Err(TextToCodeError::UnknownPlaceholder(complete_placeholder))
94 }
95
96 } else if chara == '\\' {
97 if let Some(next_chara) = iterator.next() {
98 if next_chara == '[' || next_chara == '\\' {
99 let slice = next_chara.encode_utf16(&mut buffer);
100 result.extend(slice.iter());
101 } else {
102 return Err(TextToCodeError::UselessEscape(next_chara));
103 }
104 } else {
105 return Err(TextToCodeError::UnfinishedEscape);
106 }
107 } else {
108 let slice = chara.encode_utf16(&mut buffer);
109 result.extend(slice.iter());
110 }
111 }
112
113 Ok(result)
114 }
115}