Guest User

Untitled

a guest
Jul 19th, 2014
575
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. #Choose where you dumped the files and where to put the decoded audio:
  3. itextureDirectory   = r"F:\Symthic\BF4\Data\bf4 dump\bundles\res"
  4. targetDirectory = r"F:\Symthic\BF4\Data\bf4 dump\res"
  5.  
  6. ##itextureDirectory   = r"F:\Symthic\BF4\Data\bf4 dump\bundles\res"
  7. #These paths are relative to the dumpDirectory. They don't need to be changed.
  8. ##ebxFolder    = r"bundles\ebx" #files are not restricted to the Sound folder in bf4. As a result it will seem that the script does nothing for a while.
  9. resFolder    = r"bundles\res"
  10. chunkFolder  = r"F:\Symthic\BF4\Data\bf4 dump\chunks"
  11. chunkFolder2 = r"F:\Symthic\BF4\Data\bf4 dump\bundles\chunks" #if the chunk is not found in the first folder, use this one
  12.  
  13.  
  14. #There was a console game for Frostbite 2 in which the byte order of the chunk ids given in the ebx was changed a bit
  15. #so it did not match the ids in the chunk folders. See also http://www.bfeditor.org/forums/index.php?showtopic=15780&view=findpost&p=106500
  16. #Unless you know for sure that the ids are obfuscated, don't set this to True.
  17. ChunkIdObfuscation=True
  18. obfuscationPermutation=[3,2,1,0,5,4,7,6,8,9,10,11,12,13,14,15]
  19. EXTENSION=".itexture" #Use a different file extension if you like.
  20. #I'm at a loss as to what the fuck the devs were thinking. I wrote tools to decrypt the toc files (all credit to gibbed/Rick though for the algorithm),
  21. #then read in the decrypted data to split the sb into separate bundles, then read in the bundles to get the individual entries.
  22. #Then wrote like 6 different functions to retrieve the actual payload depending on whether it's patched or not, and using cas or not.
  23. #Then wrote a tool to deal with the binary XML/ebx files. Then hacked something together to decode the audio.
  24. #And they expected me to get that far, but stop at a simplistic permutation, which leaves the second half of the id intact?
  25. #I'll just leave this in, just in case another dev has a brilliant idea again.
  26.  
  27.  
  28.  
  29.  
  30.  
  31. ##############################################################
  32. ##############################################################
  33. from binascii import hexlify
  34. from struct import unpack,pack
  35. import os
  36. from cStringIO import StringIO
  37. import subprocess
  38. from ctypes import *
  39.  
  40. def makeLongDirs(path):
  41.     #create folders if necessary and return the file handle
  42.     #first of all, create one folder level manully because makedirs might fail
  43.     path=os.path.normpath(path)
  44.     pathParts=path.split("\\")
  45.     manualPart="\\".join(pathParts[:2])
  46.     if not os.path.isdir(manualPart): os.makedirs(manualPart)
  47.    
  48.     #now handle the rest, including extra long path names
  49.     folderPath=lp(os.path.dirname(path))
  50.     if not os.path.isdir(folderPath): os.makedirs(folderPath)
  51.    
  52.  
  53. def open2(path,mode="rb"):
  54.     if mode=="wb": makeLongDirs(path)
  55.     return open(lp(path),mode)
  56.  
  57. def lp(path): #long pathnames
  58.     if len(path)<=247 or path=="" or path[:4]=='\\\\?\\': return path
  59.     return unicode('\\\\?\\' + os.path.normpath(path))
  60.  
  61. class iTexture:
  62.     def __init__(self, f, relPath, newout):
  63.         #metadata
  64.         self.header=f.read(28)
  65.         self.ChunkId=f.read(16)
  66.         ##print "oldchunk  "+hexlify(self.ChunkId)
  67.         self.footer=f.read(84)
  68.        
  69.         f.close()
  70.        
  71.         chunkname=chunkFolder2+"\\"+(hexlify(self.ChunkId))+".chunk"
  72.         if os.path.isfile(chunkname):
  73.             raise ValueError("ChunkId is obfuscation FALSE: ")
  74.         chunkname2=chunkFolder+"\\"+(hexlify(self.ChunkId))+".chunk"
  75.         if os.path.isfile(chunkname2):
  76.             raise ValueError("ChunkId is obfuscation FALSE: ")
  77.         else:
  78.             print newout[:-58]+ " is missing chunk"
  79.  
  80.     def decode(self, relPath, newout):
  81.         if ChunkIdObfuscation: self.ChunkId="".join([self.ChunkId[permute] for permute in obfuscationPermutation])
  82.         ##print "newchunk  "+hexlify(self.ChunkId)
  83.  
  84.         outName=newout
  85.         ##outName=targetDirectory+relPath+EXTENSION
  86.  
  87.         f2=open2(outName,"wb")
  88.         f2.write(self.header+self.ChunkId+self.footer)
  89.         f2.close()
  90.         print "replaced"
  91.        
  92.  
  93. #make the paths absolute and normalize the slashes
  94. targetDirectory=os.path.normpath(targetDirectory) #it's an absolute path already
  95.  
  96. def main():
  97.     for dir0, dirs, ff in os.walk(itextureDirectory):
  98.         for fname in ff:
  99.             if fname[-9:]!=".itexture": continue
  100.             absPath=os.path.join(dir0,fname)
  101.             relPath=absPath[len(itextureDirectory):-9]
  102.            
  103.             f=open(lp(absPath),"rb")
  104.             newout=absPath
  105.             try:
  106.                 itexture=iTexture(f, relPath, newout)
  107.                 f.close()
  108.             except ValueError as msg:
  109.                 f.close()
  110.                 if str(msg).startswith("ChunkId is obfuscation FALSE: "):
  111.                     continue
  112.                 else: asdf
  113.             itexture.decode(relPath, newout)
  114.  
  115.  
  116. main()
RAW Paste Data