1#![crate_name = "sims_far"]
2
3use std::convert::Infallible;
4use std::fs::File;
5use std::io;
6use std::io::SeekFrom::Start;
7use std::io::{Read, Seek};
8use std::str::{from_utf8, Utf8Error};
9use thiserror::Error;
10
11#[derive(Error, Debug)]
12pub enum FarError {
13 #[error("File error: {0}")]
14 FileError(#[from] io::Error),
15 #[error("utf8 error: {0}")]
16 Utf8Error(#[from] Utf8Error),
17 #[error("infallible error: {0}")]
18 InfallibleError(#[from] Infallible),
19}
20
21#[derive(Clone)]
25pub struct Far {
26 pub signature: String,
29 pub version: u32,
31 pub manifest_offset: u32,
37 pub manifest: Manifest,
41}
42
43impl Far {
44 pub fn new(path: &str) -> Result<Far, FarError> {
46 return parse_far(path);
47 }
48}
49
50#[derive(Clone)]
54pub struct Manifest {
55 pub number_of_files: u32,
57 pub manifest_entries: Vec<ManifestEntry>,
59}
60
61#[derive(Clone)]
64pub struct ManifestEntry {
65 file_path: String,
66 pub file_length1: u32,
70 pub file_length2: u32,
74 pub file_offset: u32,
76 pub file_name_length: u32,
80 pub file_name: String,
82}
83
84impl ManifestEntry {
85 pub fn get_bytes(&self) -> Result<Vec<u8>, FarError> {
86 let mut f = File::open(self.file_path.as_str())?;
87 let mut buf: Vec<u8> = vec![0x00; self.file_length1 as usize];
88 f.seek(Start(self.file_offset as u64))?;
89 f.read_exact(&mut *buf)?;
90 return Ok(buf);
91 }
92}
93
94fn parse_far(path: &str) -> Result<Far, FarError> {
95 let mut far = Far {
96 signature: "".to_string(),
97 version: 0,
98 manifest_offset: 0,
99 manifest: Manifest {
100 number_of_files: 0,
101 manifest_entries: vec![],
102 },
103 };
104
105 let mut f = File::open(path)?;
106
107 let mut buf: [u8; 8] = [0x00; 8];
109 f.read_exact(&mut buf)?;
110 far.signature = from_utf8(&buf)?.to_string();
111
112 let mut buf: [u8; 4] = [0x00; 4];
114 f.read_exact(&mut buf)?;
115 far.version = u32::from_le_bytes(buf.try_into()?);
116
117 f.read_exact(&mut buf)?;
119 far.manifest_offset = u32::from_le_bytes(buf.try_into()?);
120
121 f.seek(Start(far.manifest_offset as u64))?;
123 f.read_exact(&mut buf)?;
124 far.manifest.number_of_files = u32::from_le_bytes(buf.try_into()?);
125
126 for _ in 0..far.manifest.number_of_files {
128 let me = parse_manifest_entry(&mut f, path)?;
129 far.manifest.manifest_entries.push(me);
130 }
131
132 return Ok(far);
133}
134
135fn parse_manifest_entry(f: &mut File, uigraphics_path: &str) -> Result<ManifestEntry, FarError> {
136 let mut me = ManifestEntry {
137 file_path: uigraphics_path.to_string(),
138 file_length1: 0,
139 file_length2: 0,
140 file_offset: 0,
141 file_name_length: 0,
142 file_name: "".to_string(),
143 };
144 let mut buf: [u8; 4] = [0x00; 4];
145
146 f.read_exact(&mut buf)?;
148 me.file_length1 = u32::from_le_bytes(buf.try_into()?);
149
150 f.read_exact(&mut buf)?;
152 me.file_length2 = u32::from_le_bytes(buf.try_into()?);
153
154 f.read_exact(&mut buf)?;
156 me.file_offset = u32::from_le_bytes(buf.try_into()?);
157
158 f.read_exact(&mut buf)?;
160 me.file_name_length = u32::from_le_bytes(buf.try_into()?);
161
162 let mut buf: Vec<u8> = vec![0x00; me.file_name_length as usize];
164 f.read_exact(&mut buf)?;
165 me.file_name = from_utf8(&buf)?.to_string();
166
167 return Ok(me);
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173
174 #[test]
175 fn test_new() {
176 let path = r"test.far";
177 let far = Far::new(path).unwrap();
178 assert_eq!(far.signature, "FAR!byAZ");
179 assert_eq!(far.version, 1);
180 assert_eq!(far.manifest_offset, 160);
181 assert_eq!(far.manifest.number_of_files, 1);
182 assert_eq!(far.manifest.manifest_entries[0].file_length1, 144);
183 assert_eq!(far.manifest.manifest_entries[0].file_length2, 144);
184 assert_eq!(far.manifest.manifest_entries[0].file_offset, 16);
185 assert_eq!(far.manifest.manifest_entries[0].file_name_length, 8);
186 assert_eq!(far.manifest.manifest_entries[0].file_name, "test.bmp");
187 }
188
189 #[test]
190 fn test_get_bytes() {
191 let path = r"test.far";
192 let far = Far::new(path).unwrap();
193 assert_eq!(
194 far.manifest.manifest_entries[0]
195 .get_bytes()
196 .expect("bad")
197 .len(),
198 144
199 );
200 }
201}