1use crate::error::Hl7Error;
2
3const SEGMENT_DELIMITERS: [&str; 4] = ["\r\n", "\n\r", "\r", "\n"];
5
6#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct HL7Encoding {
13 pub field_delimiter: char,
15 pub component_delimiter: char,
17 pub repeat_delimiter: char,
19 pub escape_character: char,
21 pub subcomponent_delimiter: char,
23 pub segment_delimiter: String,
25 pub present_but_null: String,
27}
28
29impl Default for HL7Encoding {
30 fn default() -> Self {
31 Self {
32 field_delimiter: '|',
33 component_delimiter: '^',
34 repeat_delimiter: '~',
35 escape_character: '\\',
36 subcomponent_delimiter: '&',
37 segment_delimiter: "\r".to_string(),
38 present_but_null: "\"\"".to_string(),
39 }
40 }
41}
42
43impl HL7Encoding {
44 pub fn new() -> Self {
46 Self::default()
47 }
48
49 pub fn all_delimiters(&self) -> String {
52 let mut s = String::new();
53 s.push(self.field_delimiter);
54 s.push(self.component_delimiter);
55 s.push(self.repeat_delimiter);
56 if self.escape_character != '\0' {
57 s.push(self.escape_character);
58 }
59 s.push(self.subcomponent_delimiter);
60 s
61 }
62
63 pub fn evaluate_delimiters(&mut self, delimiters: &str) -> Result<(), Hl7Error> {
69 let chars: Vec<char> = delimiters.chars().collect();
70
71 if chars.len() < 5 {
72 return Err(Hl7Error::with_code(
73 "Not enough delimiter characters in MSH segment",
74 Self::bad(),
75 ));
76 }
77
78 self.field_delimiter = chars[0];
79 self.component_delimiter = chars[1];
80 self.repeat_delimiter = chars[2];
81
82 if chars[4] == self.field_delimiter {
83 self.escape_character = '\0';
84 self.subcomponent_delimiter = chars[3];
85 } else {
86 self.escape_character = chars[3];
87 self.subcomponent_delimiter = chars[4];
88 }
89
90 Ok(())
91 }
92
93 pub fn evaluate_segment_delimiter(&mut self, message: &str) -> Result<(), Hl7Error> {
95 for delim in SEGMENT_DELIMITERS {
96 if message.contains(delim) {
97 self.segment_delimiter = delim.to_string();
98 return Ok(());
99 }
100 }
101
102 Err(Hl7Error::with_code(
103 "Segment delimiter not found in message",
104 Self::bad(),
105 ))
106 }
107
108 pub fn encode(&self, val: &str) -> String {
110 if val.is_empty() {
111 return String::new();
112 }
113
114 let chars: Vec<char> = val.chars().collect();
115 let esc = self.escape_character;
116 let mut sb = String::with_capacity(val.len());
117 let mut i = 0;
118
119 while i < chars.len() {
120 let c = chars[i];
121 let mut continue_encoding = true;
122
123 if c == '<' {
124 continue_encoding = false;
125
126 if i + 2 < chars.len() && chars[i + 1] == 'B' && chars[i + 2] == '>' {
127 sb.push(esc);
129 sb.push('H');
130 sb.push(esc);
131 i += 2;
132 } else if i + 3 < chars.len()
133 && chars[i + 1] == '/'
134 && chars[i + 2] == 'B'
135 && chars[i + 3] == '>'
136 {
137 sb.push(esc);
139 sb.push('N');
140 sb.push(esc);
141 i += 3;
142 } else if i + 3 < chars.len()
143 && chars[i + 1] == 'B'
144 && chars[i + 2] == 'R'
145 && chars[i + 3] == '>'
146 {
147 sb.push(esc);
149 sb.push_str(".br");
150 sb.push(esc);
151 i += 3;
152 } else {
153 continue_encoding = true;
154 }
155 }
156
157 if continue_encoding {
158 if c == self.component_delimiter {
159 sb.push(esc);
160 sb.push('S');
161 sb.push(esc);
162 } else if c == esc {
163 sb.push(esc);
164 sb.push('E');
165 sb.push(esc);
166 } else if c == self.field_delimiter {
167 sb.push(esc);
168 sb.push('F');
169 sb.push(esc);
170 } else if c == self.repeat_delimiter {
171 sb.push(esc);
172 sb.push('R');
173 sb.push(esc);
174 } else if c == self.subcomponent_delimiter {
175 sb.push(esc);
176 sb.push('T');
177 sb.push(esc);
178 } else if c == '\n' || c == '\r' {
179 let mut v = format!("{:X}", c as u32);
181 if v.len() % 2 != 0 {
182 v.insert(0, '0');
183 }
184 sb.push(esc);
185 sb.push('X');
186 sb.push_str(&v);
187 sb.push(esc);
188 } else {
189 sb.push(c);
190 }
191 }
192
193 i += 1;
194 }
195
196 sb
197 }
198
199 pub fn encode_opt(&self, val: Option<&str>) -> String {
202 match val {
203 Some(v) => self.encode(v),
204 None => self.present_but_null.clone(),
205 }
206 }
207
208 pub fn decode(&self, encoded: &str) -> String {
210 if encoded.trim().is_empty() {
211 return encoded.to_string();
212 }
213
214 if !encoded.contains(self.escape_character) {
215 return encoded.to_string();
216 }
217
218 let chars: Vec<char> = encoded.chars().collect();
219 let esc = self.escape_character;
220 let mut result = String::with_capacity(encoded.len());
221 let mut i = 0;
222
223 while i < chars.len() {
224 let c = chars[i];
225
226 if c != esc {
227 result.push(c);
228 i += 1;
229 continue;
230 }
231
232 i += 1;
234
235 let li = (i..chars.len()).find(|&k| chars[k] == esc);
237
238 match li {
239 None => {
240 result.push(esc);
242 if i < chars.len() {
243 result.push(chars[i]);
244 }
245 i += 1;
246 }
247 Some(li) => {
248 let seq: String = chars[i..li].iter().collect();
249
250 if seq.is_empty() {
251 i = li + 1;
252 continue;
253 }
254
255 match seq.as_str() {
256 "H" => result.push_str("<B>"),
257 "N" => result.push_str("</B>"),
258 "F" => result.push(self.field_delimiter),
259 "S" => result.push(self.component_delimiter),
260 "T" => result.push(self.subcomponent_delimiter),
261 "R" => result.push(self.repeat_delimiter),
262 "E" => result.push(self.escape_character),
263 ".br" => result.push_str("<BR>"),
264 _ => {
265 if let Some(hex) = seq.strip_prefix('X') {
266 result.push_str(&Self::decode_hex_string(hex));
267 } else {
268 result.push_str(&seq);
269 }
270 }
271 }
272
273 i = li + 1;
274 }
275 }
276 }
277
278 result
279 }
280
281 pub fn decode_hex_string(hex: &str) -> String {
284 let n = hex.len();
285 let mut bytes = Vec::with_capacity(n / 2);
286
287 let mut i = 0;
288 while i + 2 <= n {
289 match u8::from_str_radix(&hex[i..i + 2], 16) {
290 Ok(b) => bytes.push(b),
291 Err(_) => bytes.push(0),
292 }
293 i += 2;
294 }
295
296 if bytes.len() == 1 {
297 char::from_u32(bytes[0] as u32).map(String::from).unwrap_or_default()
298 } else if bytes.len() == 2 && bytes[0] == 0 {
299 char::from_u32(bytes[1] as u32).map(String::from).unwrap_or_default()
300 } else {
301 String::from_utf8_lossy(&bytes).into_owned()
302 }
303 }
304
305 fn bad() -> &'static str {
306 Hl7Error::BAD_MESSAGE
307 }
308}