rfmod/
file.rs

1/*
2* Rust-FMOD - Copyright (c) 2014 Gomez Guillaume.
3*
4* The Original software, FmodEx library, is provided by FIRELIGHT TECHNOLOGIES.
5*
6* This software is provided 'as-is', without any express or implied warranty.
7* In no event will the authors be held liable for any damages arising from
8* the use of this software.
9*
10* Permission is granted to anyone to use this software for any purpose,
11* including commercial applications, and to alter it and redistribute it
12* freely, subject to the following restrictions:
13*
14* 1. The origin of this software must not be misrepresented; you must not claim
15*    that you wrote the original software. If you use this software in a product,
16*    an acknowledgment in the product documentation would be appreciated but is
17*    not required.
18*
19* 2. Altered source versions must be plainly marked as such, and must not be
20*    misrepresented as being the original software.
21*
22* 3. This notice may not be removed or altered from any source distribution.
23*/
24
25use libc::{fopen, fread, fclose, fseek, ftell};
26use libc::{SEEK_SET, SEEK_CUR, SEEK_END};
27use libc::FILE;
28use libc::stat;
29use std::mem::zeroed;
30use libc::fstat;
31use libc::fileno;
32use libc::{c_void, c_char, c_long};
33use std::ffi::CString;
34
35#[doc(hidden)]
36pub fn get_ffi(file: &FmodFile) -> *mut FILE {
37    file.fd
38}
39
40#[doc(hidden)]
41pub fn from_ffi(fd: *mut FILE) -> FmodFile {
42    FmodFile {
43        fd: fd,
44    }
45}
46
47#[derive(Debug, PartialOrd, PartialEq)]
48pub enum SeekStyle {
49    /// Seek from the beginning of the stream
50    SeekSet,
51    /// Seek from the end of the stream
52    SeekEnd,
53    /// Seek from the current position
54    SeekCur,
55}
56
57/// A little struct to wrap C files.
58///
59/// IMPORTANT: it doesn't close the file when dropped!
60///
61/// I'll try to improve this or to replace it by File.
62pub struct FmodFile {
63    fd: *mut FILE,
64}
65
66impl FmodFile {
67    pub fn open(file_name: &str) -> Result<FmodFile, ::RStatus> {
68        let tmp_file_name = match CString::new(file_name) {
69            Ok(s) => s,
70            Err(e) => return Err(::RStatus::Other(format!("invalid file name: {}", e))),
71        };
72        unsafe {
73            let tmp = fopen(tmp_file_name.as_ptr() as *const c_char,
74                            "rb".as_ptr() as *const c_char);
75
76            if tmp.is_null() {
77                Err(::RStatus::Other(format!("fopen call failed")))
78            } else {
79                Ok(FmodFile{fd: tmp})
80            }
81        }
82    }
83
84    pub fn read(&self, buffer: &mut [u8]) -> usize {
85        unsafe {
86            if self.fd.is_null() {
87                0usize
88            } else {
89                fread(buffer.as_mut_ptr() as *mut c_void, buffer.len() as usize, 1usize,
90                      self.fd) as usize
91            }
92        }
93    }
94
95    pub fn seek(&self, pos: i64, style: self::SeekStyle) -> usize {
96        unsafe {
97            if self.fd.is_null() {
98                0usize
99            } else {
100                fseek(self.fd, pos as c_long, match style {
101                    self::SeekStyle::SeekSet => SEEK_SET,
102                    self::SeekStyle::SeekEnd => SEEK_END,
103                    self::SeekStyle::SeekCur => SEEK_CUR
104                }) as usize
105            }
106        }
107    }
108
109    pub fn get_file_size(&self) -> i64 {
110        unsafe {
111            if self.fd.is_null() {
112                0i64
113            } else {
114                let mut tmp : stat = zeroed::<stat>();
115                let id = fileno(self.fd);
116                match fstat(id, &mut tmp) {
117                    0 => tmp.st_size,
118                    _ => 0i64
119                }
120            }
121        }
122    }
123
124    pub fn tell(&self) -> i64 {
125        unsafe {
126            if self.fd.is_null() {
127                0i64
128            } else {
129                ftell(self.fd) as i64
130            }
131        }
132    }
133
134    pub fn close(&mut self) {
135        unsafe {
136            if !self.fd.is_null() {
137                fclose(self.fd);
138                self.fd = ::std::ptr::null_mut();
139            }
140        }
141    }
142}