edgeparse_core/pdf/
pdf_string.rs1pub fn decode_pdf_string(bytes: &[u8]) -> String {
10 if bytes.len() >= 2 && bytes[0] == 0xFE && bytes[1] == 0xFF {
11 return decode_utf16be(&bytes[2..]);
12 }
13 if bytes.len() >= 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF {
14 return String::from_utf8_lossy(&bytes[3..]).into_owned();
15 }
16 if let Ok(s) = std::str::from_utf8(bytes) {
17 if !s.chars().any(|c| c == '\u{0}') {
20 return s.to_string();
21 }
22 }
23 decode_pdfdoc_encoding(bytes)
24}
25
26fn decode_utf16be(bytes: &[u8]) -> String {
27 let mut out = String::with_capacity(bytes.len() / 2);
28 let mut i = 0;
29 while i + 1 < bytes.len() {
30 let code = u16::from_be_bytes([bytes[i], bytes[i + 1]]);
31 i += 2;
32 if let Some(c) = char::from_u32(u32::from(code)) {
33 if (0xD800..=0xDBFF).contains(&code) {
35 if i + 1 < bytes.len() {
36 let low = u16::from_be_bytes([bytes[i], bytes[i + 1]]);
37 i += 2;
38 if (0xDC00..=0xDFFF).contains(&low) {
39 let cp = 0x10000
40 + (((code as u32) - 0xD800) << 10)
41 + ((low as u32) - 0xDC00);
42 if let Some(ch) = char::from_u32(cp) {
43 out.push(ch);
44 }
45 }
46 }
47 } else if !(0xDC00..=0xDFFF).contains(&code) {
48 out.push(c);
49 }
50 }
51 }
52 out
53}
54
55fn decode_pdfdoc_encoding(bytes: &[u8]) -> String {
58 let mut out = String::with_capacity(bytes.len());
59 for &b in bytes {
60 let c = match b {
61 0x20..=0x7E => b as char,
62 0x80 => '\u{2022}', 0x8A => '\u{0160}',
65 0x8C => '\u{0152}',
66 0x8E => '\u{017D}',
67 0x91 => '\u{2018}',
68 0x92 => '\u{2019}',
69 0x93 => '\u{201C}',
70 0x94 => '\u{201D}',
71 0x95 => '\u{2013}', 0x96 => '\u{2014}',
73 0x97 => '\u{2022}',
74 0xA0 => '\u{00A0}',
75 0xA1..=0xFF => char::from_u32(u32::from(b)).unwrap_or('\u{FFFD}'),
76 _ => '\u{FFFD}',
77 };
78 out.push(c);
79 }
80 out
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn utf16be_with_bom() {
89 let bytes = [0xFE, 0xFF, 0x00, b'2'];
91 assert_eq!(decode_pdf_string(&bytes), "2");
92 }
93
94 #[test]
95 fn ascii_literal() {
96 assert_eq!(decode_pdf_string(b"Hello"), "Hello");
97 }
98
99 #[test]
100 fn utf16be_word() {
101 let mut bytes = vec![0xFE, 0xFF];
102 for c in "Hi".encode_utf16() {
103 bytes.extend_from_slice(&c.to_be_bytes());
104 }
105 assert_eq!(decode_pdf_string(&bytes), "Hi");
106 }
107}