#!/usr/bin/env python

# Cross+Channel .PD archive extraction tool
#
#   Extracts a .PD archive to a directory of files.
#
# Last modified 2006-06-12, Edward Keyes, ed-at-insani-dot-org

import sys, os
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)

assert_string(arcfile,'PackOnly',ERROR_ABORT)
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)
   outfile.write(arcfile.read(size))
   totalsize += size
   outfile.close()

if (totalsize != filesize) :
   print "Missed extracting %d bytes!" % filesize-totalsize
arcfile.close()

