@@ -352,6 +352,57 @@ impl<'a> Memory<'a> {
352352 self . write_fixed ( offset, value. to_le_bytes ( ) )
353353 }
354354
355+ /// @yard
356+ /// Read a NUL-terminated C string starting at +offset+ as an ASCII-8BIT
357+ /// (binary) +String+.
358+ ///
359+ /// @def read_cstring(offset)
360+ /// @param offset [Integer]
361+ /// @return [String]
362+ pub fn read_cstring ( ruby : & Ruby , rb_self : Obj < Self > , offset : usize ) -> Result < RString , Error > {
363+ let context = rb_self. store . context ( ) ?;
364+ let data = rb_self. get_wasmtime_memory ( ) . data ( context) ;
365+
366+ let bytes: & [ u8 ] = match data. get ( offset..) {
367+ Some ( slice) => {
368+ let end = slice. iter ( ) . position ( |& b| b == 0 ) . unwrap_or ( slice. len ( ) ) ;
369+ & slice[ ..end]
370+ }
371+ None => & [ ] ,
372+ } ;
373+
374+ Ok ( ruby. str_from_slice ( bytes) )
375+ }
376+
377+ /// @yard
378+ /// Write +value+'s bytes followed by a NUL terminator at +offset+.
379+ ///
380+ /// @def write_cstring(offset, value)
381+ /// @param offset [Integer]
382+ /// @param value [String]
383+ /// @return [void]
384+ pub fn write_cstring ( & self , offset : usize , value : RString ) -> Result < ( ) , Error > {
385+ let slice = unsafe { value. as_slice ( ) } ;
386+ if slice. contains ( & 0 ) {
387+ return Err ( Error :: new (
388+ Ruby :: get_with ( value) . exception_arg_error ( ) ,
389+ "string contains null byte" ,
390+ ) ) ;
391+ }
392+ let len = slice. len ( ) ;
393+ let mut context = self . store . context_mut ( ) ?;
394+ let dst = self
395+ . get_wasmtime_memory ( )
396+ . data_mut ( & mut context)
397+ . get_mut ( offset..)
398+ . and_then ( |s| s. get_mut ( ..len + 1 ) )
399+ . ok_or_else ( || error ! ( "out of bounds memory access" ) ) ?;
400+
401+ dst[ ..len] . copy_from_slice ( slice) ;
402+ dst[ len] = 0 ;
403+ Ok ( ( ) )
404+ }
405+
355406 /// @yard
356407 /// Grows a memory by +delta+ pages.
357408 /// Raises if the memory grows beyond its limit.
@@ -443,6 +494,8 @@ pub fn init(ruby: &Ruby) -> Result<(), Error> {
443494 class. define_method ( "size" , method ! ( Memory :: size, 0 ) ) ?;
444495 class. define_method ( "data_size" , method ! ( Memory :: data_size, 0 ) ) ?;
445496 class. define_method ( "read_unsafe_slice" , method ! ( Memory :: read_unsafe_slice, 2 ) ) ?;
497+ class. define_method ( "read_cstring" , method ! ( Memory :: read_cstring, 1 ) ) ?;
498+ class. define_method ( "write_cstring" , method ! ( Memory :: write_cstring, 2 ) ) ?;
446499
447500 unsafe_slice:: init ( ruby) ?;
448501
0 commit comments