1use std::any::Any;
2use std::io::Read;
3use nom::{
4 number::complete::{le_u8, le_i8, le_u16, le_i16, le_u32, le_i32, le_u64, le_i64, le_f32},
5 bytes::complete::{tag, take},
6 combinator::{map, flat_map, opt},
7 sequence::{pair, tuple},
8 multi::count,
9};
10use super::{
11 PropFile,
12 BinEntry,
13 BinEntryHeader,
14 data::*,
15 binvalue_map_keytype,
16 binvalue_map_type,
17};
18use cdragon_hashes::HashDef;
19use cdragon_utils::{
20 parsing::{ParseError, IResult, ReadArray},
21 parse_buf,
22};
23
24type Result<T> = std::result::Result<T, ParseError>;
25
26
27pub(super) trait BinParsable where Self: Sized {
29 fn binparse(i: &[u8]) -> IResult<&[u8], Self>;
30}
31
32pub(super) fn binparse<T: BinParsable>(i: &[u8]) -> Result<T> {
33 match T::binparse(i) {
34 Ok((i, v)) => {
35 if !i.is_empty() {
36 Err(ParseError::TooMuchData)
37 } else {
38 Ok(v)
39 }
40 },
41 Err(e) => Err(e.into())
42 }
43}
44
45fn length_count<I, O1, O2, F, G>(f: F, g: G) -> impl Fn(I) -> IResult<I, Vec<O2>>
47where
48 I: Clone + PartialEq,
49 F: Fn(I) -> IResult<I, O1>,
50 G: Fn(I) -> IResult<I, O2>,
51 O1: nom::ToUsize,
52{
53 move |i: I| {
54 let (i, n) = f(i)?;
55 let (i, v) = nom::multi::count(&g, n.to_usize())(i)?;
56 Ok((i, v))
57 }
58}
59
60
61macro_rules! impl_binparsable {
62 ($type:ty, $expr:expr) => {
63 impl BinParsable for $type {
64 fn binparse(i: &[u8]) -> IResult<&[u8], Self> { $expr(i) }
65 }
66 };
67 ($type:ty, =$parser:expr) => {
68 impl_binparsable!($type, map($parser, |v| Self(v)));
69 };
70 ($type:ty, =>($($parser:expr),* $(,)?)) => {
71 impl_binparsable!($type, map(tuple(($($parser,)*)), <$type>::from));
72 };
73}
74
75impl BinParsable for PropFile {
76 fn binparse(i: &[u8]) -> IResult<&[u8], Self> {
77 let (i, opt_ptch) = opt(tag("PTCH"))(i)?;
79 let (i, is_patch) = match opt_ptch {
80 Some(_) => {
81 let (i, header) = tuple((le_u32, le_u32))(i)?;
82 assert_eq!(header, (1, 0));
83 (i, true)
84 }
85 None => (i, false)
86 };
87
88 let (i, (_, version)) = tuple((tag("PROP"), le_u32))(i)?;
89 let (i, linked_files) =
90 if version >= 2 {
91 length_count(le_u32, parse_binstring)(i)?
92 } else {
93 (i, vec![])
94 };
95
96 let (i, entry_types) = length_count(le_u32, BinClassName::binparse)(i)?;
97 let (i, entries) = {
99 let (mut i, mut entries) = (i, Vec::<BinEntry>::with_capacity(entry_types.len()));
100 for ctype in entry_types {
101 i = {
102 let (i, entry) = parse_entry_from_type(i, ctype)?;
103 entries.push(entry);
104 i
105 }
106 }
107 (i, entries)
108 };
109
110 Ok((i, Self { version, is_patch, linked_files, entries }))
111 }
112}
113
114
115#[derive(Debug)]
117pub struct BinEntryScanner<R: Read> {
118 reader: R,
119 htypes_iter: std::vec::IntoIter<BinClassName>,
120 pub is_patch: bool,
124}
125
126impl<R: Read> BinEntryScanner<R> {
127 pub fn new(mut reader: R) -> Result<Self> {
129 let (is_patch, version): (bool, u32) = {
131 let mut buf = [0u8; 4 + 4 + 4]; reader.read_exact(&mut buf[..8])?;
133 let is_patch = match parse_buf!(buf[..4], opt(tag("PTCH"))) {
134 Some(_) => {
135 reader.read_exact(&mut buf[8..12])?;
136 let header = parse_buf!(buf[4..12], tuple((le_u32, le_u32)));
137 assert_eq!(header, (1, 0));
138 reader.read_exact(&mut buf[..8])?;
139 true
140 }
141 None => false
142 };
143
144 let (_, version) = parse_buf!(buf[..8], tuple((tag("PROP"), le_u32)));
145 (is_patch, version)
146 };
147
148 if version >= 2 {
149 let buf = reader.read_array::<4>()?;
151 let n = parse_buf!(buf, le_u32);
152 for _ in 0..n {
153 let buf = reader.read_array::<2>()?;
154 let n = parse_buf!(buf, le_u16);
155 std::io::copy(&mut reader.by_ref().take(n as u64), &mut std::io::sink())?;
156 }
157 };
158
159 let entry_types: Vec<BinClassName> = {
161 let buf = reader.read_array::<4>()?;
162 let n = parse_buf!(buf, le_u32);
163 let mut buf = Vec::<u8>::new();
164 reader.by_ref().take(4 * n as u64).read_to_end(&mut buf)?;
165 let entry_types = parse_buf!(buf, count(BinClassName::binparse, n as usize));
166 entry_types
167 };
168
169 Ok(Self { reader, htypes_iter: entry_types.into_iter(), is_patch })
170 }
171
172 pub fn scan(self) -> BinEntryScanScan<R> {
176 BinEntryScanScan {
177 reader: self.reader,
178 htypes_iter: self.htypes_iter,
179 length: None,
180 }
181 }
182
183 pub fn headers(self) -> BinEntryScanHeaders<R> {
185 BinEntryScanHeaders {
186 reader: self.reader,
187 htypes_iter: self.htypes_iter,
188 }
189 }
190
191 pub fn filter_parse<F>(self, f: F) -> BinEntryScanFilterParse<R, F>
193 where F: Fn(BinEntryPath, BinClassName) -> bool {
194 BinEntryScanFilterParse {
195 reader: self.reader,
196 htypes_iter: self.htypes_iter,
197 filter: f,
198 }
199 }
200
201 pub fn parse(self) -> BinEntryScanParse<R> {
203 BinEntryScanParse {
204 reader: self.reader,
205 htypes_iter: self.htypes_iter,
206 }
207 }
208}
209
210pub type BinEntryScannerItem = Result<BinEntry>;
213
214
215trait BinEntryScan {
217 type Reader: Read;
218 type Output;
219
220 fn next_scan(reader: &mut Self::Reader) -> Result<(u32, BinEntryPath)> {
222 let buf = reader.read_array::<{4 + 4}>()?;
223 let (length, path) = parse_buf!(buf, tuple((le_u32, BinEntryPath::binparse)));
224 Ok((length - 4, path)) }
226
227 fn read_fields(reader: &mut Self::Reader, length: u32) -> Result<Vec<BinField>> {
229 let mut buf = Vec::<u8>::new();
230 reader.by_ref().take(length as u64).read_to_end(&mut buf)?;
231 let fields = parse_buf!(buf, length_count(le_u16, BinField::binparse));
232 Ok(fields)
233 }
234
235 fn skip_fields(reader: &mut Self::Reader, length: u32) -> Result<()> {
237 std::io::copy(&mut reader.by_ref().take(length as u64), &mut std::io::sink())?;
240 Ok(())
241 }
242
243 fn next_result(&mut self, ctype: BinClassName) -> Result<Self::Output>;
244}
245
246
247pub struct BinEntryScanHeaders<R>
248where R: Read {
249 reader: R,
250 htypes_iter: std::vec::IntoIter<BinClassName>,
251}
252
253impl<R: Read> BinEntryScan for BinEntryScanHeaders<R> {
254 type Reader = R;
255 type Output = (BinEntryPath, BinClassName);
256
257 fn next_result(&mut self, ctype: BinClassName) -> Result<Self::Output> {
258 let (length, path) = Self::next_scan(&mut self.reader)?;
259 Self::skip_fields(&mut self.reader, length)?;
260 Ok((path, ctype))
261 }
262}
263
264impl<R: Read> Iterator for BinEntryScanHeaders<R> {
265 type Item = Result<(BinEntryPath, BinClassName)>;
266
267 fn next(&mut self) -> Option<Self::Item> {
268 let ctype = self.htypes_iter.next()?;
269 Some(self.next_result(ctype))
270 }
271}
272
273
274pub struct BinEntryScanFilterParse<R, F>
275where R: Read, F: Fn(BinEntryPath, BinClassName) -> bool {
276 reader: R,
277 htypes_iter: std::vec::IntoIter<BinClassName>,
278 filter: F,
279}
280
281impl<R, F> BinEntryScan for BinEntryScanFilterParse<R, F>
282where R: Read, F: Fn(BinEntryPath, BinClassName) -> bool {
283 type Reader = R;
284 type Output = Option<BinEntry>;
285
286 fn next_result(&mut self, ctype: BinClassName) -> Result<Self::Output> {
287 let (length, path) = Self::next_scan(&mut self.reader)?;
288 if (self.filter)(path, ctype) {
289 let fields = Self::read_fields(&mut self.reader, length)?;
290 Ok(Some(BinEntry { path, ctype, fields }))
291 } else {
292 Self::skip_fields(&mut self.reader, length)?;
293 Ok(None)
294 }
295 }
296}
297
298impl<R, F> Iterator for BinEntryScanFilterParse<R, F>
299where R: Read, F: Fn(BinEntryPath, BinClassName) -> bool {
300 type Item = BinEntryScannerItem;
301
302 fn next(&mut self) -> Option<Self::Item> {
303 loop {
304 let ctype = self.htypes_iter.next()?;
305 match self.next_result(ctype) {
306 Ok(None) => continue,
307 Ok(Some(v)) => return Some(Ok(v)),
308 Err(e) => return Some(Err(e)),
309 }
310 }
311 }
312}
313
314
315pub struct BinEntryScanParse<R>
316where R: Read {
317 reader: R,
318 htypes_iter: std::vec::IntoIter<BinClassName>,
319}
320
321impl<R: Read> BinEntryScan for BinEntryScanParse<R> {
322 type Reader = R;
323 type Output = BinEntry;
324
325 fn next_result(&mut self, ctype: BinClassName) -> Result<Self::Output> {
326 let (length, path) = Self::next_scan(&mut self.reader)?;
327 let fields = Self::read_fields(&mut self.reader, length)?;
328 Ok(BinEntry { path, ctype, fields })
329 }
330}
331
332impl<R: Read> Iterator for BinEntryScanParse<R> {
333 type Item = BinEntryScannerItem;
334
335 fn next(&mut self) -> Option<Self::Item> {
336 let ctype = self.htypes_iter.next()?;
337 Some(self.next_result(ctype))
338 }
339}
340
341
342pub struct BinEntryScanScan<R>
346where R: Read {
347 reader: R,
348 length: Option<u32>,
349 htypes_iter: std::vec::IntoIter<BinClassName>,
350}
351
352pub struct BinEntryScanItem<'a, R>
353where R: Read {
354 owner: &'a mut BinEntryScanScan<R>,
355 pub path: BinEntryPath,
356 pub ctype: BinClassName,
357}
358
359impl<'a, R> BinEntryScanItem<'a, R>
360where R: Read {
361 pub fn read(self) -> Result<BinEntry> {
362 self.owner.read_entry(self.path, self.ctype)
363 }
364}
365
366
367impl<R> BinEntryScan for BinEntryScanScan<R>
368where R: Read {
369 type Reader = R;
370 type Output = (u32, BinEntryPath, BinClassName);
371
372 fn next_result(&mut self, ctype: BinClassName) -> Result<Self::Output> {
373 let (length, path) = Self::next_scan(&mut self.reader)?;
374 Ok((length, path, ctype))
375 }
376}
377
378impl<R> BinEntryScanScan<R>
379where R: Read {
380 pub fn next(&mut self) -> Option<Result<BinEntryScanItem<'_, R>>> {
381 if let Some(length) = self.length.take() {
383 if let Err(err) = Self::skip_fields(&mut self.reader, length) {
384 return Some(Err(err));
385 }
386 }
387 let ctype = self.htypes_iter.next()?;
388 match self.next_result(ctype) {
389 Ok((length, path, ctype)) => {
390 self.length = Some(length);
391 Some(Ok(BinEntryScanItem { owner: self, path, ctype }))
392 }
393 Err(err) => Some(Err(err)),
394 }
395 }
396
397 fn read_entry(&mut self, path: BinEntryPath, ctype: BinClassName) -> Result<BinEntry> {
398 let length = self.length.take().unwrap();
400 let fields = Self::read_fields(&mut self.reader, length)?;
401 Ok(BinEntry { path, ctype, fields })
402 }
403}
404
405
406
407fn parse_entry_from_type(i: &[u8], ctype: BinClassName) -> IResult<&[u8], BinEntry> {
409 let (i, (_length, path)) = tuple((le_u32, BinEntryPath::binparse))(i)?;
410 parse_entry_from_header(i, (path, ctype))
411}
412
413fn parse_entry_from_header(i: &[u8], (path, ctype): BinEntryHeader) -> IResult<&[u8], BinEntry> {
415 map(length_count(le_u16, BinField::binparse),
416 |fields| BinEntry { path, ctype, fields })(i)
417}
418
419fn parse_binstring(i: &[u8]) -> IResult<&[u8], String> {
420 map(flat_map(le_u16, take), |s| std::str::from_utf8(s).expect("invalid UTF-8 string in BIN").to_string())(i)
421}
422
423
424impl BinParsable for BinField {
425 fn binparse(i: &[u8]) -> IResult<&[u8], Self> {
426 let (i, (name, vtype)) = tuple((BinFieldName::binparse, BinType::binparse))(i)?;
427 let (i, value) = binvalue_map_type!(vtype, T, map(T::binparse, |v| { Box::new(v) as Box<dyn Any> })(i)?);
428 Ok((i, Self { name, vtype, value }))
429 }
430}
431
432impl_binparsable!(BinHashValue, map(le_u32, Self::from));
433impl_binparsable!(BinEntryPath, map(le_u32, Self::from));
434impl_binparsable!(BinClassName, map(le_u32, Self::from));
435impl_binparsable!(BinFieldName, map(le_u32, Self::from));
436impl_binparsable!(BinPathValue, map(le_u64, Self::from));
437
438impl_binparsable!(BinNone, map(take(6usize), |_| Self()));
439impl_binparsable!(BinBool, map(le_u8, |v| Self(v != 0u8)));
440impl_binparsable!(BinS8, =le_i8);
441impl_binparsable!(BinU8, =le_u8);
442impl_binparsable!(BinS16, =le_i16);
443impl_binparsable!(BinU16, =le_u16);
444impl_binparsable!(BinS32, =le_i32);
445impl_binparsable!(BinU32, =le_u32);
446impl_binparsable!(BinS64, =le_i64);
447impl_binparsable!(BinU64, =le_u64);
448impl_binparsable!(BinFloat, =le_f32);
449impl_binparsable!(BinVec2, =>(le_f32, le_f32));
450impl_binparsable!(BinVec3, =>(le_f32, le_f32, le_f32));
451impl_binparsable!(BinVec4, =>(le_f32, le_f32, le_f32, le_f32));
452impl_binparsable!(BinColor, map(tuple((le_u8, le_u8, le_u8, le_u8)), |t| Self { r: t.0, g: t.1, b: t.2, a: t.3 }));
453impl_binparsable!(BinMatrix, map(tuple((le_f32, le_f32, le_f32, le_f32,
454 le_f32, le_f32, le_f32, le_f32,
455 le_f32, le_f32, le_f32, le_f32,
456 le_f32, le_f32, le_f32, le_f32)),
457 |t| Self([
458 [t.0, t.1, t.2, t.3],
459 [t.4, t.5, t.6, t.7],
460 [t.8, t.9, t.10, t.11],
461 [t.12, t.13, t.14, t.15]])
462 ));
463
464impl BinParsable for BinList {
465 fn binparse(i: &[u8]) -> IResult<&[u8], Self> {
466 let (i, (vtype, _)) = tuple((BinType::binparse, le_u32))(i)?;
467 let (i, values) = binvalue_map_type!(vtype, T, map(length_count(le_u32, T::binparse), |v| { Box::new(v) as Box<dyn Any> })(i)?);
468 Ok((i, Self { vtype, values }))
469 }
470}
471
472impl BinParsable for BinStruct {
473 fn binparse(i: &[u8]) -> IResult<&[u8], Self> {
474 let (i, ctype) = BinClassName::binparse(i)?;
475 if ctype.is_null() {
476 Ok((i, Self { ctype, fields: vec![] }))
477 } else {
478 let (i, (_, fields)) = tuple((le_u32, length_count(le_u16, BinField::binparse)))(i)?;
479 Ok((i, Self { ctype, fields }))
480 }
481 }
482}
483
484impl BinParsable for BinEmbed {
485 fn binparse(i: &[u8]) -> IResult<&[u8], Self> {
486 let (i, ctype) = BinClassName::binparse(i)?;
487 if ctype.is_null() {
488 Ok((i, Self { ctype, fields: vec![] }))
489 } else {
490 let (i, (_, fields)) = tuple((le_u32, length_count(le_u16, BinField::binparse)))(i)?;
491 Ok((i, Self { ctype, fields }))
492 }
493 }
494}
495
496impl BinParsable for BinOption {
497 fn binparse(i: &[u8]) -> IResult<&[u8], Self> {
498 let (i, vtype) = BinType::binparse(i)?;
499 let (i, n) = le_u8(i)?;
500 let (i, value) = match n {
501 0 => (i, None),
502 1 => {
503 let (i, v) = binvalue_map_type!(vtype, T, map(T::binparse, |v| Box::new(v) as Box<dyn Any>)(i)?);
504 (i, Some(v))
505 }
506 _ => panic!("unexpected option count: {}", n),
507 };
508 Ok((i, Self { vtype, value }))
509 }
510}
511
512impl BinParsable for BinMap {
513 fn binparse(i: &[u8]) -> IResult<&[u8], Self> {
514 let (i, (ktype, vtype, _, n)) = tuple((BinType::binparse, BinType::binparse, le_u32, le_u32))(i)?;
515 let (i, values) =
516 binvalue_map_keytype!(
517 ktype, K, binvalue_map_type!(
518 vtype, V, map(count(pair(K::binparse, V::binparse), n as usize), |v| {
519 let v: Vec<(K, V)> = v.into_iter().collect();
520 Box::new(v) as Box<dyn Any>
521 })(i)?));
522 Ok((i, Self { ktype, vtype, values }))
523 }
524}
525
526impl_binparsable!(BinHash, =BinHashValue::binparse);
527impl_binparsable!(BinPath, =BinPathValue::binparse);
528impl_binparsable!(BinLink, =BinEntryPath::binparse);
529impl_binparsable!(BinFlag, map(le_u8, |v| Self(v != 0u8)));
530impl_binparsable!(BinString, =parse_binstring);
531impl_binparsable!(BinType, map(le_u8, |mut v| {
532 if v >= 0x80 {
533 v = v - 0x80 + BinType::List as u8;
534 }
535 Self::try_from(v).expect("invalid BIN type")
536}));
537