From bce52276af564c6ec5837ba8482c94f89330c1c5 Mon Sep 17 00:00:00 2001 From: Robert Straw Date: Wed, 7 Jan 2015 08:30:54 -0600 Subject: [PATCH] Fix up CString interop Working with `*const c_char` now works as follows: * Call `c_str_to_bytes(*const char)` helper function to get a slice of data w/o the null terminator. (`&'a [u8]`) * Use that slice of data to construct a standard `String` using the checked, unchecked, or lossy UTF-8 conversion methods. --- CString now only exists to go the other way (from String -> CString). It simply adds the invariants that the string contains no interior NULL bytes and has a null-terminator. --- src/sdl2/audio.rs | 22 ++++++++-------- src/sdl2/clipboard.rs | 12 ++++----- src/sdl2/event.rs | 4 ++- src/sdl2/filesystem.rs | 16 +++++------- src/sdl2/keyboard.rs | 22 +++++++--------- src/sdl2/messagebox.rs | 11 ++++---- src/sdl2/render.rs | 4 ++- src/sdl2/rwops.rs | 4 ++- src/sdl2/sdl.rs | 12 ++++----- src/sdl2/version.rs | 7 +++-- src/sdl2/video.rs | 59 +++++++++++++++++++----------------------- 11 files changed, 83 insertions(+), 90 deletions(-) diff --git a/src/sdl2/audio.rs b/src/sdl2/audio.rs index 9bb548b7..4f5c0063 100644 --- a/src/sdl2/audio.rs +++ b/src/sdl2/audio.rs @@ -1,7 +1,7 @@ //! Audio Functions use std::ptr; use std::mem; -use std::ffi::CString; +use std::ffi::{c_str_to_bytes, CString}; use std::borrow::ToOwned; use std::num::FromPrimitive; use libc; @@ -50,8 +50,8 @@ pub fn get_num_audio_drivers() -> int { pub fn get_audio_driver(index: int) -> String { unsafe { - let buf = ll::SDL_GetAudioDriver(index as c_int); - CString::new(buf, false).as_str().unwrap().to_owned() + let driver = ll::SDL_GetAudioDriver(index as c_int); + String::from_utf8_lossy(c_str_to_bytes(&driver)).to_string() } } @@ -61,15 +61,15 @@ pub fn get_num_audio_devices(iscapture: int) -> int { pub fn get_audio_device_name(index: int, iscapture: int) -> String { unsafe { - let buf = ll::SDL_GetAudioDeviceName(index as c_int, iscapture as c_int); - CString::new(buf, false).as_str().unwrap().to_owned() + let dev_name = ll::SDL_GetAudioDeviceName(index as c_int, iscapture as c_int); + String::from_utf8_lossy(c_str_to_bytes(&dev_name)).to_string() } } pub fn audio_init(name: &str) -> SdlResult<()> { - let ret = name.with_c_str(|buf| { - unsafe { ll::SDL_AudioInit(buf) } - }); + let buf = CString::from_slice(name.as_bytes()).as_ptr(); + let ret = unsafe { ll::SDL_AudioInit(buf) }; + if ret == 0 { Ok(()) } else { @@ -83,8 +83,8 @@ pub fn audio_quit() { pub fn get_current_audio_driver() -> String { unsafe { - let buf = ll::SDL_GetCurrentAudioDriver(); - CString::new(buf, false).as_str().unwrap().to_owned() + let driver = ll::SDL_GetCurrentAudioDriver(); + String::from_utf8_lossy(c_str_to_bytes(&driver)).to_string() } } @@ -245,7 +245,7 @@ impl, CB: AudioCallback> AudioSpecDesired { unsafe { let device_cstr: Option = match device { None => None, - Some(d) => Some(d.to_c_str()) + Some(d) => Some(CString::from_slice(d.as_bytes())) }; let device_cstr_ptr: *const c_char = match device_cstr { None => null(), diff --git a/src/sdl2/clipboard.rs b/src/sdl2/clipboard.rs index e7303e7d..e42dfd36 100644 --- a/src/sdl2/clipboard.rs +++ b/src/sdl2/clipboard.rs @@ -1,5 +1,4 @@ -use std::ffi::CString; - +use std::ffi::{c_str_to_bytes, CString}; use SdlResult; use get_error; @@ -7,9 +6,8 @@ pub use sys::clipboard as ll; pub fn set_clipboard_text(text: &String) -> SdlResult<()> { unsafe { - let result = text.with_c_str(|buff| { - ll::SDL_SetClipboardText(buff) - }); + let buff = CString::from_slice(text.as_slice().as_bytes()); + let result = ll::SDL_SetClipboardText(buff.as_ptr()); if result == 0 { Err(get_error()) @@ -21,8 +19,8 @@ pub fn set_clipboard_text(text: &String) -> SdlResult<()> { pub fn get_clipboard_text() -> SdlResult { let result = unsafe { - let cstr = ll::SDL_GetClipboardText() as *const u8; - String::from_raw_buf(cstr) + let buf = ll::SDL_GetClipboardText(); + String::from_utf8_lossy(c_str_to_bytes(&buf)).to_string() }; if result.len() == 0 { diff --git a/src/sdl2/event.rs b/src/sdl2/event.rs index 4a416ae1..b0a66909 100644 --- a/src/sdl2/event.rs +++ b/src/sdl2/event.rs @@ -2,6 +2,7 @@ Event Handling */ +use std::ffi::{c_str_to_bytes}; use std::mem; use libc::{c_int, c_void, uint32_t}; use std::num::FromPrimitive; @@ -592,7 +593,8 @@ impl Event { EventType::DropFile => { let ref event = *raw.drop(); - let text = String::from_raw_buf(event.file as *const u8); + let buf = c_str_to_bytes(&event.file); + let text = String::from_utf8_lossy(buf).to_string(); ll::SDL_free(event.file as *const c_void); Event::DropFile(event.timestamp as uint, text) diff --git a/src/sdl2/filesystem.rs b/src/sdl2/filesystem.rs index 42c32a5d..550631d3 100644 --- a/src/sdl2/filesystem.rs +++ b/src/sdl2/filesystem.rs @@ -1,4 +1,4 @@ -use std::ffi::CString; +use std::ffi::{c_str_to_bytes, CString}; use SdlResult; use get_error; @@ -6,8 +6,8 @@ pub use sys::filesystem as ll; pub fn get_base_path() -> SdlResult { let result = unsafe { - let cstr = ll::SDL_GetBasePath(); - String::from_raw_buf(cstr as *const u8) + let buf = ll::SDL_GetBasePath(); + String::from_utf8_lossy(c_str_to_bytes(&buf)).to_string() }; if result.len() == 0 { @@ -19,12 +19,10 @@ pub fn get_base_path() -> SdlResult { pub fn get_pref_path(org: &str, app: &str) -> SdlResult { let result = unsafe { - let cstr = - org.with_c_str(|org_cstr| { - app.with_c_str(|app_cstr| { - ll::SDL_GetPrefPath(org_cstr, app_cstr) - })}); - String::from_raw_buf(cstr as *const u8) + let org_cstr = CString::from_slice(org.as_bytes()).as_ptr(); + let app_cstr = CString::from_slice(app.as_bytes()).as_ptr(); + let buf = ll::SDL_GetPrefPath(org_cstr, app_cstr); + String::from_utf8_lossy(c_str_to_bytes(&buf)).to_string() }; if result.len() == 0 { diff --git a/src/sdl2/keyboard.rs b/src/sdl2/keyboard.rs index eab52d5a..4031ef08 100644 --- a/src/sdl2/keyboard.rs +++ b/src/sdl2/keyboard.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::ffi::CString; +use std::ffi::{c_str_to_bytes, CString}; use std::num::FromPrimitive; use std::ptr; @@ -80,32 +80,30 @@ pub fn get_scancode_from_key(key: KeyCode) -> ScanCode { pub fn get_scancode_name(scancode: ScanCode) -> String { unsafe { let scancode_name = ll::SDL_GetScancodeName(scancode as u32); - String::from_raw_buf(scancode_name as *const u8) + String::from_utf8_lossy(c_str_to_bytes(&scancode_name)).to_string() } } pub fn get_scancode_from_name(name: &str) -> ScanCode { unsafe { - name.with_c_str(|name| { - FromPrimitive::from_int(ll::SDL_GetScancodeFromName(name) as int) - .unwrap_or(ScanCode::Unknown) - }) - } + let name = CString::from_slice(name.as_bytes()).as_ptr(); + FromPrimitive::from_int(ll::SDL_GetScancodeFromName(name) as int) + .unwrap_or(ScanCode::Unknown) + } } pub fn get_key_name(key: KeyCode) -> String { unsafe { let key_name = ll::SDL_GetKeyName(key as i32); - String::from_raw_buf(key_name as *const u8) + String::from_utf8_lossy(c_str_to_bytes(&key_name)).to_string() } } pub fn get_key_from_name(name: &str) -> KeyCode { unsafe { - name.with_c_str(|name| { - FromPrimitive::from_int(ll::SDL_GetKeyFromName(name) as int) - .unwrap_or(KeyCode::Unknown) - }) + let name = CString::from_slice(name.as_bytes()).as_ptr(); + FromPrimitive::from_int(ll::SDL_GetKeyFromName(name) as int) + .unwrap_or(KeyCode::Unknown) } } diff --git a/src/sdl2/messagebox.rs b/src/sdl2/messagebox.rs index 9aab85da..11a3b52f 100644 --- a/src/sdl2/messagebox.rs +++ b/src/sdl2/messagebox.rs @@ -17,11 +17,12 @@ bitflags! { pub fn show_simple_message_box(flags: MessageBoxFlag, title: &str, message: &str, window: Option<&Window>) -> SdlResult<()> { let result = unsafe { - title.with_c_str(|title_cstr| { - message.with_c_str(|message_cstr| { - ll::SDL_ShowSimpleMessageBox(flags.bits(), title_cstr, message_cstr, window.map_or(ptr::null(), |win| win.raw())) - }) - }) + let title_cstr = CString::from_slice(title.as_bytes()).as_ptr(); + let message_cstr = CString::from_slice(message.as_bytes()).as_ptr(); + ll::SDL_ShowSimpleMessageBox(flags.bits(), + title_cstr, + message_cstr, + window.map_or(ptr::null(), |win| win.raw())) } == 0; if result { diff --git a/src/sdl2/render.rs b/src/sdl2/render.rs index 504d7d32..54fc27c3 100644 --- a/src/sdl2/render.rs +++ b/src/sdl2/render.rs @@ -8,8 +8,10 @@ use SdlResult; use std::ptr; use libc; use libc::{c_int, uint32_t, c_float, c_double, c_void, size_t}; +use ::c_vec::CVec; use rect::Point; use rect::Rect; +use std::ffi::c_str_to_bytes; use std::num::FromPrimitive; use std::vec::Vec; use std::borrow::ToOwned; @@ -72,7 +74,7 @@ impl RendererInfo { }).collect(); RendererInfo { - name: String::from_raw_buf(info.name as *const _), + name: String::from_utf8_lossy(c_str_to_bytes(&info.name)).to_string(), flags: actual_flags, texture_formats: texture_formats, max_texture_width: info.max_texture_width as int, diff --git a/src/sdl2/rwops.rs b/src/sdl2/rwops.rs index b9049155..0f11e960 100644 --- a/src/sdl2/rwops.rs +++ b/src/sdl2/rwops.rs @@ -20,7 +20,9 @@ impl_owned_accessors!(RWops, close_on_drop); impl RWops { pub fn from_file(path: &Path, mode: &str) -> SdlResult { let raw = unsafe { - ll::SDL_RWFromFile(CString::from_slice(path), CString::from_slice(mode)) + let path_c = CString::from_slice(path.as_vec()).as_ptr(); + let mode_c = CString::from_slice(mode.as_bytes()).as_ptr(); + ll::SDL_RWFromFile(path_c, mode_c) }; if raw.is_null() { Err(get_error()) } else { Ok(RWops{raw: raw, close_on_drop: true}) } diff --git a/src/sdl2/sdl.rs b/src/sdl2/sdl.rs index 17bb77d8..6cd742e2 100644 --- a/src/sdl2/sdl.rs +++ b/src/sdl2/sdl.rs @@ -1,5 +1,4 @@ -use std::borrow::ToOwned; -use std::ffi::CString; +use std::ffi::{c_str_to_bytes, CString}; use sys::sdl as ll; @@ -57,15 +56,14 @@ pub fn was_inited(flags: InitFlag) -> InitFlag { pub fn get_error() -> String { unsafe { - let cstr = CString::new(ll::SDL_GetError(), false); - cstr.as_str().unwrap().to_owned() + let err = ll::SDL_GetError(); + String::from_utf8_lossy(c_str_to_bytes(&err)).to_string() } } pub fn set_error(err: &str) { - err.with_c_str(|buf| { - unsafe { ll::SDL_SetError(buf); } - }) + let buf = CString::from_slice(err.as_bytes()).as_ptr(); + unsafe { ll::SDL_SetError(buf); } } pub fn set_error_from_code(err: Error) { diff --git a/src/sdl2/version.rs b/src/sdl2/version.rs index 8da7bb08..433c41e1 100644 --- a/src/sdl2/version.rs +++ b/src/sdl2/version.rs @@ -2,9 +2,8 @@ Querying SDL Version */ -use std::ffi::CString; +use std::ffi::c_str_to_bytes; use std::fmt; -use std::borrow::ToOwned; pub use sys::version as ll; @@ -47,8 +46,8 @@ pub fn get_version() -> Version { /// Get the code revision of SDL that is linked against your program. pub fn get_revision() -> String { unsafe { - let ret = ll::SDL_GetRevision(); - CString::new(ret, false).as_str().unwrap().to_owned() + let rev = ll::SDL_GetRevision(); + String::from_utf8_lossy(c_str_to_bytes(&rev)).to_string() } } diff --git a/src/sdl2/video.rs b/src/sdl2/video.rs index 9099da1b..8e13204d 100644 --- a/src/sdl2/video.rs +++ b/src/sdl2/video.rs @@ -1,5 +1,5 @@ use libc::{c_int, c_float, uint32_t}; -use std::ffi::CString; +use std::ffi::{c_str_to_bytes, CString}; use std::ptr; use std::vec::Vec; @@ -190,16 +190,15 @@ impl Drop for Window { impl Window { pub fn new(title: &str, x: WindowPos, y: WindowPos, width: int, height: int, window_flags: WindowFlags) -> SdlResult { unsafe { - let raw = title.with_c_str(|buff| { - ll::SDL_CreateWindow( + let buff = CString::from_slice(title.as_bytes()).as_ptr(); + let raw = ll::SDL_CreateWindow( buff, unwrap_windowpos(x), unwrap_windowpos(y), width as c_int, height as c_int, window_flags.bits() - ) - }); + ); if raw == ptr::null() { Err(get_error()) @@ -272,15 +271,14 @@ impl Window { } pub fn set_title(&self, title: &str) { - title.with_c_str(|buff| { - unsafe { ll::SDL_SetWindowTitle(self.raw, buff) } - }) + let buff = CString::from_slice(title.as_bytes()).as_ptr(); + unsafe { ll::SDL_SetWindowTitle(self.raw, buff) } } pub fn get_title(&self) -> String { unsafe { - let cstr = ll::SDL_GetWindowTitle(self.raw); - String::from_raw_buf(cstr as *const _) + let buf = ll::SDL_GetWindowTitle(self.raw); + String::from_utf8_lossy(c_str_to_bytes(&buf)).to_string() } } @@ -467,15 +465,14 @@ pub fn get_num_video_drivers() -> SdlResult { pub fn get_video_driver(id: int) -> String { unsafe { - let cstr = ll::SDL_GetVideoDriver(id as c_int); - String::from_raw_buf(cstr as *const _) + let buf = ll::SDL_GetVideoDriver(id as c_int); + String::from_utf8_lossy(c_str_to_bytes(&buf)).to_string() } } pub fn video_init(name: &str) -> bool { - name.with_c_str(|buf| { - unsafe { ll::SDL_VideoInit(buf) == 0 } - }) + let buf = CString::from_slice(name.as_bytes()).as_ptr(); + unsafe { ll::SDL_VideoInit(buf) == 0 } } pub fn video_quit() { @@ -484,8 +481,8 @@ pub fn video_quit() { pub fn get_current_video_driver() -> String { unsafe { - let cstr = ll::SDL_GetCurrentVideoDriver(); - String::from_raw_buf(cstr as *const _) + let video = ll::SDL_GetCurrentVideoDriver(); + String::from_utf8_lossy(c_str_to_bytes(&video)).to_string() } } @@ -500,8 +497,8 @@ pub fn get_num_video_displays() -> SdlResult { pub fn get_display_name(display_index: int) -> String { unsafe { - let cstr = ll::SDL_GetDisplayName(display_index as c_int); - String::from_raw_buf(cstr as *const _) + let display = ll::SDL_GetDisplayName(display_index as c_int); + String::from_utf8_lossy(c_str_to_bytes(&display)).to_string() } } @@ -585,13 +582,13 @@ pub fn disable_screen_saver() { pub fn gl_load_library(path: &str) -> SdlResult<()> { unsafe { - path.with_c_str(|path| { - if ll::SDL_GL_LoadLibrary(path) == 0 { - Ok(()) - } else { - Err(get_error()) - } - }) + let path = CString::from_slice(path.as_bytes()).as_ptr(); + + if ll::SDL_GL_LoadLibrary(path) == 0 { + Ok(()) + } else { + Err(get_error()) + } } } @@ -601,16 +598,14 @@ pub fn gl_unload_library() { pub fn gl_get_proc_address(procname: &str) -> Option { unsafe { - procname.with_c_str(|procname| { - ll::SDL_GL_GetProcAddress(procname) - }) + let procname = CString::from_slice(procname.as_bytes()).as_ptr(); + ll::SDL_GL_GetProcAddress(procname) } } pub fn gl_extension_supported(extension: &str) -> bool { - extension.with_c_str(|buff| { - unsafe { ll::SDL_GL_ExtensionSupported(buff) == 1 } - }) + let buff = CString::from_slice(extension.as_bytes()).as_ptr(); + unsafe { ll::SDL_GL_ExtensionSupported(buff) == 1 } } pub fn gl_set_attribute(attr: GLAttr, value: int) -> bool {