7
7
import os
8
8
import threading
9
9
10
- from typing import ClassVar , Dict , List , Literal , Tuple , Any , Optional , Union , BinaryIO , overload
10
+ from typing import ClassVar , Dict , List , Literal , Tuple , Any , Optional , Union , BinaryIO , overload , Sequence
11
11
12
12
import bsdiff4
13
13
@@ -41,7 +41,7 @@ def get_handler(file: str) -> Optional[AutoPatchRegister]:
41
41
42
42
class AutoPatchExtensionRegister (abc .ABCMeta ):
43
43
extension_types : ClassVar [Dict [str , AutoPatchExtensionRegister ]] = {}
44
- required_extensions : List [str ] = []
44
+ required_extensions : Tuple [str , ... ] = ()
45
45
46
46
def __new__ (mcs , name : str , bases : Tuple [type , ...], dct : Dict [str , Any ]) -> AutoPatchExtensionRegister :
47
47
# construct class
@@ -51,7 +51,9 @@ def __new__(mcs, name: str, bases: Tuple[type, ...], dct: Dict[str, Any]) -> Aut
51
51
return new_class
52
52
53
53
@staticmethod
54
- def get_handler (game : str ) -> Union [AutoPatchExtensionRegister , List [AutoPatchExtensionRegister ]]:
54
+ def get_handler (game : Optional [str ]) -> Union [AutoPatchExtensionRegister , List [AutoPatchExtensionRegister ]]:
55
+ if not game :
56
+ return APPatchExtension
55
57
handler = AutoPatchExtensionRegister .extension_types .get (game , APPatchExtension )
56
58
if handler .required_extensions :
57
59
handlers = [handler ]
@@ -191,7 +193,7 @@ class APProcedurePatch(APAutoPatchInterface):
191
193
hash : Optional [str ] # base checksum of source file
192
194
source_data : bytes
193
195
patch_file_ending : str = ""
194
- files : Dict [str , bytes ] = {}
196
+ files : Dict [str , bytes ]
195
197
196
198
@classmethod
197
199
def get_source_data (cls ) -> bytes :
@@ -206,6 +208,7 @@ def get_source_data_with_cache(cls) -> bytes:
206
208
207
209
def __init__ (self , * args : Any , ** kwargs : Any ):
208
210
super (APProcedurePatch , self ).__init__ (* args , ** kwargs )
211
+ self .files = {}
209
212
210
213
def get_manifest (self ) -> Dict [str , Any ]:
211
214
manifest = super (APProcedurePatch , self ).get_manifest ()
@@ -277,7 +280,7 @@ def __init__(self, *args: Any, patched_path: str = "", **kwargs: Any) -> None:
277
280
super (APDeltaPatch , self ).__init__ (* args , ** kwargs )
278
281
self .patched_path = patched_path
279
282
280
- def write_contents (self , opened_zipfile : zipfile .ZipFile ):
283
+ def write_contents (self , opened_zipfile : zipfile .ZipFile ) -> None :
281
284
self .write_file ("delta.bsdiff4" ,
282
285
bsdiff4 .diff (self .get_source_data_with_cache (), open (self .patched_path , "rb" ).read ()))
283
286
super (APDeltaPatch , self ).write_contents (opened_zipfile )
@@ -296,21 +299,21 @@ class APTokenMixin:
296
299
"""
297
300
A class that defines functions for generating a token binary, for use in patches.
298
301
"""
299
- tokens : List [
302
+ _tokens : Sequence [
300
303
Tuple [APTokenTypes , int , Union [
301
304
bytes , # WRITE
302
305
Tuple [int , int ], # COPY, RLE
303
306
int # AND_8, OR_8, XOR_8
304
- ]]] = []
307
+ ]]] = ()
305
308
306
309
def get_token_binary (self ) -> bytes :
307
310
"""
308
311
Returns the token binary created from stored tokens.
309
312
:return: A bytes object representing the token data.
310
313
"""
311
314
data = bytearray ()
312
- data .extend (len (self .tokens ).to_bytes (4 , "little" ))
313
- for token_type , offset , args in self .tokens :
315
+ data .extend (len (self ._tokens ).to_bytes (4 , "little" ))
316
+ for token_type , offset , args in self ._tokens :
314
317
data .append (token_type )
315
318
data .extend (offset .to_bytes (4 , "little" ))
316
319
if token_type in [APTokenTypes .AND_8 , APTokenTypes .OR_8 , APTokenTypes .XOR_8 ]:
@@ -351,11 +354,14 @@ def write_token(self,
351
354
data : bytes ) -> None :
352
355
...
353
356
354
- def write_token (self , token_type : APTokenTypes , offset : int , data : Union [bytes , Tuple [int , int ], int ]):
357
+ def write_token (self , token_type : APTokenTypes , offset : int , data : Union [bytes , Tuple [int , int ], int ]) -> None :
355
358
"""
356
359
Stores a token to be used by patching.
357
360
"""
358
- self .tokens .append ((token_type , offset , data ))
361
+ if not isinstance (self ._tokens , list ):
362
+ assert len (self ._tokens ) == 0 , f"{ type (self )} ._tokens was tampered with."
363
+ self ._tokens = []
364
+ self ._tokens .append ((token_type , offset , data ))
359
365
360
366
361
367
class APPatchExtension (metaclass = AutoPatchExtensionRegister ):
@@ -371,10 +377,10 @@ class APPatchExtension(metaclass=AutoPatchExtensionRegister):
371
377
Patch extension functions must return the changed bytes.
372
378
"""
373
379
game : str
374
- required_extensions : List [ str ] = []
380
+ required_extensions : ClassVar [ Tuple [ str , ...]] = ()
375
381
376
382
@staticmethod
377
- def apply_bsdiff4 (caller : APProcedurePatch , rom : bytes , patch : str ):
383
+ def apply_bsdiff4 (caller : APProcedurePatch , rom : bytes , patch : str ) -> bytes :
378
384
"""Applies the given bsdiff4 from the patch onto the current file."""
379
385
return bsdiff4 .patch (rom , caller .get_file (patch ))
380
386
@@ -411,7 +417,7 @@ def apply_tokens(caller: APProcedurePatch, rom: bytes, token_file: str) -> bytes
411
417
return bytes (rom_data )
412
418
413
419
@staticmethod
414
- def calc_snes_crc (caller : APProcedurePatch , rom : bytes ):
420
+ def calc_snes_crc (caller : APProcedurePatch , rom : bytes ) -> bytes :
415
421
"""Calculates and applies a valid CRC for the SNES rom header."""
416
422
rom_data = bytearray (rom )
417
423
if len (rom ) < 0x8000 :
0 commit comments