1use std::collections::HashMap;
2
3#[cfg(any(feature = "level_data", doc))]
5pub mod level_data;
6
7use super::Rect;
8
9#[derive(thiserror::Error, Debug)]
11pub enum Error {
12 #[error("Can't open the file!")]
14 CantOpenFile {
15 source: std::io::Error
17 },
18 #[error("The file isn't a CNM LParse file.")]
20 NotLParseFile,
21 #[error("Unknown LParse version ({0}).")]
23 UnknownVersion(u32),
24 #[error("LParse file corrupted possibly for reason {0}.")]
26 Corrupted(String),
27 #[error("Entry {0} (id {1}) is corrupted.")]
29 EntryCorrupted(String, usize),
30 #[error("Entry {0} (id {1}) has a unknown type id of {2}!")]
32 UnknownEntryType(String, usize, u32),
33 #[error("Can't save file! Version number {0} only allows up to {1} entries, but you're trying to save {2} entries!")]
35 EntryOverflow(u32, usize, usize),
36 #[error("The CNMB file's version id {0} is mismatched with the CNMS file's version id {1}.")]
38 MismatchedVersions(u32, u32),
39 #[error("Can't find the entry {0}!")]
41 CannotFindEntry(String),
42 #[error("Unexpected entry data type! Expected type {0} but got type {1} instead!")]
44 UnexpectedEntryType(u32, u32),
45}
46
47macro_rules! generate_entry_data_func {
48 ($func_name:ident, $variant:ident, $return:ident) => {
49 pub fn $func_name(&self) -> Result<&[$return], Error> {
51 match self {
52 &Self::$variant(ref vec) => Ok(vec),
53 _ => Err(Error::UnexpectedEntryType(Self::$variant(Vec::new()).get_typeid(), self.get_typeid())),
54 }
55 }
56 };
57}
58
59macro_rules! generate_entry_data_func_mut {
60 ($func_name:ident, $variant:ident, $return:ident) => {
61 pub fn $func_name(&mut self) -> Result<&mut Vec<$return>, Error> {
63 match self {
64 &mut Self::$variant(ref mut vec) => Ok(vec),
65 _ => Err(Error::UnexpectedEntryType(Self::$variant(Vec::new()).get_typeid(), self.get_typeid())),
66 }
67 }
68 };
69}
70
71#[derive(Debug)]
73pub enum EntryData {
74 Null,
76 Dummy,
78 I32(Vec<i32>),
80 U32(Vec<u32>),
82 U8(Vec<u8>),
84 U16(Vec<u16>),
86 F32(Vec<f32>),
88 Rect(Vec<Rect>),
90}
91
92impl EntryData {
93 fn from_lparse(
94 typeid: u32,
95 len: usize,
96 name: &str,
97 entry_id: usize,
98 buffer: &mut bytebuffer::ByteBuffer,
99 ) -> Result<Self, Error> {
100 match typeid {
101 0 => Ok(Self::Null),
102 1 => Ok(Self::Dummy),
103 2 => Ok(Self::I32(
104 (0..len)
105 .map(|_| buffer.read_i32().unwrap_or_default())
106 .collect(),
107 )),
108 3 => Ok(Self::U32(
109 (0..len)
110 .map(|_| buffer.read_u32().unwrap_or_default())
111 .collect(),
112 )),
113 4 => Ok(Self::U8(
114 (0..len)
115 .map(|_| buffer.read_u8().unwrap_or_default())
116 .collect(),
117 )),
118 5 => Ok(Self::U16(
119 (0..len)
120 .map(|_| buffer.read_u16().unwrap_or_default())
121 .collect(),
122 )),
123 6 => Ok(Self::F32(
124 (0..len)
125 .map(|_| buffer.read_f32().unwrap_or_default())
126 .collect(),
127 )),
128 7 => Ok(Self::Rect(
129 (0..len)
130 .map(|_| {
131 let x = buffer.read_i32().unwrap_or_default();
132 let y = buffer.read_i32().unwrap_or_default();
133 let w = buffer.read_i32().unwrap_or_default();
134 let h = buffer.read_i32().unwrap_or_default();
135 Rect { x, y, w, h }
136 })
137 .collect(),
138 )),
139 id => Err(Error::UnknownEntryType(name.to_string(), entry_id, id)),
140 }
141 }
142
143 fn save(&self, buffer: &mut bytebuffer::ByteBuffer) {
144 match &self {
145 &Self::I32(vec) => vec.iter().for_each(|i| buffer.write_i32(*i)),
146 &Self::U32(vec) => vec.iter().for_each(|i| buffer.write_u32(*i)),
147 &Self::U8(vec) => vec.iter().for_each(|i| buffer.write_u8(*i)),
148 &Self::U16(vec) => vec.iter().for_each(|i| buffer.write_u16(*i)),
149 &Self::F32(vec) => vec.iter().for_each(|i| buffer.write_f32(*i)),
150 &Self::Rect(vec) => vec.iter().for_each(|Rect { x, y, w, h }| {
151 buffer.write_i32(*x);
152 buffer.write_i32(*y);
153 buffer.write_i32(*w);
154 buffer.write_i32(*h);
155 }),
156 _ => {}
157 }
158 }
159
160 pub fn get_entry_len(&self) -> usize {
162 match &self {
163 &Self::Null | &Self::Dummy => 0,
164 &Self::I32(vec) => vec.len(),
165 &Self::U32(vec) => vec.len(),
166 &Self::U8(vec) => vec.len(),
167 &Self::U16(vec) => vec.len(),
168 &Self::F32(vec) => vec.len(),
169 &Self::Rect(vec) => vec.len(),
170 }
171 }
172
173 fn get_saved_data_size(&self) -> usize {
174 match &self {
175 &Self::Null | &Self::Dummy => 0,
176 &Self::I32(vec) => vec.len() * std::mem::size_of::<i32>(),
177 &Self::U32(vec) => vec.len() * std::mem::size_of::<u32>(),
178 &Self::U8(vec) => vec.len() * std::mem::size_of::<u8>(),
179 &Self::U16(vec) => vec.len() * std::mem::size_of::<u16>(),
180 &Self::F32(vec) => vec.len() * std::mem::size_of::<f32>(),
181 &Self::Rect(vec) => vec.len() * std::mem::size_of::<Rect>(),
182 }
183 }
184
185 fn get_typeid(&self) -> u32 {
186 match &self {
187 &Self::Null => 0,
188 &Self::Dummy => 1,
189 &Self::I32(_) => 2,
190 &Self::U32(_) => 3,
191 &Self::U8(_) => 4,
192 &Self::U16(_) => 5,
193 &Self::F32(_) => 6,
194 &Self::Rect(_) => 7,
195 }
196 }
197
198 generate_entry_data_func!(try_get_i32, I32, i32);
199 generate_entry_data_func!(try_get_u32, U32, u32);
200 generate_entry_data_func!(try_get_u8, U8, u8);
201 generate_entry_data_func!(try_get_u16, U16, u16);
202 generate_entry_data_func!(try_get_f32, F32, f32);
203 generate_entry_data_func!(try_get_rect, Rect, Rect);
204 generate_entry_data_func_mut!(try_get_i32_mut, I32, i32);
205 generate_entry_data_func_mut!(try_get_u32_mut, U32, u32);
206 generate_entry_data_func_mut!(try_get_u8_mut, U8, u8);
207 generate_entry_data_func_mut!(try_get_u16_mut, U16, u16);
208 generate_entry_data_func_mut!(try_get_f32_mut, F32, f32);
209 generate_entry_data_func_mut!(try_get_rect_mut, Rect, Rect);
210}
211
212#[derive(Debug)]
219pub struct VersionSpecs {
220 version: u32,
221 num_entries: usize,
222 entry_name_size: usize,
223 header_size: usize,
224 entry_header_size: usize,
225}
226
227impl VersionSpecs {
228 pub fn from_version(version: u32) -> Result<Self, Error> {
232 match version {
233 1 => Ok(Self {
234 version,
235 num_entries: 128,
236 entry_name_size: 16,
237 header_size: 4 + std::mem::size_of::<u32>(),
238 entry_header_size: std::mem::size_of::<u32>() * 3 + 16,
239 }),
240 version_id => Err(Error::UnknownVersion(version_id)),
241 }
242 }
243
244 pub fn get_version_id(&self) -> u32 {
246 self.version
247 }
248
249 pub fn get_num_entries(&self) -> usize {
251 self.num_entries
252 }
253
254 pub fn get_entry_name_size(&self) -> usize {
256 self.entry_name_size
257 }
258
259 pub fn get_header_size(&self) -> usize {
261 self.header_size
262 }
263
264 pub fn get_entry_header_size(&self) -> usize {
266 self.entry_header_size
267 }
268}
269
270#[derive(Debug)]
272pub struct LParse {
273 version: VersionSpecs,
274 pub entries: HashMap<String, EntryData>,
276}
277
278impl LParse {
279 pub fn new(version: u32) -> Result<Self, Error> {
281 Ok(Self {
282 version: VersionSpecs::from_version(version)?,
283 entries: HashMap::new(),
284 })
285 }
286
287 pub fn get_version(&self) -> &VersionSpecs {
289 &self.version
290 }
291
292 pub fn try_get_entry(&self, name: &str) -> Result<&EntryData, Error> {
294 match self.entries.get(name) {
295 Some(entry_data) => Ok(entry_data),
296 None => Err(Error::CannotFindEntry(name.to_string())),
297 }
298 }
299
300 pub fn from_file<P: AsRef<std::path::Path>>(path: P) -> Result<Self, Error> {
302 let buffer = match std::fs::read(path) {
303 Ok(f) => f,
304 Err(e) => return Err(Error::CantOpenFile { source: e }),
305 };
306
307 Self::from_memory(buffer)
308 }
309
310 pub fn from_memory(buffer: Vec<u8>) -> Result<Self, Error> {
312 let mut buffer = bytebuffer::ByteBuffer::from_vec(buffer);
313 buffer.set_endian(bytebuffer::Endian::LittleEndian);
314
315 match buffer.read_bytes(4) {
316 Ok(bytes) => match String::from_utf8(bytes) {
317 Ok(s) if s == "CNML" => (),
318 _ => return Err(Error::NotLParseFile),
319 },
320 Err(_) => return Err(Error::NotLParseFile),
321 };
322
323 let version = VersionSpecs::from_version(match buffer.read_u32() {
324 Ok(x) => x,
325 Err(_) => return Err(Error::NotLParseFile),
326 })?;
327 let mut entries = HashMap::new();
328
329 for entry_id in 0..version.num_entries {
330 let name = match buffer.read_bytes(version.entry_name_size) {
331 Ok(b) => match String::from_utf8(b.clone()) {
332 Ok(s) => s.trim_end_matches('\0').to_string(),
333 Err(_) => {
334 return Err(Error::EntryCorrupted(
335 String::from_utf8_lossy(&b).into_owned(),
336 entry_id,
337 ))
338 }
339 },
340 Err(_) => {
341 return Err(Error::EntryCorrupted(
342 "<Entry name corrupted>".to_string(),
343 entry_id,
344 ))
345 }
346 };
347
348 let (typeid, len, offset) =
349 match (buffer.read_u32(), buffer.read_u32(), buffer.read_u32()) {
350 (Ok(typeid), Ok(len), Ok(offset)) => (typeid, len, offset),
351 _ => return Err(Error::EntryCorrupted(name.clone(), entry_id)),
352 };
353
354 let mut data = EntryData::Null;
356 if name.len() != 0
357 && typeid != EntryData::Null.get_typeid()
358 && typeid != EntryData::Dummy.get_typeid()
359 {
360 let loc = buffer.get_rpos();
361 buffer.set_rpos(offset as usize);
362 data = EntryData::from_lparse(typeid, len as usize, &name, entry_id, &mut buffer)?;
363 buffer.set_rpos(loc);
364 }
365
366 if name.len() != 0 {
367 entries.insert(name, data);
368 }
369 }
370
371 Ok(Self { version, entries })
372 }
373
374 pub fn save_to_file<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), Error> {
376 if self.entries.len() > self.version.num_entries {
377 return Err(Error::EntryOverflow(self.version.version, self.version.num_entries, self.entries.len()))
378 }
379
380 let mut buffer = bytebuffer::ByteBuffer::new();
381 buffer.set_endian(bytebuffer::Endian::LittleEndian);
382
383 buffer.write_bytes(&"CNML".as_bytes()[0..4]);
384 buffer.write_u32(self.version.version);
385
386 let mut data_offset =
387 self.version.header_size + self.version.entry_header_size * self.version.num_entries;
388 let null_entry = (&"".to_string(), &EntryData::Null);
389 for (name, data) in self
390 .entries
391 .iter()
392 .chain((0..self.version.num_entries - self.entries.len()).map(|_| null_entry))
393 {
394 let mut name_padded = name.clone();
395 name_padded.extend((0..self.version.entry_name_size).map(|_| '\0'));
396 buffer.write_bytes(&name_padded.as_bytes()[0..self.version.entry_name_size]);
397 buffer.write_u32(data.get_typeid());
398 buffer.write_u32(data.get_entry_len() as u32);
399 buffer.write_u32(data_offset as u32);
400 data_offset += data.get_saved_data_size();
401 }
402 for (_, data) in self.entries.iter() {
403 data.save(&mut buffer);
404 }
405
406 match std::fs::write(path, buffer.as_bytes()) {
407 Ok(_) => Ok(()),
408 Err(e) => Err(Error::CantOpenFile { source: e }),
409 }
410 }
411}