#! /usr/bin/perl -w

# Read the "monster.sou" from a SCUMM game, and split it in to seperate
# sound files.  It will be broken in to many Creative Labs VOC files.

# The mounster.sou file contains an eight byte file header of unknown
# meaning, then multiple sound entries.  Each sound entry is a ten byte
# header of unknown meaning, then a VOC file.

# A VOC file is the string "Creative Voice File" followed by seven unknwon
# bytes, a single file type byte which must be 0x01, three bytes of file
# size, which are stored LSB, middle, MSB, and then that many bytes of data.

# This is copyright (C) 2001, Louis W. Erickson.  All rights reserved.

# Create a place to put them all.
mkdir "explode"; # I deliberately don't care if it fails.

# The name for the file we're extracting.
my $id = 0;

# Open the file.
open (INPUT, "monster.sou") or die "Can't read monster.sou $!";

# Skip the file header
sysseek(INPUT, 8, 0);

while(splitVOC($id, *INPUT))
{
	$id++;
}

my $pos = sysseek(INPUT, 0, 1);
print "Processed $pos bytes, split in to $id files\n";

close INPUT;

# Read a VOC chunk
sub splitVOC
{
	my ($id, $input) = @_;
	my $bytes = 0;
	my $buffer = 0;
	my $length = 0;
	my $filename = 0;

	print "Extracting VOC $id.";

	# Skip unknown 10 byte header
	$bytes = sysread($input, $buffer, 10, 0);
	if($bytes != 10)
	{
		print " - Not enough bytes at unknown header.\n";
		return 0;
	}
	print ".";

	# Read VOC header information - label, extra, type and size
	$bytes = sysread($input, $buffer, 30, 0);
	if($bytes != 30)
	{
		print " - Not enough bytes at VOC header. $!\n";
		return 0;
	}
	print ".";

	# Validate data.
	if(substr($buffer, 0, 19) ne "Creative Voice File")
	{
		print " - No Creative Voice File signature.\n";
		print "Got: " . substr($buffer, 0, 19) . "\n";
		return 0;
	}
	print ".";

	if(ord(substr($buffer, 26, 1)) ne 0x01)
	{
		print " - Not file type 1.\n";
		return 0;
	}
	print ".";

	# Extract length.
	$length = (ord(substr($buffer, 29, 1)) * 0x10000);
	$length += (ord(substr($buffer, 28, 1)) * 0x100);
	$length += ord(substr($buffer, 27, 1));

	# Knowing what we now know, we can probably extract a file!

	$filename = sprintf("explode/%04.04d.voc", $id);
	open (OUTPUT, ">$filename") or die "Can't write $filename $!";
	print ".";

	# Write the header we already have
	$bytes = syswrite(OUTPUT, $buffer, 30);
	if($bytes != 30)
	{
		print " - Can't write header. $!\n";
		return 0;
	}
	print ".";

	# Read the rest of the bytes
	$bytes = sysread($input, $buffer, $length, 0);
	if($bytes != $length)
	{
		print " - Can't read enough data. $!\n";
		return 0;
	}
	print ".";

	# Save them off.
	$bytes = syswrite(OUTPUT, $buffer, $length);
	if($bytes != $length)
	{
		print " - Can't write enough data. $!\n";
		return 0;
	}
	print ".";

	close OUTPUT;

	# Skip the trailing null
	$bytes = sysread($input, $buffer, 1, 0);
	if($bytes != 1)
	{
		print " - Can't skip trailing null.\n";
		return 0;
	}
	print ".";

	print ". ok.\n";
	return 1;
}



