Mercurial > touhou
comparison src/th06/ecl.rs @ 714:fcc8f736c746
ecl: Simplify parsing.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Mon, 23 Sep 2019 00:06:02 +0200 |
parents | 81232dac8136 |
children | 5016c09e5d7c |
comparison
equal
deleted
inserted
replaced
713:258f4aebf3fc | 714:fcc8f736c746 |
---|---|
2 | 2 |
3 use nom::{ | 3 use nom::{ |
4 IResult, | 4 IResult, |
5 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, | 6 sequence::tuple, |
7 multi::many_m_n, | 7 multi::{count, many0}, |
8 error::ErrorKind, | |
9 Err, | |
8 }; | 10 }; |
9 use encoding_rs::SHIFT_JIS; | 11 use encoding_rs::SHIFT_JIS; |
10 use bitflags::bitflags; | 12 use bitflags::bitflags; |
11 | 13 |
12 bitflags! { | 14 bitflags! { |
144 } | 146 } |
145 }; | 147 }; |
146 } | 148 } |
147 | 149 |
148 /// Parse a SHIFT_JIS byte string of length 34 into a String. | 150 /// Parse a SHIFT_JIS byte string of length 34 into a String. |
151 #[allow(non_snake_case)] | |
149 pub fn le_String(i: &[u8]) -> IResult<&[u8], String> { | 152 pub fn le_String(i: &[u8]) -> IResult<&[u8], String> { |
150 assert_eq!(i.len(), 34); | |
151 let data = i.splitn(2, |c| *c == b'\0').nth(0).unwrap(); | 153 let data = i.splitn(2, |c| *c == b'\0').nth(0).unwrap(); |
152 let (string, encoding, replaced) = SHIFT_JIS.decode(data); | 154 let (string, _encoding, _replaced) = SHIFT_JIS.decode(data); |
153 Ok((&i[34..], string.into_owned())) | 155 Ok((&i[34..], string.into_owned())) |
154 } | 156 } |
155 | 157 |
156 macro_rules! declare_sub_instructions { | 158 macro_rules! declare_sub_instructions { |
157 ($($opcode:tt => fn $name:ident($($arg:ident: $arg_type:ident),*)),*,) => { | 159 ($($opcode:tt => fn $name:ident($($arg:ident: $arg_type:ident),*)),*,) => { |
299 113 => fn SetLowLifeTrigger(trigger: i32), | 301 113 => fn SetLowLifeTrigger(trigger: i32), |
300 114 => fn SetLowLifeCallback(sub: i32), | 302 114 => fn SetLowLifeCallback(sub: i32), |
301 115 => fn SetTimeout(timeout: i32), | 303 115 => fn SetTimeout(timeout: i32), |
302 116 => fn SetTimeoutCallback(sub: i32), | 304 116 => fn SetTimeoutCallback(sub: i32), |
303 117 => fn SetTouchable(touchable: i32), | 305 117 => fn SetTouchable(touchable: i32), |
304 118 => fn DropParticles(anim: i32, number: u32, r: u8, g: u8, b: u8, UNUSED: u8), | 306 118 => fn DropParticles(anim: i32, number: u32, r: u8, g: u8, b: u8, a: u8), |
305 119 => fn DropBonus(number: i32), | 307 119 => fn DropBonus(number: i32), |
306 120 => fn SetAutomaticOrientation(automatic: i32), | 308 120 => fn SetAutomaticOrientation(automatic: i32), |
307 121 => fn CallSpecialFunction(function: i32, argument: i32), | 309 121 => fn CallSpecialFunction(function: i32, argument: i32), |
308 // TODO: Found in stage 3 then 5 onward. | 310 122 => fn SetSpecialFunctionCallback(function: i32), |
309 122 => fn UNK_ins122(TODO: i32), | |
310 123 => fn SkipFrames(frames: i32), | 311 123 => fn SkipFrames(frames: i32), |
311 124 => fn DropSpecificBonus(type_: i32), | 312 124 => fn DropSpecificBonus(type_: i32), |
312 // TODO: Found in stage 3. | 313 // TODO: Found in stage 3. |
313 125 => fn UNK_ins125(), | 314 125 => fn UNK_ins125(), |
314 126 => fn SetRemainingLives(lives: i32), | 315 126 => fn SetRemainingLives(lives: i32), |
324 // TODO: Found in stage 4. | 325 // TODO: Found in stage 4. |
325 134 => fn UNK_ins134(), | 326 134 => fn UNK_ins134(), |
326 135 => fn EnableSpellcardBonus(UNKNOW: i32), | 327 135 => fn EnableSpellcardBonus(UNKNOW: i32), |
327 } | 328 } |
328 | 329 |
330 fn parse_sub_instruction(input: &[u8]) -> IResult<&[u8], CallSub> { | |
331 let i = &input[..]; | |
332 let (i, (time, opcode)) = tuple((le_i32, le_u16))(i)?; | |
333 if time == -1 || opcode == 0xffff { | |
334 return Err(Err::Error((i, ErrorKind::Eof))); | |
335 } | |
336 | |
337 let (i, (size, rank_mask, param_mask)) = tuple((le_u16, le_u16, le_u16))(i)?; | |
338 let rank_mask = Rank::from_bits(rank_mask).unwrap(); | |
339 let (i, instr) = parse_sub_instruction_args(i, opcode)?; | |
340 assert_eq!(input.len() - i.len(), size as usize); | |
341 let call = CallSub { time, rank_mask, param_mask, instr }; | |
342 Ok((i, call)) | |
343 } | |
344 | |
345 fn parse_sub(i: &[u8]) -> IResult<&[u8], Sub> { | |
346 let (i, instructions) = many0(parse_sub_instruction)(i)?; | |
347 let sub = Sub { instructions }; | |
348 Ok((i, sub)) | |
349 } | |
350 | |
351 fn parse_main_instruction(input: &[u8]) -> IResult<&[u8], CallMain> { | |
352 let i = &input[..]; | |
353 let (i, (time, sub)) = tuple((le_u16, le_u16))(i)?; | |
354 if time == 0xffff && sub == 4 { | |
355 return Err(Err::Error((i, ErrorKind::Eof))); | |
356 } | |
357 | |
358 let (i, (opcode, size)) = tuple((le_u16, le_u16))(i)?; | |
359 let size = size as usize; | |
360 let (i, instr) = parse_main_instruction_args(i, opcode)?; | |
361 assert_eq!(input.len() - i.len(), size as usize); | |
362 let call = CallMain { time, sub, instr }; | |
363 Ok((i, call)) | |
364 } | |
365 | |
366 fn parse_main(i: &[u8]) -> IResult<&[u8], Main> { | |
367 let (i, instructions) = many0(parse_main_instruction)(i)?; | |
368 let main = Main { instructions }; | |
369 Ok((i, main)) | |
370 } | |
371 | |
329 fn parse_ecl(input: &[u8]) -> IResult<&[u8], Ecl> { | 372 fn parse_ecl(input: &[u8]) -> IResult<&[u8], Ecl> { |
330 let i = input; | 373 let i = input; |
331 | 374 |
332 let (i, sub_count) = le_u16(i)?; | 375 let (i, (sub_count, main_count)) = tuple((le_u16, le_u16))(i)?; |
333 let sub_count = sub_count as usize; | 376 let sub_count = sub_count as usize; |
334 let (i, main_count) = le_u16(i)?; | 377 |
335 assert_eq!(main_count, 0); | 378 if main_count != 0 { |
336 | 379 // TODO: use a better error. |
337 let (i, main_offsets) = many_m_n(3, 3, le_u32)(i)?; | 380 return Err(Err::Error((i, ErrorKind::Eof))); |
338 let (_, sub_offsets) = many_m_n(sub_count, sub_count, le_u32)(i)?; | 381 } |
382 | |
383 let (_, (main_offsets, sub_offsets)) = tuple(( | |
384 count(le_u32, 3), | |
385 count(le_u32, sub_count), | |
386 ))(i)?; | |
339 | 387 |
340 // Read all subs. | 388 // Read all subs. |
341 let mut subs = Vec::new(); | 389 let mut subs = Vec::new(); |
342 for offset in sub_offsets.into_iter().map(|offset| offset as usize) { | 390 for offset in sub_offsets.into_iter().map(|offset| offset as usize) { |
343 let mut i = &input[offset..]; | 391 let (_, sub) = parse_sub(&input[offset..])?; |
344 let mut instructions = Vec::new(); | 392 subs.push(sub); |
345 loop { | |
346 let (i2, (time, opcode)) = tuple((le_i32, le_u16))(i)?; | |
347 if time == -1 || opcode == 0xffff { | |
348 break; | |
349 } | |
350 | |
351 let (i2, (size, rank_mask, param_mask)) = tuple((le_u16, le_u16, le_u16))(i2)?; | |
352 let size = size as usize; | |
353 let rank_mask = Rank::from_bits(rank_mask).unwrap(); | |
354 // FIXME: this - 12 can trigger a panic, fuzz it! | |
355 let data = &i2[..size - 12]; | |
356 let (data, instr) = parse_sub_instruction_args(data, opcode)?; | |
357 assert_eq!(data.len(), 0); | |
358 instructions.push(CallSub { time, rank_mask, param_mask, instr }); | |
359 i = &i[size..]; | |
360 } | |
361 subs.push(Sub { instructions }); | |
362 } | 393 } |
363 | 394 |
364 // Read all mains (always a single one atm). | 395 // Read all mains (always a single one atm). |
365 let mut mains = Vec::new(); | 396 let mut mains = Vec::new(); |
366 for offset in main_offsets.into_iter().map(|offset| offset as usize) { | 397 for offset in main_offsets.into_iter().map(|offset| offset as usize) { |
367 if offset == 0 { | 398 if offset == 0 { |
368 break; | 399 break; |
369 } | 400 } |
370 | 401 let (_, main) = parse_main(&input[offset..])?; |
371 let mut i = &input[offset..]; | 402 mains.push(main); |
372 let mut instructions = Vec::new(); | |
373 loop { | |
374 let (i2, (time, sub)) = tuple((le_u16, le_u16))(i)?; | |
375 if time == 0xffff && sub == 4 { | |
376 break; | |
377 } | |
378 | |
379 let (i2, (opcode, size)) = tuple((le_u16, le_u16))(i2)?; | |
380 let size = size as usize; | |
381 // FIXME: this - 8 can trigger a panic, fuzz it! | |
382 let data = &i2[..size - 8]; | |
383 let (data, instr) = parse_main_instruction_args(data, opcode)?; | |
384 assert_eq!(data.len(), 0); | |
385 instructions.push(CallMain { time, sub, instr }); | |
386 i = &i[size..]; | |
387 } | |
388 mains.push(Main { instructions }); | |
389 } | 403 } |
390 | 404 |
391 let ecl = Ecl { | 405 let ecl = Ecl { |
392 subs, | 406 subs, |
393 mains, | 407 mains, |