maikor_vm_file/
read_write_impl.rs1use crate::file_utils::ReaderExt;
2use crate::GameFileError::{FileAccessError, FileNotFound, FileTooLarge, FileTooSmall, NotAFile};
3use crate::{GameFile, GameFileError, GameFileHeader, MAX_FILE_SIZE, MIN_FILE_SIZE};
4use std::fs::File;
5use std::io::{BufReader, BufWriter, Write};
6use std::path::Path;
7
8fn create_reader<P: AsRef<Path>>(path: P) -> Result<BufReader<File>, GameFileError> {
9 let path = path.as_ref();
10 validate_file(path, true)?;
11 let file = File::open(path).map_err(|e| FileAccessError(e, "reading file"))?;
12 let reader = BufReader::new(file);
13 Ok(reader)
14}
15
16fn create_writer<P: AsRef<Path>>(path: P) -> Result<BufWriter<File>, GameFileError> {
17 let file = File::open(path).map_err(|e| FileAccessError(e, "writing file"))?;
18 let writer = BufWriter::new(file);
19 Ok(writer)
20}
21
22pub fn get_file_size<P: AsRef<Path>>(path: P) -> u64 {
23 let path = path.as_ref();
24 if let Ok(data) = path.metadata() {
25 data.len()
26 } else {
27 0
28 }
29}
30
31pub fn validate_file<P: AsRef<Path>>(path: P, size_check: bool) -> Result<(), GameFileError> {
32 let path = path.as_ref();
33 if !path.exists() {
34 return Err(FileNotFound());
35 }
36 if !path.is_file() {
37 return Err(NotAFile());
38 }
39 let size = get_file_size(path);
40 if size_check {
41 if size > MAX_FILE_SIZE {
42 return Err(FileTooLarge(size));
43 }
44 if size < MIN_FILE_SIZE {
45 return Err(FileTooSmall());
46 }
47 }
48 Ok(())
49}
50
51pub trait FileReadable {
52 fn read<P: AsRef<Path>>(path: P) -> Result<Self, GameFileError>
53 where
54 Self: Sized + Readable,
55 {
56 let path = path.as_ref();
57 validate_file(path, true)?;
58 let mut reader = create_reader(path)?;
59 let header = Self::from_reader(&mut reader)?;
60 Ok(header)
61 }
62}
63
64pub trait Readable {
65 fn from_reader<R: ReaderExt>(reader: &mut R) -> Result<Self, GameFileError>
66 where
67 Self: Sized;
68}
69
70pub trait Writeable {
71 fn as_bytes(&self) -> Result<Vec<u8>, GameFileError>;
72}
73
74impl FileReadable for GameFileHeader {}
75
76impl FileReadable for GameFile {}
77
78impl GameFile {
79 pub fn write<P: AsRef<Path>>(&self, path: P) -> Result<(), GameFileError> {
80 let mut writer = create_writer(path)?;
81 writer
82 .write_all(&self.as_bytes()?)
83 .map_err(|e| FileAccessError(e, "writing file"))?;
84 Ok(())
85 }
86}