indymilter/
ffi_util.rs

1// indymilter – asynchronous milter library
2// Copyright © 2021–2023 David Bürgin <dbuergin@gluet.ch>
3//
4// This program is free software: you can redistribute it and/or modify it under
5// the terms of the GNU General Public License as published by the Free Software
6// Foundation, either version 3 of the License, or (at your option) any later
7// version.
8//
9// This program is distributed in the hope that it will be useful, but WITHOUT
10// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12// details.
13//
14// You should have received a copy of the GNU General Public License along with
15// this program. If not, see <https://www.gnu.org/licenses/>.
16
17use std::ffi::{CStr, CString};
18
19/// Infallible conversion to a C string.
20pub trait IntoCString {
21    /// Converts this value to a C string.
22    fn into_c_string(self) -> CString;
23}
24
25impl IntoCString for CString {
26    fn into_c_string(self) -> Self {
27        self
28    }
29}
30
31impl IntoCString for &CStr {
32    fn into_c_string(self) -> CString {
33        self.to_owned()
34    }
35}
36
37impl IntoCString for String {
38    fn into_c_string(self) -> CString {
39        let s = if self.contains('\0') {
40            sanitize_nul(&self)
41        } else {
42            self
43        };
44        CString::new(s).unwrap()
45    }
46}
47
48impl IntoCString for &str {
49    fn into_c_string(self) -> CString {
50        if self.contains('\0') {
51            let s = sanitize_nul(self);
52            CString::new(s).unwrap()
53        } else {
54            CString::new(self).unwrap()
55        }
56    }
57}
58
59fn sanitize_nul(s: &str) -> String {
60    s.replace('\0', "\u{fffd}")
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66    use byte_strings::c_str;
67
68    #[test]
69    fn into_c_string_ok() {
70        assert_eq!("bonjour".into_c_string().as_ref(), c_str!("bonjour"));
71        assert_eq!("al\0ias\0".into_c_string().as_ref(), c_str!("al�ias�"));
72        assert_eq!(c_str!(b"ab\xefe").into_c_string().as_ref(), c_str!(b"ab\xefe"));
73    }
74}