use std::ffi::CString;
use libc::{c_char, c_int};
use crate::{err::BlkidErr, Result};
fn string_shared<F>(string: &str, closure: F) -> Result<String>
where
F: Fn(&CString, &mut Vec<u8>) -> c_int,
{
let mut buffer = vec![0u8; string.len() * 4];
let cstring = CString::new(string)?;
if closure(&cstring, &mut buffer) != 0 {
return Err(BlkidErr::InvalidConv);
}
let first_null = buffer
.iter()
.position(|u| *u == 0)
.ok_or_else(|| BlkidErr::Other("No null found in C string".to_string()))?;
buffer.truncate(first_null);
let buffer_cstring = CString::new(buffer)?;
buffer_cstring.into_string().map_err(BlkidErr::IntoString)
}
pub fn encode_string(string: &str) -> Result<String> {
string_shared(string, |cstring, buffer| unsafe {
libblkid_rs_sys::blkid_encode_string(
cstring.as_ptr(),
buffer.as_mut_ptr() as *mut c_char,
buffer.len(),
)
})
}
pub fn safe_string(string: &str) -> Result<String> {
string_shared(string, |cstring, buffer| unsafe {
libblkid_rs_sys::blkid_safe_string(
cstring.as_ptr(),
buffer.as_mut_ptr() as *mut c_char,
buffer.len(),
)
})
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_encode_string() {
let encoded_string = encode_string("\\test string").unwrap();
assert_eq!(encoded_string, "\\x5ctest\\x20string");
}
#[test]
fn test_safe_string() {
let safe_string = safe_string("test string").unwrap();
assert_eq!(safe_string, "test_string");
}
}