kernel/library/std/
string.rs1use 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
13pub 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
38pub 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
55pub 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; }
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]; 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 let task = crate::task::new_user_task("test".into(), 1);
128
129 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 let task = crate::task::new_user_task("test".into(), 1);
138
139 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}