1pub fn to_char_code(c: char) -> u8 {
3 c as u8
4}
5
6pub fn to_hex_string(num: u8) -> String {
8 format!("{:02X}", num)
9}
10
11pub fn to_hex_string_of_min_length(num: u16, min_length: usize) -> String {
13 let hex = format!("{:X}", num);
14 if hex.len() < min_length {
15 let padding = "0".repeat(min_length - hex.len());
16 format!("{}{}", padding, hex)
17 } else {
18 hex
19 }
20}
21
22pub fn char_from_hex_code(hex: &str) -> char {
24 u8::from_str_radix(hex, 16).unwrap_or(0) as char
25}
26
27pub fn copy_string_into_buffer(s: &str, buffer: &mut [u8], offset: usize) -> usize {
29 let bytes = s.as_bytes();
30 let len = bytes.len();
31 buffer[offset..offset + len].copy_from_slice(bytes);
32 len
33}
34
35pub fn number_to_string(value: f64) -> String {
38 if value.fract() == 0.0 && value.abs() < 1e20 {
39 format!("{}", value as i64)
41 } else if value.abs() >= 1e20 || (value != 0.0 && value.abs() < 1e-6) {
42 format_no_exponent(value)
44 } else {
45 let s = format!("{}", value);
47 if s.contains('.') {
49 let trimmed = s.trim_end_matches('0');
50 let trimmed = trimmed.trim_end_matches('.');
51 trimmed.to_string()
52 } else {
53 s
54 }
55 }
56}
57
58fn format_no_exponent(value: f64) -> String {
59 let s = format!("{:.50}", value);
61 if s.contains('.') {
63 let trimmed = s.trim_end_matches('0');
64 let trimmed = trimmed.trim_end_matches('.');
65 trimmed.to_string()
66 } else {
67 s
68 }
69}
70
71pub fn typed_array_for(s: &str) -> Vec<u8> {
73 s.bytes().collect()
74}
75
76pub fn array_as_string(bytes: &[u8]) -> String {
78 bytes.iter().map(|&b| b as char).collect()
79}
80
81pub fn merge_into_typed_array(parts: &[&[u8]]) -> Vec<u8> {
83 let total_len: usize = parts.iter().map(|p| p.len()).sum();
84 let mut result = Vec::with_capacity(total_len);
85 for part in parts {
86 result.extend_from_slice(part);
87 }
88 result
89}
90
91pub fn has_utf16_bom(bytes: &[u8]) -> bool {
93 bytes.len() >= 2 && ((bytes[0] == 0xFE && bytes[1] == 0xFF) || (bytes[0] == 0xFF && bytes[1] == 0xFE))
94}
95
96pub fn utf16_decode(bytes: &[u8]) -> String {
98 if bytes.len() < 2 {
99 return String::new();
100 }
101
102 let big_endian = bytes[0] == 0xFE && bytes[1] == 0xFF;
103 let data = &bytes[2..]; let mut code_units: Vec<u16> = Vec::with_capacity(data.len() / 2);
106 let mut i = 0;
107 while i + 1 < data.len() {
108 let unit = if big_endian {
109 ((data[i] as u16) << 8) | (data[i + 1] as u16)
110 } else {
111 ((data[i + 1] as u16) << 8) | (data[i] as u16)
112 };
113 code_units.push(unit);
114 i += 2;
115 }
116
117 String::from_utf16_lossy(&code_units)
118}
119
120pub fn utf16_encode(text: &str) -> Vec<u16> {
122 let mut result = vec![0xFEFF]; for c in text.chars() {
124 let mut buf = [0u16; 2];
125 let encoded = c.encode_utf16(&mut buf);
126 result.extend_from_slice(encoded);
127 }
128 result
129}
130
131pub fn pdf_doc_encoding_decode(bytes: &[u8]) -> String {
135 bytes.iter().map(|&b| {
141 match b {
142 0x00..=0x7F => b as char,
144 0x80 => '\u{2022}', 0x81 => '\u{2020}', 0x82 => '\u{2021}', 0x83 => '\u{2026}', 0x84 => '\u{2014}', 0x85 => '\u{2013}', 0x86 => '\u{0192}', 0x87 => '\u{2044}', 0x88 => '\u{2039}', 0x89 => '\u{203A}', 0x8A => '\u{2212}', 0x8B => '\u{2030}', 0x8C => '\u{201E}', 0x8D => '\u{201C}', 0x8E => '\u{201D}', 0x8F => '\u{2018}', 0x90 => '\u{2019}', 0x91 => '\u{201A}', 0x92 => '\u{2122}', 0x93 => '\u{FB01}', 0x94 => '\u{FB02}', 0x95 => '\u{0141}', 0x96 => '\u{0152}', 0x97 => '\u{0160}', 0x98 => '\u{0178}', 0x99 => '\u{017D}', 0x9A => '\u{0131}', 0x9B => '\u{0142}', 0x9C => '\u{0153}', 0x9D => '\u{0161}', 0x9E => '\u{017E}', 0x9F => '\u{FFFD}', 0xA0 => '\u{00A0}',
179 0xA1 => '\u{00A1}',
180 0xA2..=0xAC => b as char,
181 0xAD => '\u{00AD}', 0xAE..=0xFF => b as char,
183 }
184 }).collect()
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190
191 #[test]
192 fn test_to_char_code() {
193 assert_eq!(to_char_code('A'), 65);
194 assert_eq!(to_char_code(' '), 32);
195 assert_eq!(to_char_code('\n'), 10);
196 }
197
198 #[test]
199 fn test_to_hex_string() {
200 assert_eq!(to_hex_string(0), "00");
201 assert_eq!(to_hex_string(255), "FF");
202 assert_eq!(to_hex_string(16), "10");
203 assert_eq!(to_hex_string(9), "09");
204 }
205
206 #[test]
207 fn test_char_from_hex_code() {
208 assert_eq!(char_from_hex_code("20"), ' ');
209 assert_eq!(char_from_hex_code("41"), 'A');
210 assert_eq!(char_from_hex_code("42"), 'B');
211 }
212
213 #[test]
214 fn test_copy_string_into_buffer() {
215 let mut buf = vec![b' '; 10];
216 let written = copy_string_into_buffer("hello", &mut buf, 2);
217 assert_eq!(written, 5);
218 assert_eq!(&buf, b" hello ");
219 }
220
221 #[test]
222 fn test_number_to_string_integers() {
223 assert_eq!(number_to_string(21.0), "21");
224 assert_eq!(number_to_string(-43.0), "-43");
225 assert_eq!(number_to_string(0.0), "0");
226 }
227
228 #[test]
229 fn test_typed_array_for() {
230 assert_eq!(typed_array_for("ABC"), vec![65, 66, 67]);
231 assert_eq!(typed_array_for(" "), vec![32, 32, 32]);
232 }
233
234 #[test]
235 fn test_has_utf16_bom() {
236 assert!(has_utf16_bom(&[0xFE, 0xFF, 0x00, 0x41])); assert!(has_utf16_bom(&[0xFF, 0xFE, 0x41, 0x00])); assert!(!has_utf16_bom(&[0x41, 0x42]));
239 assert!(!has_utf16_bom(&[0xFE]));
240 }
241
242 #[test]
243 fn test_utf16_decode_be() {
244 let bytes = vec![0xFE, 0xFF, 0x00, 0x45, 0x00, 0x67, 0x00, 0x67, 0x00, 0x20];
246 assert_eq!(utf16_decode(&bytes), "Egg ");
247 }
248
249 #[test]
250 fn test_utf16_decode_le() {
251 let bytes = vec![0xFF, 0xFE, 0x45, 0x00, 0x67, 0x00, 0x67, 0x00, 0x20, 0x00];
253 assert_eq!(utf16_decode(&bytes), "Egg ");
254 }
255
256 #[test]
257 fn test_utf16_encode() {
258 let encoded = utf16_encode("");
259 assert_eq!(encoded, vec![0xFEFF]); let encoded = utf16_encode("A");
262 assert_eq!(encoded, vec![0xFEFF, 0x0041]);
263 }
264
265 #[test]
266 fn test_pdf_doc_encoding_decode_ascii() {
267 let bytes = vec![0x61, 0x45, 0x62, 0x73]; assert_eq!(pdf_doc_encoding_decode(&bytes), "aEbs");
269 }
270}