diff options
author | Karl Berry <karl@freefriends.org> | 2009-10-19 23:14:41 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2009-10-19 23:14:41 +0000 |
commit | b375450c6edee29aeb73380c081d8237543a1ae6 (patch) | |
tree | 73814453d5d3e30fa9b492397d75c87259ed9ec3 /Build/source | |
parent | 03070f532392d9e24d8dc2b79df0c626abc599f0 (diff) |
copy in manuel's fixes
git-svn-id: svn://tug.org/texlive/trunk@15843 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source')
-rwxr-xr-x | Build/source/utils/epstopdf/epstopdf.pl | 168 |
1 files changed, 119 insertions, 49 deletions
diff --git a/Build/source/utils/epstopdf/epstopdf.pl b/Build/source/utils/epstopdf/epstopdf.pl index 26c4e6f60f9..b850ae3b239 100755 --- a/Build/source/utils/epstopdf/epstopdf.pl +++ b/Build/source/utils/epstopdf/epstopdf.pl @@ -4,20 +4,20 @@ use strict; # $Id$ # (Copyright lines below.) -# +# # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: -# +# # 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. +# notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. +# documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote # products derived from this software without specific prior written -# permission. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR [AS IS'' AND ANY EXPRESS OR +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, @@ -28,9 +28,9 @@ use strict; # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -# +# # ---------------------------------------------------------------- -# +# # This is a script to transform an EPS file such that: # a) it is guaranteed to start at the 0,0 coordinate. # b) it sets a page size exactly corresponding to the BoundingBox @@ -44,9 +44,16 @@ use strict; # One thing not allowed for is the case of # "%%BoundingBox: (atend)" when input is not seekable (e.g., from a pipe), # which is more complicated. -# +# # emacs-page # History +# 2009/10/18 v2.13 (Manuel P\'egouri\'e-Gonnard) +# * Better argument validation, from Alexander Cherepanov. +# * Use the list form of pipe open() (resp. system()) to prevent injection. +# Since Perl's fork() emulation doesn't work on Windows with Perl 5.8.8 from +# TeX Live 2009, use a temporary file instead of a pipe on Windows. +# 2009/10/14 v2.12 (Manuel P\'egouri\'e-Gonnard) +# * Added restricted mode. # 2009/09/27 v2.11 (Karl Berry) # * Fixed two bugs in the (atend) handling code (Martin von Gagern) # * Improved handling of CR line ending (Martin von Gagern) @@ -111,7 +118,7 @@ use strict; # * using of $bbxpat in all BoundingBox cases, # correct the first white space to '...Box:\s*$bb...' # * corrected first line (one line instead of two before 'if 0;'; -# +# # Thomas Esser, Sept. 1998: change initial lines to find # perl along $PATH rather than guessing a fixed location. The above # construction should work with most shells. @@ -137,6 +144,10 @@ my $title = "$program $ident\n"; my $GS = "gs"; $GS = "gswin32c" if $^O eq 'MSWin32'; +### restricted mode +my $restricted = 0; +$restricted = 1 if $0 =~ /repstopdf/; + ### options $::opt_outfile=""; $::opt_compress=1; @@ -162,7 +173,7 @@ Convert EPS to PDF, by default using Ghostscript. Options: --help display this help and exit --version display version information and exit - + --outfile=FILE write result to FILE --(no)compress use compression (default: $bool[$::opt_compress]) --(no)debug write debugging info (default: $bool[$::opt_debug]) @@ -176,6 +187,7 @@ Options: --autorotate=VAL set AutoRotatePages (default: $rotmsg) Recognized VAL choices: None, All, PageByPage For EPS files, PageByPage is equivalent to All + --restricted use restricted mode (default: $bool[$restricted]) Examples for producing 'test.pdf': * $program test.eps @@ -197,7 +209,7 @@ use Getopt::Long; GetOptions ( "help", "version", - "outfile=s", + "outfile=s", # \ref{openout_any} "compress!", "debug!", "embed!", @@ -205,9 +217,10 @@ GetOptions ( "filter!", "gs!", "hires!", - "gscmd=s", - "res=i", - "autorotate=s", + "gscmd=s", # \ref{val_gscmd} + "res=i", # validated by Getopt ('i' specifier) + "autorotate=s", # \ref{val_autorotate} + "restricted", ) or die $usage; ### help functions @@ -224,6 +237,10 @@ sub errorUsage { die "$usage\n!!! Error: @_\n"; } +### restricted option +$restricted = 1 if $::opt_restricted; +debug "Restricted mode activated" if $restricted; + ### help, version options. if ($::opt_help) { print $usage; @@ -236,7 +253,6 @@ if ($::opt_version) { exit (0); } - ### get input filename my $InputFilename = ""; if ($::opt_filter) { @@ -253,19 +269,35 @@ else { debug "Input filename:", $InputFilename; } -### option compress & embed -my $GSOPTS = "-dSAFER "; -$GSOPTS .= (" -dPDFSETTINGS=/prepress -dMaxSubsetPct=100 " - . "-dSubsetFonts=true -dEmbedAllFonts=true ") - if $::opt_embed; -$GSOPTS .= "-dUseFlateCompression=false " unless $::opt_compress; -$GSOPTS .= "-r$::opt_res " if $::opt_res; +### option gscmd +if ($::opt_gscmd) { + debug "Switching from $GS to $::opt_gscmd"; + $GS = $::opt_gscmd; + # validate GS \label{val_gscmd} + if ($restricted) { + $GS =~ /^(gs|mgs|gswin32c|gs386|gsos2)\z/ + or $GS =~ /^gs[\-_]?(\d|\d[\.-_]?\d\d)c?\z/ + or die error "Value of gscmd '$GS' not allowed in restricted mode."; + } +} + +### start building GS command line for the pipe +my @GS = ($GS); +push @GS, qw(-q -dNOPAUSE -dSAFER -sDEVICE=pdfwrite); + +### options compress, embed, res, autorotate +push @GS, ('-dPDFSETTINGS=/prepress', '-dMaxSubsetPct=100', + '-dSubsetFonts=true', '-dEmbedAllFonts=true') if $::opt_embed; +push @GS, '-dUseFlateCompression=false' unless $::opt_compress; +push @GS, "-r$::opt_res" if $::opt_res; $resmsg= $::opt_res ? $::opt_res : "[use gs default]"; -$GSOPTS .= "-dAutoRotatePages=/$::opt_autorotate " if $::opt_autorotate; -die "Invalid value for autorotate: '$::opt_autorotate' (use 'All', 'None' or 'PageByPage').\n" - if ($::opt_autorotate and - not $::opt_autorotate =~ /^(None|All|PageByPage)$/); +push @GS, "-dAutoRotatePages=/$::opt_autorotate" if $::opt_autorotate; $rotmsg = $::opt_autorotate ? $::opt_autorotate : "[use gs default]"; +# \label{val_autorotate} +error "Invalid value for autorotate: '$::opt_autorotate' " + . "(use 'All', 'None' or 'PageByPage')." + if ($::opt_autorotate and + not $::opt_autorotate =~ /^(None|All|PageByPage)\z/); ### option BoundingBox types my $BBName = "%%BoundingBox:"; @@ -295,11 +327,33 @@ if ($::opt_filter) { else { debug "Output filename:", $OutputFilename; } - -### option gscmd -if ($::opt_gscmd) { - debug "Switching from $GS to $::opt_gscmd"; - $GS = $::opt_gscmd; +push @GS, "-sOutputFile=$OutputFilename"; + +### validate output file name in restricted mode \label{openout_any} +use File::Spec::Functions qw(splitpath file_name_is_absolute); +if ($restricted) { + # use the equivalent of openout_any = p + # (see opennameok() web2c/lib/texmfmp.c) + # Well, for now, be even more paranoid: don't allow absolute path at all + my $ok = 1; + # disallow opening dot-files on Unix + unless ($^O eq "MSWin32") { + my ($drive, $path, $basename) = splitpath($OutputFilename); + $ok = 0 if $basename =~ /^\./; + } + # disallow absolute path + $ok = 0 if file_name_is_absolute($OutputFilename); + # disallow colon on Windows. It could be used either after a drive + # (like "a:dir\file") or for an alternate data stream (like + # "file:ads"). + if ($^O eq "MSWin32" || $^O eq "cygwin") { + $ok = 0 if $OutputFilename =~ /:/; + } + # disallow going to parent directory + my $ds = ($^O eq "MSWin32" || $^O eq "cygwin") ? qr([\\/]) : qr(/); + $ok = 0 if $OutputFilename =~ /^\.\.$ds|$ds\.\.$ds/; + # we passed all tests + die error "Output filename '$OutputFilename' not allowed in restricted mode." unless $ok; } ### option gs @@ -313,24 +367,32 @@ if ($::opt_gs) { ### emacs-page ### open input file -open(IN, "<$InputFilename") or error "Cannot open", +open(IN, '<', $InputFilename) or error "Cannot open", ($::opt_filter) ? "standard input" : "\"$InputFilename\": $!"; binmode IN; ### open output file my $outname; # used in error message at end +my $tmp_filename; # temporary file for windows +my $OUT; # filehandle for output (GS pipe or temporary file) +use File::Temp 'tempfile'; if ($::opt_gs) { - my $pipe = "$GS -q -sDEVICE=pdfwrite $GSOPTS" . - " -sOutputFile=\"$OutputFilename\" - -c quit"; - debug "Ghostscript pipe:", $pipe; - open(OUT,"|$pipe") or error "Cannot open Ghostscript for piped input"; + unless ($^O eq 'MSWin32' || $^O eq 'cygwin') { # list piped open works + push @GS, qw(- -c -quit); + debug "Ghostscript pipe:", join(' ', @GS); + open($OUT, '|-', @GS) or error "Cannot open Ghostscript for piped input"; + } + else { # use a temporary file + ($OUT, $tmp_filename) = tempfile(UNLINK => 1); + debug "Using temporary file '$tmp_filename'"; + } $outname = $GS; } else { - open(OUT,">$OutputFilename") or error "Cannot write \"$OutputFilename\""; + open($OUT, '>', $OutputFilename) or error "Cannot write \"$OutputFilename\""; $outname = $OutputFilename; } -binmode OUT; +binmode $OUT; # reading a cr-eol file on a lf-eol system makes it impossible to parse # the header and besides it will read the intire file into yor line by line @@ -414,7 +476,7 @@ if (/%!/) { } $header = 1 if /^%/; debug "Scanning header for BoundingBox"; -print OUT; +print $OUT $_; ### variables and pattern for BoundingBox search my $bbxpatt = '[0-9eE\.\-]'; @@ -431,9 +493,9 @@ sub CorrectBoundingBox debug "New BoundingBox: 0 0", $width, $height; debug "Offset:", $xoffset, $yoffset; - print OUT "%%BoundingBox: 0 0 $width $height$/"; - print OUT "<< /PageSize [$width $height] >> setpagedevice$/"; - print OUT "gsave $xoffset $yoffset translate$/"; + print $OUT "%%BoundingBox: 0 0 $width $height$/"; + print $OUT "<< /PageSize [$width $height] >> setpagedevice$/"; + print $OUT "gsave $xoffset $yoffset translate$/"; } ### emacs-page @@ -445,7 +507,7 @@ if ($header) { ### end of header if (!/^%/ or /^%%EndComments/) { - print OUT; + print $OUT $_; last; } @@ -486,20 +548,28 @@ if ($header) { } # print header line - print OUT; + print $OUT $_; } } ### print rest of file while (getline()) { - print OUT; + print $OUT $_; } ### emacs-page ### close files close(IN); -print OUT "$/grestore$/" if $BBCorrected; -close(OUT); +print $OUT "$/grestore$/" if $BBCorrected; +close($OUT); + +### actually run GS if we were writing to a temporary file +if (defined $tmp_filename) { + push @GS, $tmp_filename; + push @GS, qw(-c quit); + debug "Ghostscript command:", join(' ', @GS); + system @GS; +} # if ghostscript exited badly, we should too. if ($? & 127) { |