maikor_vm_file/
read_write_impl.rs

1use 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}