kernel/library/std/
string.rs

1use alloc::string::String;
2use alloc::vec::Vec;
3
4#[derive(Debug, PartialEq)]
5pub enum StringConversionError {
6    NullPointer,
7    ExceedsMaxLength,
8    Utf8Error,
9    TranslationError,
10    TooManyStrings,
11}
12
13/// Convert a C string pointer to a Rust String
14pub fn cstring_to_string(
15    cstr_ptr: *const u8,
16    max_len: usize,
17) -> Result<(String, usize), StringConversionError> {
18    if cstr_ptr.is_null() {
19        return Err(StringConversionError::NullPointer);
20    }
21    if max_len == 0 {
22        return Ok((String::new(), 0));
23    }
24
25    let mut len = 0;
26    while len < max_len && unsafe { *cstr_ptr.add(len) } != 0 {
27        len += 1;
28    }
29
30    if len > max_len {
31        return Err(StringConversionError::ExceedsMaxLength);
32    }
33
34    let bytes = unsafe { alloc::slice::from_raw_parts(cstr_ptr, len) };
35    match String::from_utf8(bytes.to_vec()) {
36        Ok(string) => Ok((string, len)),
37        Err(_) => Err(StringConversionError::Utf8Error),
38    }
39}
40
41/// Parse a null-terminated C string from user space using task's VM manager
42pub fn parse_c_string_from_userspace(
43    task: &crate::task::Task,
44    ptr: usize,
45    max_len: usize,
46) -> Result<String, StringConversionError> {
47    if ptr == 0 {
48        return Err(StringConversionError::NullPointer);
49    }
50
51    let c_str_ptr = task
52        .vm_manager
53        .translate_vaddr(ptr)
54        .ok_or(StringConversionError::TranslationError)? as *const u8;
55
56    let (string, _) = cstring_to_string(c_str_ptr, max_len)?;
57    Ok(string)
58}
59
60/// Parse an array of string pointers (char **) from user space
61pub fn parse_string_array_from_userspace(
62    task: &crate::task::Task,
63    array_ptr: usize,
64    max_strings: usize,
65    max_string_len: usize,
66) -> Result<Vec<String>, StringConversionError> {
67    if array_ptr == 0 {
68        return Ok(Vec::new());
69    }
70
71    let ptr_array = task
72        .vm_manager
73        .translate_vaddr(array_ptr)
74        .ok_or(StringConversionError::TranslationError)? as *const usize;
75
76    let mut strings = Vec::new();
77    let mut i = 0;
78
79    unsafe {
80        loop {
81            let str_ptr = *ptr_array.add(i);
82            if str_ptr == 0 {
83                break; // Null pointer terminates the array
84            }
85
86            let string = parse_c_string_from_userspace(task, str_ptr, max_string_len)?;
87            strings.push(string);
88            i += 1;
89
90            if i > max_strings {
91                return Err(StringConversionError::TooManyStrings);
92            }
93        }
94    }
95
96    Ok(strings)
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[test_case]
104    fn test_cstring_to_string() {
105        let cstr = b"Hello, world!\0";
106        let res = cstring_to_string(cstr.as_ptr(), cstr.len()).unwrap();
107        assert_eq!(res, ("Hello, world!".into(), 13));
108    }
109
110    #[test_case]
111    fn test_cstring_to_string_empty() {
112        let cstr = b"\0";
113        let result = cstring_to_string(cstr.as_ptr(), cstr.len()).unwrap();
114        assert_eq!(result, ("".into(), 0));
115    }
116
117    #[test_case]
118    fn test_cstring_to_string_truncated() {
119        let cstr = b"Hello\0World\0";
120        let result = cstring_to_string(cstr.as_ptr(), 5);
121        assert_eq!(result, Ok(("Hello".into(), 5)));
122    }
123
124    #[test_case]
125    fn test_cstring_to_string_utf8_error() {
126        let invalid_utf8 = &[0xFF, 0xFE, 0xFD, 0x00]; // Invalid UTF-8 sequence
127        let result = cstring_to_string(invalid_utf8.as_ptr(), 4);
128        assert_eq!(result, Err(StringConversionError::Utf8Error));
129    }
130
131    #[test_case]
132    fn test_parse_c_string_from_userspace_null_pointer() {
133        // Create a minimal task for testing
134        let task = crate::task::new_user_task("test".into(), 1);
135
136        // Test null pointer
137        let result = parse_c_string_from_userspace(&task, 0, 100);
138        assert_eq!(result, Err(StringConversionError::NullPointer));
139    }
140
141    #[test_case]
142    fn test_parse_string_array_from_userspace_null_pointer() {
143        // Create a minimal task for testing
144        let task = crate::task::new_user_task("test".into(), 1);
145
146        // Test null pointer array
147        let result = parse_string_array_from_userspace(&task, 0, 10, 100);
148        assert!(result.is_ok());
149        assert_eq!(result.unwrap().len(), 0);
150    }
151}