#!/usr/bin/perl -w ############################################################################# # # Zwrap v1.00 # # Copyright (C) 2004 David Griffith # # This program will create, in effect, a self-extracting executable # from a Z-machine binary or zcode file. This is intended to simplify # giving zcode games to people using Unix machines who might not # clearly understand what a zcode interpreter is and how to use it. # This program creates a Perl script which includes the zcode file # encoded in uuencode format along with code to extract it. When that # script is executed, the game is extracted to /tmp and given as a # command-line parameter to a zcode interpreter. When the interpreter # exits, the zcode file is deleted. # ############################################################################# ############################################################################# # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Although this program is GPLed, the programs it creates are not. # That decision is the business of the user. In other words, you can # distribute your zwrapped program however you like. # ############################################################################# use strict; use POSIX; use File::Basename; use File::Copy; use vars qw($opt_a $opt_o $opt_r $opt_s $opt_t); use Getopt::Std; # uuencode / uudecode code taken from: # http://search.cpan.org/author/ANDK/Convert-UU-0.52/lib/Convert/UU.pm my ($zwrap_version, $zwrap_date, $zwrap_author, $zwrap_author_email); my ($tempdir, $encoded_string, $zcode, $filename, $gzfilename, @zcode); my ($uufilename, $filename_fix, $outfile, $pwd, $umask_save, $terp); my ($author, $title, $release, $serial); $zwrap_version = "1.00"; $zwrap_date = "2003"; $zwrap_author = "David Griffith"; $zwrap_author_email = ""; $author = "Unknown Author"; $release = "Unknown Release"; $serial = "Unknown Serial"; $title = "Unknown Title"; $tempdir = "/tmp"; $terp = "frotz"; getopts("a:o:r:s:t:"); if ($opt_a) { $author = $opt_a; } if ($opt_o) { $outfile = $opt_o; } if ($opt_r) { $release = $opt_r; } if ($opt_s) { $serial = $opt_s; } if ($opt_t) { $title = $opt_t; } if ($ARGV[0]) { $filename = $ARGV[0]; if (! -f $filename) { die "I don't see that file.\n"; } } else { usage(); } $filename_fix = basename($filename)."$$"; $gzfilename = "$tempdir/" . $filename_fix; $umask_save = umask(); umask(077); copy($filename, $gzfilename); `gzip -q $gzfilename`; $gzfilename = "$gzfilename.gz"; $uufilename = basename($filename).".gz"; open(GAMEFILE, "< $gzfilename"); @zcode = ; close(GAMEFILE); umask($umask_save); foreach my $i (@zcode) { $zcode = $zcode.$i; } unlink $gzfilename; $encoded_string = uuencode($zcode, $uufilename); # Protect single-quotes and backslashes from being mangled. # $encoded_string =~ s/\134/\134\134/g; $encoded_string =~ s/\'/\\'/g; # Now write out the wrapper script. # if (!$outfile) { $outfile = basename("$filename"); $outfile =~ s/\..+//; $outfile = "$outfile.pl"; } open(OUTFILE, "> $outfile") || die "Unable to write $outfile\n"; print OUTFILE <) { if (\$file eq "" and !\$mode){ (\$mode,\$file) = (\$1, \$2) if /^begin\\s+(\\d+)\\s+(.+)\$/ ; next; } last if /^end/; push \@result, uudecode_chunk(\$_); } } elsif (ref(\\\$in) eq "SCALAR") { while (\$in =~ m/\\G(.*?(\\n|\\r|\\r\\n|\\n\\r))/gc) { my \$line = \$1; if (\$file eq "" and !\$mode){ (\$mode,\$file) = \$line =~ /^begin\\s+(\\d+)\\s+(.+)\$/ ; next; } next if \$file eq "" and !\$mode; last if \$line =~ /^end/; push \@result, uudecode_chunk(\$line); } } elsif (ref(\$in) eq "ARRAY") { my \$line; foreach \$line (\@\$in) { if (\$file eq "" and !\$mode){ (\$mode,\$file) = \$line =~ /^begin\\s+(\\d+)\\s+(.+)\$/ ; next; } next if \$file eq "" and !\$mode; last if \$line =~ /^end/; push \@result, uudecode_chunk(\$line); } } wantarray ? (join("",\@result),\$file,\$mode) : join("",\@result); } sub uudecode_chunk { my(\$chunk) = \@_; return "" if \$chunk =~ /^(?:--|CREATED)/; my \$string = substr(\$chunk,0,int((((ord(\$chunk) - 32) & 077) + 2) / 3)*4+1); my \$ret = unpack("u", \$string); defined \$ret ? \$ret : ""; } # It should be obvious how to extract the zcode file if you want to. # my \$filestring =\n\'$encoded_string\'; my (\$tempdir, \$zcode, \$filename, \$mode, \$terp); \$tempdir = "$tempdir"; \$terp = "$terp"; (\$zcode, \$filename, \$mode) = uudecode(\$filestring); \$filename = "\$tempdir\"."/zwrap_\".\"\$\$\".\"_\".\"\$filename"; umask 077; open(OUTFILE, "> \$filename") || die "Unable to write \$filename.\\n"; print OUTFILE \$zcode; close(OUTFILE); system("gzip -d \$filename"); \$filename =~ s/.gz\$//; system("\$terp \$filename"); system("reset -Q"); unlink(\$filename); EOF close(OUTFILE); # Finished creating the wrapper script # sub usage { die "usage: $0 [options] zcodefile options: -a \"Joe Bloggs\" (author) -t \"My Game\" (game title) -r \"4\" (release number) -s \"010101\" (serial number)\n"; } sub uuencode { die("Usage: uuencode( {string|filehandle} [,filename] [, mode] )") unless(@_ >= 1 && @_ <= 3); my ($in, $file, $mode) = @_; $mode ||= "644"; $file ||= "uuencode.uu"; my ($chunk, @result, $r); if ( ref($in) eq 'IO::Handle' or ref(\$in) eq "GLOB" or ref($in) eq "GLOB" or ref($in) eq 'FileHandle' ) { # local $^W = 0; # Why did I get use of undefined value here ? binmode($in); local $/; $in = <$in>; } pos($in)=0; while ($in =~ m/\G(.{1,45})/sgc) { push @result, uuencode_chunk($1); } push @result, "`\n"; join "", "begin $mode $file\n", @result, "end\n"; } sub uuencode_chunk { my($string) = shift; my $encoded_string = pack("u", $string); # unix uuencode $encoded_string; }