#[cfg(not(target_os = "android"))] use std::fs::File as StdFile; use std::io::{Read, Result, Seek, SeekFrom}; #[cfg(not(target_os = "android"))] use std::io::BufReader; use std::mem::{size_of, transmute}; #[cfg(target_os = "android")] use super::android::asset as aas; #[derive(Debug)] pub struct File { pub endian_compatible: bool, offset: usize, #[cfg(not(target_os = "android"))] pub reader: BufReader, #[cfg(target_os = "android")] pub asset: *mut aas::AAsset, } impl File { #[cfg(target_endian = "big")] fn check_endian(&mut self) { if self.read_bool() { self.endian_compatible = false; } else { self.endian_compatible = true; } } #[cfg(target_endian = "little")] fn check_endian(&mut self) { if self.read_bool() { self.endian_compatible = true; } else { self.endian_compatible = false; } } #[cfg(not(target_os = "android"))] pub fn new(file_name: &String) -> Self { match StdFile::open(file_name) { Ok(f) => { let mut s = File { endian_compatible: true, offset: 0, reader: BufReader::new(f), }; s.check_endian(); s } Err(e) => { logf!("Error {:?} in file reading.", e); } } } #[cfg(target_os = "android")] pub fn new(file_name: &String, asset_manager: *mut aas::AAssetManager) -> Self { use std::ffi::CString; use std::ptr::null_mut; // let file_name: String = file_name.clone(); let cstr_name = CString::new(file_name.clone().into_bytes()).unwrap(); let asset = unsafe { aas::AAssetManager_open(asset_manager, cstr_name.as_ptr(), aas::AccesMode::O_RDONLY.bits()) }; if asset == null_mut() { logf!("File {} not found!", file_name); } let mut file = File { endian_compatible: true, offset: 0, asset: asset, }; file.check_endian(); return file; } pub fn read_typed_bytes(&mut self, des: *mut u8, count: usize) { let b = self.read_bytes(count); if self.endian_compatible { for i in 0..count { unsafe { *des.offset(i as isize) = b[i]; } } } else { let mut i = 0isize; let mut j = count - 1; let count = count as isize; while i < count { unsafe { *des.offset(i) = b[j]; } i += 1; j -= 1; } } } pub fn read_bytes(&mut self, count: usize) -> Vec { let mut b = vec![0u8; count]; let mut read_count = 0; while read_count < count { let tmp_count = match self.read(&mut b[read_count..count]) { Ok(c) => c, Err(_) => { logf!("Error in reading stream."); } }; read_count += tmp_count; if tmp_count == 0 { logf!( "Expected bytes count is {} but the read bytes count is {}.", count, read_count ); } } return b; } pub fn read_bool(&mut self) -> bool { let b = self.read_bytes(1); if b[0] == 1 { return true; } return false; } pub fn read_type(&mut self) -> T where T: Default, { let mut r = T::default(); self.read_typed_bytes(unsafe { transmute(&mut r) }, size_of::()); r } pub fn read_id(&mut self) -> u64 { self.read_type() } pub fn read_count(&mut self) -> u64 { self.read_type() } pub fn read_offset(&mut self) -> u64 { self.read_type() } pub fn tell(&self) -> usize { return self.offset; } pub fn goto(&mut self, offset: usize) { if offset == self.offset { return; } let _ = self.seek(SeekFrom::Start(offset as u64)); } } impl Read for File { fn read(&mut self, buf: &mut [u8]) -> Result { #[cfg(not(target_os = "android"))] let result = self.reader.read(buf); #[cfg(target_os = "android")] let result = Ok(unsafe { aas::AAsset_read(self.asset, transmute(buf.as_mut_ptr()), buf.len()) as usize }); match result { Ok(c) => self.offset += c, _ => { logf!("Error in reading stream."); } }; return result; } } impl Seek for File { fn seek(&mut self, pos: SeekFrom) -> Result { #[cfg(not(target_os = "android"))] { let result = self.reader.seek(pos); match result { Ok(c) => { self.offset = c as usize; } _ => { logf!("Error in file seeking!"); } } return result; } #[cfg(target_os = "android")] { return Ok(match pos { SeekFrom::Start(pos) => unsafe { aas::AAsset_seek(self.asset, pos as isize, aas::SeekDir::SEEK_SET.bits()) as u64 }, SeekFrom::End(pos) => unsafe { aas::AAsset_seek(self.asset, pos as isize, aas::SeekDir::SEEK_END.bits()) as u64 }, SeekFrom::Current(pos) => unsafe { aas::AAsset_seek(self.asset, pos as isize, aas::SeekDir::SEEK_CUR.bits()) as u64 }, }); } } }