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