comparison src/th06/anm0.rs @ 713:258f4aebf3fc

anm0: Parse only a single anm0 at once and use many0 for more, to simplify parsing.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Tue, 17 Sep 2019 17:36:02 +0200
parents 84af5bedbde4
children fc937d93a57c
comparison
equal deleted inserted replaced
712:13fd434d5d1b 713:258f4aebf3fc
3 use nom::{ 3 use nom::{
4 IResult, 4 IResult,
5 bytes::complete::{tag, take_while_m_n}, 5 bytes::complete::{tag, take_while_m_n},
6 number::complete::{le_u8, le_u16, le_u32, le_i32, le_f32}, 6 number::complete::{le_u8, le_u16, le_u32, le_i32, le_f32},
7 sequence::tuple, 7 sequence::tuple,
8 multi::many_m_n, 8 multi::{many_m_n, many0},
9 }; 9 };
10 use std::collections::HashMap; 10 use std::collections::HashMap;
11 11
12 /// Coordinates of a sprite into the image. 12 /// Coordinates of a sprite into the image.
13 #[derive(Debug, Clone)] 13 #[derive(Debug, Clone)]
71 } 71 }
72 72
73 impl Anm0 { 73 impl Anm0 {
74 /// Parse a slice of bytes into an `Anm0` struct. 74 /// Parse a slice of bytes into an `Anm0` struct.
75 pub fn from_slice(data: &[u8]) -> IResult<&[u8], Vec<Anm0>> { 75 pub fn from_slice(data: &[u8]) -> IResult<&[u8], Vec<Anm0>> {
76 parse_anm0(data) 76 many0(parse_anm0)(data)
77 } 77 }
78 78
79 /// TODO 79 /// TODO
80 pub fn inv_size(&self) -> (f32, f32) { 80 pub fn inv_size(&self) -> (f32, f32) {
81 let (x, y) = self.size; 81 let (x, y) = self.size;
165 29 => fn SetVisible(visible: u32), 165 29 => fn SetVisible(visible: u32),
166 30 => fn ScaleIn(sx: f32, sy: f32, duration: u32), 166 30 => fn ScaleIn(sx: f32, sy: f32, duration: u32),
167 31 => fn Todo(todo: u32), 167 31 => fn Todo(todo: u32),
168 } 168 }
169 169
170 fn parse_anm0(input: &[u8]) -> IResult<&[u8], Vec<Anm0>> { 170 fn parse_anm0(input: &[u8]) -> IResult<&[u8], Anm0> {
171 let mut list = vec![]; 171 let (i, (num_sprites, num_scripts, _, width, height, format, _unknown1,
172 let start_offset = 0; 172 first_name_offset, _unused, second_name_offset, version, _unknown2,
173 loop { 173 _texture_offset, has_data, _next_offset, unknown3)) =
174 let i = &input[start_offset..]; 174 tuple((le_u32, le_u32, tag(b"\0\0\0\0"), le_u32, le_u32, le_u32, le_u32, le_u32,
175 let (mut i, (num_sprites, num_scripts, _, width, height, format, _unknown1, 175 le_u32, le_u32, le_u32, le_u32, le_u32, le_u32, le_u32, le_u32))(input)?;
176 first_name_offset, _unused, second_name_offset, version, _unknown2, 176
177 _texture_offset, has_data, _next_offset, unknown3)) = 177 assert_eq!(version, 0);
178 tuple((le_u32, le_u32, tag(b"\0\0\0\0"), le_u32, le_u32, le_u32, le_u32, le_u32, 178 assert_eq!(unknown3, 0);
179 le_u32, le_u32, le_u32, le_u32, le_u32, le_u32, le_u32, le_u32))(i)?; 179 assert_eq!(has_data, 0);
180 180 let num_sprites = num_sprites as usize;
181 assert_eq!(version, 0); 181 let num_scripts = num_scripts as usize;
182 assert_eq!(unknown3, 0); 182
183 assert_eq!(has_data, 0); 183 let (i, sprite_offsets) = many_m_n(num_sprites, num_sprites, le_u32)(i)?;
184 let num_sprites = num_sprites as usize; 184 let (_, script_offsets) = many_m_n(num_scripts, num_scripts, tuple((le_u32, le_u32)))(i)?;
185 let num_scripts = num_scripts as usize; 185
186 186 let png_filename = if first_name_offset > 0 {
187 let (i, sprite_offsets) = many_m_n(num_sprites, num_sprites, le_u32)(i)?; 187 if input.len() < first_name_offset as usize {
188 let (_, script_offsets) = many_m_n(num_scripts, num_scripts, tuple((le_u32, le_u32)))(i)?; 188 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof)));
189 189 }
190 let png_filename = if first_name_offset > 0 { 190 let i = &input[first_name_offset as usize..];
191 if input.len() < start_offset + first_name_offset as usize { 191 let (_, name) = parse_name(i)?;
192 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); 192 name
193 } else {
194 String::new()
195 };
196
197 let alpha_filename = if second_name_offset > 0 {
198 if input.len() < second_name_offset as usize {
199 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof)));
200 }
201 let i = &input[second_name_offset as usize..];
202 let (_, name) = parse_name(i)?;
203 Some(name)
204 } else {
205 None
206 };
207
208 let mut sprites = vec![];
209 let mut i = &input[..];
210 for offset in sprite_offsets.into_iter().map(|x| x as usize) {
211 if input.len() < offset {
212 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof)));
213 }
214 i = &input[offset..];
215 let (_, sprite) = parse_sprite(i)?;
216 sprites.push(sprite);
217 }
218
219 let mut scripts = HashMap::new();
220 for (index, offset) in script_offsets.into_iter().map(|(index, offset)| (index as u8, offset as usize)) {
221 if input.len() < offset {
222 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof)));
223 }
224 i = &input[offset..];
225 let mut instruction_offsets = vec![];
226
227 let mut instructions = vec![];
228 loop {
229 let tell = input.len() - i.len();
230 instruction_offsets.push(tell - offset);
231 // TODO: maybe check against the size of parsed data?
232 let (i2, (time, opcode, _size)) = tuple((le_u16, le_u8, le_u8))(i)?;
233 let (i2, instr) = parse_instruction_args(i2, opcode)?;
234 instructions.push(Call { time, instr });
235 i = i2;
236 if opcode == 0 {
237 break;
193 } 238 }
194 let i = &input[start_offset + first_name_offset as usize..]; 239 }
195 let (_, name) = parse_name(i)?; 240 let mut interrupts = HashMap::new();
196 name 241 let mut j = 0;
197 } else { 242 for Call { time: _, instr } in &mut instructions {
198 String::new() 243 match instr {
199 }; 244 Instruction::Jump(ref mut offset) => {
200 245 let result = instruction_offsets.binary_search(&(*offset as usize));
201 let alpha_filename = if second_name_offset > 0 { 246 match result {
202 if input.len() < start_offset + second_name_offset as usize { 247 Ok(ptr) => *offset = ptr as u32,
203 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof))); 248 Err(ptr) => {
204 } 249 // XXX: use a more specific error instead.
205 let i = &input[start_offset + second_name_offset as usize..]; 250 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof)));
206 let (_, name) = parse_name(i)?; 251 //println!("Instruction offset not found for pointer: {}", ptr);
207 Some(name)
208 } else {
209 None
210 };
211
212 let mut sprites = vec![];
213 let mut i;
214 for offset in sprite_offsets.into_iter().map(|x| x as usize) {
215 if input.len() < start_offset + offset {
216 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof)));
217 }
218 i = &input[start_offset + offset..];
219 let (_, sprite) = parse_sprite(i)?;
220 sprites.push(sprite);
221 }
222
223 let mut scripts = HashMap::new();
224 for (index, offset) in script_offsets.into_iter().map(|(index, offset)| (index as u8, offset as usize)) {
225 if input.len() < start_offset + offset {
226 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof)));
227 }
228 i = &input[start_offset + offset..];
229 let mut instruction_offsets = vec![];
230
231 let mut instructions = vec![];
232 loop {
233 let tell = input.len() - i.len();
234 instruction_offsets.push(tell - (start_offset + offset));
235 // TODO: maybe check against the size of parsed data?
236 let (i2, (time, opcode, _size)) = tuple((le_u16, le_u8, le_u8))(i)?;
237 let (i2, instr) = parse_instruction_args(i2, opcode)?;
238 instructions.push(Call { time, instr });
239 i = i2;
240 if opcode == 0 {
241 break;
242 }
243 }
244 let mut interrupts = HashMap::new();
245 let mut j = 0;
246 for Call { time: _, instr } in &mut instructions {
247 match instr {
248 Instruction::Jump(ref mut offset) => {
249 let result = instruction_offsets.binary_search(&(*offset as usize));
250 match result {
251 Ok(ptr) => *offset = ptr as u32,
252 Err(ptr) => {
253 // XXX: use a more specific error instead.
254 return Err(nom::Err::Failure((input, nom::error::ErrorKind::Eof)));
255 //println!("Instruction offset not found for pointer: {}", ptr);
256 }
257 } 252 }
258 } 253 }
259 Instruction::InterruptLabel(interrupt) => {
260 interrupts.insert(*interrupt, j + 1);
261 }
262 _ => ()
263 } 254 }
264 j += 1; 255 Instruction::InterruptLabel(interrupt) => {
256 interrupts.insert(*interrupt, j + 1);
257 }
258 _ => ()
265 } 259 }
266 scripts.insert(index, Script { 260 j += 1;
267 instructions, 261 }
268 interrupts, 262 scripts.insert(index, Script {
269 }); 263 instructions,
270 } 264 interrupts,
271 265 });
272 let anm0 = Anm0 { 266 }
273 size: (width, height), 267
274 format, 268 let anm0 = Anm0 {
275 png_filename, 269 size: (width, height),
276 alpha_filename, 270 format,
277 sprites, 271 png_filename,
278 scripts, 272 alpha_filename,
279 }; 273 sprites,
280 list.push(anm0); 274 scripts,
281 break; 275 };
282 } 276 Ok((i, anm0))
283 Ok((b"", list))
284 } 277 }
285 278
286 #[cfg(test)] 279 #[cfg(test)]
287 mod tests { 280 mod tests {
288 use super::*; 281 use super::*;