diff -r 632dfc73cf83 -r a1613788130d rust/physfs-rs/src/physfs/mod.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/physfs-rs/src/physfs/mod.rs Thu Dec 13 23:44:46 2018 +0100 @@ -0,0 +1,190 @@ +use std::ffi::{ CString, CStr, OsStr }; +use std::io::Result; +use std::sync::{ Mutex }; +use libc::{ c_int, c_char }; + +/// Keep track of the number of global contexts. +static mut NUM_CONTEXTS: usize = 0; + +/// Utility +mod util; +/// File operations +pub mod file; + +#[link(name = "physfs")] +extern { + // nonzero on success, zero on error. + fn PHYSFS_init(arg0: *const c_char) -> c_int; + // nonzero if initialized, zero if not. + fn PHYSFS_isInit() -> c_int; + // nonzero if success, zero if error. + fn PHYSFS_deinit() -> c_int; + // string if success, NULL if error. + fn PHYSFS_getLastError() -> *const c_char; + // nonzero if success, zero if error + fn PHYSFS_mount(new_dir: *const c_char, mount_point: *const c_char, append_to_path: c_int) -> c_int; + // nonzero if success, zero if error. + fn PHYSFS_setWriteDir(write_dir: *const c_char) -> c_int; + // nonzero on success, zero on error. + fn PHYSFS_mkdir(dir_name: *const c_char) -> c_int; + // Checks if a given path exists; returns nonzero if true + fn PHYSFS_exists(path: *const c_char) -> c_int; + // Checks if a given path is a directory; returns nonzero if true + fn PHYSFS_isDirectory(path: *const c_char) -> c_int; +} + +/// The access point for PhysFS function calls. +pub struct PhysFSContext; + +unsafe impl Send for PhysFSContext {} + +impl PhysFSContext { + /// Creates a new PhysFS context. + pub fn new() -> Result { + let con = PhysFSContext; + match PhysFSContext::init() { + Err(e) => Err(e), + _ => { + // Everything's gone right so far + // now, increment the instance counter + println!("Inc"); + unsafe { + NUM_CONTEXTS += 1; + } + // and return the newly created context + Ok(con) + } + } + } + + /// initializes the PhysFS library. + fn init() -> Result<()> { + // Initializing multiple times throws an error. So let's not! + if PhysFSContext::is_init() { return Ok(()); } + + let mut args = ::std::env::args(); + let default_arg0 = "".to_string(); + let arg0 = args.next().unwrap_or(default_arg0); + let c_arg0 = try!(CString::new(arg0)); + let ret = unsafe { PHYSFS_init(c_arg0.as_ptr()) }; + + match ret { + 0 => Err(util::physfs_error_as_io_error()), + _ => Ok(()) + } + } + + /// Checks if PhysFS is initialized + pub fn is_init() -> bool { + unsafe { PHYSFS_isInit() != 0 } + } + + /// De-initializes PhysFS. It is recommended to close + /// all file handles manually before calling this. + fn de_init() { + // de_init'ing more than once can cause a double-free -- do not want. + if !PhysFSContext::is_init() { return } + unsafe { + PHYSFS_deinit(); + } + } + /// Adds an archive or directory to the search path. + /// mount_point is the location in the tree to mount it to. + pub fn mount

(&self, new_dir: P, mount_point: String, append_to_path: bool) -> Result<()> + where P: AsRef + { + let c_new_dir = CString::new(new_dir.as_ref().to_string_lossy().as_bytes()).unwrap(); + let c_mount_point = try!(CString::new(mount_point)); + match unsafe { + PHYSFS_mount( + c_new_dir.as_c_str().as_ptr(), + c_mount_point.as_ptr(), + append_to_path as c_int + ) + } { + 0 => Err(util::physfs_error_as_io_error()), + _ => Ok(()) + } + } + + /// Gets the last error message in a human-readable format + /// This message may be localized, so do not expect it to + /// match a specific string of characters. + pub fn get_last_error() -> String { + let ptr: *const c_char = unsafe { + PHYSFS_getLastError() + }; + if ptr.is_null() { + return "".to_string() + } + + let buf = unsafe { CStr::from_ptr(ptr).to_bytes().to_vec() }; + + String::from_utf8(buf).unwrap() + } + + /// Sets a new write directory. + /// This method will fail if the current write dir + /// still has open files in it. + pub fn set_write_dir

(&self, write_dir: P) -> Result<()> + where P: AsRef + { + let write_dir = CStr::from_bytes_with_nul(write_dir.as_ref().to_str().unwrap().as_bytes()).unwrap(); + let ret = unsafe { + PHYSFS_setWriteDir(write_dir.as_ptr()) + }; + + match ret { + 0 => Err(util::physfs_error_as_io_error()), + _ => Ok(()) + } + } + + /// Creates a new dir relative to the write_dir. + pub fn mkdir(&self, dir_name: &str) -> Result<()> { + let c_dir_name = try!(CString::new(dir_name)); + let ret = unsafe { + PHYSFS_mkdir(c_dir_name.as_ptr()) + }; + + match ret { + 0 => Err(util::physfs_error_as_io_error()), + _ => Ok(()) + } + } + + /// Checks if given path exists + pub fn exists(&self, path: &str) -> Result<()> { + let c_path = try!(CString::new(path)); + let ret = unsafe { PHYSFS_exists(c_path.as_ptr()) }; + + match ret { + 0 => Err(util::physfs_error_as_io_error()), + _ => Ok(()) + } + } + + /// Checks if given path is a directory + pub fn is_directory(&self, path: &str) -> Result<()> { + let c_path = try!(CString::new(path)); + let ret = unsafe { PHYSFS_isDirectory(c_path.as_ptr()) }; + + match ret { + 0 => Err(util::physfs_error_as_io_error()), + _ => Ok(()) + } + } +} + +impl Drop for PhysFSContext { + fn drop(&mut self) { + // decrement NUM_CONTEXTS + unsafe { + NUM_CONTEXTS -= 1; + } + // and de_init if there aren't any contexts left. + if unsafe { NUM_CONTEXTS == 0 } { + PhysFSContext::de_init(); + } + } +}