|
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 "."eshell($resfile). " -x $cmd";
|
|
Packit |
6e6f77 |
|
|
Packit |
6e6f77 |
# make icotool extraction parameters
|
|
Packit |
6e6f77 |
my ($out);
|
|
Packit |
6e6f77 |
$out = "eshell($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 |
}
|