Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I convert a Windows OsString to a CString?

Tags:

rust

ffi

I have an std::ffi::OsString on Windows, but I need to pass a std::ffi::CString to an FFI function. Is there any way to convert the OsString into the CString?

I know that on Windows, OsString is backed by a WTF-8-encoded buffer. Essentially all that needs to happen is to append an ASCII nul character and create a CString from it. Is there a good way to do that? If not, is is possible to access that buffer directly?

Here is some example code:

extern "system" fn some_ffi(s: *mut c_char);

fn my_func(os_string: &OsString) {
    let c_string: CString = // ???

    some_ffi(c_string.as_raw())
}
like image 405
ddulaney Avatar asked Mar 04 '23 16:03

ddulaney


1 Answers

On Unix-like systems, you can obtain the raw bytes of an OsStr or OsString as a &[u8] via std::os::unix::ffi::OsStrExt::as_bytes. You can pass that slice directly to CString::new.

On Windows, you cannot obtain the raw bytes of an OsStr or OsString. The WTF-8 encoding is considered a private implementation detail. The only guarantee is that if the string contains valid Unicode, then it can be converted to a str or String in constant time, using OsStr::to_str or OsString::into_string. You can also convert the string back to potentially ill-formed UTF-16 with std::os::windows::ffi::OsStrExt::encode_wide.

The motivation for not giving direct access to the raw bytes is that almost no library expects strings encoded as WTF-8. In fact, some libraries might not even expect UTF-8! (They might instead expect strings encoded in the current "ANSI" code page.) If it turns out that the library doesn't expect UTF-8 strings, you should instead convert the potentially ill-formed UTF-16 string to the expected encoding using WideCharToMultiByte.

like image 74
Francis Gagné Avatar answered Mar 07 '23 06:03

Francis Gagné