1 use crate::Error; 2 use std::convert::TryInto; 3 use std::ffi::CString; 4 use wiggle::GuestPtr; 5 6 pub struct StringArray { 7 elems: Vec<CString>, 8 pub number_elements: u32, 9 pub cumulative_size: u32, 10 } 11 12 #[derive(Debug, thiserror::Error)] 13 pub enum StringArrayError { 14 /// Provided sequence of bytes contained an unexpected NUL byte. 15 #[error("provided sequence contained an unexpected NUL byte")] 16 Nul(#[from] std::ffi::NulError), 17 /// Too many elements: must fit into u32 18 #[error("too many elements")] 19 NumElements, 20 /// Element size: must fit into u32 21 #[error("element too big")] 22 ElemSize, 23 /// Cumulative element size: must fit into u32 24 #[error("cumulative element size too big")] 25 CumElemSize, 26 } 27 28 impl StringArray { 29 pub fn new(elems: Vec<String>) -> Result<Self, StringArrayError> { 30 let elems = elems 31 .into_iter() 32 .map(|s| CString::new(s)) 33 .collect::<Result<Vec<CString>, _>>()?; 34 let number_elements = elems 35 .len() 36 .try_into() 37 .map_err(|_| StringArrayError::NumElements)?; 38 let mut cumulative_size: u32 = 0; 39 for elem in elems.iter() { 40 let elem_bytes = elem 41 .as_bytes_with_nul() 42 .len() 43 .try_into() 44 .map_err(|_| StringArrayError::ElemSize)?; 45 cumulative_size = cumulative_size 46 .checked_add(elem_bytes) 47 .ok_or(StringArrayError::CumElemSize)?; 48 } 49 Ok(Self { 50 elems, 51 number_elements, 52 cumulative_size, 53 }) 54 } 55 56 pub fn write_to_guest<'a>( 57 &self, 58 buffer: &GuestPtr<'a, u8>, 59 element_heads: &GuestPtr<'a, GuestPtr<'a, u8>>, 60 ) -> Result<(), Error> { 61 let element_heads = element_heads.as_array(self.number_elements); 62 let buffer = buffer.as_array(self.cumulative_size); 63 let mut cursor = 0; 64 for (elem, head) in self.elems.iter().zip(element_heads.iter()) { 65 let bytes = elem.as_bytes_with_nul(); 66 let len: u32 = bytes.len().try_into()?; 67 let elem_buffer = buffer 68 .get_range(cursor..(cursor + len)) 69 .ok_or(Error::Inval)?; // Elements don't fit in buffer provided 70 elem_buffer.copy_from_slice(bytes)?; 71 head?.write( 72 elem_buffer 73 .get(0) 74 .expect("all elem buffers at least length 1"), 75 )?; 76 cursor += len; 77 } 78 Ok(()) 79 } 80 } 81