From 83495f44af8c502e6f3b6cb72eca647c30f2a845 Mon Sep 17 00:00:00 2001 From: Jennifer Taylor Date: Mon, 31 May 2021 18:09:40 +0000 Subject: [PATCH] Additional typing fixes for safety and to be able to compile more code with mypyc. --- bemani/__init__.py | 3 + bemani/common/aes.py | 8 +- bemani/common/card.py | 32 +-- bemani/common/constants.py | 425 ++++++++++++++++---------------- bemani/common/time.py | 10 +- bemani/protocol/binary.py | 14 +- bemani/protocol/lz77.py | 54 ++-- bemani/protocol/node.py | 137 +++++----- bemani/protocol/protocol.py | 22 +- bemani/protocol/xml.py | 4 +- bemani/tests/helpers.py | 7 + bemani/tests/test_AES.py | 16 +- bemani/tests/test_CardCipher.py | 4 +- bemani/tests/test_RC4.py | 12 +- bemani/tests/test_lz77.py | 11 +- 15 files changed, 385 insertions(+), 374 deletions(-) diff --git a/bemani/__init__.py b/bemani/__init__.py index e69de29..0a75856 100644 --- a/bemani/__init__.py +++ b/bemani/__init__.py @@ -0,0 +1,3 @@ +import os.path + +package_root = os.path.dirname(os.path.abspath(__file__)) diff --git a/bemani/common/aes.py b/bemani/common/aes.py index a203add..140eb6e 100644 --- a/bemani/common/aes.py +++ b/bemani/common/aes.py @@ -13,19 +13,19 @@ class AESCipher: self.__padamt = 16 self.__key = hashlib.sha256(key.encode('utf-8')).digest() - def __pad(self, s: str) -> str: + def _pad(self, s: str) -> str: intermediate = f"{len(s)}.{s}" while len(intermediate) % self.__padamt != 0: intermediate = intermediate + '-' return intermediate - def __unpad(self, s: str) -> str: + def _unpad(self, s: str) -> str: length, string = s.split('.', 1) intlength = int(length) return string[:intlength] def encrypt(self, raw: str) -> str: - raw = self.__pad(raw) + raw = self._pad(raw) random = Random.new() iv = random.read(AES.block_size) cipher = AES.new(self.__key, AES.MODE_CBC, iv) @@ -35,4 +35,4 @@ class AESCipher: enc = base64.b64decode(encoded.encode('utf-8'), altchars=b"._") iv = enc[:AES.block_size] cipher = AES.new(self.__key, AES.MODE_CBC, iv) - return self.__unpad(cipher.decrypt(enc[AES.block_size:]).decode('utf-8')) + return self._unpad(cipher.decrypt(enc[AES.block_size:]).decode('utf-8')) diff --git a/bemani/common/card.py b/bemani/common/card.py index 8bd0e44..c2e2c59 100644 --- a/bemani/common/card.py +++ b/bemani/common/card.py @@ -1,4 +1,4 @@ -from typing import List +from typing import Dict, Final, List class CardCipherException(Exception): @@ -13,7 +13,7 @@ class CardCipher: Tau and converted ham-fistedly to Python. """ - KEY = [ + KEY: Final[List[int]] = [ 0x20d0d03c, 0x868ecb41, 0xbcd89c84, 0x4c0e0d0d, 0x84fc30ac, 0x4cc1890e, 0xfc5418a4, 0x02c50f44, 0x68acb4e0, 0x06cd4a4e, 0xcc28906c, 0x4f0c8ac0, @@ -40,7 +40,7 @@ class CardCipher: 0x60443ce4, 0x4c0b8b8d, 0xe054e8bc, 0x02008e89, ] - LUT_A0 = [ + LUT_A0: Final[List[int]] = [ 0x02080008, 0x02082000, 0x00002008, 0x00000000, 0x02002000, 0x00080008, 0x02080000, 0x02082008, 0x00000008, 0x02000000, 0x00082000, 0x00002008, @@ -59,7 +59,7 @@ class CardCipher: 0x02000000, 0x02080008, 0x00002000, 0x00082008, ] - LUT_A1 = [ + LUT_A1: Final[List[int]] = [ 0x08000004, 0x00020004, 0x00000000, 0x08020200, 0x00020004, 0x00000200, 0x08000204, 0x00020000, 0x00000204, 0x08020204, 0x00020200, 0x08000000, @@ -78,7 +78,7 @@ class CardCipher: 0x08020000, 0x00000204, 0x00000004, 0x08020004, ] - LUT_A2 = [ + LUT_A2: Final[List[int]] = [ 0x80040100, 0x01000100, 0x80000000, 0x81040100, 0x00000000, 0x01040000, 0x81000100, 0x80040000, 0x01040100, 0x81000000, 0x01000000, 0x80000100, @@ -97,7 +97,7 @@ class CardCipher: 0x80000100, 0x01000000, 0x81000000, 0x01040100, ] - LUT_A3 = [ + LUT_A3: Final[List[int]] = [ 0x04010801, 0x00000000, 0x00010800, 0x04010000, 0x04000001, 0x00000801, 0x04000800, 0x00010800, 0x00000800, 0x04010001, 0x00000001, 0x04000800, @@ -116,7 +116,7 @@ class CardCipher: 0x04000801, 0x00000001, 0x04010000, 0x00010800, ] - LUT_B0 = [ + LUT_B0: Final[List[int]] = [ 0x00000400, 0x00000020, 0x00100020, 0x40100000, 0x40100420, 0x40000400, 0x00000420, 0x00000000, 0x00100000, 0x40100020, 0x40000020, 0x00100400, @@ -135,7 +135,7 @@ class CardCipher: 0x40100000, 0x00100420, 0x00100400, 0x40000400, ] - LUT_B1 = [ + LUT_B1: Final[List[int]] = [ 0x00800000, 0x00001000, 0x00000040, 0x00801042, 0x00801002, 0x00800040, 0x00001042, 0x00801000, 0x00001000, 0x00000002, 0x00800002, 0x00001040, @@ -154,7 +154,7 @@ class CardCipher: 0x00000002, 0x00001042, 0x00801000, 0x00800002, ] - LUT_B2 = [ + LUT_B2: Final[List[int]] = [ 0x10400000, 0x00404010, 0x00000010, 0x10400010, 0x10004000, 0x00400000, 0x10400010, 0x00004010, 0x00400010, 0x00004000, 0x00404000, 0x10000000, @@ -173,7 +173,7 @@ class CardCipher: 0x10400000, 0x10004010, 0x00000010, 0x00404000, ] - LUT_B3 = [ + LUT_B3: Final[List[int]] = [ 0x00208080, 0x00008000, 0x20200000, 0x20208080, 0x00200000, 0x20008080, 0x20008000, 0x20200000, 0x20008080, 0x00208080, 0x00208000, 0x20000080, @@ -192,8 +192,8 @@ class CardCipher: 0x20000000, 0x20208000, 0x00000080, 0x20008080, ] - VALID_CHARS = "0123456789ABCDEFGHJKLMNPRSTUWXYZ" - CONV_CHARS = { + VALID_CHARS: Final[str] = "0123456789ABCDEFGHJKLMNPRSTUWXYZ" + CONV_CHARS: Final[Dict[str, str]] = { "I": "1", "O": "0", } @@ -231,7 +231,7 @@ class CardCipher: reverse[7 - i] = cardint[i] # Encipher - ciphered = CardCipher.__encode(bytes(reverse)) + ciphered = CardCipher._encode(bytes(reverse)) # Convert 8 x 8 bit bytes into 13 x 5 bit groups (sort of) bits = [0] * 65 @@ -330,7 +330,7 @@ class CardCipher: ciphered[int(i / 8)] |= bits[i] << (~i & 7) # Decipher and reverse - deciphered = CardCipher.__decode(bytes(ciphered)) + deciphered = CardCipher._decode(bytes(ciphered)) reverse = [0] * 8 for i in range(0, 8): reverse[i] = deciphered[7 - i] @@ -362,7 +362,7 @@ class CardCipher: return checksum @staticmethod - def __encode(inbytes: bytes) -> bytes: + def _encode(inbytes: bytes) -> bytes: if len(inbytes) != 8: raise CardCipherException( f'Expected 8-byte input, got {len(inbytes)}', @@ -378,7 +378,7 @@ class CardCipher: return bytes(out) @staticmethod - def __decode(inbytes: bytes) -> bytes: + def _decode(inbytes: bytes) -> bytes: if len(inbytes) != 8: raise CardCipherException( f'Expected 8-byte input, got {len(inbytes)}', diff --git a/bemani/common/constants.py b/bemani/common/constants.py index 7cbdb0b..4c05799 100644 --- a/bemani/common/constants.py +++ b/bemani/common/constants.py @@ -1,124 +1,127 @@ +from typing import Final + + class GameConstants: - BISHI_BASHI = 'bishi' - DANCE_EVOLUTION = 'danevo' - DDR = 'ddr' - IIDX = 'iidx' - JUBEAT = 'jubeat' - MUSECA = 'museca' - POPN_MUSIC = 'pnm' - REFLEC_BEAT = 'reflec' - SDVX = 'sdvx' + BISHI_BASHI: Final[str] = 'bishi' + DANCE_EVOLUTION: Final[str] = 'danevo' + DDR: Final[str] = 'ddr' + IIDX: Final[str] = 'iidx' + JUBEAT: Final[str] = 'jubeat' + MUSECA: Final[str] = 'museca' + POPN_MUSIC: Final[str] = 'pnm' + REFLEC_BEAT: Final[str] = 'reflec' + SDVX: Final[str] = 'sdvx' class VersionConstants: - BISHI_BASHI_TSBB = 1 + BISHI_BASHI_TSBB: Final[int] = 1 - DDR_1STMIX = 1 - DDR_2NDMIX = 2 - DDR_3RDMIX = 3 - DDR_4THMIX = 4 - DDR_5THMIX = 5 - DDR_6THMIX = 6 - DDR_7THMIX = 7 - DDR_EXTREME = 8 - DDR_SUPERNOVA = 9 - DDR_SUPERNOVA_2 = 10 - DDR_X = 11 - DDR_X2 = 12 - DDR_X3_VS_2NDMIX = 13 - DDR_2013 = 14 - DDR_2014 = 15 - DDR_ACE = 16 - DDR_A20 = 17 + DDR_1STMIX: Final[int] = 1 + DDR_2NDMIX: Final[int] = 2 + DDR_3RDMIX: Final[int] = 3 + DDR_4THMIX: Final[int] = 4 + DDR_5THMIX: Final[int] = 5 + DDR_6THMIX: Final[int] = 6 + DDR_7THMIX: Final[int] = 7 + DDR_EXTREME: Final[int] = 8 + DDR_SUPERNOVA: Final[int] = 9 + DDR_SUPERNOVA_2: Final[int] = 10 + DDR_X: Final[int] = 11 + DDR_X2: Final[int] = 12 + DDR_X3_VS_2NDMIX: Final[int] = 13 + DDR_2013: Final[int] = 14 + DDR_2014: Final[int] = 15 + DDR_ACE: Final[int] = 16 + DDR_A20: Final[int] = 17 - IIDX = 1 - IIDX_2ND_STYLE = 2 - IIDX_3RD_STYLE = 3 - IIDX_4TH_STYLE = 4 - IIDX_5TH_STYLE = 5 - IIDX_6TH_STYLE = 6 - IIDX_7TH_STYLE = 7 - IIDX_8TH_STYLE = 8 - IIDX_9TH_STYLE = 9 - IIDX_10TH_STYLE = 10 - IIDX_RED = 11 - IIDX_HAPPY_SKY = 12 - IIDX_DISTORTED = 13 - IIDX_GOLD = 14 - IIDX_DJ_TROOPERS = 15 - IIDX_EMPRESS = 16 - IIDX_SIRIUS = 17 - IIDX_RESORT_ANTHEM = 18 - IIDX_LINCLE = 19 - IIDX_TRICORO = 20 - IIDX_SPADA = 21 - IIDX_PENDUAL = 22 - IIDX_COPULA = 23 - IIDX_SINOBUZ = 24 - IIDX_CANNON_BALLERS = 25 + IIDX: Final[int] = 1 + IIDX_2ND_STYLE: Final[int] = 2 + IIDX_3RD_STYLE: Final[int] = 3 + IIDX_4TH_STYLE: Final[int] = 4 + IIDX_5TH_STYLE: Final[int] = 5 + IIDX_6TH_STYLE: Final[int] = 6 + IIDX_7TH_STYLE: Final[int] = 7 + IIDX_8TH_STYLE: Final[int] = 8 + IIDX_9TH_STYLE: Final[int] = 9 + IIDX_10TH_STYLE: Final[int] = 10 + IIDX_RED: Final[int] = 11 + IIDX_HAPPY_SKY: Final[int] = 12 + IIDX_DISTORTED: Final[int] = 13 + IIDX_GOLD: Final[int] = 14 + IIDX_DJ_TROOPERS: Final[int] = 15 + IIDX_EMPRESS: Final[int] = 16 + IIDX_SIRIUS: Final[int] = 17 + IIDX_RESORT_ANTHEM: Final[int] = 18 + IIDX_LINCLE: Final[int] = 19 + IIDX_TRICORO: Final[int] = 20 + IIDX_SPADA: Final[int] = 21 + IIDX_PENDUAL: Final[int] = 22 + IIDX_COPULA: Final[int] = 23 + IIDX_SINOBUZ: Final[int] = 24 + IIDX_CANNON_BALLERS: Final[int] = 25 - JUBEAT = 1 - JUBEAT_RIPPLES = 2 - JUBEAT_RIPPLES_APPEND = 3 - JUBEAT_KNIT = 4 - JUBEAT_KNIT_APPEND = 5 - JUBEAT_COPIOUS = 6 - JUBEAT_COPIOUS_APPEND = 7 - JUBEAT_SAUCER = 8 - JUBEAT_SAUCER_FULFILL = 9 - JUBEAT_PROP = 10 - JUBEAT_QUBELL = 11 - JUBEAT_CLAN = 12 - JUBEAT_FESTO = 13 + JUBEAT: Final[int] = 1 + JUBEAT_RIPPLES: Final[int] = 2 + JUBEAT_RIPPLES_APPEND: Final[int] = 3 + JUBEAT_KNIT: Final[int] = 4 + JUBEAT_KNIT_APPEND: Final[int] = 5 + JUBEAT_COPIOUS: Final[int] = 6 + JUBEAT_COPIOUS_APPEND: Final[int] = 7 + JUBEAT_SAUCER: Final[int] = 8 + JUBEAT_SAUCER_FULFILL: Final[int] = 9 + JUBEAT_PROP: Final[int] = 10 + JUBEAT_QUBELL: Final[int] = 11 + JUBEAT_CLAN: Final[int] = 12 + JUBEAT_FESTO: Final[int] = 13 - MUSECA = 1 - MUSECA_1_PLUS = 2 + MUSECA: Final[int] = 1 + MUSECA_1_PLUS: Final[int] = 2 - POPN_MUSIC = 1 - POPN_MUSIC_2 = 2 - POPN_MUSIC_3 = 3 - POPN_MUSIC_4 = 4 - POPN_MUSIC_5 = 5 - POPN_MUSIC_6 = 6 - POPN_MUSIC_7 = 7 - POPN_MUSIC_8 = 8 - POPN_MUSIC_9 = 9 - POPN_MUSIC_10 = 10 - POPN_MUSIC_11 = 11 - POPN_MUSIC_IROHA = 12 - POPN_MUSIC_CARNIVAL = 13 - POPN_MUSIC_FEVER = 14 - POPN_MUSIC_ADVENTURE = 15 - POPN_MUSIC_PARTY = 16 - POPN_MUSIC_THE_MOVIE = 17 - POPN_MUSIC_SENGOKU_RETSUDEN = 18 - POPN_MUSIC_TUNE_STREET = 19 - POPN_MUSIC_FANTASIA = 20 - POPN_MUSIC_SUNNY_PARK = 21 - POPN_MUSIC_LAPISTORIA = 22 - POPN_MUSIC_ECLALE = 23 - POPN_MUSIC_USANEKO = 24 - POPN_MUSIC_PEACE = 25 + POPN_MUSIC: Final[int] = 1 + POPN_MUSIC_2: Final[int] = 2 + POPN_MUSIC_3: Final[int] = 3 + POPN_MUSIC_4: Final[int] = 4 + POPN_MUSIC_5: Final[int] = 5 + POPN_MUSIC_6: Final[int] = 6 + POPN_MUSIC_7: Final[int] = 7 + POPN_MUSIC_8: Final[int] = 8 + POPN_MUSIC_9: Final[int] = 9 + POPN_MUSIC_10: Final[int] = 10 + POPN_MUSIC_11: Final[int] = 11 + POPN_MUSIC_IROHA: Final[int] = 12 + POPN_MUSIC_CARNIVAL: Final[int] = 13 + POPN_MUSIC_FEVER: Final[int] = 14 + POPN_MUSIC_ADVENTURE: Final[int] = 15 + POPN_MUSIC_PARTY: Final[int] = 16 + POPN_MUSIC_THE_MOVIE: Final[int] = 17 + POPN_MUSIC_SENGOKU_RETSUDEN: Final[int] = 18 + POPN_MUSIC_TUNE_STREET: Final[int] = 19 + POPN_MUSIC_FANTASIA: Final[int] = 20 + POPN_MUSIC_SUNNY_PARK: Final[int] = 21 + POPN_MUSIC_LAPISTORIA: Final[int] = 22 + POPN_MUSIC_ECLALE: Final[int] = 23 + POPN_MUSIC_USANEKO: Final[int] = 24 + POPN_MUSIC_PEACE: Final[int] = 25 - REFLEC_BEAT = 1 - REFLEC_BEAT_LIMELIGHT = 2 - REFLEC_BEAT_COLETTE = 3 - REFLEC_BEAT_GROOVIN = 4 - REFLEC_BEAT_VOLZZA = 5 - REFLEC_BEAT_VOLZZA_2 = 6 - REFLEC_BEAT_REFLESIA = 7 + REFLEC_BEAT: Final[int] = 1 + REFLEC_BEAT_LIMELIGHT: Final[int] = 2 + REFLEC_BEAT_COLETTE: Final[int] = 3 + REFLEC_BEAT_GROOVIN: Final[int] = 4 + REFLEC_BEAT_VOLZZA: Final[int] = 5 + REFLEC_BEAT_VOLZZA_2: Final[int] = 6 + REFLEC_BEAT_REFLESIA: Final[int] = 7 - SDVX_BOOTH = 1 - SDVX_INFINITE_INFECTION = 2 - SDVX_GRAVITY_WARS = 3 - SDVX_HEAVENLY_HAVEN = 4 + SDVX_BOOTH: Final[int] = 1 + SDVX_INFINITE_INFECTION: Final[int] = 2 + SDVX_GRAVITY_WARS: Final[int] = 3 + SDVX_HEAVENLY_HAVEN: Final[int] = 4 class APIConstants: - ID_TYPE_SERVER = 'server' - ID_TYPE_CARD = 'card' - ID_TYPE_SONG = 'song' - ID_TYPE_INSTANCE = 'instance' + ID_TYPE_SERVER: Final[str] = 'server' + ID_TYPE_CARD: Final[str] = 'card' + ID_TYPE_SONG: Final[str] = 'song' + ID_TYPE_INSTANCE: Final[str] = 'instance' class DBConstants: @@ -140,114 +143,114 @@ class DBConstants: # will only be found in the DB itself, as well as used on the frontend # to display various general information about scores. - OMNIMIX_VERSION_BUMP = 10000 + OMNIMIX_VERSION_BUMP: Final[int] = 10000 - DDR_HALO_NONE = 100 - DDR_HALO_GOOD_FULL_COMBO = 200 - DDR_HALO_GREAT_FULL_COMBO = 300 - DDR_HALO_PERFECT_FULL_COMBO = 400 - DDR_HALO_MARVELOUS_FULL_COMBO = 500 - DDR_RANK_E = 100 - DDR_RANK_D = 200 - DDR_RANK_D_PLUS = 233 - DDR_RANK_C_MINUS = 266 - DDR_RANK_C = 300 - DDR_RANK_C_PLUS = 333 - DDR_RANK_B_MINUS = 366 - DDR_RANK_B = 400 - DDR_RANK_B_PLUS = 433 - DDR_RANK_A_MINUS = 466 - DDR_RANK_A = 500 - DDR_RANK_A_PLUS = 533 - DDR_RANK_AA_MINUS = 566 - DDR_RANK_AA = 600 - DDR_RANK_AA_PLUS = 650 - DDR_RANK_AAA = 700 + DDR_HALO_NONE: Final[int] = 100 + DDR_HALO_GOOD_FULL_COMBO: Final[int] = 200 + DDR_HALO_GREAT_FULL_COMBO: Final[int] = 300 + DDR_HALO_PERFECT_FULL_COMBO: Final[int] = 400 + DDR_HALO_MARVELOUS_FULL_COMBO: Final[int] = 500 + DDR_RANK_E: Final[int] = 100 + DDR_RANK_D: Final[int] = 200 + DDR_RANK_D_PLUS: Final[int] = 233 + DDR_RANK_C_MINUS: Final[int] = 266 + DDR_RANK_C: Final[int] = 300 + DDR_RANK_C_PLUS: Final[int] = 333 + DDR_RANK_B_MINUS: Final[int] = 366 + DDR_RANK_B: Final[int] = 400 + DDR_RANK_B_PLUS: Final[int] = 433 + DDR_RANK_A_MINUS: Final[int] = 466 + DDR_RANK_A: Final[int] = 500 + DDR_RANK_A_PLUS: Final[int] = 533 + DDR_RANK_AA_MINUS: Final[int] = 566 + DDR_RANK_AA: Final[int] = 600 + DDR_RANK_AA_PLUS: Final[int] = 650 + DDR_RANK_AAA: Final[int] = 700 - IIDX_CLEAR_STATUS_NO_PLAY = 50 - IIDX_CLEAR_STATUS_FAILED = 100 - IIDX_CLEAR_STATUS_ASSIST_CLEAR = 200 - IIDX_CLEAR_STATUS_EASY_CLEAR = 300 - IIDX_CLEAR_STATUS_CLEAR = 400 - IIDX_CLEAR_STATUS_HARD_CLEAR = 500 - IIDX_CLEAR_STATUS_EX_HARD_CLEAR = 600 - IIDX_CLEAR_STATUS_FULL_COMBO = 700 - IIDX_DAN_RANK_7_KYU = 100 - IIDX_DAN_RANK_6_KYU = 200 - IIDX_DAN_RANK_5_KYU = 300 - IIDX_DAN_RANK_4_KYU = 400 - IIDX_DAN_RANK_3_KYU = 500 - IIDX_DAN_RANK_2_KYU = 600 - IIDX_DAN_RANK_1_KYU = 700 - IIDX_DAN_RANK_1_DAN = 800 - IIDX_DAN_RANK_2_DAN = 900 - IIDX_DAN_RANK_3_DAN = 1000 - IIDX_DAN_RANK_4_DAN = 1100 - IIDX_DAN_RANK_5_DAN = 1200 - IIDX_DAN_RANK_6_DAN = 1300 - IIDX_DAN_RANK_7_DAN = 1400 - IIDX_DAN_RANK_8_DAN = 1500 - IIDX_DAN_RANK_9_DAN = 1600 - IIDX_DAN_RANK_10_DAN = 1700 - IIDX_DAN_RANK_CHUDEN = 1800 - IIDX_DAN_RANK_KAIDEN = 1900 + IIDX_CLEAR_STATUS_NO_PLAY: Final[int] = 50 + IIDX_CLEAR_STATUS_FAILED: Final[int] = 100 + IIDX_CLEAR_STATUS_ASSIST_CLEAR: Final[int] = 200 + IIDX_CLEAR_STATUS_EASY_CLEAR: Final[int] = 300 + IIDX_CLEAR_STATUS_CLEAR: Final[int] = 400 + IIDX_CLEAR_STATUS_HARD_CLEAR: Final[int] = 500 + IIDX_CLEAR_STATUS_EX_HARD_CLEAR: Final[int] = 600 + IIDX_CLEAR_STATUS_FULL_COMBO: Final[int] = 700 + IIDX_DAN_RANK_7_KYU: Final[int] = 100 + IIDX_DAN_RANK_6_KYU: Final[int] = 200 + IIDX_DAN_RANK_5_KYU: Final[int] = 300 + IIDX_DAN_RANK_4_KYU: Final[int] = 400 + IIDX_DAN_RANK_3_KYU: Final[int] = 500 + IIDX_DAN_RANK_2_KYU: Final[int] = 600 + IIDX_DAN_RANK_1_KYU: Final[int] = 700 + IIDX_DAN_RANK_1_DAN: Final[int] = 800 + IIDX_DAN_RANK_2_DAN: Final[int] = 900 + IIDX_DAN_RANK_3_DAN: Final[int] = 1000 + IIDX_DAN_RANK_4_DAN: Final[int] = 1100 + IIDX_DAN_RANK_5_DAN: Final[int] = 1200 + IIDX_DAN_RANK_6_DAN: Final[int] = 1300 + IIDX_DAN_RANK_7_DAN: Final[int] = 1400 + IIDX_DAN_RANK_8_DAN: Final[int] = 1500 + IIDX_DAN_RANK_9_DAN: Final[int] = 1600 + IIDX_DAN_RANK_10_DAN: Final[int] = 1700 + IIDX_DAN_RANK_CHUDEN: Final[int] = 1800 + IIDX_DAN_RANK_KAIDEN: Final[int] = 1900 - JUBEAT_PLAY_MEDAL_FAILED = 100 - JUBEAT_PLAY_MEDAL_CLEARED = 200 - JUBEAT_PLAY_MEDAL_NEARLY_FULL_COMBO = 300 - JUBEAT_PLAY_MEDAL_FULL_COMBO = 400 - JUBEAT_PLAY_MEDAL_NEARLY_EXCELLENT = 500 - JUBEAT_PLAY_MEDAL_EXCELLENT = 600 + JUBEAT_PLAY_MEDAL_FAILED: Final[int] = 100 + JUBEAT_PLAY_MEDAL_CLEARED: Final[int] = 200 + JUBEAT_PLAY_MEDAL_NEARLY_FULL_COMBO: Final[int] = 300 + JUBEAT_PLAY_MEDAL_FULL_COMBO: Final[int] = 400 + JUBEAT_PLAY_MEDAL_NEARLY_EXCELLENT: Final[int] = 500 + JUBEAT_PLAY_MEDAL_EXCELLENT: Final[int] = 600 - MUSECA_GRADE_DEATH = 100 # 没 - MUSECA_GRADE_POOR = 200 # 拙 - MUSECA_GRADE_MEDIOCRE = 300 # 凡 - MUSECA_GRADE_GOOD = 400 # 佳 - MUSECA_GRADE_GREAT = 500 # 良 - MUSECA_GRADE_EXCELLENT = 600 # 優 - MUSECA_GRADE_SUPERB = 700 # 秀 - MUSECA_GRADE_MASTERPIECE = 800 # 傑 - MUSECA_GRADE_PERFECT = 900 # 傑 - MUSECA_CLEAR_TYPE_FAILED = 100 - MUSECA_CLEAR_TYPE_CLEARED = 200 - MUSECA_CLEAR_TYPE_FULL_COMBO = 300 + MUSECA_GRADE_DEATH: Final[int] = 100 # 没 + MUSECA_GRADE_POOR: Final[int] = 200 # 拙 + MUSECA_GRADE_MEDIOCRE: Final[int] = 300 # 凡 + MUSECA_GRADE_GOOD: Final[int] = 400 # 佳 + MUSECA_GRADE_GREAT: Final[int] = 500 # 良 + MUSECA_GRADE_EXCELLENT: Final[int] = 600 # 優 + MUSECA_GRADE_SUPERB: Final[int] = 700 # 秀 + MUSECA_GRADE_MASTERPIECE: Final[int] = 800 # 傑 + MUSECA_GRADE_PERFECT: Final[int] = 900 # 傑 + MUSECA_CLEAR_TYPE_FAILED: Final[int] = 100 + MUSECA_CLEAR_TYPE_CLEARED: Final[int] = 200 + MUSECA_CLEAR_TYPE_FULL_COMBO: Final[int] = 300 - POPN_MUSIC_PLAY_MEDAL_CIRCLE_FAILED = 100 - POPN_MUSIC_PLAY_MEDAL_DIAMOND_FAILED = 200 - POPN_MUSIC_PLAY_MEDAL_STAR_FAILED = 300 - POPN_MUSIC_PLAY_MEDAL_EASY_CLEAR = 400 - POPN_MUSIC_PLAY_MEDAL_CIRCLE_CLEARED = 500 - POPN_MUSIC_PLAY_MEDAL_DIAMOND_CLEARED = 600 - POPN_MUSIC_PLAY_MEDAL_STAR_CLEARED = 700 - POPN_MUSIC_PLAY_MEDAL_CIRCLE_FULL_COMBO = 800 - POPN_MUSIC_PLAY_MEDAL_DIAMOND_FULL_COMBO = 900 - POPN_MUSIC_PLAY_MEDAL_STAR_FULL_COMBO = 1000 - POPN_MUSIC_PLAY_MEDAL_PERFECT = 1100 + POPN_MUSIC_PLAY_MEDAL_CIRCLE_FAILED: Final[int] = 100 + POPN_MUSIC_PLAY_MEDAL_DIAMOND_FAILED: Final[int] = 200 + POPN_MUSIC_PLAY_MEDAL_STAR_FAILED: Final[int] = 300 + POPN_MUSIC_PLAY_MEDAL_EASY_CLEAR: Final[int] = 400 + POPN_MUSIC_PLAY_MEDAL_CIRCLE_CLEARED: Final[int] = 500 + POPN_MUSIC_PLAY_MEDAL_DIAMOND_CLEARED: Final[int] = 600 + POPN_MUSIC_PLAY_MEDAL_STAR_CLEARED: Final[int] = 700 + POPN_MUSIC_PLAY_MEDAL_CIRCLE_FULL_COMBO: Final[int] = 800 + POPN_MUSIC_PLAY_MEDAL_DIAMOND_FULL_COMBO: Final[int] = 900 + POPN_MUSIC_PLAY_MEDAL_STAR_FULL_COMBO: Final[int] = 1000 + POPN_MUSIC_PLAY_MEDAL_PERFECT: Final[int] = 1100 - REFLEC_BEAT_CLEAR_TYPE_NO_PLAY = 100 - REFLEC_BEAT_CLEAR_TYPE_FAILED = 200 - REFLEC_BEAT_CLEAR_TYPE_CLEARED = 300 - REFLEC_BEAT_CLEAR_TYPE_HARD_CLEARED = 400 - REFLEC_BEAT_CLEAR_TYPE_S_HARD_CLEARED = 500 - REFLEC_BEAT_COMBO_TYPE_NONE = 100 - REFLEC_BEAT_COMBO_TYPE_ALMOST_COMBO = 200 - REFLEC_BEAT_COMBO_TYPE_FULL_COMBO = 300 - REFLEC_BEAT_COMBO_TYPE_FULL_COMBO_ALL_JUST = 400 + REFLEC_BEAT_CLEAR_TYPE_NO_PLAY: Final[int] = 100 + REFLEC_BEAT_CLEAR_TYPE_FAILED: Final[int] = 200 + REFLEC_BEAT_CLEAR_TYPE_CLEARED: Final[int] = 300 + REFLEC_BEAT_CLEAR_TYPE_HARD_CLEARED: Final[int] = 400 + REFLEC_BEAT_CLEAR_TYPE_S_HARD_CLEARED: Final[int] = 500 + REFLEC_BEAT_COMBO_TYPE_NONE: Final[int] = 100 + REFLEC_BEAT_COMBO_TYPE_ALMOST_COMBO: Final[int] = 200 + REFLEC_BEAT_COMBO_TYPE_FULL_COMBO: Final[int] = 300 + REFLEC_BEAT_COMBO_TYPE_FULL_COMBO_ALL_JUST: Final[int] = 400 - SDVX_CLEAR_TYPE_NO_PLAY = 50 - SDVX_CLEAR_TYPE_FAILED = 100 - SDVX_CLEAR_TYPE_CLEAR = 200 - SDVX_CLEAR_TYPE_HARD_CLEAR = 300 - SDVX_CLEAR_TYPE_ULTIMATE_CHAIN = 400 - SDVX_CLEAR_TYPE_PERFECT_ULTIMATE_CHAIN = 500 - SDVX_GRADE_NO_PLAY = 100 - SDVX_GRADE_D = 200 - SDVX_GRADE_C = 300 - SDVX_GRADE_B = 400 - SDVX_GRADE_A = 500 - SDVX_GRADE_A_PLUS = 550 - SDVX_GRADE_AA = 600 - SDVX_GRADE_AA_PLUS = 650 - SDVX_GRADE_AAA = 700 - SDVX_GRADE_AAA_PLUS = 800 - SDVX_GRADE_S = 900 + SDVX_CLEAR_TYPE_NO_PLAY: Final[int] = 50 + SDVX_CLEAR_TYPE_FAILED: Final[int] = 100 + SDVX_CLEAR_TYPE_CLEAR: Final[int] = 200 + SDVX_CLEAR_TYPE_HARD_CLEAR: Final[int] = 300 + SDVX_CLEAR_TYPE_ULTIMATE_CHAIN: Final[int] = 400 + SDVX_CLEAR_TYPE_PERFECT_ULTIMATE_CHAIN: Final[int] = 500 + SDVX_GRADE_NO_PLAY: Final[int] = 100 + SDVX_GRADE_D: Final[int] = 200 + SDVX_GRADE_C: Final[int] = 300 + SDVX_GRADE_B: Final[int] = 400 + SDVX_GRADE_A: Final[int] = 500 + SDVX_GRADE_A_PLUS: Final[int] = 550 + SDVX_GRADE_AA: Final[int] = 600 + SDVX_GRADE_AA_PLUS: Final[int] = 650 + SDVX_GRADE_AAA: Final[int] = 700 + SDVX_GRADE_AAA_PLUS: Final[int] = 800 + SDVX_GRADE_S: Final[int] = 900 diff --git a/bemani/common/time.py b/bemani/common/time.py index 508554e..ed9f983 100644 --- a/bemani/common/time.py +++ b/bemani/common/time.py @@ -2,7 +2,7 @@ import calendar import datetime from dateutil import tz -from typing import List, Optional +from typing import List, Final, Optional class Time: @@ -11,10 +11,10 @@ class Time: standard unix timestamps at UTC timezone given various parameters. """ - SECONDS_IN_MINUTE = 60 - SECONDS_IN_HOUR = 3600 - SECONDS_IN_DAY = 86400 - SECONDS_IN_WEEK = 604800 + SECONDS_IN_MINUTE: Final[int] = 60 + SECONDS_IN_HOUR: Final[int] = 3600 + SECONDS_IN_DAY: Final[int] = 86400 + SECONDS_IN_WEEK: Final[int] = 604800 @staticmethod def now() -> int: diff --git a/bemani/protocol/binary.py b/bemani/protocol/binary.py index 3d46e31..3dcaccd 100644 --- a/bemani/protocol/binary.py +++ b/bemani/protocol/binary.py @@ -1,5 +1,5 @@ import struct -from typing import Optional, List, Dict, Any +from typing import Optional, Final, List, Dict, Any from bemani.protocol.stream import InputStream, OutputStream from bemani.protocol.node import Node @@ -708,17 +708,17 @@ class BinaryEncoding: """ Wrapper class representing a Binary Encoding. """ - MAGIC = 0xA0 + MAGIC: Final[int] = 0xA0 - COMPRESSED_WITH_DATA = 0x42 - COMPRESSED_WITHOUT_DATA = 0x43 - DECOMPRESSED_WITH_DATA = 0x45 - DECOMPRESSED_WITHOUT_DATA = 0x46 + COMPRESSED_WITH_DATA: Final[int] = 0x42 + COMPRESSED_WITHOUT_DATA: Final[int] = 0x43 + DECOMPRESSED_WITH_DATA: Final[int] = 0x45 + DECOMPRESSED_WITHOUT_DATA: Final[int] = 0x46 # The string values should match the constants in EAmuseProtocol. # I have no better way to link these than to write this comment, # as otherwise we would have a circular dependency. - ENCODINGS = { + ENCODINGS: Final[Dict[int, str]] = { 0x00: "ascii", 0x20: "shift-jis-legacy", 0x60: "euc-jp", diff --git a/bemani/protocol/lz77.py b/bemani/protocol/lz77.py index 6d93daf..6fbd9b4 100644 --- a/bemani/protocol/lz77.py +++ b/bemani/protocol/lz77.py @@ -1,13 +1,15 @@ import ctypes import os from collections import defaultdict -from typing import Generator, List, MutableMapping, Optional, Set, Tuple +from typing import Generator, Final, List, MutableMapping, Optional, Set, Tuple + +from .. import package_root # Attempt to use the faster C++ libraries if they're available try: clib = None - clib_path = os.path.dirname(os.path.abspath(__file__)) + clib_path = os.path.join(package_root, "protocol") files = [f for f in os.listdir(clib_path) if f.startswith("lz77cpp") and f.endswith(".so")] if len(files) > 0: clib = ctypes.cdll.LoadLibrary(os.path.join(clib_path, files[0])) @@ -32,10 +34,10 @@ class Lz77Decompress: over-the-wire compression of XML data, as well as compression inside a decent amount of file formats found in various Konami games. """ - RING_LENGTH = 0x1000 + RING_LENGTH: Final[int] = 0x1000 - FLAG_COPY = 1 - FLAG_BACKREF = 0 + FLAG_COPY: Final[int] = 1 + FLAG_BACKREF: Final[int] = 0 def __init__(self, data: bytes, backref: Optional[int] = None) -> None: """ @@ -56,7 +58,7 @@ class Lz77Decompress: self.ringlength: int = backref or self.RING_LENGTH self.ring: bytes = b'\x00' * self.ringlength - def __ring_read(self, copy_pos: int, copy_len: int) -> Generator[bytes, None, None]: + def _ring_read(self, copy_pos: int, copy_len: int) -> Generator[bytes, None, None]: """ Read the next bytes from the backref ring at the current copy position. @@ -72,13 +74,13 @@ class Lz77Decompress: amount = copy_len ret = self.ring[copy_pos:(copy_pos + amount)] - self.__ring_write(ret) + self._ring_write(ret) yield ret copy_pos = (copy_pos + amount) % self.ringlength copy_len -= amount - def __ring_write(self, bytedata: bytes) -> None: + def _ring_write(self, bytedata: bytes) -> None: """ Write bytes into the backref ring. @@ -117,7 +119,7 @@ class Lz77Decompress: # ringbuffer). So, since we read that last time and wrote it to the backbuffer # we are safe to read again. amount = min(self.pending_copy_amount, self.pending_copy_max) - yield from self.__ring_read(self.pending_copy_pos, amount) + yield from self._ring_read(self.pending_copy_pos, amount) # We read this many bytes and are about to write them to the ringbuffer, # so bookkeep that. @@ -149,17 +151,17 @@ class Lz77Decompress: # Grab chunk right out of the data source b = self.data[self.read_pos:(self.read_pos + amount)] - self.__ring_write(b) + self._ring_write(b) yield b self.read_pos += amount self.left -= amount elif flag == self.FLAG_BACKREF: - yield from self.__read_backref() + yield from self._read_backref() else: raise Exception("Logic error!") - def __read_backref(self) -> Generator[bytes, None, None]: + def _read_backref(self) -> Generator[bytes, None, None]: """ Read a backref chunk. Grab the copy length and copy position from the first two bytes and then read the first byte from @@ -204,7 +206,7 @@ class Lz77Decompress: while copy_pos < 0: copy_pos += self.ringlength copy_pos = copy_pos % self.ringlength - yield from self.__ring_read(copy_pos, copy_len) + yield from self._ring_read(copy_pos, copy_len) else: self.eof = True return @@ -221,12 +223,12 @@ class Lz77Compress: once, and if we use a proxy to direct traffic, possibly a second time. """ - RING_LENGTH = 0x1000 + RING_LENGTH: Final[int] = 0x1000 - LOOSE_COMPRESS_THRESHOLD = 1024 * 512 + LOOSE_COMPRESS_THRESHOLD: Final[int] = 1024 * 512 - FLAG_COPY = 1 - FLAG_BACKREF = 0 + FLAG_COPY: Final[int] = 1 + FLAG_BACKREF: Final[int] = 0 def __init__(self, data: bytes, backref: Optional[int] = None) -> None: """ @@ -246,11 +248,11 @@ class Lz77Compress: self.last_start: Tuple[int, int, int] = (0, 0, 0) if len(data) > self.LOOSE_COMPRESS_THRESHOLD: - self.__ring_write = self.__ring_write_starts_only + self._ring_write = self._ring_write_starts_only else: - self.__ring_write = self.__ring_write_both + self._ring_write = self._ring_write_both - def __ring_write_starts_only(self, bytedata: bytes) -> None: + def _ring_write_starts_only(self, bytedata: bytes) -> None: """ Write bytes into the backref ring. @@ -266,7 +268,7 @@ class Lz77Compress: # Keep track of the fact that we wrote this byte. self.bytes_written += 1 - def __ring_write_both(self, bytedata: bytes) -> None: + def _ring_write_both(self, bytedata: bytes) -> None: """ Write bytes into the backref ring. @@ -321,7 +323,7 @@ class Lz77Compress: chunk = self.data[self.read_pos:(self.read_pos + 1)] data[flagpos] = chunk - self.__ring_write(chunk) + self._ring_write(chunk) self.read_pos += 1 self.left -= 1 @@ -346,7 +348,7 @@ class Lz77Compress: chunk = self.data[self.read_pos:(self.read_pos + 1)] data[flagpos] = chunk - self.__ring_write(chunk) + self._ring_write(chunk) self.read_pos += 1 self.left -= 1 @@ -356,7 +358,7 @@ class Lz77Compress: # we're going to write at least these three bytes, so append it to the # output buffer. start_write_size = self.bytes_written - self.__ring_write(index) + self._ring_write(index) copy_amount = 3 while copy_amount < backref_amount: # First, let's see if we have any 3-wide chunks to consume. @@ -369,7 +371,7 @@ class Lz77Compress: if new_backref_locations: # Mark that we're copying an extra byte from the backref. - self.__ring_write(index) + self._ring_write(index) copy_amount += 3 possible_backref_locations = new_backref_locations else: @@ -388,7 +390,7 @@ class Lz77Compress: break # Mark that we're copying an extra byte from the backref. - self.__ring_write(self.data[(self.read_pos + copy_amount):(self.read_pos + copy_amount + 1)]) + self._ring_write(self.data[(self.read_pos + copy_amount):(self.read_pos + copy_amount + 1)]) copy_amount += 1 possible_backref_locations = new_backref_locations diff --git a/bemani/protocol/node.py b/bemani/protocol/node.py index b666be3..e3bf13a 100644 --- a/bemani/protocol/node.py +++ b/bemani/protocol/node.py @@ -1,6 +1,11 @@ import copy import struct -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, Final, List, Optional, Union + + +# Hack to get around mypy's lack of scoping on types. +_renamed_float = float +_renamed_bool = bool class NodeException(Exception): @@ -16,60 +21,60 @@ class Node: supported for a node to not have a value or children. This also includes a decent amount of constructor helper classmethods to make constructing a tree from source code easier. """ - NODE_NAME_CHARS = "0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" + NODE_NAME_CHARS: Final[str] = "0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" - NODE_TYPE_VOID = 1 - NODE_TYPE_S8 = 2 - NODE_TYPE_U8 = 3 - NODE_TYPE_S16 = 4 - NODE_TYPE_U16 = 5 - NODE_TYPE_S32 = 6 - NODE_TYPE_U32 = 7 - NODE_TYPE_S64 = 8 - NODE_TYPE_U64 = 9 - NODE_TYPE_BIN = 10 - NODE_TYPE_STR = 11 - NODE_TYPE_IP4 = 12 - NODE_TYPE_TIME = 13 - NODE_TYPE_FLOAT = 14 - NODE_TYPE_DOUBLE = 15 + NODE_TYPE_VOID: Final[int] = 1 + NODE_TYPE_S8: Final[int] = 2 + NODE_TYPE_U8: Final[int] = 3 + NODE_TYPE_S16: Final[int] = 4 + NODE_TYPE_U16: Final[int] = 5 + NODE_TYPE_S32: Final[int] = 6 + NODE_TYPE_U32: Final[int] = 7 + NODE_TYPE_S64: Final[int] = 8 + NODE_TYPE_U64: Final[int] = 9 + NODE_TYPE_BIN: Final[int] = 10 + NODE_TYPE_STR: Final[int] = 11 + NODE_TYPE_IP4: Final[int] = 12 + NODE_TYPE_TIME: Final[int] = 13 + NODE_TYPE_FLOAT: Final[int] = 14 + NODE_TYPE_DOUBLE: Final[int] = 15 - NODE_TYPE_2S8 = 16 - NODE_TYPE_2U8 = 17 - NODE_TYPE_2S16 = 18 - NODE_TYPE_2U16 = 19 - NODE_TYPE_2S32 = 20 - NODE_TYPE_2U32 = 21 - NODE_TYPE_2S64 = 22 - NODE_TYPE_2U64 = 23 - NODE_TYPE_2FLOAT = 24 - NODE_TYPE_2DOUBLE = 25 + NODE_TYPE_2S8: Final[int] = 16 + NODE_TYPE_2U8: Final[int] = 17 + NODE_TYPE_2S16: Final[int] = 18 + NODE_TYPE_2U16: Final[int] = 19 + NODE_TYPE_2S32: Final[int] = 20 + NODE_TYPE_2U32: Final[int] = 21 + NODE_TYPE_2S64: Final[int] = 22 + NODE_TYPE_2U64: Final[int] = 23 + NODE_TYPE_2FLOAT: Final[int] = 24 + NODE_TYPE_2DOUBLE: Final[int] = 25 - NODE_TYPE_3S8 = 26 - NODE_TYPE_3U8 = 27 - NODE_TYPE_3S16 = 28 - NODE_TYPE_3U16 = 29 - NODE_TYPE_3S32 = 30 - NODE_TYPE_3U32 = 31 - NODE_TYPE_3S64 = 32 - NODE_TYPE_3U64 = 33 - NODE_TYPE_3FLOAT = 34 - NODE_TYPE_3DOUBLE = 35 + NODE_TYPE_3S8: Final[int] = 26 + NODE_TYPE_3U8: Final[int] = 27 + NODE_TYPE_3S16: Final[int] = 28 + NODE_TYPE_3U16: Final[int] = 29 + NODE_TYPE_3S32: Final[int] = 30 + NODE_TYPE_3U32: Final[int] = 31 + NODE_TYPE_3S64: Final[int] = 32 + NODE_TYPE_3U64: Final[int] = 33 + NODE_TYPE_3FLOAT: Final[int] = 34 + NODE_TYPE_3DOUBLE: Final[int] = 35 - NODE_TYPE_4S8 = 36 - NODE_TYPE_4U8 = 37 - NODE_TYPE_4S16 = 38 - NODE_TYPE_4U16 = 39 - NODE_TYPE_4S32 = 40 - NODE_TYPE_4U32 = 41 - NODE_TYPE_4S64 = 42 - NODE_TYPE_4U64 = 43 - NODE_TYPE_4FLOAT = 44 - NODE_TYPE_4DOUBLE = 45 + NODE_TYPE_4S8: Final[int] = 36 + NODE_TYPE_4U8: Final[int] = 37 + NODE_TYPE_4S16: Final[int] = 38 + NODE_TYPE_4U16: Final[int] = 39 + NODE_TYPE_4S32: Final[int] = 40 + NODE_TYPE_4U32: Final[int] = 41 + NODE_TYPE_4S64: Final[int] = 42 + NODE_TYPE_4U64: Final[int] = 43 + NODE_TYPE_4FLOAT: Final[int] = 44 + NODE_TYPE_4DOUBLE: Final[int] = 45 - NODE_TYPE_BOOL = 52 + NODE_TYPE_BOOL: Final[int] = 52 - NODE_TYPES = { + NODE_TYPES: Final[Dict[int, Dict[str, Any]]] = { NODE_TYPE_VOID: { 'name': 'void', 'enc': '', @@ -347,10 +352,10 @@ class Node: 'composite': False, }, } - ARRAY_BIT = 0x40 - ATTR_TYPE = 0x2E - END_OF_NODE = 0xFE - END_OF_DOCUMENT = 0xFF + ARRAY_BIT: Final[int] = 0x40 + ATTR_TYPE: Final[int] = 0x2E + END_OF_NODE: Final[int] = 0xFE + END_OF_DOCUMENT: Final[int] = 0xFF @staticmethod def void(name: str) -> 'Node': @@ -365,11 +370,11 @@ class Node: return Node(name=name, type=Node.NODE_TYPE_BIN, value=value) @staticmethod - def __float(name: str, value: float) -> 'Node': + def float(name: str, value: _renamed_float) -> 'Node': return Node(name=name, type=Node.NODE_TYPE_FLOAT, value=value) @staticmethod - def __bool(name: str, value: bool) -> 'Node': + def bool(name: str, value: _renamed_bool) -> 'Node': return Node(name=name, type=Node.NODE_TYPE_BOOL, value=value) @staticmethod @@ -425,11 +430,11 @@ class Node: return Node(name=name, type=Node.NODE_TYPE_TIME, array=True, value=values) @staticmethod - def float_array(name: str, values: List[float]) -> 'Node': + def float_array(name: str, values: List[_renamed_float]) -> 'Node': return Node(name=name, type=Node.NODE_TYPE_FLOAT, array=True, value=values) @staticmethod - def bool_array(name: str, values: List[bool]) -> 'Node': + def bool_array(name: str, values: List[_renamed_bool]) -> 'Node': return Node(name=name, type=Node.NODE_TYPE_BOOL, array=True, value=values) @staticmethod @@ -532,7 +537,7 @@ class Node: if value < -9223372036854775808 or value > 9223372036854775807: raise NodeException(f'Invalid value {value} for s32 {name}') - def __init__(self, name: Optional[str]=None, type: Optional[int]=None, array: Optional[bool]=None, value: Optional[Any]=None) -> None: + def __init__(self, name: Optional[str]=None, type: Optional[int]=None, array: Optional[_renamed_bool]=None, value: Optional[Any]=None) -> None: """ Initialize a node, with an optional name and type. @@ -589,7 +594,7 @@ class Node: raise Exception('Logic error, tried to fetch name before setting!') return self.__name - def set_type(self, type: int, array: Optional[bool]=None) -> None: + def set_type(self, type: int, array: Optional[_renamed_bool]=None) -> None: """ Set the type of the node to a new integer type, as specified in Node.NODE_TYPES. @@ -763,7 +768,7 @@ class Node: return self.__attrs @property - def is_array(self) -> bool: + def is_array(self) -> _renamed_bool: """ Wrapper for accessing array type. @@ -773,7 +778,7 @@ class Node: return self.__array @property - def is_composite(self) -> bool: + def is_composite(self) -> _renamed_bool: """ Returns whether or not this element is a composite type (basically an array, but packed differently). @@ -905,7 +910,7 @@ class Node: attrs_dict['__type'] = translated_type['name'] order.insert(0, '__type') - def escape(val: Any, attr: bool=False) -> str: + def escape(val: Any, attr: _renamed_bool=False) -> str: if isinstance(val, str): val = val.replace('&', '&') val = val.replace('<', '<') @@ -977,7 +982,7 @@ class Node: """ return self.__to_xml(0) - def __eq__(self, other: object) -> bool: + def __eq__(self, other: object) -> _renamed_bool: """ Convenience function for comparing two nodes. @@ -1027,7 +1032,7 @@ class Node: except Exception: return False - def __ne__(self, other: object) -> bool: + def __ne__(self, other: object) -> _renamed_bool: """ Convenience function for comparing two nodes. @@ -1038,7 +1043,3 @@ class Node: True if this node doesn't equal the other node, False if it does equal. """ return not self.__eq__(other) - - # Nasty hack to get around mypy's lack of scoping - float = __float - bool = __bool diff --git a/bemani/protocol/protocol.py b/bemani/protocol/protocol.py index e6a3ee6..7ef36aa 100644 --- a/bemani/protocol/protocol.py +++ b/bemani/protocol/protocol.py @@ -1,6 +1,6 @@ import binascii import hashlib -from typing import Optional +from typing import Final, Optional from bemani.protocol.lz77 import Lz77 from bemani.protocol.binary import BinaryEncoding @@ -18,16 +18,16 @@ class EAmuseProtocol: """ A wrapper object that encapsulates encoding/decoding the E-Amusement protocol by Konami. """ - SHARED_SECRET = b'\x69\xD7\x46\x27\xD9\x85\xEE\x21\x87\x16\x15\x70\xD0\x8D\x93\xB1\x24\x55\x03\x5B\x6D\xF0\xD8\x20\x5D\xF5' + SHARED_SECRET: Final[bytes] = b'\x69\xD7\x46\x27\xD9\x85\xEE\x21\x87\x16\x15\x70\xD0\x8D\x93\xB1\x24\x55\x03\x5B\x6D\xF0\xD8\x20\x5D\xF5' - XML = 1 - BINARY = 2 + XML: Final[int] = 1 + BINARY: Final[int] = 2 - SHIFT_JIS_LEGACY = "shift-jis-legacy" - SHIFT_JIS = "shift-jis" - EUC_JP = "euc-jp" - UTF_8 = "utf-8" - ASCII = "ascii" + SHIFT_JIS_LEGACY: Final[str] = "shift-jis-legacy" + SHIFT_JIS: Final[str] = "shift-jis" + EUC_JP: Final[str] = "euc-jp" + UTF_8: Final[str] = "utf-8" + ASCII: Final[str] = "ascii" def __init__(self) -> None: """ @@ -36,7 +36,7 @@ class EAmuseProtocol: self.last_text_encoding: Optional[str] = None self.last_packet_encoding: Optional[int] = None - def __rc4_crypt(self, data: bytes, key: bytes) -> bytes: + def _rc4_crypt(self, data: bytes, key: bytes) -> bytes: """ Given a data blob and a key blob, perform RC4 encryption/decryption. @@ -95,7 +95,7 @@ class EAmuseProtocol: if key: # This is an encrypted old-style packet - return self.__rc4_crypt(data, key) + return self._rc4_crypt(data, key) # No encryption return data diff --git a/bemani/protocol/xml.py b/bemani/protocol/xml.py index 2482063..d4878cc 100644 --- a/bemani/protocol/xml.py +++ b/bemani/protocol/xml.py @@ -1,6 +1,6 @@ import copy import struct -from typing import Any, Dict, Iterator, List, Optional, Tuple +from typing import Any, Dict, Final, Iterator, List, Optional, Tuple from bemani.protocol.stream import InputStream from bemani.protocol.node import Node @@ -468,7 +468,7 @@ class XmlEncoding: # The string values should match the constants in EAmuseProtocol. # I have no better way to link these than to write this comment, # as otherwise we would have a circular dependency. - ACCEPTED_ENCODINGS = ['shift-jis', 'euc-jp', 'utf-8', 'ascii'] + ACCEPTED_ENCODINGS: Final[List[str]] = ['shift-jis', 'euc-jp', 'utf-8', 'ascii'] def __init__(self) -> None: """ diff --git a/bemani/tests/helpers.py b/bemani/tests/helpers.py index 5a77daa..87b43fc 100644 --- a/bemani/tests/helpers.py +++ b/bemani/tests/helpers.py @@ -1,4 +1,5 @@ # vim: set fileencoding=utf-8 +import os import sys import unittest from typing import Container, List, Dict, Any @@ -32,3 +33,9 @@ class FakeCursor(): def fetchall(self) -> List[Dict[str, Any]]: return self.__rows + + +def get_fixture(name: str) -> bytes: + location = os.path.dirname(os.path.abspath(__file__)) + with open(os.path.join(location, name), "rb") as fp: + return fp.read() diff --git a/bemani/tests/test_AES.py b/bemani/tests/test_AES.py index 118e194..97c865b 100644 --- a/bemani/tests/test_AES.py +++ b/bemani/tests/test_AES.py @@ -8,14 +8,14 @@ class TestAESCipher(unittest.TestCase): def test_pad(self) -> None: aes = AESCipher('a wonderful key') - self.assertEqual(aes._AESCipher__pad(''), '0.--------------') - self.assertEqual(aes._AESCipher__unpad(aes._AESCipher__pad('')), '') - self.assertEqual(aes._AESCipher__pad('1337'), '4.1337----------') - self.assertEqual(aes._AESCipher__unpad(aes._AESCipher__pad('1337')), '1337') - self.assertEqual(aes._AESCipher__pad('aaaaaaaaaaaaaaaa'), '16.aaaaaaaaaaaaaaaa-------------') - self.assertEqual(aes._AESCipher__unpad(aes._AESCipher__pad('aaaaaaaaaaaaaaaa')), 'aaaaaaaaaaaaaaaa') - self.assertEqual(aes._AESCipher__pad('aaaaaaaaaaaaa'), '13.aaaaaaaaaaaaa') - self.assertEqual(aes._AESCipher__unpad(aes._AESCipher__pad('aaaaaaaaaaaaa')), 'aaaaaaaaaaaaa') + self.assertEqual(aes._pad(''), '0.--------------') + self.assertEqual(aes._unpad(aes._pad('')), '') + self.assertEqual(aes._pad('1337'), '4.1337----------') + self.assertEqual(aes._unpad(aes._pad('1337')), '1337') + self.assertEqual(aes._pad('aaaaaaaaaaaaaaaa'), '16.aaaaaaaaaaaaaaaa-------------') + self.assertEqual(aes._unpad(aes._pad('aaaaaaaaaaaaaaaa')), 'aaaaaaaaaaaaaaaa') + self.assertEqual(aes._pad('aaaaaaaaaaaaa'), '13.aaaaaaaaaaaaa') + self.assertEqual(aes._unpad(aes._pad('aaaaaaaaaaaaa')), 'aaaaaaaaaaaaa') def test_crypto(self) -> None: aes = AESCipher('a wonderful key') diff --git a/bemani/tests/test_CardCipher.py b/bemani/tests/test_CardCipher.py index d743353..fa62a3b 100644 --- a/bemani/tests/test_CardCipher.py +++ b/bemani/tests/test_CardCipher.py @@ -15,9 +15,9 @@ class TestCardCipher(unittest.TestCase): for pair in test_ciphers: inp = bytes(pair[0]) out = bytes(pair[1]) - encoded = CardCipher._CardCipher__encode(inp) # type: ignore + encoded = CardCipher._encode(inp) # type: ignore self.assertEqual(encoded, out, f"Card encode {encoded} doesn't match expected {out}") - decoded = CardCipher._CardCipher__decode(out) # type: ignore + decoded = CardCipher._decode(out) # type: ignore self.assertEqual(decoded, inp, f"Card decode {decoded} doesn't match expected {inp}") def test_external_cipher(self) -> None: diff --git a/bemani/tests/test_RC4.py b/bemani/tests/test_RC4.py index c5c3a3b..7ec2fc0 100644 --- a/bemani/tests/test_RC4.py +++ b/bemani/tests/test_RC4.py @@ -13,10 +13,10 @@ class TestRC4Cipher(unittest.TestCase): encrypted = b'\x04]Q\x11\x0cw\x7fO\xfa\x03\xa3\xdf\xb6\x02\xb7d\x9f\x13U\x19\xc9-j\x96\x15yl\x98\xee_<\xfa\x9b\x8f\xbe}\xf4\x05l5\x0e\xd6' proto = EAmuseProtocol() - cyphertext = proto._EAmuseProtocol__rc4_crypt(data, key) + cyphertext = proto._rc4_crypt(data, key) self.assertEqual(encrypted, cyphertext) - plaintext = proto._EAmuseProtocol__rc4_crypt(cyphertext, key) + plaintext = proto._rc4_crypt(cyphertext, key) self.assertEqual(data, plaintext) def test_small_data_random(self) -> None: @@ -24,10 +24,10 @@ class TestRC4Cipher(unittest.TestCase): key = bytes([random.randint(0, 255) for _ in range(16)]) proto = EAmuseProtocol() - cyphertext = proto._EAmuseProtocol__rc4_crypt(data, key) + cyphertext = proto._rc4_crypt(data, key) self.assertNotEqual(data, cyphertext) - plaintext = proto._EAmuseProtocol__rc4_crypt(cyphertext, key) + plaintext = proto._rc4_crypt(cyphertext, key) self.assertEqual(data, plaintext) def test_large_data_random(self) -> None: @@ -35,8 +35,8 @@ class TestRC4Cipher(unittest.TestCase): key = bytes([random.randint(0, 255) for _ in range(16)]) proto = EAmuseProtocol() - cyphertext = proto._EAmuseProtocol__rc4_crypt(data, key) + cyphertext = proto._rc4_crypt(data, key) self.assertNotEqual(data, cyphertext) - plaintext = proto._EAmuseProtocol__rc4_crypt(cyphertext, key) + plaintext = proto._rc4_crypt(cyphertext, key) self.assertEqual(data, plaintext) diff --git a/bemani/tests/test_lz77.py b/bemani/tests/test_lz77.py index e00139f..08b5818 100644 --- a/bemani/tests/test_lz77.py +++ b/bemani/tests/test_lz77.py @@ -4,6 +4,7 @@ import random import unittest from bemani.protocol.lz77 import Lz77, Lz77Decompress +from bemani.tests.helpers import get_fixture class TestLZ77Decompressor(unittest.TestCase): @@ -16,22 +17,16 @@ class TestLZ77Decompressor(unittest.TestCase): # Save our ring position, write a chunk of data readpos = dec.write_pos - dec._Lz77Decompress__ring_write(data) + dec._ring_write(data) # Read a chunk of data back from that buffer, see its the same - newdata = b''.join(dec._Lz77Decompress__ring_read(readpos, amount)) + newdata = b''.join(dec._ring_read(readpos, amount)) self.assertEqual(data, newdata) # Verify integrity of ringbuffer self.assertEqual(len(dec.ring), Lz77Decompress.RING_LENGTH) -def get_fixture(name: str) -> bytes: - location = os.path.dirname(os.path.abspath(__file__)) - with open(os.path.join(location, name), "rb") as fp: - return fp.read() - - class TestLz77RealCompressor(unittest.TestCase): def test_small_data_random(self) -> None: lz77 = Lz77()