annotate pytouhou/formats/score.py @ 377:70e2ed71b09c

Add meaningful exceptions in format parsing.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Wed, 29 Aug 2012 18:34:28 +0200
parents 5492472963b0
children d1f0bb0b7a17
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
292
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
1 # -*- encoding: utf-8 -*-
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
2 ##
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
3 ## Copyright (C) 2012 Thibaut Girka <thib@sitedethib.com>
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
4 ##
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
5 ## This program is free software; you can redistribute it and/or modify
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
6 ## it under the terms of the GNU General Public License as published
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
7 ## by the Free Software Foundation; version 3 only.
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
8 ##
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
9 ## This program is distributed in the hope that it will be useful,
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
10 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
11 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
12 ## GNU General Public License for more details.
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
13 ##
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
14
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
15
305
5492472963b0 Minor cleanup
Thibaut Girka <thib@sitedethib.com>
parents: 292
diff changeset
16 from struct import pack, unpack, Struct
292
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
17 from collections import namedtuple
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
18 from io import BytesIO
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
19
377
70e2ed71b09c Add meaningful exceptions in format parsing.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents: 305
diff changeset
20 from pytouhou.formats import ChecksumError
70e2ed71b09c Add meaningful exceptions in format parsing.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents: 305
diff changeset
21
292
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
22
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
23 class TH6Score(object):
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
24 entry_types = {
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
25 b'TH6K': (Struct('<I'),
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
26 namedtuple('TH6K', ('unknown',))),
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
27 b'HSCR': (Struct('<IIBBB8sx'),
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
28 namedtuple('HSCR', ('unknown', 'score', 'character',
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
29 'rank', 'stage', 'name'))),
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
30 b'PSCR': (Struct('<IIBBBx'),
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
31 namedtuple('PSCR', ('unknown', 'score', 'character',
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
32 'rank', 'stage'))),
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
33 b'CLRD': (Struct('<I5B5BBx'),
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
34 namedtuple('CLRD', ('unknown',
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
35 'easy', 'normal', 'hard', 'lunatic',
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
36 'extra',
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
37 'easy_continue', 'normal_continue',
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
38 'hard_continue', 'lunatic_continue',
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
39 'extra_continue',
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
40 'character'))),
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
41 b'CATK': (Struct('<I I HH I 34s H HH'),
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
42 namedtuple('CATK', ('unknown', 'unknown2', 'num',
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
43 'unknown3', 'padding',
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
44 'name', 'padding2',
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
45 'seen',
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
46 'defeated'))),
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
47 }
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
48
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
49 def __init__(self):
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
50 self.key1 = 0
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
51 self.key2 = 0
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
52 self.unknown1 = 0
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
53 self.unknown2 = 16
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
54 self.unknown3 = 0
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
55 self.unknown4 = 0
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
56 self.entries = []
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
57
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
58
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
59 @classmethod
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
60 def read(cls, file, decrypt=True, verify=True):
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
61 self = cls()
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
62
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
63 # Decrypt data
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
64 if decrypt:
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
65 decrypted_file = BytesIO()
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
66 decrypted_file.write(file.read(1))
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
67 key = 0
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
68 for c in file.read():
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
69 encrypted = ord(c)
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
70 key = ((key << 3) & 0xFF) | ((key >> 5) & 7)
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
71 clear = encrypted ^ key
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
72 key += clear
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
73 decrypted_file.write(chr(clear))
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
74 file = decrypted_file
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
75
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
76 # Read first-part header
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
77 file.seek(0)
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
78 self.unknown1, self.key1, checksum = unpack('<BBH', file.read(4))
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
79
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
80 # Verify checksum
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
81 if verify:
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
82 #TODO: is there more to it?
377
70e2ed71b09c Add meaningful exceptions in format parsing.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents: 305
diff changeset
83 real_sum = sum(ord(c) for c in file.read()) & 0xFFFF
70e2ed71b09c Add meaningful exceptions in format parsing.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents: 305
diff changeset
84 if checksum != real_sum:
70e2ed71b09c Add meaningful exceptions in format parsing.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents: 305
diff changeset
85 raise ChecksumError(checksum, real_sum)
292
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
86 file.seek(4)
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
87
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
88 # Read second-part header
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
89 data = unpack('<HBBIII', file.read(16))
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
90 self.unknown2, self.key2, self.unknown3, offset, self.unknown4, size = data
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
91
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
92 #TODO: verify size
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
93
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
94 # Read tags
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
95 file.seek(offset)
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
96 while True:
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
97 tag = file.read(4)
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
98 if not tag:
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
99 break
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
100 size, size2 = unpack('<HH', file.read(4))
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
101 assert size == size2
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
102 assert size >= 8
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
103 data = file.read(size-8)
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
104 data = cls.entry_types[tag][0].unpack(data)
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
105 data = cls.entry_types[tag][1](*data)
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
106 self.entries.append((tag, data))
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
107
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
108 return self
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
109
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
110
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
111 def write(self, file, encrypt=True):
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
112 if encrypt:
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
113 clearfile = BytesIO()
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
114 else:
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
115 clearfile = file
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
116
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
117 # Write data
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
118 clearfile.seek(20)
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
119 for entry in self.entries:
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
120 #TODO
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
121 tag, data = entry
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
122 format = TH6Score.entry_types[tag][0]
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
123 clearfile.write(tag)
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
124 clearfile.write(pack('<H', format.size + 8) * 2)
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
125 clearfile.write(format.pack(*data))
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
126
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
127 # Patch header
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
128 size = clearfile.tell()
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
129 clearfile.seek(0)
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
130 clearfile.write(pack('<BBHHBBIII',
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
131 self.unknown1, self.key1, 0, self.unknown2,
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
132 self.key2, self.unknown3, 20, self.unknown4,
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
133 size))
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
134
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
135 # Patch checksum
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
136 clearfile.seek(4)
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
137 checksum = sum(ord(c) for c in clearfile.read()) & 0xFFFF
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
138 clearfile.seek(2)
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
139 clearfile.write(pack('<H', checksum))
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
140
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
141 # Encrypt
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
142 if encrypt:
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
143 clearfile.seek(0)
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
144 file.write(clearfile.read(1))
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
145 key = 0
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
146 for c in clearfile.read():
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
147 clear = ord(c)
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
148 key = ((key << 3) & 0xFF) | ((key >> 5) & 7)
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
149 encrypted = clear ^ key
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
150 key += clear
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
151 file.write(chr(encrypted))
3a81b607f974 Add TH6 score.dat support.
Thibaut Girka <thib@sitedethib.com>
parents:
diff changeset
152