Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/python
- from __future__ import print_function, division
- import struct
- def read_int32(file):
- return struct.unpack("i", file.read(4))[0]
- def read_string(file, length):
- return file.read(length)
- def read_lengthstring(file):
- return read_string(file, read_int32(file))
- def convert_valuestring(file, offset, expectedname):
- # We'll want to return back to the point in the file we started from.
- restore = file.tell()
- rval = False # We use this to let the caller know if we did anything.
- file.seek(offset) # This should take us right to the start of the object.
- file.read(4) # Skip the total object length
- byte = file.read(1)
- if byte[0] != 1:
- print("Expected a byte of 0x01; got %r instead" % byte)
- length = file.read(1)[0]
- if length == 255: # Length is >= 255; need to read a 4-byte integer.
- length = read_int32(file)
- expectedlength = length - 4
- secondlength = read_int32(file)
- if not secondlength == expectedlength:
- print("[name] secondlength/expectedlength mismatch: got %d, expected "
- "%d" % (secondlength, expectedlength))
- name = read_string(file, secondlength)
- if not name == expectedname:
- print("name/expectedname mismatch: got %r, expected %r" %
- (name, expectedname))
- if file.read(1)[0] == 3:
- # This string needs converting.
- file.seek(-1, 1)
- file.write(b"\x02")
- length = file.read(1)[0]
- if length == 255:
- length = read_int32(file)
- expectedlength = length - 4
- secondlength = read_int32(file)
- if not secondlength == expectedlength:
- print("[string] secondlength/expectedlength mismatch: got %d, "
- "expected %d" % (secondlength, expectedlength))
- memory = file.tell() # We'll come back to here to convert.
- length = read_int32(file)
- if length > secondlength:
- print("[string] Unexpectedly long third length: %d (compared to"
- "%d)" % (length, secondlength))
- # We start getting characters now.
- chars = []
- length = secondlength - 4
- while length > 0:
- chars.append(file.read(1))
- length -= 1
- byte = file.read(1)
- if byte[0]:
- print("Unexpectedly non-null byte %r at %d bytes from the end "
- "of the string" % (byte, length))
- length -= 1
- if length < 0:
- print("Length ended up at %d" % length)
- # print("DEBUG: detected string: %r" % b"".join(chars))
- byte = file.read(1)
- if not byte[0] == 6:
- print("Expected a 0x06 byte at the end of the string; found %r "
- "instead." % byte)
- file.seek(memory)
- file.write(b"".join(chars))
- if not (chars and chars[-1] == 0): # If we didn't just write a null
- file.write(b"\0") # write one to make sure
- rval = True
- file.seek(restore)
- return rval
- def find_all_valuestrings(file):
- total = 0
- filetype = read_lengthstring(file)
- if not filetype == b"Diversions Entertainment Objects File2\0":
- print("Filetype did not match expectations: %r" % filetype)
- byte = file.read(1)
- if not byte[0] == 2:
- print("Expected 0x02 byte; got %r instead" % byte)
- byteseq = file.read(4)
- if not byteseq == b"\0\0\0\0":
- print("Expected 4 null bytes, got %r instead" % byteseq)
- endheader = read_int32(file) # Get the header length
- endheader += file.tell() # I want to know when I've exceeded it.
- byte = file.read(1)
- if not byte[0] == 9:
- print("Expected 0x09 byte; got %r instead" % byte)
- length = file.read(1)[0]
- if length == 255:
- length = read_int32(file)
- byte = file.read(1)
- if not byte[0] == 4:
- print("[header] Expected 0x04 byte; got %r instead" % byte)
- length = file.read(1)[0]
- if length == 255:
- length = read_int32(file)
- file.seek(length, 1) # Skip the rest of the header
- byte = file.read(1)
- if not byte[0] == 4:
- print("[predirectory] Expected 0x04 byte; got %r instead" % byte)
- byteseq = file.read(4)
- # if not byteseq == b"\0\0\0\0":
- # print("DEBUG: Any idea what %r means?" % byteseq)
- byte = file.read(1)
- if not byte[0] == 1:
- print("[predirectory] Expected 0x01 byte; got %r instead" % byte)
- length = file.read(1)[0]
- if length == 255:
- length = read_int32(file)
- file.seek(length, 1) # Skip the indecipherable blob
- file.read(4) # Can't do anything with this number yet.
- while file.tell() < endheader:
- byte = file.read(1)
- if not byte[0] == 4:
- if file.tell() < endheader: # We haven't left the directory yet
- print("[directory<] Expected 0x04 byte; got %r instead" % byte)
- else:
- if file.read(1)[0] == 255: # Skip directory entry length
- read_int32(file)
- name = read_lengthstring(file)
- objtype = read_lengthstring(file)
- file.read(16) # Skip the GUID
- byte = file.read(1)
- if byte[0]:
- print("[directory] Expected null byte; got %r instead" % byte)
- file.read(8) # Can't do anything with this yet.
- byte = file.read(1)
- if not byte[0] == 4:
- print("[directory>] Expected 0x04 byte; got %r instead" % byte)
- offset = read_int32(file)
- if objtype == b"Value\\String\0":
- # print("DEBUG: Trying to convert string named %r, located at "
- # "offset 0x%x" % (name, offset))
- if convert_valuestring(file, offset, name):
- total += 1
- # else:
- # print("DEBUG: Ignoring object of type %r" % (objtype))
- if not endheader == file.tell():
- print("endheader mismatch: %r, current offset %r" %
- (endheader, file.tell()))
- # print("DEBUG: These numbers should match: %r == %r" %
- # (endheader, file.tell()), end="...and they ")
- # if endheader == file.tell():
- # print("do.")
- # else:
- # print("don't!!!")
- return total
- if __name__ == "__main__":
- import sys
- if len(sys.argv) > 1:
- file_to_open = sys.argv[1]
- else:
- file_to_open = input("Filename:")
- with open(file_to_open, "r+b") as f:
- total = find_all_valuestrings(f)
- print("Converted %d string(s) to be v2172-compatible." % total)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement