Blame extresso/extresso.in

Packit 6e6f77
#! /usr/bin/perl -w
Packit 6e6f77
#
Packit 6e6f77
# extresso - Extract and convert resources using resource scripts
Packit 6e6f77
#
Packit 6e6f77
# Copyright (C) 1998-2005 Oskar Liljeblad
Packit 6e6f77
#
Packit 6e6f77
# This program is free software; you can redistribute it and/or modify
Packit 6e6f77
# it under the terms of the GNU General Public License as published by
Packit 6e6f77
# the Free Software Foundation; either version 2 of the License, or
Packit 6e6f77
# (at your option) any later version.
Packit 6e6f77
#
Packit 6e6f77
# This program is distributed in the hope that it will be useful,
Packit 6e6f77
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6e6f77
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 6e6f77
# GNU General Public License for more details.
Packit 6e6f77
#
Packit 6e6f77
# You should have received a copy of the GNU General Public License
Packit 6e6f77
# along with this program; if not, write to the Free Software Foundation,
Packit 6e6f77
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
Packit 6e6f77
#
Packit 6e6f77
Packit 6e6f77
use Getopt::Long;
Packit 6e6f77
use File::Spec;
Packit 6e6f77
use File::Basename;
Packit 6e6f77
use Term::ReadLine;
Packit 6e6f77
use LWP::Simple;
Packit 6e6f77
use HTTP::Status;
Packit 6e6f77
Packit 6e6f77
# global stuff
Packit 6e6f77
$PROGRAM = 'extresso';
Packit 6e6f77
Packit 6e6f77
$path_icotool = &path_or('icotool','../icotool/icotool');
Packit 6e6f77
$path_w32rtool = &path_or('wrestool','../wrestool/wrestool');
Packit 6e6f77
$path_tmpfile = 'extresso.fetch.tmp';
Packit 6e6f77
$tmpfile_exists = 0;
Packit 6e6f77
Packit 6e6f77
# initialize options
Packit 6e6f77
$arg_output = '.';
Packit 6e6f77
$arg_format = undef;
Packit 6e6f77
$arg_base = undef;
Packit 6e6f77
$arg_match = undef;
Packit 6e6f77
$arg_interactive = 0;
Packit 6e6f77
$arg_verbose = 0;
Packit 6e6f77
$arg_help = $arg_version = 0;
Packit 6e6f77
Packit 6e6f77
# get options
Packit 6e6f77
exit 1 if (!GetOptions("o|output=s"		=> \$arg_output,
Packit 6e6f77
                       "format=s"   		=> \$arg_format,
Packit 6e6f77
		       "b|base=s"   		=> \$arg_base,
Packit 6e6f77
                       "m|match=s"  		=> \$arg_match,
Packit 6e6f77
                       "i|interactive"	=> \$arg_interactive,
Packit 6e6f77
         	       "v|verbose"     => \$arg_verbose,
Packit 6e6f77
                       "help"          => \$arg_help,
Packit 6e6f77
                       "version"       => \$arg_version));
Packit 6e6f77
Packit 6e6f77
# deal with standard options
Packit 6e6f77
if ($arg_help) {
Packit 6e6f77
	print "Usage: extresso [OPTION]... [FILE]...\n";
Packit 6e6f77
	print "Extract and convert resources using resource scripts.\n";
Packit 6e6f77
	print "\n";
Packit 6e6f77
	print " -o, --output=DIR     where to place extracted files (default `.')\n";
Packit 6e6f77
	print "     --format=FORMAT  extraction format of icon resources (see icotool)\n";
Packit 6e6f77
	print " -b, --base=DIR       base directory of local files in scripts\n";
Packit 6e6f77
#	print " -m, --match=REGEXP   extract only from binaries whose name match this\n";
Packit 6e6f77
	print " -i, --interactive    prompt before extraction\n";
Packit 6e6f77
	print " -v, --verbose        explain what is being done\n";
Packit 6e6f77
	print "     --help           display this help and exit\n";
Packit 6e6f77
	print "     --version        output version information and exit\n";
Packit 6e6f77
  print "\n";
Packit 6e6f77
	print 'Report bugs to <@PACKAGE_BUGREPORT@>', "\n";
Packit 6e6f77
	exit;
Packit 6e6f77
}
Packit 6e6f77
if ($arg_version) {
Packit 6e6f77
	print "$PROGRAM (@PACKAGE@) @VERSION@\n";
Packit 6e6f77
	print "Written by Oskar Liljeblad.\n\n";
Packit 6e6f77
	print "Copyright (C) 1998-2005 Oskar Liljeblad.\n";
Packit 6e6f77
	print "This is free software; see the source for copying conditions.  There is NO\n";
Packit 6e6f77
	print "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n";
Packit 6e6f77
	exit;
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
# got no arguments?
Packit 6e6f77
if ($#ARGV == -1) {
Packit 6e6f77
	print STDERR "$PROGRAM: missing file argument\n";
Packit 6e6f77
	print STDERR "Try `$PROGRAM --help' for more information.\n"
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
# initialize objects if necessary
Packit 6e6f77
$obj_term = new Term::ReadLine 'extresso' if ($arg_interactive);
Packit 6e6f77
Packit 6e6f77
# process each non-option argument
Packit 6e6f77
for ($c = 0 ; $c <= $#ARGV ; $c++) {
Packit 6e6f77
	print STDERR "Processing $ARGV[$c]\n" if $arg_verbose;
Packit 6e6f77
	&process_script($ARGV[$c]);
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
#
Packit 6e6f77
# Subroutines
Packit 6e6f77
#
Packit 6e6f77
sub process_script {
Packit 6e6f77
	my ($file) = @_;
Packit 6e6f77
Packit 6e6f77
	# open the file
Packit 6e6f77
	die "$PROGRAM: $file: $!\n" if (!open(FH, $file));
Packit 6e6f77
Packit 6e6f77
	# variable initializations
Packit 6e6f77
	my ($line, $keyword, $param);
Packit 6e6f77
Packit 6e6f77
	my ($current_file) = undef;							# name of current resource achive
Packit 6e6f77
	my ($process_file) = 1;									# how to process resource archives
Packit 6e6f77
	my ($always_process_file) = undef;			# true if process_file should not be changed
Packit 6e6f77
	my ($process_resource) = 1;							# how to process a resource
Packit 6e6f77
	my ($always_process_resource) = undef;	# true if process_resource should not be changed
Packit 6e6f77
Packit 6e6f77
	# read each line
Packit 6e6f77
	while (defined ($line = <FH>)) {
Packit 6e6f77
		# strip leading and trailing whitespace
Packit 6e6f77
		$line =~ s/^\s*(\S?.*?\S?)\s*$/$1/;
Packit 6e6f77
Packit 6e6f77
		# skip empty lines and comments
Packit 6e6f77
		next if ($line eq '' || $line =~ /^#/);
Packit 6e6f77
Packit 6e6f77
		# split line into keyword and parameters
Packit 6e6f77
		($keyword,$param) = ($line =~ /^(\S*)\s*(.*)?$/);
Packit 6e6f77
		next if (!defined $keyword || $keyword eq '');
Packit 6e6f77
Packit 6e6f77
		# check parameter
Packit 6e6f77
		next if &check_missing($file, $keyword, $param);
Packit 6e6f77
Packit 6e6f77
		# version keyword
Packit 6e6f77
		if ($keyword eq 'version') {
Packit 6e6f77
			if ($param > 1) {
Packit 6e6f77
				warn "$file: resource script version `$param' not supported\n";
Packit 6e6f77
				return;
Packit 6e6f77
			}
Packit 6e6f77
		}
Packit 6e6f77
		# archive keyword
Packit 6e6f77
		elsif ($keyword eq 'file') {
Packit 6e6f77
			$current_file = $param;
Packit 6e6f77
Packit 6e6f77
			# if interactive, ask if we are to process this archive
Packit 6e6f77
			if (!$always_process_file) {
Packit 6e6f77
				if ($arg_interactive) {
Packit 6e6f77
					print "line ${.}: $keyword $param\n";
Packit 6e6f77
					my $res = &ask_interaction("Process resources in `$param'", 'yin');
Packit 6e6f77
					$always_process_file = 1 if (lc $res ne $res);
Packit 6e6f77
					$process_file = 0 if (lc $res eq 'n');
Packit 6e6f77
					$process_file = 1 if (lc $res eq 'y');
Packit 6e6f77
					$process_file = 2 if (lc $res eq 'i');
Packit 6e6f77
				} else {
Packit 6e6f77
					$process_file = 1;
Packit 6e6f77
				}
Packit 6e6f77
			}
Packit 6e6f77
Packit 6e6f77
			# get the file (local or remote)
Packit 6e6f77
			if ($tmpfile_exists) {
Packit 6e6f77
			    unlink $path_tmpfile;
Packit 6e6f77
			    $tmpfile_exists = 0;
Packit 6e6f77
			}
Packit 6e6f77
			$current_file = &fetch_file($current_file);
Packit 6e6f77
			return if (!defined $current_file);
Packit 6e6f77
Packit 6e6f77
			# check if the file actually exists
Packit 6e6f77
			if (!-e $current_file) {
Packit 6e6f77
				warn "$current_file: No such file or directory\n";
Packit 6e6f77
				return;
Packit 6e6f77
			}
Packit 6e6f77
		}
Packit 6e6f77
		# resource keyword
Packit 6e6f77
		elsif ($keyword eq 'resource' && $process_file) {
Packit 6e6f77
			($type, $name, $language, $dest_file)
Packit 6e6f77
			  = ($param =~ /^([^,]*?)\s*(?:,\s*([^,]*))?\s*(?:,\s*([^,]*))?\s*:\s*(.*)$/);
Packit 6e6f77
Packit 6e6f77
			# check for missing items
Packit 6e6f77
			next if &check_missing($file, $keyword, $type);
Packit 6e6f77
			next if &check_missing($file, $keyword, $name);
Packit 6e6f77
			next if &check_missing($file, $keyword, $dest_file);
Packit 6e6f77
Packit 6e6f77
			# if interactive
Packit 6e6f77
			if (!$always_process_resource) {
Packit 6e6f77
				if ($process_file == 2) {
Packit 6e6f77
					print "line ${.}: $keyword $param\n";
Packit 6e6f77
					my $res = &ask_interaction("Process resource type `$type' name `$name'", 'yn');
Packit 6e6f77
					$always_process_resource = 1 if (lc $res ne $res);
Packit 6e6f77
					$process_resource = 0 if (lc $res eq 'n');
Packit 6e6f77
					$process_resource = 1 if (lc $res eq 'y');
Packit 6e6f77
				} else {
Packit 6e6f77
					$process_resource = 1;
Packit 6e6f77
				}
Packit 6e6f77
			}
Packit 6e6f77
			next if !$process_resource;
Packit 6e6f77
Packit 6e6f77
			warn "Extracting $type resource $name to $dest_file\n" if $arg_verbose;
Packit 6e6f77
Packit 6e6f77
			&process_resource($current_file, $dest_file, $type, $name, $language);
Packit 6e6f77
		}
Packit 6e6f77
    # other keywords
Packit 6e6f77
    elsif ($keyword ne '') {
Packit 6e6f77
    	warn "$file: invalid keyword `$keyword' in line $.\n";
Packit 6e6f77
    }
Packit 6e6f77
	}
Packit 6e6f77
Packit 6e6f77
	# finally, close it
Packit 6e6f77
	close(FH);
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
sub process_resource {
Packit 6e6f77
	my ($resfile, $destfile, $type, $name, $language) = @_;
Packit 6e6f77
Packit 6e6f77
	# make w32rtool extraction parameters
Packit 6e6f77
	my ($cmd);
Packit 6e6f77
	$cmd = "-t$type -n$name";
Packit 6e6f77
	$cmd .= " -L$language" if (defined $language && $language ne '');
Packit 6e6f77
	$cmd = "$path_w32rtool ".&quoteshell($resfile). " -x $cmd";
Packit 6e6f77
Packit 6e6f77
	# make icotool extraction parameters
Packit 6e6f77
	my ($out);
Packit 6e6f77
	$out = &quoteshell($destfile);
Packit 6e6f77
	$out = File::Spec->catdir($arg_output, $out) if (defined $arg_output && $arg_output ne '');
Packit 6e6f77
	&make_directories(File::Basename::dirname($out));
Packit 6e6f77
Packit 6e6f77
	if (&is_icotool_type($type)) {
Packit 6e6f77
		$cmd .= " | $path_icotool -x -o " . $out . " -";
Packit 6e6f77
	} else {
Packit 6e6f77
		$cmd .= " -o$out";
Packit 6e6f77
	}
Packit 6e6f77
Packit 6e6f77
	# execute the command
Packit 6e6f77
#	print $cmd, "\n" if ($arg_verbose);
Packit 6e6f77
	system $cmd;
Packit 6e6f77
Packit 6e6f77
	return $path_icotool;
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
sub is_icotool_type {
Packit 6e6f77
	my ($type) = @_;
Packit 6e6f77
	
Packit 6e6f77
	$type = lc $type;
Packit 6e6f77
	return TRUE if (substr($type,0,1) eq '+' &&
Packit 6e6f77
		(substr($type,1) eq 'group_icon' || substr($type,1) eq 'group_cursor'));
Packit 6e6f77
Packit 6e6f77
	return TRUE if (substr($type,0,1) eq '-' &&
Packit 6e6f77
		(substr($type,1) == 12 || substr($type,1) == 14));
Packit 6e6f77
Packit 6e6f77
	return TRUE if ($type eq 'group_icon' || $type eq 'group_cursor'
Packit 6e6f77
		|| $type == 12 || $type == 14);
Packit 6e6f77
Packit 6e6f77
	return FALSE;
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
sub check_missing {
Packit 6e6f77
	my ($file, $keyword, $var) = @_;
Packit 6e6f77
Packit 6e6f77
	if (!defined $var || $var eq '') {
Packit 6e6f77
		warn "$file: missing parameter in `$keyword' statement in line ${.}.\n";
Packit 6e6f77
		return 1;
Packit 6e6f77
	}
Packit 6e6f77
Packit 6e6f77
	return 0;
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
# quote shell characters
Packit 6e6f77
sub quoteshell {
Packit 6e6f77
	my ($str) = @_;
Packit 6e6f77
	$str =~ s/([^-\w_.\/])/\\$1/g;
Packit 6e6f77
	return $str;
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
sub ask_interaction {
Packit 6e6f77
	my ($msg, $ch) = @_;
Packit 6e6f77
Packit 6e6f77
	# lowercase choices and put '/' between characters
Packit 6e6f77
	$ch = lc $ch;
Packit 6e6f77
	$ch =~ s/(.)(?=.)/$1\//g;
Packit 6e6f77
Packit 6e6f77
	my $in;
Packit 6e6f77
	do {
Packit 6e6f77
		$in = $obj_term->readline($msg . " ($ch)? ");
Packit 6e6f77
	} while (length($in) != 1 || $in eq '/' || index($ch,lc $in) == -1);
Packit 6e6f77
Packit 6e6f77
	return $in;
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
sub make_directories {
Packit 6e6f77
	my (@comp) = split(/\//, $_[0]);
Packit 6e6f77
Packit 6e6f77
	my ($check) = undef;
Packit 6e6f77
	foreach my $dir (@comp) {
Packit 6e6f77
		$check = File::Spec->catdir($check, $dir) if (defined $check);
Packit 6e6f77
		$check = $dir if (!defined $check);
Packit 6e6f77
		mkdir($check, 0777) if (!-e $check);
Packit 6e6f77
	}
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
sub fetch_file {
Packit 6e6f77
	my ($file) = @_;
Packit 6e6f77
Packit 6e6f77
	# if file is local, return it
Packit 6e6f77
	return $file if (-e $file);
Packit 6e6f77
Packit 6e6f77
	# try with --base argument 
Packit 6e6f77
  if (defined $arg_base) {
Packit 6e6f77
		my $tfile = File::Spec->catfile($arg_base, $file);
Packit 6e6f77
		return $tfile if (-e $tfile);
Packit 6e6f77
	}
Packit 6e6f77
Packit 6e6f77
	# absolutely not a file address
Packit 6e6f77
	return $file if (substr($file, 0, 1) eq '/');
Packit 6e6f77
Packit 6e6f77
	# get remote file
Packit 6e6f77
	print STDERR "Getting `$file'... ";
Packit 6e6f77
	my $rc = LWP::Simple::mirror($file, $path_tmpfile);
Packit 6e6f77
	if ($rc != RC_OK) {
Packit 6e6f77
		warn "failed!\n";
Packit 6e6f77
		warn "$file: " . HTTP::Status::status_message($rc) . "\n";
Packit 6e6f77
		return undef;
Packit 6e6f77
	}
Packit 6e6f77
Packit 6e6f77
	warn "done.\n";
Packit 6e6f77
	$tmpfile_exists = 1;
Packit 6e6f77
	return $path_tmpfile;
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
sub extract_file {
Packit 6e6f77
	my ($file, $archive) = @_;
Packit 6e6f77
Packit 6e6f77
	return "blah";
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
sub path_or {
Packit 6e6f77
	my ($cmd,$def) = @_;
Packit 6e6f77
Packit 6e6f77
	my $real = `which $cmd`;
Packit 6e6f77
  return $def if !defined $real;
Packit 6e6f77
  chop $real;
Packit 6e6f77
  return $def if ($real eq '');
Packit 6e6f77
Packit 6e6f77
	return $real;
Packit 6e6f77
}
Packit 6e6f77
Packit 6e6f77
sub END {
Packit 6e6f77
  unlink $path_tmpfile if $tmpfile_exists;
Packit 6e6f77
}