Advertisement
MageKing17

convert_strings.py

Apr 26th, 2016
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.59 KB | None | 0 0
  1. #!/usr/bin/python
  2. from __future__ import print_function, division
  3.  
  4. import struct
  5.  
  6.  
  7. def read_int32(file):
  8.     return struct.unpack("i", file.read(4))[0]
  9.  
  10.  
  11. def read_string(file, length):
  12.     return file.read(length)
  13.  
  14.  
  15. def read_lengthstring(file):
  16.     return read_string(file, read_int32(file))
  17.  
  18.  
  19. def convert_valuestring(file, offset, expectedname):
  20.     # We'll want to return back to the point in the file we started from.
  21.     restore = file.tell()
  22.     rval = False    # We use this to let the caller know if we did anything.
  23.     file.seek(offset)   # This should take us right to the start of the object.
  24.     file.read(4)    # Skip the total object length
  25.     byte = file.read(1)
  26.     if byte[0] != 1:
  27.         print("Expected a byte of 0x01; got %r instead" % byte)
  28.     length = file.read(1)[0]
  29.     if length == 255:   # Length is >= 255; need to read a 4-byte integer.
  30.         length = read_int32(file)
  31.     expectedlength = length - 4
  32.     secondlength = read_int32(file)
  33.     if not secondlength == expectedlength:
  34.         print("[name] secondlength/expectedlength mismatch: got %d, expected "
  35.               "%d" % (secondlength, expectedlength))
  36.     name = read_string(file, secondlength)
  37.     if not name == expectedname:
  38.         print("name/expectedname mismatch: got %r, expected %r" %
  39.               (name, expectedname))
  40.     if file.read(1)[0] == 3:
  41.         # This string needs converting.
  42.         file.seek(-1, 1)
  43.         file.write(b"\x02")
  44.         length = file.read(1)[0]
  45.         if length == 255:
  46.             length = read_int32(file)
  47.         expectedlength = length - 4
  48.         secondlength = read_int32(file)
  49.         if not secondlength == expectedlength:
  50.             print("[string] secondlength/expectedlength mismatch: got %d, "
  51.                   "expected %d" % (secondlength, expectedlength))
  52.         memory = file.tell()    # We'll come back to here to convert.
  53.         length = read_int32(file)
  54.         if length > secondlength:
  55.             print("[string] Unexpectedly long third length: %d (compared to"
  56.                   "%d)" % (length, secondlength))
  57.         # We start getting characters now.
  58.         chars = []
  59.         length = secondlength - 4
  60.         while length > 0:
  61.             chars.append(file.read(1))
  62.             length -= 1
  63.             byte = file.read(1)
  64.             if byte[0]:
  65.                 print("Unexpectedly non-null byte %r at %d bytes from the end "
  66.                       "of the string" % (byte, length))
  67.             length -= 1
  68.         if length < 0:
  69.             print("Length ended up at %d" % length)
  70.         # print("DEBUG: detected string: %r" % b"".join(chars))
  71.         byte = file.read(1)
  72.         if not byte[0] == 6:
  73.             print("Expected a 0x06 byte at the end of the string; found %r "
  74.                   "instead." % byte)
  75.         file.seek(memory)
  76.         file.write(b"".join(chars))
  77.         if not (chars and chars[-1] == 0):   # If we didn't just write a null
  78.             file.write(b"\0")   # write one to make sure
  79.         rval = True
  80.     file.seek(restore)
  81.     return rval
  82.  
  83.  
  84. def find_all_valuestrings(file):
  85.     total = 0
  86.     filetype = read_lengthstring(file)
  87.     if not filetype == b"Diversions Entertainment Objects File2\0":
  88.         print("Filetype did not match expectations: %r" % filetype)
  89.     byte = file.read(1)
  90.     if not byte[0] == 2:
  91.         print("Expected 0x02 byte; got %r instead" % byte)
  92.     byteseq = file.read(4)
  93.     if not byteseq == b"\0\0\0\0":
  94.         print("Expected 4 null bytes, got %r instead" % byteseq)
  95.     endheader = read_int32(file)    # Get the header length
  96.     endheader += file.tell()    # I want to know when I've exceeded it.
  97.     byte = file.read(1)
  98.     if not byte[0] == 9:
  99.         print("Expected 0x09 byte; got %r instead" % byte)
  100.     length = file.read(1)[0]
  101.     if length == 255:
  102.         length = read_int32(file)
  103.     byte = file.read(1)
  104.     if not byte[0] == 4:
  105.         print("[header] Expected 0x04 byte; got %r instead" % byte)
  106.     length = file.read(1)[0]
  107.     if length == 255:
  108.         length = read_int32(file)
  109.     file.seek(length, 1)    # Skip the rest of the header
  110.     byte = file.read(1)
  111.     if not byte[0] == 4:
  112.         print("[predirectory] Expected 0x04 byte; got %r instead" % byte)
  113.     byteseq = file.read(4)
  114.     # if not byteseq == b"\0\0\0\0":
  115.     #     print("DEBUG: Any idea what %r means?" % byteseq)
  116.     byte = file.read(1)
  117.     if not byte[0] == 1:
  118.         print("[predirectory] Expected 0x01 byte; got %r instead" % byte)
  119.     length = file.read(1)[0]
  120.     if length == 255:
  121.         length = read_int32(file)
  122.     file.seek(length, 1)    # Skip the indecipherable blob
  123.     file.read(4)    # Can't do anything with this number yet.
  124.     while file.tell() < endheader:
  125.         byte = file.read(1)
  126.         if not byte[0] == 4:
  127.             if file.tell() < endheader:     # We haven't left the directory yet
  128.                 print("[directory<] Expected 0x04 byte; got %r instead" % byte)
  129.         else:
  130.             if file.read(1)[0] == 255:  # Skip directory entry length
  131.                 read_int32(file)
  132.             name = read_lengthstring(file)
  133.             objtype = read_lengthstring(file)
  134.             file.read(16)   # Skip the GUID
  135.             byte = file.read(1)
  136.             if byte[0]:
  137.                 print("[directory] Expected null byte; got %r instead" % byte)
  138.             file.read(8)    # Can't do anything with this yet.
  139.             byte = file.read(1)
  140.             if not byte[0] == 4:
  141.                 print("[directory>] Expected 0x04 byte; got %r instead" % byte)
  142.             offset = read_int32(file)
  143.             if objtype == b"Value\\String\0":
  144.                 # print("DEBUG: Trying to convert string named %r, located at "
  145.                 #       "offset 0x%x" % (name, offset))
  146.                 if convert_valuestring(file, offset, name):
  147.                     total += 1
  148.             # else:
  149.             #     print("DEBUG: Ignoring object of type %r" % (objtype))
  150.     if not endheader == file.tell():
  151.         print("endheader mismatch: %r, current offset %r" %
  152.               (endheader, file.tell()))
  153.     # print("DEBUG: These numbers should match: %r == %r" %
  154.     #       (endheader, file.tell()), end="...and they ")
  155.     # if endheader == file.tell():
  156.     #     print("do.")
  157.     # else:
  158.     #     print("don't!!!")
  159.     return total
  160.  
  161. if __name__ == "__main__":
  162.     import sys
  163.     if len(sys.argv) > 1:
  164.         file_to_open = sys.argv[1]
  165.     else:
  166.         file_to_open = input("Filename:")
  167.     with open(file_to_open, "r+b") as f:
  168.         total = find_all_valuestrings(f)
  169.     print("Converted %d string(s) to be v2172-compatible." % total)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement