Support more versions of *.ani files

This commit is contained in:
Quantum 2020-09-27 14:40:16 -04:00
parent d887ea0ca6
commit 3c043bc518

View file

@ -35,14 +35,21 @@ class ANIParser(BaseParser):
def _unpack(self, struct_cls: struct.Struct, offset: int) -> Tuple[Any, ...]: def _unpack(self, struct_cls: struct.Struct, offset: int) -> Tuple[Any, ...]:
return struct_cls.unpack(self.blob[offset:offset + struct_cls.size]) return struct_cls.unpack(self.blob[offset:offset + struct_cls.size])
def _read_chunk(self, offset: int, expected: Iterable[bytes]) -> Tuple[int, int]: def _read_chunk(self, offset: int, expected: Iterable[bytes]) -> Tuple[bytes, int, int]:
found = []
while True:
name, size = self._unpack(self.CHUNK_HEADER, offset) name, size = self._unpack(self.CHUNK_HEADER, offset)
if name not in expected: offset += self.CHUNK_HEADER.size
raise ValueError('Expected chunk %r, found %r' % (expected, name)) if name in expected:
return size, offset + self.CHUNK_HEADER.size break
found += [name]
offset += size
if offset >= len(self.blob):
raise ValueError('Expected chunk %r, found %r' % (expected, found))
return name, size, offset
def _parse(self, offset: int) -> List[CursorFrame]: def _parse(self, offset: int) -> List[CursorFrame]:
size, offset = self._read_chunk(offset, expected=[b'anih']) _, size, offset = self._read_chunk(offset, expected=[b'anih'])
if size != self.ANIH_HEADER.size: if size != self.ANIH_HEADER.size:
raise ValueError('Unexpected anih header size %d, expected %d' % (size, self.ANIH_HEADER.size)) raise ValueError('Unexpected anih header size %d, expected %d' % (size, self.ANIH_HEADER.size))
@ -54,38 +61,42 @@ class ANIParser(BaseParser):
raise NotImplementedError('Raw BMP images not supported.') raise NotImplementedError('Raw BMP images not supported.')
offset += self.ANIH_HEADER.size offset += self.ANIH_HEADER.size
list_size, offset = self._read_chunk(offset, expected=[b'LIST'])
list_end = list_size + offset
frames = []
order = list(range(frame_count))
delays = [display_rate for _ in range(step_count)]
while offset < len(self.blob):
name, size, offset = self._read_chunk(offset, expected=[b'LIST', b'seq ', b'rate'])
if name == b'LIST':
list_end = offset + size
if self.blob[offset:offset + 4] != self.FRAME_TYPE: if self.blob[offset:offset + 4] != self.FRAME_TYPE:
raise ValueError('Unexpected RIFF list type: %r, expected %r' % raise ValueError('Unexpected RIFF list type: %r, expected %r' %
(self.blob[offset:offset + 4], self.FRAME_TYPE)) (self.blob[offset:offset + 4], self.FRAME_TYPE))
offset += 4 offset += 4
frames = []
for i in range(frame_count): for i in range(frame_count):
size, offset = self._read_chunk(offset, expected=[b'icon']) _, size, offset = self._read_chunk(offset, expected=[b'icon'])
frames.append(CURParser(self.blob[offset:offset + size]).frames[0]) frames.append(CURParser(self.blob[offset:offset + size]).frames[0])
offset += size offset += size
if offset != list_end: if offset != list_end:
raise ValueError('Wrong RIFF list size: %r, expected %r' % (offset, list_end)) raise ValueError('Wrong RIFF list size: %r, expected %r' % (offset, list_end))
elif name == b'seq ':
sequence = frames order = [i for i, in self.UNSIGNED.iter_unpack(self.blob[offset:offset + size])]
if flags & self.SEQUENCE_FLAG: if len(order) != step_count:
size, offset = self._read_chunk(offset, expected=[b'seq ']) raise ValueError('Wrong animation sequence size: %r, expected %r' % (len(order), step_count))
sequence = [copy(frames[i]) for i, in self.UNSIGNED.iter_unpack(self.blob[offset:offset + size])] offset += size
if len(sequence) != step_count: elif name == b'rate':
raise ValueError('Wrong animation sequence size: %r, expected %r' % (len(sequence), step_count)) delays = [i for i, in self.UNSIGNED.iter_unpack(self.blob[offset:offset + size])]
if len(delays) != step_count:
raise ValueError('Wrong animation rate size: %r, expected %r' % (len(delays), step_count))
offset += size offset += size
delays = [display_rate for _ in range(step_count)] if len(order) != step_count:
if offset < len(self.blob): raise ValueError('Required chunk "seq " not found.')
size, offset = self._read_chunk(offset, expected=[b'rate'])
delays = [i for i, in self.UNSIGNED.iter_unpack(self.blob[offset:offset + size])]
if len(sequence) != step_count:
raise ValueError('Wrong animation rate size: %r, expected %r' % (len(delays), step_count))
sequence = [copy(frames[i]) for i in order]
for frame, delay in zip(sequence, delays): for frame, delay in zip(sequence, delays):
frame.delay = delay / 60 frame.delay = delay / 60