diff pytouhou/formats/t6rp.py @ 188:008f90ebfdc0

Fix replay handling and add support for encrypted replays
author Thibaut Girka <thib@sitedethib.com>
date Thu, 27 Oct 2011 14:24:07 +0200
parents 46793ccfedca
children ba3297ab3bde
line wrap: on
line diff
--- a/pytouhou/formats/t6rp.py
+++ b/pytouhou/formats/t6rp.py
@@ -13,6 +13,9 @@
 ##
 
 from struct import unpack
+from io import BytesIO
+
+from pytouhou.utils.random import Random
 from pytouhou.utils.helpers import read_string
 
 from pytouhou.utils.helpers import get_logger
@@ -22,43 +25,70 @@ logger = get_logger(__name__)
 
 class Level(object):
     def __init__(self):
+        self.score = 0
+        self.random_seed = 0
+
+        self.power = 0
+        self.lives = 2
+        self.bombs = 3
+        self.difficulty = 16
         self.keys = []
 
 
 class T6RP(object):
     def __init__(self):
+        self.version = 0x102
+        self.character = 0
+        self.rank = 0
+        self.key = 0
         self.levels = []
 
 
     @classmethod
-    def read(cls, file):
+    def read(cls, file, decrypt=True, verify=True):
         if file.read(4) != b'T6RP':
             raise Exception
-        if file.read(2) != b'\x02\x01':
-            raise Exception
 
         replay = cls()
 
-        replay.character, replay.rank, checksum, unknown, key, unknown = unpack('<BBHIBB', file.read(10))
+        replay.version, replay.character, replay.rank = unpack('<HBB', file.read(4))
+        checksum, replay.unknown1, replay.unknown2, replay.key = unpack('<IBBB', file.read(7))
+
+        # Decrypt data
+        if decrypt:
+            decrypted_file = BytesIO()
+            file.seek(0)
+            decrypted_file.write(file.read(15))
+            decrypted_file.write(b''.join(chr((ord(c) - replay.key - 7*i) & 0xff) for i, c in enumerate(file.read())))
+            file = decrypted_file
+            file.seek(15)
+
+        # Verify checksum
+        if verify:
+            data = file.read()
+            file.seek(15)
+            if checksum != (sum(ord(c) for c in data) + 0x3f000318 + replay.key) & 0xffffffff:
+                raise Exception #TODO
+
+        replay.unknown3 = unpack('<B', file.read(1))
         replay.date = read_string(file, 9, 'ascii')
         replay.name = read_string(file, 9, 'ascii').rstrip()
-        unknown, replay.score, unknown, replay.slowdown, unknown = unpack('<HIIfI', file.read(18))
+        replay.unknown4, replay.score, replay.unknown5, replay.slowdown, replay.unknown6 = unpack('<HIIfI', file.read(18))
 
         stages_offsets = unpack('<7I', file.read(28))
 
         replay.levels = []
 
         for offset in stages_offsets:
-            replay.levels.append(None)
-
             if offset == 0:
                 continue
 
             level = Level()
-            replay.levels[-1] = level
+            replay.levels.append(level)
 
             file.seek(offset)
-            level.score, level.random_seed, unknown, level.power, level.lives, level.bombs, level.difficulty, unknown = unpack('<IHHBbbBI', file.read(16))
+            (level.score, level.random_seed, level.unknown1, level.power,
+             level.lives, level.bombs, level.difficulty, level.unknown2) = unpack('<IHHBbbBI', file.read(16))
 
             while True:
                 time, keys, unknown = unpack('<IHH', file.read(8))
@@ -66,5 +96,6 @@ class T6RP(object):
                 if time == 9999999:
                     break
 
-                level.keys.append((time, keys))
+                level.keys.append((time, keys, unknown))
 
+        return replay