kpal_plugin/
strings.rs

1//! Provides tools for working with strings in KPAL plugins.
2use std::error::Error;
3use std::fmt;
4use std::slice;
5
6/// Copies a string of values of a primitive data type to a buffer.
7///
8/// # Arguments
9///
10/// * `string` - A reference to an string of values to copy
11/// * `buffer` - A buffer to receive the copy of the string
12/// * `length` - The length of the input buffer
13///
14/// # Safety
15///
16/// This function is unsafe because of its use of slice::from_raw_parts, which relies on the caller
17/// to not exceed the length of the buffer when generating the slice.
18pub unsafe fn copy_string<T: Copy>(
19    string: &[T],
20    buffer: *mut T,
21    length: usize,
22) -> Result<(), BufferOverflowError> {
23    let buffer = slice::from_raw_parts_mut(buffer, length);
24    if string.len() > buffer.len() {
25        return Err(BufferOverflowError {});
26    }
27
28    buffer[..string.len()].copy_from_slice(string);
29
30    Ok(())
31}
32
33/// Raised when the length of a string exceeds the length of the buffer into which it is copied.
34#[derive(Debug)]
35pub struct BufferOverflowError {}
36
37impl fmt::Display for BufferOverflowError {
38    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39        write!(f, "BufferOverflowError")
40    }
41}
42
43impl Error for BufferOverflowError {
44    fn description(&self) -> &str {
45        "provided buffer is too small to copy the full contents of the data"
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use std::ffi::{CStr, CString};
52
53    use super::*;
54
55    #[test]
56    fn test_copy_string() {
57        let string = CString::new("foo").expect("Could not create CString");
58        let buffer: &mut [u8; 4] = &mut [0; 4];
59        let buffer_p = buffer.as_mut_ptr();
60
61        let bytes = string.to_bytes_with_nul();
62
63        unsafe {
64            match copy_string(&bytes, buffer_p, buffer.len()) {
65                Ok(_) => (),
66                Err(_e) => panic!("Failed to copy string to buffer"),
67            }
68        }
69
70        let result = CStr::from_bytes_with_nul(buffer).expect("Could not convert buffer to Cstr");
71        assert_eq!(string.as_c_str(), result)
72    }
73
74    #[test]
75    fn test_copy_string_buffer_overflow() {
76        let string = CString::new("foo").expect("Could not create CString");
77        let buffer: &mut [u8; 3] = &mut [0; 3];
78        let buffer_p = buffer.as_mut_ptr();
79
80        let bytes = string.to_bytes_with_nul();
81
82        unsafe {
83            if copy_string(&bytes, buffer_p, buffer.len()).is_ok() {
84                panic!("Failed to return an error due to a buffer overflow")
85            };
86        }
87    }
88}