rust/physfs-rs/src/physfs/mod.rs
changeset 14435 a1613788130d
equal deleted inserted replaced
14434:632dfc73cf83 14435:a1613788130d
       
     1 use std::ffi::{ CString, CStr, OsStr };
       
     2 use std::io::Result;
       
     3 use std::sync::{ Mutex };
       
     4 use libc::{ c_int, c_char };
       
     5 
       
     6 /// Keep track of the number of global contexts.
       
     7 static mut NUM_CONTEXTS: usize = 0;
       
     8 
       
     9 /// Utility
       
    10 mod util;
       
    11 /// File operations
       
    12 pub mod file;
       
    13 
       
    14 #[link(name = "physfs")]
       
    15 extern {
       
    16     // nonzero on success, zero on error.
       
    17     fn PHYSFS_init(arg0: *const c_char) -> c_int;
       
    18     // nonzero if initialized, zero if not.
       
    19     fn PHYSFS_isInit() -> c_int;
       
    20     // nonzero if success, zero if error.
       
    21     fn PHYSFS_deinit() -> c_int;
       
    22     // string if success, NULL if error.
       
    23     fn PHYSFS_getLastError() -> *const c_char;
       
    24     // nonzero if success, zero if error
       
    25     fn PHYSFS_mount(new_dir: *const c_char, mount_point: *const c_char, append_to_path: c_int) -> c_int;
       
    26     // nonzero if success, zero if error.
       
    27     fn PHYSFS_setWriteDir(write_dir: *const c_char) -> c_int;
       
    28     // nonzero on success, zero on error.
       
    29     fn PHYSFS_mkdir(dir_name: *const c_char) -> c_int;
       
    30     // Checks if a given path exists; returns nonzero if true
       
    31     fn PHYSFS_exists(path: *const c_char) -> c_int;
       
    32     // Checks if a given path is a directory; returns nonzero if true
       
    33     fn PHYSFS_isDirectory(path: *const c_char) -> c_int;
       
    34 }
       
    35 
       
    36 /// The access point for PhysFS function calls.
       
    37 pub struct PhysFSContext;
       
    38 
       
    39 unsafe impl Send for PhysFSContext {}
       
    40 
       
    41 impl PhysFSContext {
       
    42     /// Creates a new PhysFS context.
       
    43     pub fn new() -> Result<Self> {
       
    44         let con = PhysFSContext;
       
    45         match PhysFSContext::init() {
       
    46             Err(e) => Err(e),
       
    47             _ => {
       
    48                 // Everything's gone right so far
       
    49                 // now, increment the instance counter
       
    50                 println!("Inc");
       
    51                 unsafe {
       
    52                     NUM_CONTEXTS += 1;
       
    53                 }
       
    54                 // and return the newly created context
       
    55                 Ok(con)
       
    56             }
       
    57         }
       
    58     }
       
    59 
       
    60     /// initializes the PhysFS library.
       
    61     fn init() -> Result<()> {
       
    62         // Initializing multiple times throws an error. So let's not!
       
    63         if PhysFSContext::is_init() { return Ok(()); }
       
    64 
       
    65         let mut args = ::std::env::args();
       
    66         let default_arg0 = "".to_string();
       
    67         let arg0 = args.next().unwrap_or(default_arg0);
       
    68         let c_arg0 = try!(CString::new(arg0));
       
    69         let ret = unsafe { PHYSFS_init(c_arg0.as_ptr()) };
       
    70 
       
    71         match ret {
       
    72             0 => Err(util::physfs_error_as_io_error()),
       
    73             _ => Ok(())
       
    74         }
       
    75     }
       
    76 
       
    77     /// Checks if PhysFS is initialized
       
    78     pub fn is_init() -> bool {
       
    79         unsafe { PHYSFS_isInit() != 0 }
       
    80     }
       
    81 
       
    82     /// De-initializes PhysFS. It is recommended to close
       
    83     /// all file handles manually before calling this.
       
    84     fn de_init() {
       
    85         // de_init'ing more than once can cause a double-free -- do not want.
       
    86         if !PhysFSContext::is_init() { return }
       
    87         unsafe {
       
    88             PHYSFS_deinit();
       
    89         }
       
    90     }
       
    91     /// Adds an archive or directory to the search path.
       
    92     /// mount_point is the location in the tree to mount it to.
       
    93     pub fn mount<P>(&self, new_dir: P, mount_point: String, append_to_path: bool) -> Result<()>
       
    94         where P: AsRef<OsStr>
       
    95     {
       
    96         let c_new_dir = CString::new(new_dir.as_ref().to_string_lossy().as_bytes()).unwrap();
       
    97         let c_mount_point = try!(CString::new(mount_point));
       
    98         match unsafe {
       
    99             PHYSFS_mount(
       
   100                 c_new_dir.as_c_str().as_ptr(),
       
   101                 c_mount_point.as_ptr(),
       
   102                 append_to_path as c_int
       
   103             )
       
   104         } {
       
   105             0 => Err(util::physfs_error_as_io_error()),
       
   106             _ => Ok(())
       
   107         }
       
   108     }
       
   109 
       
   110     /// Gets the last error message in a human-readable format
       
   111     /// This message may be localized, so do not expect it to
       
   112     /// match a specific string of characters.
       
   113     pub fn get_last_error() -> String {
       
   114         let ptr: *const c_char = unsafe {
       
   115             PHYSFS_getLastError()
       
   116         };
       
   117         if ptr.is_null() {
       
   118             return "".to_string()
       
   119         }
       
   120 
       
   121         let buf = unsafe { CStr::from_ptr(ptr).to_bytes().to_vec() };
       
   122 
       
   123         String::from_utf8(buf).unwrap()
       
   124     }
       
   125 
       
   126     /// Sets a new write directory.
       
   127     /// This method will fail if the current write dir
       
   128     /// still has open files in it.
       
   129     pub fn set_write_dir<P>(&self, write_dir: P) -> Result<()>
       
   130         where P: AsRef<OsStr>
       
   131     {
       
   132         let write_dir = CStr::from_bytes_with_nul(write_dir.as_ref().to_str().unwrap().as_bytes()).unwrap();
       
   133         let ret = unsafe {
       
   134             PHYSFS_setWriteDir(write_dir.as_ptr())
       
   135         };
       
   136 
       
   137         match ret {
       
   138             0 => Err(util::physfs_error_as_io_error()),
       
   139             _ => Ok(())
       
   140         }
       
   141     }
       
   142 
       
   143     /// Creates a new dir relative to the write_dir.
       
   144     pub fn mkdir(&self, dir_name: &str) -> Result<()> {
       
   145         let c_dir_name = try!(CString::new(dir_name));
       
   146         let ret = unsafe {
       
   147             PHYSFS_mkdir(c_dir_name.as_ptr())
       
   148         };
       
   149 
       
   150         match ret {
       
   151             0 => Err(util::physfs_error_as_io_error()),
       
   152             _ => Ok(())
       
   153         }
       
   154     }
       
   155 
       
   156     /// Checks if given path exists
       
   157     pub fn exists(&self, path: &str) -> Result<()> {
       
   158         let c_path = try!(CString::new(path));
       
   159         let ret = unsafe { PHYSFS_exists(c_path.as_ptr()) };
       
   160 
       
   161         match ret {
       
   162             0 => Err(util::physfs_error_as_io_error()),
       
   163             _ => Ok(())
       
   164         }
       
   165     }
       
   166 
       
   167     /// Checks if given path is a directory
       
   168     pub fn is_directory(&self, path: &str) -> Result<()> {
       
   169         let c_path = try!(CString::new(path));
       
   170         let ret = unsafe { PHYSFS_isDirectory(c_path.as_ptr()) };
       
   171 
       
   172         match ret {
       
   173             0 => Err(util::physfs_error_as_io_error()),
       
   174             _ => Ok(())
       
   175         }
       
   176     }
       
   177 }
       
   178 
       
   179 impl Drop for PhysFSContext {
       
   180     fn drop(&mut self) {
       
   181         // decrement NUM_CONTEXTS
       
   182         unsafe {
       
   183             NUM_CONTEXTS -= 1;
       
   184         }
       
   185         // and de_init if there aren't any contexts left.
       
   186         if unsafe { NUM_CONTEXTS == 0 } {
       
   187             PhysFSContext::de_init();
       
   188         }
       
   189     }
       
   190 }