# HG changeset patch # User Wuzzy # Date 1544742965 -3600 # Node ID cef0bb953ddf597b34ef9d3e2611f1973b3068f8 # Parent 3f679f2fb45a6454425c31347c70547faa9221ed# Parent a1613788130d48b87cbc285ddd4842d9b1934099 Merge recent Rust changes diff -r 3f679f2fb45a -r cef0bb953ddf rust/physfs-rs/Cargo.toml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/physfs-rs/Cargo.toml Fri Dec 14 00:16:05 2018 +0100 @@ -0,0 +1,15 @@ +[package] + +name = "physfs-rs" +version = "0.1.0" +license = "zlib" +authors = [ "Robert Habermeier" ] + +[lib] + +name = "physfs" + +[dependencies] + +libc = "0.1" + diff -r 3f679f2fb45a -r cef0bb953ddf rust/physfs-rs/LICENSE.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/physfs-rs/LICENSE.txt Fri Dec 14 00:16:05 2018 +0100 @@ -0,0 +1,20 @@ +Copyright (c) 2014 Robert Habermeier + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. \ No newline at end of file diff -r 3f679f2fb45a -r cef0bb953ddf rust/physfs-rs/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/physfs-rs/README.md Fri Dec 14 00:16:05 2018 +0100 @@ -0,0 +1,7 @@ +# physfs-rs [![Build Status](https://travis-ci.org/PistonDevelopers/physfs-rs.svg?branch=master)](https://travis-ci.org/PistonDevelopers/physfs-rs) + +## Rust bindings for PhysFS + +This project is built against the Rust nightly and PhysFS 2.0.3 + +[How to contribute](https://github.com/PistonDevelopers/piston/blob/master/CONTRIBUTING.md) diff -r 3f679f2fb45a -r cef0bb953ddf rust/physfs-rs/build.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/physfs-rs/build.rs Fri Dec 14 00:16:05 2018 +0100 @@ -0,0 +1,4 @@ +fn main() { + #[cfg(target_os = "freebsd")] + println!("cargo:rustc-link-search=native=/usr/local/lib"); +} \ No newline at end of file diff -r 3f679f2fb45a -r cef0bb953ddf rust/physfs-rs/src/lib.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/physfs-rs/src/lib.rs Fri Dec 14 00:16:05 2018 +0100 @@ -0,0 +1,13 @@ +//! PhysFS bindings for Rust + +#![deny(missing_docs)] + +extern crate libc; + +pub use physfs::*; +pub use physfs::file::*; + +/// PhysFS bindings +mod physfs; +/// Definitions for the PhysFS primitives +mod primitives; diff -r 3f679f2fb45a -r cef0bb953ddf rust/physfs-rs/src/physfs/file.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/physfs-rs/src/physfs/file.rs Fri Dec 14 00:16:05 2018 +0100 @@ -0,0 +1,216 @@ +use std::ffi::CString; +use std::io::{ Read, Write, Seek, SeekFrom, Result }; +use std::mem; +use libc::{ c_int, c_char, c_void }; +use primitives::*; +use super::{ PhysFSContext }; +use super::util::physfs_error_as_io_error; + +#[link(name = "physfs")] +extern { + // valid filehandle on success, NULL on failure + fn PHYSFS_openAppend(filename: *const c_char) -> *const RawFile; + fn PHYSFS_openRead(filename: *const c_char) -> *const RawFile; + fn PHYSFS_openWrite(filename: *const c_char) -> *const RawFile; + + // nonzero on success, 0 on failure (and the handle stays open) + // The docs make it sound like failure is rare. + fn PHYSFS_close(file: *const RawFile) -> c_int; + + // Number of bytes read on success, -1 on failure. + fn PHYSFS_read(file: *const RawFile, buffer: *mut c_void, + obj_size: PHYSFS_uint32, obj_count: PHYSFS_uint32) -> PHYSFS_sint64; + + // Number of bytes written on success, -1 on failure. + fn PHYSFS_write(file: *const RawFile, buffer: *const c_void, + obj_size: PHYSFS_uint32, obj_count: PHYSFS_uint32) -> PHYSFS_sint64; + + // Flush buffered file; no-op for unbuffered files. + fn PHYSFS_flush(file: *const RawFile) -> c_int; + + // Seek to position in file; nonzero on succss, zero on error. + fn PHYSFS_seek(file: *const RawFile, pos: PHYSFS_uint64) -> c_int; + + // Current position in file, -1 on failure. + fn PHYSFS_tell(file: *const RawFile) -> PHYSFS_sint64; + + // nonzero if EOF, zero if not. + fn PHYSFS_eof(file: *const RawFile) -> c_int; + + // Determine file size; returns -1 if impossible + fn PHYSFS_fileLength(file: *const RawFile) -> PHYSFS_sint64; +} + +/// Possible ways to open a file. +#[derive(Copy, Clone)] +pub enum Mode { + /// Append to the end of the file. + Append, + /// Read from the file. + Read, + /// Write to the file, overwriting previous data. + Write, +} + +/// A wrapper for the PHYSFS_File type. +#[repr(C)] +struct RawFile { + opaque: *const c_void, +} + +/// A file handle. +#[allow(dead_code)] +pub struct File<'f> { + raw: *const RawFile, + mode: Mode, + context: &'f PhysFSContext, +} + +impl<'f> File<'f> { + /// Opens a file with a specific mode. + pub fn open<'g>(context: &'g PhysFSContext, filename: String, mode: Mode) -> Result> { + let c_filename = try!(CString::new(filename)); + let raw = unsafe { match mode { + Mode::Append => PHYSFS_openAppend(c_filename.as_ptr()), + Mode::Read => PHYSFS_openRead(c_filename.as_ptr()), + Mode::Write => PHYSFS_openWrite(c_filename.as_ptr()) + }}; + + if raw.is_null() { + Err(physfs_error_as_io_error()) + } + else { + Ok(File{raw: raw, mode: mode, context: context}) + } + } + + /// Closes a file handle. + fn close(&self) -> Result<()> { + match unsafe { + PHYSFS_close(self.raw) + } { + 0 => Err(physfs_error_as_io_error()), + _ => Ok(()) + } + } + + /// Checks whether eof is reached or not. + pub fn eof(&self) -> bool { + let ret = unsafe { + PHYSFS_eof(self.raw) + }; + + ret != 0 + } + + /// Determine length of file, if possible + pub fn len(&self) -> Result { + let len = unsafe { PHYSFS_fileLength(self.raw) }; + + if len >= 0 { + Ok(len as u64) + } else { + Err(physfs_error_as_io_error()) + } + } + + /// Determines current position within a file + pub fn tell(&self) -> Result { + let ret = unsafe { + PHYSFS_tell(self.raw) + }; + + match ret { + -1 => Err(physfs_error_as_io_error()), + _ => Ok(ret as u64) + } + } +} + +impl<'f> Read for File<'f> { + /// Reads from a file + fn read(&mut self, buf: &mut [u8]) -> Result { + let ret = unsafe { + PHYSFS_read( + self.raw, + buf.as_ptr() as *mut c_void, + mem::size_of::() as PHYSFS_uint32, + buf.len() as PHYSFS_uint32 + ) + }; + + match ret { + -1 => Err(physfs_error_as_io_error()), + _ => Ok(ret as usize) + } + } +} + +impl<'f> Write for File<'f> { + /// Writes to a file. + /// This code performs no safety checks to ensure + /// that the buffer is the correct length. + fn write(&mut self, buf: &[u8]) -> Result { + let ret = unsafe { + PHYSFS_write( + self.raw, + buf.as_ptr() as *const c_void, + mem::size_of::() as PHYSFS_uint32, + buf.len() as PHYSFS_uint32 + ) + }; + + match ret { + -1 => Err(physfs_error_as_io_error()), + _ => Ok(ret as usize) + } + } + + /// Flushes a file if buffered; no-op if unbuffered. + fn flush(&mut self) -> Result<()> { + let ret = unsafe { + PHYSFS_flush(self.raw) + }; + + match ret { + 0 => Err(physfs_error_as_io_error()), + _ => Ok(()) + } + } +} + +impl<'f> Seek for File<'f> { + /// Seek to a new position within a file + fn seek(&mut self, pos: SeekFrom) -> Result { + let seek_pos = match pos { + SeekFrom::Start(n) => n as i64, + SeekFrom::End(n) => { + let len = try!(self.len()); + n + len as i64 + } + SeekFrom::Current(n) => { + let curr_pos = try!(self.tell()); + n + curr_pos as i64 + } + }; + + let result = unsafe { + PHYSFS_seek( + self.raw, + seek_pos as PHYSFS_uint64 + ) + }; + + if result == -1 { + return Err(physfs_error_as_io_error()); + } + + self.tell() + } +} + +impl<'f> Drop for File<'f> { + fn drop(&mut self) { + let _ = self.close(); + } +} diff -r 3f679f2fb45a -r cef0bb953ddf 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 Fri Dec 14 00:16:05 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(); + } + } +} diff -r 3f679f2fb45a -r cef0bb953ddf rust/physfs-rs/src/physfs/util.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/physfs-rs/src/physfs/util.rs Fri Dec 14 00:16:05 2018 +0100 @@ -0,0 +1,7 @@ +use std::io::{ Error, ErrorKind }; +use super::PhysFSContext; + +pub fn physfs_error_as_io_error() -> Error { + Error::new(ErrorKind::Other, + &format!("PhysicsFS Error: `{}`", PhysFSContext::get_last_error())[..]) +} diff -r 3f679f2fb45a -r cef0bb953ddf rust/physfs-rs/src/primitives.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/physfs-rs/src/primitives.rs Fri Dec 14 00:16:05 2018 +0100 @@ -0,0 +1,19 @@ +#![allow(non_camel_case_types)] + +pub type PHYSFS_uint8 = ::libc::c_uchar; +pub type PHYSFS_sint8 = ::libc::c_char; +pub type PHYSFS_uint16 = ::libc::c_ushort; +pub type PHYSFS_sint16 = ::libc::c_short; +pub type PHYSFS_uint32 = ::libc::c_uint; +pub type PHYSFS_sint32 = ::libc::c_int; + +#[cfg(target_pointer_width = "64")] +pub type PHYSFS_uint64 = ::libc::c_ulonglong; +#[cfg(target_pointer_width = "64")] +pub type PHYSFS_sint64 = ::libc::c_longlong; + +// PhysFS defines the 64-bit types to 32 bits on 32-bit systems. +#[cfg(target_pointer_width = "32")] +pub type PHYSFS_uint64 = ::libc::c_uint; +#[cfg(target_pointer_width = "32")] +pub type PHYSFS_sint64 = ::libc::c_int; diff -r 3f679f2fb45a -r cef0bb953ddf rust/physfs-rs/tests/directory/mod.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/physfs-rs/tests/directory/mod.rs Fri Dec 14 00:16:05 2018 +0100 @@ -0,0 +1,40 @@ +use std::io::Read; +use std::path::Path; + +use physfs::{ PhysFSContext, file }; + +#[test] +fn read_file_from_directory() { + let con = match PhysFSContext::new() { + Err(e) => panic!(e), + Ok(con) => con + }; + + assert!(PhysFSContext::is_init()); + + match con.mount(&Path::new(super::PATH_TO_HERE), "/test/".to_string(), true) { + Err(e) => panic!(e), + _ => () + } + + let mut file = match file::File::open(&con, "/test/directory/read.txt".to_string(), file::Mode::Read) { + Ok(f) => f, + Err(e) => panic!(e) + }; + + let buf = &mut [0; 32]; + + match file.read(buf) { + Err(e) => panic!(e), + _ => () + } + + let mut contents = String::new(); + for &mut byte in buf { + if byte == 0 { break } + contents.push(byte as char); + } + + assert!(contents == "Read from me."); +} + diff -r 3f679f2fb45a -r cef0bb953ddf rust/physfs-rs/tests/directory/read.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/physfs-rs/tests/directory/read.txt Fri Dec 14 00:16:05 2018 +0100 @@ -0,0 +1,1 @@ +Read from me. \ No newline at end of file diff -r 3f679f2fb45a -r cef0bb953ddf rust/physfs-rs/tests/test.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/physfs-rs/tests/test.rs Fri Dec 14 00:16:05 2018 +0100 @@ -0,0 +1,15 @@ +extern crate physfs; + +use physfs::PhysFSContext; + +mod directory; + +// from project_root +const PATH_TO_HERE: &'static str = "tests/"; + +//#[test] +fn test_create_physfs_context() { + let _c = PhysFSContext::new().unwrap(); + assert!(PhysFSContext::is_init()); +} +