import struct class SaveReader: def __init__(self, filename): self.successful = False try: file = open(filename, 'rb').read() pointer = 13 pointer += file[pointer] +1 if file[pointer] != 0x65: print("Error interpreting file - missed first marker.") return pointer += 1 while (file[pointer] != 1 or file[pointer+1] != 1 or file[pointer+2] != 5 or file[pointer+3] != 11): #In observed files this should advance two or three bytes. pointer += 1 #Actually have a decent idea how to tell if it's going to be two or three bytes (it seems to be a number in the continuation bit + 7-bit int format). #But this is a good check that the format is reading as expected. pointer += 4 pointer += file[pointer]+1 #generally skipping two or three bytes if file[pointer] == 0x20: self.switches = () pointer += 2 elif file[pointer] == 0x1F: pointer += 1 fieldlen = file[pointer] if (fieldlen == 1): switchlen = file[pointer+1]%128 elif (fieldlen == 2): switchlen = (file[pointer+1]%128)*128+(file[pointer+2]%128) pointer += fieldlen*2+2 self.switches = [file[i] for i in range(pointer, pointer+switchlen)] pointer += switchlen else: print ("Error interpreting file - missed switch-start marker.") return if file[pointer] == 0x22: self.variables = () self.successful = True return elif file[pointer] == 0x21: pointer += 1 pointer += file[pointer]+1 if file[pointer] != 0x22: print("Error interpreting file - variable-start marker not understood.") return pointer += 1 varbytes = file[pointer]%128 while (file[pointer] // 128 == 1): varbytes *= 128 pointer += 1 varbytes += file[pointer]%128 #The switch array header and variable array header have similar formats: #(marker byte) (number of bytes next number takes up) (number of switches or variables, in continuation-bit + 7-bit format) (marker byte) (number of bytes in following byte array). #It's just that switches are 1 byte and vars are 4 (little-endian). #And I didn't have the difference fully down until I'd already written the switch interpreter. pointer += 1 self.variables = [struct.unpack(' len(self.switches): return 0 #2k(3) doesn't necessarily save all the switches or variables if they haven't been used yet. else: return self.switches[num-1] #In-editor labeling of switches starts at 1, not 0. #Variables that haven't been used or allocated default to 0. def variable(self, num): if not self.successful: print("File read did not complete, don't ask for vars.") raise AssertionError if num <= 0: print("Vars start at 1.") raise AssertionError if num > len(self.variables): return 0 #2k(3) doesn't necessarily save all the switches or variables if they haven't been used yet. else: return self.variables[num-1] #In-editor labeling starts at 1, not 0.