duskwolf Trick Member
  
 
  Joined: 04 Oct 2006
  | 
		
			
				0.  Posted: Tue Nov 14, 2006 2:44 am    Post subject: ITG packer | 
				      | 
			 
			
				
  | 
			 
			
				Went ahead and got myself a copy of ITG. So the question came up: How could one create those PCK files? Tacking data on the end didn't work: an error message comes up describing the file as "corrupted" and suggesting that I reinstall. So a little bit more subtlety is required. Not much, though...
 
 
 	  | Code: | 	 		  #!/usr/bin/python
 
import struct, sys, zlib, os
 
 
def main(args):
 
  if len(args) not in (4, 5):
 
    print "Usage: [python] itgpack.py itg-file.pck input-directory identifier [padding size]"
 
    sys.exit(1)
 
  
 
  files = []
 
  for dirpath, dirnames, filenames in os.walk(args[2]):
 
    for filename in filenames:
 
      if filename[0] == '.':
 
        continue # skip dotfiles
 
      abspath = os.path.join(dirpath, filename)
 
      files.append((abspath,
 
                    abspath.split(os.path.sep, 1)[1],
 
                    os.stat(abspath).st_size))
 
 
  outf = file(args[1], "w")
 
  outf.write(struct.pack("< 4s 128s L", "PCKF", args[3], len(files)))
 
  header_offset = outf.tell()
 
 
  # Write a preliminary header - leave offsets and sizes zero
 
  print "Scanning...",
 
  for abspath, pckpath, filesize in files:
 
    outf.write(struct.pack("<LLLLL", 0, 0, 0, len(pckpath), 0))
 
    outf.write(pckpath)
 
 
  print "Writing files..."
 
  offsets = []
 
  # Start writing results
 
  for abspath, pckpath, filesize in files:
 
    data = file(abspath, "r").read()
 
    cdata = zlib.compress(data, 9)[2:] # wtfwtfwtfwtfwtf
 
    offset = outf.tell()
 
    outf.write(cdata)
 
    offsets.append((offset, len(cdata)))
 
    print "  " + pckpath
 
  eof_offset = outf.tell()
 
 
  print "Tidying up...",
 
  # Go back and fix the header
 
  outf.seek(header_offset)
 
  for (abspath, pckpath, filesize), (offset, datasize) in zip(files, offsets):
 
    outf.write(struct.pack("<LLLLL",
 
      datasize, filesize, offset, len(pckpath), 1))
 
    outf.write(pckpath)
 
 
  # sanity check
 
  if outf.tell() != offsets[0][0]:
 
    print "Augh. Header changed size. This is bad."
 
    sys.exit(1)
 
 
  if len(args) == 5:
 
    padlen = int(args[4])
 
    if padlen < eof_offset:
 
      print "Padding failed. Delete something."
 
      sys.exit(1)
 
    outf.seek(eof_offset)
 
    padding = padlen - eof_offset
 
    while padding > 0:
 
      padnum = min(padding, 1024)
 
      padding -= padnum
 
      outf.write("\0" * padnum)
 
    print "Written with %d bytes slack space." % (padlen - eof_offset)
 
 
  print "OK, done. Enjoy."
 
 
main(sys.argv) | 	  
 
 
First argument is the name of a file to pack into. Second argument is the path to a directory containing the ITG virtual directory structure to be packed (the parent of the Themes directory, for example). Third argument is the package identifier, which appears to be ignored by ITG, and fourth argument is the length of the file to pack to.
 
 
This fourth argument is critical. It must be the same as the length (in bytes) of the file that's to be replaced! ITG checks PCK files for validity simply by looking at their length. There may be some relation between the package name and the length; however, it isn't obvious to me at this point. Fortunately, my packer seems to generate slightly smaller PCKs than the tool used by Roxor, so this isn't a big problem - on basepatch/DDF0C003.PCK, it ended up with around 14 KB of slack space (on a 240 KB file). This is plenty for script tweaks, for example.
 
 
This tool probably won't work very well for packing songs - I built it specifically to do some theme tweaking, and that's what it's best at. It wouldn't be hard to make it selectively disable compression, so I'll leave that as an exercise for the reader. | 
			 
		  |