My favorites | Sign in
Project Home Source
Checkout   Browse   Changes    
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#!/usr/bin/python

#
# d2checksum.py - (c) 2010 mauvehead
#
# The file is a simple PoC for calculating the checksum of a Diablo II saved game file
#
# Because python does not have MAXINT in the way C does, additional bitwise operations
# are needed to ensure only the required bits are being kept from each bitshift
#
# Options:
# -h, --help show this help message and exit
# -b, --bytes print the contents of the file byte by byte
# -d, --debug displays additional output on the checksum processing
# -s, --slow decreases output refresh to 1 second intervals, used
# with --debug
# -x, --expand expand the checksum output to show every cycle of
# processing, used with --debug
# -f FILE, --filename=FILE
# path to the character file
#


import os
import sys
import time
from optparse import OptionParser

prog = sys.argv[0]

def usage():
usage = "usage: %s [-h] [options] -f filename" % prog
return usage


def getArgs():
parser = OptionParser(usage=usage())

if len(sys.argv) <= 1:
parser.error("you must specify at least a filename with -f, see --help for more details")

parser.add_option("-b", "--bytes", action="store_const", const="1", dest="bytes",
help="print the contents of the file byte by byte")
parser.add_option("-d", "--debug", action="store_const", const="1", dest="debug",
help="displays additional output on the checksum processing")
parser.add_option("-s", "--slow", action="store_const", const="1", dest="slow",
help="decreases output refresh to 1 second intervals, used with --debug")
parser.add_option("-x", "--expand", action="store_const", const="1", dest="expand",
help="expand the checksum output to show every cycle of processing, used with --debug")
parser.add_option("-f", "--filename", action="store", dest="filename", default="NONE",
help="path to the character file")

(options, args) = parser.parse_args()

if options.filename == "NONE":
parser.error("you must specify at least a filename with -f, see --help for more details")

return options


def printBinary(num):
binary = ''
i = 31
for i in range(31,-1,-1):
if(num & (1 << i)):
binary += "1"
else:
binary += "0"
return binary


def calculateChecksum(options, filedata, filesize):
checksum = i = 0

if len(filedata) >= 15:
for index in range(12,16,1):
filedata[index] = 0

for byte in filedata:
if options.debug == '1':
print "\n\n1) number preshift: %d" % checksum
print "1) checksum preshift: %s" % printBinary(checksum)

checksum = (checksum << 1) & 0xfffffffe | (checksum >> 31)

if(options.debug == '1'):
print "\n2) number postshift: %d" % checksum
print "2) checksum postshift: %s" % printBinary(checksum)

checksum = (checksum + byte) & 0xffffffff

if options.debug == '1':
print "\n3) now add byte[%d]: 0x%X" % (i, byte)
print "3) which is dec: %d" % byte
print "\n4) number post fileadd: %d" % checksum
print "4) checksum post fileadd: %s\n" % printBinary(checksum)
if(options.slow == '1'):
time.sleep(1)
if((options.expand != '1') and (i < (filesize - 1))):
os.system("clear")
i += 1
if options.debug == '1':
print "5) number after loop: %d" % checksum
print "5) checksum after loop: %s" % printBinary(checksum)
print ""
return checksum


def readFile(filename, filesize):
filedata = []
f = open(filename,'rb')
try:
header = f.read(4)
if header.encode("hex") != "55aa55aa":
print "%s: error: header on %s does not match known DiabloII header: invalid file" % (prog,filename)
sys.exit(1)
f.seek(0)
ch = f.read(1)
while ch:
filedata.append(ord(ch))
ch = f.read(1)
finally:
f.close()
return filedata


def printBytes(filedata):
i = 0

for byte in filedata:
print "byte[%d]: %x" % (i, byte)
i += 1
sys.exit(0)


def getFilesize(filename):
if os.path.isfile(filename):
filesize = os.path.getsize(filename)
else:
print "%s: error: unable to open file: %s" % (prog,filename)
sys.exit(1)
return filesize


def main():
options = getArgs()
filesize = getFilesize(options.filename)
filedata = readFile(options.filename, filesize)

if options.bytes == '1':
printBytes(filedata)

checksum = calculateChecksum(options, filedata, filesize)

print "Checksum hex: 0x%X" % checksum
return 0


# RUN MAIN()
if __name__ == "__main__":
main()

Change log

r7 by mauvehead on Jun 3, 2010   Diff
dynamic allocation of program name from
argv
Go to: 
Project members, sign in to write a code review

Older revisions

r6 by mauvehead on Jun 3, 2010   Diff
minor cleanup on debugging prints
r5 by mauvehead on Jun 2, 2010   Diff
uneeded struct import
r4 by mauvehead on Jun 2, 2010   Diff
initial checkin for d2checksum PoC
All revisions of this file

File info

Size: 5100 bytes, 162 lines

File properties

svn:executable
*
Powered by Google Project Hosting