1use miniz_oxide::{deflate::compress_to_vec, inflate::decompress_to_vec};
2use serde_repr::{Deserialize_repr, Serialize_repr};
3
4use crate::{
5 io::Source,
6 parse::{Encode, Token, TokenBuilder},
7 prebuilt::{ver1_46, ver1_47, ver1_48, ver1_49, ver1_51, ver1_53},
8};
9use std::{
10 fs::{self, File, OpenOptions},
11 io::{Read, Write},
12};
13
14pub struct Scenario {
15 pub versio: Token,
16 version: String,
17}
18
19impl Scenario {
20 pub fn from_file(filename: &str) -> Result<Self, String> {
30 let mut file = File::open(&filename).expect("File not found");
31 let metadata = fs::metadata(&filename).expect("Unable to read metadata");
32 let mut buffer = vec![0; metadata.len() as usize];
33 file.read_exact(&mut buffer).expect("buffer overflow");
34
35 Self::from_le_vec(buffer)
36 }
37
38 pub fn from_le_vec(buffer: Vec<u8>) -> Result<Self, String> {
51 let version = Self::get_scenario_version(&buffer);
52 let mut source = Source::new(buffer);
53 match version.as_str() {
54 "1.46" => {
55 let header = TokenBuilder::create_from_template(
56 &ver1_46::FileHeader::template(),
57 &mut source,
58 )?;
59
60 let mut uncompressed = header.to_le_vec();
61 let content = decompress_to_vec(&source.get_rest_vec()).unwrap();
62 uncompressed.extend(content);
63
64 let mut source = Source::new(uncompressed);
65 Ok(Scenario {
66 versio: TokenBuilder::create_from_template(
67 &ver1_46::Versio::template(),
68 &mut source,
69 )?,
70 version,
71 })
72 }
73 "1.47" => {
74 let header = TokenBuilder::create_from_template(
75 &ver1_47::FileHeader::template(),
76 &mut source,
77 )?;
78
79 let mut uncompressed = header.to_le_vec();
80 let content = decompress_to_vec(&source.get_rest_vec()).unwrap();
81 uncompressed.extend(content);
82
83 let mut source = Source::new(uncompressed);
84 Ok(Scenario {
85 versio: TokenBuilder::create_from_template(
86 &ver1_47::Versio::template(),
87 &mut source,
88 )?,
89 version,
90 })
91 }
92 "1.48" => {
93 let header = TokenBuilder::create_from_template(
94 &ver1_48::FileHeader::template(),
95 &mut source,
96 )?;
97
98 let mut uncompressed = header.to_le_vec();
99 let content = decompress_to_vec(&source.get_rest_vec()).unwrap();
100 uncompressed.extend(content);
101
102 let mut source = Source::new(uncompressed);
103 Ok(Scenario {
104 versio: TokenBuilder::create_from_template(
105 &ver1_48::Versio::template(),
106 &mut source,
107 )?,
108 version,
109 })
110 }
111 "1.49" => {
112 let header = TokenBuilder::create_from_template(
113 &ver1_49::FileHeader::template(),
114 &mut source,
115 )?;
116
117 let mut uncompressed = header.to_le_vec();
118 let content = decompress_to_vec(&source.get_rest_vec()).unwrap();
119 uncompressed.extend(content);
120
121 let mut source = Source::new(uncompressed);
122 Ok(Scenario {
123 versio: TokenBuilder::create_from_template(
124 &ver1_49::Versio::template(),
125 &mut source,
126 )?,
127 version,
128 })
129 }
130 "1.51" => {
131 let header = TokenBuilder::create_from_template(
132 &ver1_51::FileHeader::template(),
133 &mut source,
134 )?;
135
136 let mut uncompressed = header.to_le_vec();
137 let content = decompress_to_vec(&source.get_rest_vec()).unwrap();
138 uncompressed.extend(content);
139
140 let mut source = Source::new(uncompressed);
141 Ok(Scenario {
142 versio: TokenBuilder::create_from_template(
143 &ver1_49::Versio::template(),
144 &mut source,
145 )?,
146 version,
147 })
148 }
149 "1.53" => {
150 let header = TokenBuilder::create_from_template(
151 &ver1_53::FileHeader::template(),
152 &mut source,
153 )?;
154
155 let mut uncompressed = header.to_le_vec();
156 let content = decompress_to_vec(&source.get_rest_vec()).unwrap();
157 uncompressed.extend(content);
158
159 let mut source = Source::new(uncompressed);
160 Ok(Scenario {
161 versio: TokenBuilder::create_from_template(
162 &ver1_49::Versio::template(),
163 &mut source,
164 )?,
165 version,
166 })
167 }
168 _ => Err("Unsupported version!".to_string()),
169 }
170 }
171
172 pub fn from_versio(versio: &Token) -> Result<Self, String> {
173 let version = versio
174 .get_by_path("/file_header/version")
175 .try_c4()
176 .content()
177 .clone();
178
179 return Ok(Scenario {
180 version,
181 versio: versio.clone(),
182 });
183 }
184
185 pub fn to_le_vec(self) -> Vec<u8> {
199 self.versio.to_le_vec()
200 }
201
202 pub fn to_le_export_vec(&self) -> Vec<u8> {
212 let file_header = &self.versio.try_map()["file_header"];
213 let mut content = file_header.to_le_vec();
214 let header_size = content.len();
215
216 let uncompressed = &self.versio.to_le_vec()[header_size..];
217 let mut compressed = compress_to_vec(uncompressed, 6);
218
219 content.append(&mut compressed);
220
221 content
222 }
223
224 pub fn to_file(&self, file_path: &str, format: ExportFormat) -> Result<(), String> {
234 match format {
235 ExportFormat::AoE2Scenario => self.to_aoe2scenario(file_path),
236 ExportFormat::JSON => self.to_json_file(file_path),
237 }
238 }
239
240 pub fn to_aoe2scenario(&self, file_path: &str) -> Result<(), String> {
241 let buffer = self.to_le_export_vec();
242
243 let path = std::path::Path::new(file_path);
244 let prefix = path.parent().expect("Fail to get parent path!");
245 std::fs::create_dir_all(prefix).expect("Fail to create directory!");
246
247 let mut file = OpenOptions::new()
248 .create(true)
249 .write(true)
250 .open(file_path)
251 .unwrap();
252
253 file.write_all(&buffer).expect("Fail to write content!");
254 Ok(())
255 }
256
257 pub fn to_json_file(&self, file_path: &str) -> Result<(), String> {
258 let buffer = serde_json::to_string(&self.versio).expect("Fail to convert to json format");
259
260 let path = std::path::Path::new(file_path);
261 let prefix = path.parent().expect("Fail to get parent path!");
262 std::fs::create_dir_all(prefix).expect("Fail to create directory!");
263
264 let mut file = OpenOptions::new()
265 .create(true)
266 .write(true)
267 .open(file_path)
268 .unwrap();
269
270 file.write_all(buffer.as_bytes())
271 .expect("Fail to write content!");
272 Ok(())
273 }
274
275 pub fn version(&self) -> &str {
276 &self.version
277 }
278
279 fn get_scenario_version(buffer: &[u8]) -> String {
280 std::str::from_utf8(&buffer[0..4]).unwrap().to_string()
281 }
282}
283
284#[derive(Serialize_repr, Deserialize_repr, PartialEq, Clone, Debug)]
285#[repr(u8)]
286pub enum ExportFormat {
287 AoE2Scenario = 0,
288 JSON = 1,
289}