1use base64::Engine;
7use base64::engine::general_purpose::STANDARD;
8
9pub fn maybe_decode_base64(input: &str) -> String {
14 if input.is_empty() {
15 return String::new();
16 }
17
18 match STANDARD.decode(input.trim()) {
22 Ok(bytes) => match String::from_utf8(bytes) {
23 Ok(decoded) => {
24 let control_count = decoded
28 .chars()
29 .filter(|c| c.is_control() && *c != '\n')
30 .count();
31 if decoded.len() > 4 && control_count > decoded.len() / 4 {
32 input.to_string()
33 } else {
34 decoded
35 }
36 }
37 Err(_) => input.to_string(),
38 },
39 Err(_) => input.to_string(),
40 }
41}
42
43pub fn decode_epg_field(field: &Option<String>) -> Option<String> {
48 field.as_ref().map(|s| maybe_decode_base64(s))
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn decodes_valid_base64() {
57 assert_eq!(maybe_decode_base64("TmV3cw=="), "News");
59 }
60
61 #[test]
62 fn decodes_base64_description() {
63 assert_eq!(maybe_decode_base64("RGFpbHkgbmV3cw=="), "Daily news");
65 }
66
67 #[test]
68 fn returns_plain_text_unchanged() {
69 assert_eq!(maybe_decode_base64("Just plain text"), "Just plain text");
70 }
71
72 #[test]
73 fn handles_empty_string() {
74 assert_eq!(maybe_decode_base64(""), "");
75 }
76
77 #[test]
78 fn handles_unicode_plain_text() {
79 let text = "Programme en fran\u{00e7}ais";
80 assert_eq!(maybe_decode_base64(text), text);
81 }
82
83 #[test]
84 fn decode_epg_field_some() {
85 let field = Some("TmV3cw==".to_string());
86 assert_eq!(decode_epg_field(&field), Some("News".to_string()));
87 }
88
89 #[test]
90 fn decode_epg_field_none() {
91 assert_eq!(decode_epg_field(&None), None);
92 }
93
94 #[test]
95 fn decodes_base64_with_whitespace() {
96 assert_eq!(maybe_decode_base64(" TmV3cw== "), "News");
97 }
98}