comparison src/th06/ecl.rs @ 703:81232dac8136

ecl: simplify parsing with more combinators.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Fri, 23 Aug 2019 17:37:22 +0200
parents 7ae576a418ff
children fcc8f736c746
comparison
equal deleted inserted replaced
702:718348c7608e 703:81232dac8136
1 //! ECL enemy script format support. 1 //! ECL enemy script format support.
2 2
3 use nom::{ 3 use nom::{
4 IResult, 4 IResult,
5 bytes::complete::take_while_m_n,
6 number::complete::{le_u8, le_u16, le_u32, le_i16, le_i32, le_f32}, 5 number::complete::{le_u8, le_u16, le_u32, le_i16, le_i32, le_f32},
6 sequence::tuple,
7 multi::many_m_n,
7 }; 8 };
8 use encoding_rs::SHIFT_JIS; 9 use encoding_rs::SHIFT_JIS;
9 use bitflags::bitflags; 10 use bitflags::bitflags;
10 11
11 bitflags! { 12 bitflags! {
12 /// Bit flags describing the current difficulty level. 13 /// Bit flags describing the current difficulty level.
13 pub struct Rank: u16 { 14 pub struct Rank: u16 {
14 /// Easy mode. 15 /// Easy mode.
15 const Easy = 0x100; 16 const EASY = 0x100;
16 17
17 /// Normal mode. 18 /// Normal mode.
18 const Normal = 0x200; 19 const NORMAL = 0x200;
19 20
20 /// Hard mode. 21 /// Hard mode.
21 const Hard = 0x400; 22 const HARD = 0x400;
22 23
23 /// Lunatic mode. 24 /// Lunatic mode.
24 const Lunatic = 0x800; 25 const LUNATIC = 0x800;
25 26
26 /// Any or all modes. 27 /// Any or all modes.
27 const All = 0xff00; 28 const ALL = 0xff00;
28 } 29 }
29 } 30 }
30 31
31 impl std::str::FromStr for Rank { 32 impl std::str::FromStr for Rank {
32 type Err = String; 33 type Err = String;
33 34
34 fn from_str(s: &str) -> Result<Rank, Self::Err> { 35 fn from_str(s: &str) -> Result<Rank, Self::Err> {
35 Ok(match s { 36 Ok(match s {
36 "easy" => Rank::Easy, 37 "easy" => Rank::EASY,
37 "normal" => Rank::Normal, 38 "normal" => Rank::NORMAL,
38 "hard" => Rank::Hard, 39 "hard" => Rank::HARD,
39 "lunatic" => Rank::Lunatic, 40 "lunatic" => Rank::LUNATIC,
40 _ => return Err(format!("unknown rank {}", s)) 41 _ => return Err(format!("unknown rank {}", s))
41 }) 42 })
42 } 43 }
43 } 44 }
44 45
327 328
328 fn parse_ecl(input: &[u8]) -> IResult<&[u8], Ecl> { 329 fn parse_ecl(input: &[u8]) -> IResult<&[u8], Ecl> {
329 let i = input; 330 let i = input;
330 331
331 let (i, sub_count) = le_u16(i)?; 332 let (i, sub_count) = le_u16(i)?;
332 let (mut i, main_count) = le_u16(i)?; 333 let sub_count = sub_count as usize;
334 let (i, main_count) = le_u16(i)?;
333 assert_eq!(main_count, 0); 335 assert_eq!(main_count, 0);
334 336
335 let mut main_offsets = Vec::new(); 337 let (i, main_offsets) = many_m_n(3, 3, le_u32)(i)?;
336 for _ in 0..3 { 338 let (_, sub_offsets) = many_m_n(sub_count, sub_count, le_u32)(i)?;
337 let (i2, offset) = le_u32(i)?;
338 main_offsets.push(offset as usize);
339 i = i2;
340 }
341
342 let mut sub_offsets = Vec::new();
343 for _ in 0..sub_count {
344 let (i2, offset) = le_u32(i)?;
345 sub_offsets.push(offset as usize);
346 i = i2;
347 }
348 339
349 // Read all subs. 340 // Read all subs.
350 let mut subs = Vec::new(); 341 let mut subs = Vec::new();
351 for offset in sub_offsets { 342 for offset in sub_offsets.into_iter().map(|offset| offset as usize) {
352 let mut i = &input[offset..]; 343 let mut i = &input[offset..];
353 let mut instructions = Vec::new(); 344 let mut instructions = Vec::new();
354 loop { 345 loop {
355 let (i2, time) = le_i32(i)?; 346 let (i2, (time, opcode)) = tuple((le_i32, le_u16))(i)?;
356 let (i2, opcode) = le_u16(i2)?;
357 if time == -1 || opcode == 0xffff { 347 if time == -1 || opcode == 0xffff {
358 break; 348 break;
359 } 349 }
360 350
361 let (i2, size) = le_u16(i2)?; 351 let (i2, (size, rank_mask, param_mask)) = tuple((le_u16, le_u16, le_u16))(i2)?;
362 let (i2, rank_mask) = le_u16(i2)?; 352 let size = size as usize;
363 let rank_mask = Rank::from_bits(rank_mask).unwrap(); 353 let rank_mask = Rank::from_bits(rank_mask).unwrap();
364 let (i2, param_mask) = le_u16(i2)?;
365 // FIXME: this - 12 can trigger a panic, fuzz it! 354 // FIXME: this - 12 can trigger a panic, fuzz it!
366 let data = &i2[..size as usize - 12]; 355 let data = &i2[..size - 12];
367 let (data, instr) = parse_sub_instruction_args(data, opcode)?; 356 let (data, instr) = parse_sub_instruction_args(data, opcode)?;
368 assert_eq!(data.len(), 0); 357 assert_eq!(data.len(), 0);
369 instructions.push(CallSub { time, rank_mask, param_mask, instr }); 358 instructions.push(CallSub { time, rank_mask, param_mask, instr });
370 i = &i[size as usize..]; 359 i = &i[size..];
371 } 360 }
372 subs.push(Sub { instructions }); 361 subs.push(Sub { instructions });
373 } 362 }
374 363
375 // Read all mains (always a single one atm). 364 // Read all mains (always a single one atm).
376 let mut mains = Vec::new(); 365 let mut mains = Vec::new();
377 for offset in main_offsets { 366 for offset in main_offsets.into_iter().map(|offset| offset as usize) {
378 if offset == 0 { 367 if offset == 0 {
379 break; 368 break;
380 } 369 }
381 370
382 let mut i = &input[offset..]; 371 let mut i = &input[offset..];
383 let mut instructions = Vec::new(); 372 let mut instructions = Vec::new();
384 loop { 373 loop {
385 let (i2, time) = le_u16(i)?; 374 let (i2, (time, sub)) = tuple((le_u16, le_u16))(i)?;
386 let (i2, sub) = le_u16(i2)?;
387 if time == 0xffff && sub == 4 { 375 if time == 0xffff && sub == 4 {
388 break; 376 break;
389 } 377 }
390 378
391 let (i2, opcode) = le_u16(i2)?; 379 let (i2, (opcode, size)) = tuple((le_u16, le_u16))(i2)?;
392 let (i2, size) = le_u16(i2)?; 380 let size = size as usize;
393 // FIXME: this - 8 can trigger a panic, fuzz it! 381 // FIXME: this - 8 can trigger a panic, fuzz it!
394 let data = &i2[..size as usize - 8]; 382 let data = &i2[..size - 8];
395 let (data, instr) = parse_main_instruction_args(data, opcode)?; 383 let (data, instr) = parse_main_instruction_args(data, opcode)?;
396 assert_eq!(data.len(), 0); 384 assert_eq!(data.len(), 0);
397 instructions.push(CallMain { time, sub, instr }); 385 instructions.push(CallMain { time, sub, instr });
398 i = &i[size as usize..]; 386 i = &i[size..];
399 } 387 }
400 mains.push(Main { instructions }); 388 mains.push(Main { instructions });
401 } 389 }
402 390
403 let ecl = Ecl { 391 let ecl = Ecl {