Compare commits

...

2 commits

Author SHA1 Message Date
909ee0932b
Replace deprecated chunk module with inline IFF parser
The chunk module was deprecated in 3.11 and removed in 3.13.
Our usage was minimal (read name, size, data, skip padding),
so a small _read_iff_chunk() helper replaces it with no deps.
2026-02-10 17:20:01 -05:00
3140a4d617
Add return_addr to ZStackBottom for uniform frame access
ZStackBottom already had stack and local_vars for uniform treatment,
but was missing return_addr. Adding it removes 5 type: ignore
suppressions and fixes all ty possibly-missing-attribute warnings.
2026-02-10 17:16:25 -05:00
2 changed files with 29 additions and 17 deletions

View file

@ -12,14 +12,30 @@
# root directory of this distribution. # root directory of this distribution.
# #
# Woohoo! Python has a module to parse IFF files, which is a generic
# interchange format. A Quetzal file is in fact a type of IFF file.
import chunk
import os import os
import struct
from . import bitfield, zstackmanager from . import bitfield, zstackmanager
from .zlogging import log from .zlogging import log
def _read_iff_chunk(f):
"""Read one IFF chunk from a file-like object. Returns (name, data).
Raises EOFError when there are no more chunks to read.
"""
header = f.read(8)
if len(header) < 8:
raise EOFError
name = header[:4]
(size,) = struct.unpack(">I", header[4:8])
data = f.read(size)
# IFF chunks are padded to even byte boundaries
if size % 2 == 1:
f.read(1)
return name, data
# The general format of Queztal is that of a "FORM" IFF file, which is # The general format of Queztal is that of a "FORM" IFF file, which is
# a container class for 'chunks'. # a container class for 'chunks'.
# #
@ -339,10 +355,8 @@ class QuetzalParser:
log("Parsing chunks from byte data") log("Parsing chunks from byte data")
try: try:
while 1: while 1:
c = chunk.Chunk(self._file) chunkname, chunk_data = _read_iff_chunk(self._file)
chunkname = c.getname() chunksize = len(chunk_data)
chunksize = c.getsize()
chunk_data = c.read(chunksize)
log(f"** Found chunk ID {chunkname}: length {chunksize}") log(f"** Found chunk ID {chunkname}: length {chunksize}")
self._last_loaded_metadata[chunkname] = chunksize self._last_loaded_metadata[chunkname] = chunksize
@ -406,10 +420,8 @@ class QuetzalParser:
try: try:
while 1: while 1:
c = chunk.Chunk(self._file) chunkname, data = _read_iff_chunk(self._file)
chunkname = c.getname() chunksize = len(data)
chunksize = c.getsize()
data = c.read(chunksize)
log(f"** Found chunk ID {chunkname}: length {chunksize}") log(f"** Found chunk ID {chunkname}: length {chunksize}")
self._last_loaded_metadata[chunkname] = chunksize self._last_loaded_metadata[chunkname] = chunksize

View file

@ -104,6 +104,7 @@ class ZStackBottom:
def __init__(self): def __init__(self):
self.program_counter = 0 # used as a cache only self.program_counter = 0 # used as a cache only
self.return_addr = None
self.stack = [] self.stack = []
self.local_vars = [0 for _ in range(15)] self.local_vars = [0 for _ in range(15)]
@ -201,15 +202,14 @@ class ZStackManager:
current_routine = self._call_stack[-1] current_routine = self._call_stack[-1]
# Depending on many things, return stuff. # Depending on many things, return stuff.
if exiting_routine.return_addr is not None: # type: ignore[possibly-missing-attribute] if exiting_routine.return_addr is not None:
if exiting_routine.return_addr == 0: # type: ignore[possibly-missing-attribute] if exiting_routine.return_addr == 0:
# Push to stack # Push to stack
self.push_stack(return_value) self.push_stack(return_value)
elif 0 < exiting_routine.return_addr < 0x10: # type: ignore[possibly-missing-attribute] elif 0 < exiting_routine.return_addr < 0x10:
# Store in local var # Store in local var
self.set_local_variable(exiting_routine.return_addr - 1, return_value) # type: ignore[possibly-missing-attribute] self.set_local_variable(exiting_routine.return_addr - 1, return_value)
else: else:
# Store in global var # Store in global var
self._memory.write_global(exiting_routine.return_addr, return_value) # type: ignore[possibly-missing-attribute] self._memory.write_global(exiting_routine.return_addr, return_value)
return current_routine.program_counter return current_routine.program_counter