Advertisement
Guest User

QB Bulk Script Dumper v1

a guest
Nov 19th, 2015
161
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.02 KB | None | 0 0
  1. #How to use
  2. #Need shared.bin in the same folder as this tool and run. That's it.
  3.  
  4. import struct
  5. import zlib
  6.  
  7. ARCHIVE_TOC_POS = 0x17da00
  8.  
  9. def I(f, offset = -1):                  #Function is supposed to unpack a 32-bit integer from a file-like object or from a bytes-like object
  10.     if hasattr(f, 'read'):              #File-like object
  11.         if offset == -1:                #If no 2nd parameter
  12.             return struct.unpack('<I', f.read(4))[0]    #Read data at current position
  13.         else:                           #2nd parameter was specified
  14.             origpos = f.tell()          #Save original position
  15.             f.seek(offset)              #Go to specified position
  16.             val = struct.unpack('<I', f.read(4))[0]     #Read data
  17.             f.seek(origpos)             #Go back to original position
  18.             return val
  19.     elif isinstance(f, bytes):          #Bytes-like object
  20.         if len(f[offset:offset+4]) != 4:                #Checking for EOF error
  21.             raise Exception('Not enough data in file.')
  22.         return struct.unpack('<I', f[offset:offset+4])[0]   #Unpack data
  23.     else:                               #Not a file or bytes object
  24.         raise Exception('Unknown object type.')
  25.  
  26. ptrs1 = []                              #Archive TOC data container
  27. with open('shared.orig','rb') as f:    
  28.     #Stores the archive TOC data
  29.     f.seek(ARCHIVE_TOC_POS + 4)         #Go to entry for # of files
  30.     num_of_files = I(f)
  31.     for x in range(num_of_files):       #Read TOC entries
  32.         offset = I(f)                   #Offset 1st
  33.         f.seek(4, 1)                    #We don't care about unzipped size (so seek past it)
  34.         size = I(f)                     #Zipped size last
  35.         ptrs1.append((offset, size))
  36.  
  37.     #This is the part that unpacks each file
  38.     for i, (offset, size) in enumerate(ptrs1):      #Loop over the list of TOC data
  39.                                                     #The offset and the zipped size are stored in the TOC data
  40.         f.seek(ARCHIVE_TOC_POS + offset)            #Go to data position
  41.         filedata = zlib.decompress(f.read(size))    #Decompress data
  42.         #The rest of these steps work with the decompressed data    
  43.         num_of_pointers = I(filedata, 0x38)         #How many strings are in the file
  44.         text_addr = I(filedata, 0x4c)               #Where is the text located
  45.         pos = I(filedata, 0x44)                     #Where is the text TOC located
  46.         ptrs2 = []                          #Container for text TOC data
  47.         for x in range(num_of_pointers):    #Repeat for as many times as there are strings in the text data
  48.             ptrs2.append(I(filedata, pos))  #Save the pointer
  49.             pos += 4                        
  50.         filedata = filedata[text_addr:]     #Cut off everything that isn't the text
  51.                                             #Pointers are relative to start of text
  52.  
  53.         output = []                         #Container for outputted data
  54.         for ptr in ptrs2:                   #For each string pointer
  55.             output.append(hex(ptr) + '\t')  #Store position to output
  56.             s = filedata[ptr:filedata.find(b'\x00',ptr)].decode('cp932')    #Get the string
  57.             lines = s.split('@')            #Split by @ which is the game substring marker
  58.             output.append(lines.pop(0) + '\t')  #Add the "name" info (really 1st substring)
  59.             for line in lines:              #For each line, add it to the output
  60.                 output.append(line + '\n\t\t')
  61.             if len(lines) == 0:             #Special case where there is only one line
  62.                 output.append('\n')
  63.             else:                           #Delete extra tabs from "output.append(line + '\n\t\t')"
  64.                 output[-1] = output[-1][:-2]
  65.  
  66.         #This outputs the text
  67.         filename = '{:0>3d}'.format(i)      #Formats the "file number" like 000, 001, etc...
  68.         with open(filename + '.tsv','wb') as g:
  69.             for x in output:
  70.                 g.write(x.encode('cp932'))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement