flpak/
utils.rs

1use std::{borrow::Cow, io, str};
2
3use encoding_rs::Encoding;
4
5#[macro_export]
6macro_rules! io_error {
7    ($kind:ident, $($arg:tt)+) => {
8        std::io::Error::new(std::io::ErrorKind::$kind, format!($($arg)+))
9    };
10}
11
12pub fn buffer_to_zstring<'a>(
13    buf: &'a [u8],
14    encoding: &'static Encoding,
15) -> io::Result<Cow<'a, str>> {
16    let Some(null_byte_position) = buf.iter().position(|&x| x == 0) else {
17        return Err(io_error!(UnexpectedEof, "should be a null-terminated string"));
18    };
19
20    let (cow, _, had_error) = encoding.decode(&buf[..null_byte_position]);
21
22    if had_error {
23        return Err(io_error!(
24            InvalidData,
25            "should be a correct sequence of characters"
26        ));
27    }
28
29    Ok(cow)
30}
31
32#[cfg(test)]
33mod tests {
34    mod buffer_to_zstring {
35        use encoding_rs::UTF_8;
36
37        use super::super::buffer_to_zstring;
38        use std::io::ErrorKind;
39
40        #[test]
41        fn correct() {
42            let res = buffer_to_zstring(b"text\0\0\0\0\0", UTF_8);
43            assert_eq!(res.unwrap(), "text");
44        }
45
46        #[test]
47        fn not_null_terminated() {
48            let res = buffer_to_zstring(b"text", UTF_8);
49            assert_eq!(res.unwrap_err().kind(), ErrorKind::UnexpectedEof);
50        }
51
52        #[test]
53        fn invalid_utf8_sequence() {
54            let res = buffer_to_zstring(b"text\xc3\x28\0", UTF_8);
55            assert_eq!(res.unwrap_err().kind(), ErrorKind::InvalidData);
56        }
57    }
58}