#!/bin/sh
# ǶᡢpdftopsνϤϵǤꡢpdftocairo -psνϤϾΤǡ
# pdftocairo -psνϤùpdftopsˤ뤳Ȥ

POPPLER_ERR_CODE=99
err(){ # err [exitval] [msg...]
	EXITVAL=$POPPLER_ERR_CODE; is_int "$1" && { EXITVAL="$1"; shift; }
	[ $# -gt 0 ] && echo "$@" >&2; exit $EXITVAL
}

NAWK=gawk
[ -x "`which "$NAWK" 2>/dev/null`" ] || err "no $NAWK found"

is_match(){
	LC_ALL=C perl -e 'exit($ARGV[0] !~ $ARGV[1])' -- "$1" "$2"
}

is_int(){ # is_int "$1"
	is_match "$1" '^-?\d+\z'
}

is_ufloat(){ # is_ufloat "$1"
	is_match "$1" '^(\d+(\.\d*)?|\.\d+)([Ee][-+]?\d+)?\z'
}

is_seekable(){
	[ -r "$1" ] && LC_ALL=C perl -e 'exit(!seek(STDIN, 0, 1))' < "$1"
}

echon(){
	$NAWK 'BEGIN{for(i=1;i<ARGC;i++) printf i==1?"%s":" %s", ARGV[i]}' "$@"
}

usage(){ # usage [exitval]
	EXITVAL=; is_int "$1" && { EXITVAL="$1"; shift; }
	err $EXITVAL "Usage: `basename "$0"` `cat <<-'EOF'
		[-h] [-q] [-f int] [-l int] [-eps] [-opw opw] [-upw upw]
		  [-r num] [-duplex] [-level2] [-level3] PDF [PS]
	EOF`"
	# -opw -upwΰʤüϤ褦ˤ
	# (ꥸʥpdftopsˤüѥɤϤ뵡ǽϤʤ)
	# -opw -upwΰΤ1Ǥ ⤦1ʤ餽äȤ
	# ΤüϤϵʤ
}

FPG=1; LPG=; OPWSET=f; UPWSET=f; OPW=; UPW=; EPS=f; PSOPT='-r 300'; QUIET=f
while :; do
	case "$1" in
	-h)	usage 0;;
	-q)	QUIET=t; shift;;
	-f)	is_int "$2" || usage; FPG="$2"; shift 2;;
	-l)	is_int "$2" || usage; LPG="$2"; shift 2;;
	-eps)	EPS=t; shift;;
	-opw)	[ $# -ge 2 ] || usage; OPW="$2"; OPWSET=t; shift 2;;
	-upw)	[ $# -ge 2 ] || usage; UPW="$2"; UPWSET=t; shift 2;;
	-r)	is_ufloat "$2" || usage; PSOPT="$PSOPT $1 $2"; shift 2;;
	-duplex|-level[23])
		PSOPT="$PSOPT $1"; shift;;
	--)	shift; break;;
	*)	break;;
	esac	  # $FPG $LPGüʸʤ $PSOPTˤ϶ʳüʸʤ
done
case "$#" in
1)	case "$1" in -)	usage;; esac
	PSFNM="`expr " $1" : ' \(.*\)\.pdf$'`"
	[ X"$PSFNM" = X ] && PSFNM="$1"
	case "$EPS" in
	t)	PSFNM="$PSFNM".eps;;
	*)	PSFNM="$PSFNM".ps;;
	esac;;
2)	PSFNM="$2";;
*)	usage;;
esac
PDFNM="$1"
case "$PDFNM" in -|/*) :;; *) PDFNM="./$PDFNM";; esac

case $QUIET in t) exec 2>/dev/null;; esac

# PDFunseekableޥɥ饤-opw -upwΤ줫ꤵƤ
if [ $OPWSET$UPWSET != ff -o X"$PDFNM" = X- ] || ! is_seekable "$PDFNM"; then
	case "$PDFNM" in
	-)	fromtty(){ "$@" < /dev/tty; };;
	*)	fromtty(){ "$@"; };;
	esac		# sttyread˻Ȥ

	trap '' HUP INT QUIT PIPE TERM

	# -opw -upwΤ줫ꤵƤ뤬ɤΥѥɤ
	# ʤ ѥϤstty -echo
	OSTTY=
	if [ $OPWSET$UPWSET != ff -a X"$OPW$UPW" = X ]; then
		OSTTY="`fromtty stty -g`" || err
		fromtty stty -echo
	fi

	TMPD="`mktemp -d`" || err

	trap '
		ST=$?; trap : EXIT
		[ X"$OSTTY" != X ] && fromtty stty "$OSTTY"
		rm -rf "$TMPD"
		exit $ST
	' EXIT HUP INT QUIT PIPE TERM

	# qpdfunseekableϤ򰷤ʤΤǡξޤᤳ
	# եäƤޤ
	cat "$PDFNM" > "$TMPD/a.pdf" || err 1
	if [ $OPWSET$UPWSET != ff ]; then # -opw -upwΤ줫ξ
		if [ X"$OPW" != X ]; then
			QOPT="$OPW"
		elif [ X"$UPW" != X ]; then
			QOPT="$UPW"
		else # ѥ
			echon 'Password: ' >&2		# 1Ԥ
			fromtty read QOPT || err Cannot read password
			fromtty stty "$OSTTY"
			echo >&2
		fi
		# ѥɤüϤϤ줬psǸΤɤ
		# qpdf --password=ˤϤ echoѥפǥѥɤϤ
		# --password-file=-Ȥ(Τ¾ΥޥɤǼ¸echo
		# ޥɤǤϤʤechoȤ)
		#
		#  qpdf--password-file=-ǥѥɤľü
		# üɽƤޤ ˤξ
		# qpdfϥѥɤCtrl-Dǽü뤳Ȥ(=ʣϤ
		# Ƥ)γˤϤѥɤƬԤȤʤ
		# ޤ̣ȻפʤΤǥѥϤϼreadǤ
		echo "$QOPT" | qpdf --replace-input --decrypt \
			--password-file=- "$TMPD/a.pdf" || err 3
	fi
	PDFNM="$TMPD/a.pdf"
fi
# λ$PDFNMϡ-פǻϤޤʤ($TMPDIR-פǻϤޤʤ¤)
# $PDFNM(-opwޤ-upwꤵƤ)decryptѤ

if [ X"$LPG" = X ]; then
	LPG=`pdfinfo "$PDFNM" | $NAWK '/^Pages:/{print $2+0; exit}'`
	[ X"$LPG" = X ] && err
fi
PGOPT="-f $FPG -l $LPG"	# üʸϺäƤʤ

[ X"$PSFNM" != X- ] && { command exec > "$PSFNM" || err 2; }
{
	pdfinfo $PGOPT "$PDFNM"
	echo - $?

	# С23.11pdftocairo -epsνϤϲĹξХ
	# ǥС23.11ǲĹPDFPDF礷
	# ĹǤʤƤ
	# epsξPDF1ڡʤΤǥڡ礭ۤʤǽθ
	if [ $EPS = t ]; then
		if pdftocairo -v 2>&1 | $NAWK '{exit($3+0 < 23.11 ? 0 : 1)}' &&
		WH=`pdfinfo $PGOPT "$PDFNM" | $NAWK '
			sub(/^Page +([^ ]+ +)?size:/, ""){s[0] = $1; s[1] = $3}
			sub(/^Page +([^ ]+ +)?rot:/, ""){r = !($1 % 180)}
			s[0] && r != ""{print s[!r]; exit(s[r] < s[!r]? 0 : 1)}
		'`; then # rot90270Ǥʤr=1exit(0)ƤвĹ
			pdfcrop --bbox "0 0 $WH $WH" "$PDFNM" /dev/fd/3 \
				3>&1 >/dev/null
		else
			cat "$PDFNM"
		fi | pdftocairo -eps $PGOPT $PSOPT - -
	else
		pdftocairo -ps $PGOPT $PSOPT "$PDFNM" -
	fi
	echo "%%!Exit:", $?
} | $NAWK -v eps=$EPS -v poppler_err_code=$POPPLER_ERR_CODE '
	BEGIN{
		IGNORECASE = 1
		eps = (eps == "t")
		while(getline > 0){ # ǽʬ򸫤
			if($1 == "-"){if($2) exit($2); break}
			# breakwhileȴȰʸpdftocairoν

			if($1 == "Page"){ # pdfinfoϤڡ
				if($2 !~ /^[0-9]+$/) sub(/ /, " 1 ")
				# "Page size": to "Page 1 size:"
				if(!($2 in pg_corr)){
				# pg_corr: pdfinfopdftocairoȤ
				# ڡֹб(-fξԤϰۤʤ
				# pdfcairoνϤΥڡֹϾ1)
					pg_corr[$2] = ++pg_last
					pg_rcorr[pg_last] = $2
				}
				pg = pg_corr[$2]; kind = $3
				split($0, a, /:/); $0 = a[2]
				if(kind ~ /^rot/){
					if($1 % 180) r[pg] = 1
				} else {
					sub(/x/, " "); w[pg] = $1; h[pg] = $2
					cnt++
				}
			}
		}
		if(!cnt){
			print "Unexpected output from pdfinfo" > "/dev/stderr"
			exit(poppler_err_code)
		} else if(eps && cnt != 1){
			print "EPS files can only contain 1 page">"/dev/stderr"
			exit(poppler_err_code)
		}

		for(pg in r){
			tmp = h[pg]; h[pg] = w[pg]; w[pg] = tmp
		}
		w_all = h_all = 0
		for(pg in w) if(w_all < w[pg]) w_all = w[pg]
		for(pg in h) if(h_all < h[pg]) h_all = h[pg]
	}
	function rup(x){ # for nun-minus numbers only
		return int(x) + (x != int(x))
	}

	/^%%BoundingBox:/{
		print "%%BoundingBox:", 0, 0, rup(w_all), rup(h_all)
		print "%%HiResBoundingBox:", 0, 0, w_all, h_all
		next
	}
	/^%%HiResBoundingBox:/{next}
	/^%%Page:/{
	# pdftopsνϤPage:ΥڡֹȽΥڡֹ
	# pdftocairoνϤPage:ξȤΥڡֹ
		sub(/: ?/, ": ")
		pg = $2
		if(pg != $3){
			print "Unexpected output from pdftocairo">"/dev/stderr"
			exit(poppler_err_code)
		}
		print "%%Page:", pg_rcorr[$2], $2; next
	}
	/^%%PageBoundingBox:/{
		w_pg = w[pg in w ? pg : 1]
		h_pg = h[pg in h ? pg : 1]
		print "%%PageBoundingBox:", 0, 0, rup(w_pg), rup(h_pg)
		print "%%PageHiResBoundingBox:", 0, 0, w_pg, h_pg
		next
	}
	/^%%(PageHiRes|HiResPage)BoundingBox:/{next}
	/^%%!Exit:/{exit($2)}
	1
'
