#!/usr/bin/env python # Cross+Channel .PD archive extraction tool # # Extracts a .PD archive to a directory of files. Handles both the # PackOnly and the PackPlus formats. # # Last modified 2006-06-12, Edward Keyes, ed-at-insani-dot-org import sys, os from array import array from insani import * if len(sys.argv) != 3 : print 'Please give a Cross+Channel archive filename and a desired'+ \ ' destination\ndirectory on the command line.' sys.exit(0) arcfile=open(sys.argv[1],'rb') filesize=os.stat(sys.argv[1]).st_size dirname=sys.argv[2] if not os.path.isdir(dirname) : # Skip creation if directory already exists os.mkdir(dirname) signature = arcfile.read(8) if signature == 'PackOnly' : xorbyte = 0 elif signature == 'PackPlus' : xorbyte = 0x00FF else : print 'Unknown file signature %s, aborting.' % \ escape_string(signature) sys.exit(0) assert_zeroes(arcfile,56,ERROR_WARNING) numfiles = read_unsigned(arcfile,LONG_LENGTH) print 'Extracting %d files...' % numfiles assert (numfiles <= 16384) entries = [] print 'Reading archive index...' for i in xrange(numfiles) : filename = read_string(arcfile) assert_zeroes(arcfile,128-len(filename)-1) position = read_unsigned(arcfile,LONG_LENGTH) assert (position <= filesize) size = read_unsigned(arcfile,LONG_LENGTH) assert (position + size <= filesize) entries.append( (filename, position, size) ) assert_zeroes(arcfile,144*(16384-numfiles),ERROR_WARNING) totalsize = arcfile.tell() for (filename, position, size) in entries : print 'Extracting %s (%d bytes) from offset 0x%X' % \ (filename, size, position) outfile=open(os.path.join(dirname,filename),'wb') arcfile.seek(position) data = array('B',arcfile.read(size)) if xorbyte!=0 : for i in xrange(len(data)) : data[i] ^= xorbyte outfile.write(data.tostring()) totalsize += size outfile.close() if (totalsize != filesize) : print "Missed extracting %d bytes!" % filesize-totalsize arcfile.close()