summaryrefslogtreecommitdiffstats
path: root/latex
diff options
context:
space:
mode:
authorThomas Orgis2018-12-05 20:56:25 +0100
committerThomas Orgis2018-12-05 21:29:30 +0100
commitd759aa768517a934c81d9b4f7a27a2a8126f92da (patch)
treebfca8b3fc9f7a4b2fd17f16f4a8cb0b04067c24e /latex
parent9d6d134df923742978089313f9057b54f60832dc (diff)
texlive: fix build of pdftex with current poppler, at least
Luatex is still broken. Upstream is switching away from poppler there. I hope for the next release. Or somebody can take on the funky macros that dig around in poppler data structures.
Diffstat (limited to 'latex')
-rwxr-xr-xlatex/texlive/DEPENDS1
-rw-r--r--latex/texlive/HISTORY8
-rwxr-xr-xlatex/texlive/PRE_BUILD26
-rw-r--r--latex/texlive/patches/texlive-20180414-source-upstream_fixes-1.patch119
-rw-r--r--latex/texlive/patches/texlive-20180414-source-upstream_fixes-2.patch6350
5 files changed, 6381 insertions, 123 deletions
diff --git a/latex/texlive/DEPENDS b/latex/texlive/DEPENDS
index 49fb739220..5ad19183c9 100755
--- a/latex/texlive/DEPENDS
+++ b/latex/texlive/DEPENDS
@@ -44,6 +44,7 @@ runtime_depends dvipng '--disable-dvipng' &&
runtime_depends lacheck '--disable-lacheck' &&
runtime_depends lcdf-typetools '--disable-lcdf-typetools' &&
# FIXME LUA and luajit dependencies aren't actually used, see PRE_BUILD
+message "${MESSAGE_COLOR}Luatex build is broken with poppler 0.71 (fix in texlive 2019?).$DEFAULT_COLOR" &&
optional_depends LUA \
'--enable-luatex' \
'--disable-luatex' \
diff --git a/latex/texlive/HISTORY b/latex/texlive/HISTORY
index 46c8076394..07924eb1d7 100644
--- a/latex/texlive/HISTORY
+++ b/latex/texlive/HISTORY
@@ -1,3 +1,11 @@
+2018-12-05 Thomas Orgis <sobukus@sourcemage.org>
+ * patches/texlive-20180414-source-upstream_fixes-2.patch,
+ patches/texlive-20180414-source-upstream_fixes-1.patch
+ yet more fixes to really support poppler > 0.64.0 now, all
+ pdftexdir changes now in patch 2, rest in patch 1
+ * PRE_BUILD: insane logic to support differing poppler versions
+ * DEPENDS: note about still broken luatex
+
2018-10-31 Pavel Vinogradov <public@sourcemage.org>
* patches/texlive-20180414-source-upstream_fixes-1.patch:
adapted to poppler 0.71.0 or higher
diff --git a/latex/texlive/PRE_BUILD b/latex/texlive/PRE_BUILD
index 478ec649e5..9b4a92017d 100755
--- a/latex/texlive/PRE_BUILD
+++ b/latex/texlive/PRE_BUILD
@@ -71,10 +71,28 @@ sed '/utypes.h/i\
mkdir "$COMPILE_DIRECTORY" &&
-# Poppler >= 0.59.0 fix
-if spell_ok poppler && ! is_version_less "$(installed_version poppler)" "0.59.0"; then
+# Poppler sources:
+# really old: keep things as-is
+# 0.59.x to 0.68.x: pdftoepdf-poppler0.68.0.cc, pdftosrc-newpoppler.cc
+# 0.69.x: pdftoepdf-poppler0.69.0.cc, pdftosrc-newpoppler.cc
+# 0.70.x: pdftoepdf-poppler0.70.0.cc, pdftosrc-newpoppler.cc
+# 0.71.x: pdftoepdf-poppler0.71.0.cc, pdftosrc-poppler0.71.0.cc
+# This is nuts.
+if spell_ok poppler; then
cd "${SOURCE_DIRECTORY}/texk/web2c/pdftexdir" &&
- cp pdftoepdf-newpoppler.cc pdftoepdf.cc &&
- cp pdftosrc-newpoppler.cc pdftosrc.cc &&
+ popplerver="$(installed_version poppler | cut -f 1,2 -d .)" &&
+ if is_version_between 0.59 "$popplerver" 0.68; then
+ cp pdftoepdf-poppler0.68.0.cc pdftoepdf.cc &&
+ cp pdftosrc-newpoppler.cc pdftosrc.cc
+ elif [[ "$popplerver" = 0.69 ]]; then
+ cp pdftoepdf-poppler0.69.0.cc pdftoepdf.cc &&
+ cp pdftosrc-newpoppler.cc pdftosrc.cc
+ elif [[ "$popplerver" = 0.70 ]]; then
+ cp pdftoepdf-poppler0.70.0.cc pdftoepdf.cc &&
+ cp pdftosrc-newpoppler.cc pdftosrc.cc
+ elif ! is_version_less "$popplerver" 0.71; then
+ cp pdftoepdf-poppler0.71.0.cc pdftoepdf.cc &&
+ cp pdftosrc-poppler0.71.0.cc pdftosrc.cc
+ fi &&
cd "${SOURCE_DIRECTORY}"
fi
diff --git a/latex/texlive/patches/texlive-20180414-source-upstream_fixes-1.patch b/latex/texlive/patches/texlive-20180414-source-upstream_fixes-1.patch
index f3c379f25b..38091a110f 100644
--- a/latex/texlive/patches/texlive-20180414-source-upstream_fixes-1.patch
+++ b/latex/texlive/patches/texlive-20180414-source-upstream_fixes-1.patch
@@ -241,125 +241,6 @@ diff -Naur a/texk/web2c/luatexdir/lua/lepdflib.cc b/texk/web2c/luatexdir/lua/lep
a = ((StructElement *) uin->d)->findAttribute(t,g,o);
if (a!=NULL){
-diff -Naur a/texk/web2c/pdftexdir/pdftoepdf-newpoppler.cc b/texk/web2c/pdftexdir/pdftoepdf-newpoppler.cc
---- a/texk/web2c/pdftexdir/pdftoepdf-newpoppler.cc 2018-04-04 05:08:11.000000000 +0100
-+++ b/texk/web2c/pdftexdir/pdftoepdf-newpoppler.cc 2018-04-30 16:29:35.849907790 +0100
-@@ -120,7 +120,7 @@
-
- static InObj *inObjList;
- static UsedEncoding *encodingList;
--static GBool isInit = gFalse;
-+static bool isInit = false;
-
- // --------------------------------------------------------------------
- // Maintain list of open embedded PDF files
-@@ -290,7 +290,7 @@
- static void copyDictEntry(Object * obj, int i)
- {
- Object obj1;
-- copyName(obj->dictGetKey(i));
-+ copyName((char *)obj->dictGetKey(i));
- pdf_puts(" ");
- obj1 = obj->dictGetValNF(i);
- copyObject(&obj1);
-@@ -355,7 +355,7 @@
- if (!procset.isName())
- pdftex_fail("PDF inclusion: invalid ProcSet entry type <%s>",
- procset.getTypeName());
-- copyName(procset.getName());
-+ copyName((char *)procset.getName());
- pdf_puts(" ");
- }
- pdf_puts("]\n");
-@@ -418,7 +418,7 @@
- && fontdescRef.isRef()
- && fontdesc.isDict()
- && embeddableFont(&fontdesc)
-- && (fontmap = lookup_fontmap(basefont.getName())) != NULL) {
-+ && (fontmap = lookup_fontmap((char *)basefont.getName())) != NULL) {
- // round /StemV value, since the PDF input is a float
- // (see Font Descriptors in PDF reference), but we only store an
- // integer, since we don't want to change the struct.
-@@ -427,7 +427,7 @@
- charset = fontdesc.dictLookup("CharSet");
- if (!charset.isNull() &&
- charset.isString() && is_subsetable(fontmap))
-- epdf_mark_glyphs(fd, charset.getString()->getCString());
-+ epdf_mark_glyphs(fd, (char *)charset.getString()->getCString());
- else
- embed_whole_font(fd);
- addFontDesc(fontdescRef.getRef(), fd);
-@@ -456,7 +456,7 @@
- if (fontRef.isRef())
- copyFont(obj->dictGetKey(i), &fontRef);
- else if (fontRef.isDict()) { // some programs generate pdf with embedded font object
-- copyName(obj->dictGetKey(i));
-+ copyName((char *)obj->dictGetKey(i));
- pdf_puts(" ");
- copyObject(&fontRef);
- }
-@@ -565,7 +565,7 @@
- } else if (obj->isNum()) {
- pdf_printf("%s", convertNumToPDF(obj->getNum()));
- } else if (obj->isString()) {
-- s = obj->getString();
-+ s = (GooString *)obj->getString();
- p = s->getCString();
- l = s->getLength();
- if (strlen(p) == (unsigned int) l) {
-@@ -589,7 +589,7 @@
- pdf_puts(">");
- }
- } else if (obj->isName()) {
-- copyName(obj->getName());
-+ copyName((char *)obj->getName());
- } else if (obj->isNull()) {
- pdf_puts("null");
- } else if (obj->isArray()) {
-@@ -724,8 +724,8 @@
- // initialize
- if (!isInit) {
- globalParams = new GlobalParams();
-- globalParams->setErrQuiet(gFalse);
-- isInit = gTrue;
-+ globalParams->setErrQuiet(false);
-+ isInit = true;
- }
- // open PDF file
- pdf_doc = find_add_document(image_name);
-@@ -977,7 +977,7 @@
- }
- l = dic1.getLength();
- for (i = 0; i < l; i++) {
-- groupDict.dictAdd(copyString(dic1.getKey(i)),
-+ groupDict.dictAdd((const char *) copyString(dic1.getKey(i)),
- dic1.getValNF(i));
- }
- // end modification
-diff -Naur a/texk/web2c/pdftexdir/pdftosrc-newpoppler.cc b/texk/web2c/pdftexdir/pdftosrc-newpoppler.cc
---- a/texk/web2c/pdftexdir/pdftosrc-newpoppler.cc 2017-10-17 22:52:13.000000000 +0100
-+++ b/texk/web2c/pdftexdir/pdftosrc-newpoppler.cc 2018-04-30 16:29:41.360904749 +0100
-@@ -109,7 +109,7 @@
- fprintf(stderr, "No SourceName found\n");
- exit(1);
- }
-- outname = srcName.getString()->getCString();
-+ outname = (char *)srcName.getString()->getCString();
- // We cannot free srcName, as objname shares its string.
- // srcName.free();
- } else if (objnum > 0) {
-@@ -173,9 +173,9 @@
-
- // parse the header: object numbers and offsets
- objStr.streamReset();
-- str = new EmbedStream(objStr.getStream(), Object(objNull), gTrue, first);
-+ str = new EmbedStream(objStr.getStream(), Object(objNull), true, first);
- lexer = new Lexer(xref, str);
-- parser = new Parser(xref, lexer, gFalse);
-+ parser = new Parser(xref, lexer, false);
- for (n = 0; n < nObjects; ++n) {
- obj1 = parser->getObj();
- obj2 = parser->getObj();
diff -Naur a/texk/web2c/ptexdir/ptex_version.h b/texk/web2c/ptexdir/ptex_version.h
--- a/texk/web2c/ptexdir/ptex_version.h 2018-01-21 03:48:06.000000000 +0000
+++ b/texk/web2c/ptexdir/ptex_version.h 2018-04-30 16:27:55.978626503 +0100
diff --git a/latex/texlive/patches/texlive-20180414-source-upstream_fixes-2.patch b/latex/texlive/patches/texlive-20180414-source-upstream_fixes-2.patch
new file mode 100644
index 0000000000..eb152f3352
--- /dev/null
+++ b/latex/texlive/patches/texlive-20180414-source-upstream_fixes-2.patch
@@ -0,0 +1,6350 @@
+diff -ruN r47457/texk/web2c/pdftexdir/am/pdftex.am r49040/texk/web2c/pdftexdir/am/pdftex.am
+--- r47457/texk/web2c/pdftexdir/am/pdftex.am 2018-12-05 19:19:35.376778487 +0100
++++ r49040/texk/web2c/pdftexdir/am/pdftex.am 2018-12-05 19:19:35.404778485 +0100
+@@ -1,6 +1,6 @@
+ ## texk/web2c/pdftexdir/am/pdftex.am: Makefile fragment for pdfTeX.
+ ##
+-## Copyright 2016-2017 Karl Berry <tex-live@tug.org>
++## Copyright 2016-2018 Karl Berry <tex-live@tug.org>
+ ## Copyright 2009-2015 Peter Breitenlohner <tex-live@tug.org>
+ ## You may freely use, modify and/or distribute this file.
+
+@@ -92,10 +92,13 @@
+ pdftexdir/README \
+ pdftexdir/change-files.txt
+
+-# pdfTeX Tests
++# pdfTeX tests
+ #
+-pdftex_tests = pdftexdir/wprob.test pdftexdir/pdftex.test pdftexdir/pdfimage.test
+-pdftexdir/wprob.log pdftexdir/pdftex.log pdftexdir/pdfimage.log: pdftex$(EXEEXT)
++pdftex_tests = pdftexdir/wprob.test pdftexdir/pdftex.test \
++ pdftexdir/pdfimage.test pdftexdir/expanded.test
++
++pdftexdir/wprob.log pdftexdir/pdftex.log \
++ pdftexdir/pdfimage.log pdftexdir/expanded.log: pdftex$(EXEEXT)
+
+ EXTRA_DIST += $(pdftex_tests)
+
+@@ -112,3 +115,6 @@
+ tests/1-4.jpg tests/B.pdf tests/basic.tex tests/lily-ledger-broken.png
+ DISTCLEANFILES += pdfimage.fmt pdfimage.log pdfimage.pdf
+
++## expanded.test
++EXTRA_DIST += tests/expanded.tex
++DISTCLEANFILES += expanded.log
+diff -ruN r47457/texk/web2c/pdftexdir/ChangeLog r49040/texk/web2c/pdftexdir/ChangeLog
+--- r47457/texk/web2c/pdftexdir/ChangeLog 2018-12-05 19:19:35.373778487 +0100
++++ r49040/texk/web2c/pdftexdir/ChangeLog 2018-12-05 19:19:35.402778485 +0100
+@@ -1,3 +1,98 @@
++2018-11-01 Akira Kakuto <kakuto@fuk.kindai.ac.jp>
++
++ * pdftosrc-poppler0.71.0.cc, pdftoepdf-poppler0.71.0.cc:
++ Add to support system poppler-0.71.0.
++ * NEWS: Change comments on system poppler.
++
++2018-10-24 Karl Berry <karl@tug.org>
++
++ * writet1.c (t1_check_unusual_charstring): don't call
++ strlen(t1_buf_array) if it is null.
++ From Luigi, 22 Oct 2018 22:43:03.
++
++2018-10-22 Akira Kakuto <kakuto@fuk.kindai.ac.jp>
++
++ * pdftosrc-newpoppler.cc: Add a comment that it works upto
++ the poppler 0.70.0.
++ * pdftoepdf-poppler0.70.0.cc: A new file for poppler-0.70.0
++ and newer.
++
++2018-10-02 Akira Kakuto <kakuto@fuk.kindai.ac.jp>
++
++ * pdftoepdf.cc: Remove changes for w32.
++
++2018-09-23 Akira Kakuto <kakuto@fuk.kindai.ac.jp>
++
++ * pdftosrc-newpoppler.cc: Add a comment that it works upto
++ the poppler 0.69.0.
++ * pdftoepdf-poppler0.68.0.cc: Rename pdftoepdf-newpoppler.cc
++ and add comments.
++ * pdftoepdf-poppler0.69.0.cc: A new file for poppler-0.69.0
++ and newer.
++
++2018-09-18 Nick Roessler <nicholas.e.roessler@gmail.com>
++
++ * writet1.c (t1_check_unusual_charstring): protect against buffer
++ overflow.
++
++2018-09-09 Karl Berry <karl@tug.org>
++
++ * expanded.test,
++ * ttf2afm.test: LC_ALL=LANGUAGE=C.
++
++2018-07-09 Karl Berry <karl@freefriends.org>
++
++ * writefont.c (write_fontdescriptor) [ENABLE_PDF_CHARSET]:
++ compile-time conditional for re-enabling output of PDF /CharSet,
++ which is now disabled by default.
++
++2018-06-13 TANAKA Takuji <ttk@t-lab.opal.ne.jp>
++
++ * ptexlib.h: Output correct Unicode strings on console
++ (w32 only).
++
++2018-06-12 Akira Kakuto <kakuto@fuk.kindai.ac.jp>
++
++ * pdftoepdf.cc: Free unused memory (w32 only).
++
++2018-06-11 Akira Kakuto <kakuto@fuk.kindai.ac.jp>
++
++ * pdftoepdf.cc: Remove xfree(file_name) in order to avoid
++ to output garbage.
++ * pdftoepdf-newpoppler.cc: Remove _WIN32 changes, since
++ utf-8 names are transformed to Unicode and _wopened
++ in poppler.
++
++2018-06-10 TANAKA Takuji <ttk@t-lab.opal.ne.jp>
++
++ * ptexlib.h, pdftoepdf.cc, pdftoepdf-newpoppler.cc:
++ Allow non-ascii file names for pdfTeX with UTF-8 source files
++ (w32 only). The function is enabled by setting
++ 'command_line_encoding=utf-8' in texmf.cnf.
++
++2018-05-29 Akira Kakuto <kakuto@fuk.kindai.ac.jp>
++
++ * ptexlib.h: Discard the changes on 2018-05-11, since
++ 'command_line_encoding=utf-8' is not so natural for
++ pdfTeX (w32 only).
++
++2018-05-13 Joseph Wright <joseph.wright@morningstar2.co.uk>
++
++ * pdftex.web: New primitive \expanded based on original
++ suggestion by Heiko Oberdiek, and with work by
++ Bruno Le Floch and David Carlisle (on behalf of The LaTeX Project).
++ (expanded_code): new @d, new cases.
++ https://mailman.ntg.nl/pipermail/ntg-pdftex/2018-May/004233.html
++
++2018-05-11 Akira Kakuto <kakuto@fuk.kindai.ac.jp>
++
++ * ptexlib.h: Allow non-ascii file names in pdfTeX (w32 only).
++
++2018-04-28 Akira Kakuto <kakuto@fuk.kindai.ac.jp>
++
++ * pdftoepdf-newpoppler.cc, pdftosrc-newpoppler.cc:
++ Support poppler 0.64.0.
++
+ 2018-04-14 Karl Berry <karl@tug.org>
+
+ * TeX Live 2018 release, pdftex 1.40.19.
+diff -ruN r47457/texk/web2c/pdftexdir/expanded.test r49040/texk/web2c/pdftexdir/expanded.test
+--- r47457/texk/web2c/pdftexdir/expanded.test 1970-01-01 01:00:00.000000000 +0100
++++ r49040/texk/web2c/pdftexdir/expanded.test 2018-12-05 19:19:35.386778486 +0100
+@@ -0,0 +1,19 @@
++#! /bin/sh -vx
++# $Id$
++# Public domain
++# David Carlisle: version for \expanded based on existing test scripts
++# by Peter Breitenlohner and Karl Berry.
++
++LC_ALL=C; export LC_ALL; LANGUAGE=C; export LANGUAGE
++
++TEXMFCNF=$srcdir/../kpathsea; export TEXMFCNF
++TEXINPUTS=$srcdir/pdftexdir/tests:.; export TEXINPUTS
++
++./pdftex -ini -etex --interaction batchmode expanded.tex
++sed -n -e 's/[\\]pdf/\\/g' -e '/START/,/END/p' expanded.log \
++ >expanded_pdftex.log || exit 1
++
++diff "$srcdir/pdftexdir/tests/expanded.txt" expanded_pdftex.log || exit 1
++
++exit 0
++
+diff -ruN r47457/texk/web2c/pdftexdir/NEWS r49040/texk/web2c/pdftexdir/NEWS
+--- r47457/texk/web2c/pdftexdir/NEWS 2018-12-05 19:19:35.369778487 +0100
++++ r49040/texk/web2c/pdftexdir/NEWS 2018-12-05 19:19:35.399778485 +0100
+@@ -1,3 +1,8 @@
++- changes:
++ - new primitive \expanded (from unreleased pdftex 1.50 branch + luatex).
++ - the /CharSet string is now always omitted from the PDF output, since
++ it cannot feasibly be guaranteed correct, but the standard requires this.
++
+ pdfTeX 3.14159265-2.6-1.40.19 (TeX Live 2018) (April 14, 2018)
+ - changes:
+ - do not hash current directory into PDF ID, for more reproducible builds
+@@ -11,12 +16,20 @@
+ non-primitive (pdftex r784).
+ - \pdfprimitive does not swallow a following control sequence (pdftex r784).
+ - \ifpdfprimitive now correctly returns true for "\ " (TL r45394).
++ - \pdfglyphtounicode now warns if the argument is outside the valid
++ range for Unicode; the implication is that multiple code points must
++ now be separated by spaces (as has always been documented).
+
+ - source: support xpdf-4 by default, or xpdf-3.04, or poppler-0.57.0
+- and older, via #defines. Provide new files, pdftoepdf-newpoppler.cc
+- and pdftosrc-newpoppler.cc, to support poppler-0.59.0 and newer:
+- they should be renamed as pdftoepdf.cc and pdftosrc.cc, respectively,
+- before compilation.
++ and older, via #defines. Provide new files, pdftosrc-newpoppler.cc
++ for poppler-0.59.0 upto poppler-0.70.1, pdftosrc-poppler0.71.0 for
++ poppler-0.71.0 and newer, pdftoepdf-poppler0.68.0.cc for
++ poppler-0.59.0 upto poppler-0.68.0, pdftoepdf-poppler0.69.0.cc
++ for poppler-0.69.0, pdftoepdf-poppler0.70.0.cc for poppler-0.70.0
++ and poppler-0.71.0, and pdftoepdf-poppler0.71.0 for poppler-0.71.0
++ and newer. Note that pdftosrc-*.cc and pdftoepdf-*.cc should be
++ renamed as pdftosrc.cc, and pdftoepdf.cc, respectively, before
++ compilation.
+
+ ---------------------------------------------------------------
+ pdfTeX 3.14159265-2.6-1.40.18 (TeX Live 2017) (April 27, 2017)
+diff -ruN r47457/texk/web2c/pdftexdir/pdfimage.test r49040/texk/web2c/pdftexdir/pdfimage.test
+--- r47457/texk/web2c/pdftexdir/pdfimage.test 2018-12-05 19:19:35.276778494 +0100
++++ r49040/texk/web2c/pdftexdir/pdfimage.test 2018-12-05 19:19:35.385778486 +0100
+@@ -1,17 +1,15 @@
+ #! /bin/sh -vx
+ # $Id$
+-# Copyright 2017 Karl Berry <tex-live@tug.org>#
++# Copyright 2017-2018 Karl Berry <tex-live@tug.org>#
+ # Copyright 2013 Peter Breitenlohner <tex-live@tug.org>
+ # You may freely use, modify and/or distribute this file.
+
+-TEXMFCNF=$srcdir/../kpathsea
+-TEXINPUTS=$srcdir/pdftexdir/tests:$srcdir/tests
+-TEXFORMATS=.
++TEXMFCNF=$srcdir/../kpathsea; export TEXMFCNF
++TEXINPUTS=$srcdir/pdftexdir/tests:$srcdir/tests; export TEXINPUTS
++TEXFORMATS=.; export TEXFORMATS
+
+-export TEXMFCNF TEXINPUTS TEXFORMATS
++./pdftex -ini -interaction=batchmode pdfimage </dev/null || exit 1
+
+-./pdftex -ini pdfimage || exit 1
+-
+-./pdftex -fmt=pdfimage pdfimage || exit 1
++./pdftex -fmt=pdfimage -interaction=batchmode pdfimage </dev/null || exit 1
+
+ exit 0
+diff -ruN r47457/texk/web2c/pdftexdir/pdftex.test r49040/texk/web2c/pdftexdir/pdftex.test
+--- r47457/texk/web2c/pdftexdir/pdftex.test 2018-12-05 19:19:35.277778494 +0100
++++ r49040/texk/web2c/pdftexdir/pdftex.test 2018-12-05 19:19:35.386778486 +0100
+@@ -1,10 +1,11 @@
+ #! /bin/sh -vx
+ # $Id$
+-# Copyright 2017 Karl Berry <tex-live@tug.org>
++# Copyright 2017-2018 Karl Berry <tex-live@tug.org>
+ # Copyright 2010 Peter Breitenlohner <tex-live@tug.org>
+ # You may freely use, modify and/or distribute this file.
+
+-# Not really a test, just making sure the program executes.
+-
+-./pdftex -version || exit 1
++# Make sure the program executes.
+
++./pdftex --version || exit 1
++./pdftex --help || exit 1
++exit 0
+diff -ruN r47457/texk/web2c/pdftexdir/pdftex.web r49040/texk/web2c/pdftexdir/pdftex.web
+--- r47457/texk/web2c/pdftexdir/pdftex.web 2018-12-05 19:19:35.333778490 +0100
++++ r49040/texk/web2c/pdftexdir/pdftex.web 2018-12-05 19:19:35.398778485 +0100
+@@ -10748,7 +10748,8 @@
+ @d etex_convert_base=5 {base for \eTeX's command codes}
+ @d eTeX_revision_code=etex_convert_base {command code for \.{\\eTeXrevision}}
+ @d etex_convert_codes=etex_convert_base+1 {end of \eTeX's command codes}
+-@d pdftex_first_expand_code = etex_convert_codes {base for \pdfTeX's command codes}
++@d expanded_code = etex_convert_codes {command code for \.{\\expanded}}
++@d pdftex_first_expand_code = expanded_code + 1 {base for \pdfTeX's command codes}
+ @d pdftex_revision_code = pdftex_first_expand_code + 0 {command code for \.{\\pdftexrevision}}
+ @d pdftex_banner_code = pdftex_first_expand_code + 1 {command code for \.{\\pdftexbanner}}
+ @d pdf_font_name_code = pdftex_first_expand_code + 2 {command code for \.{\\pdffontname}}
+@@ -10790,6 +10791,9 @@
+ primitive("fontname",convert,font_name_code);@/
+ @!@:font_name_}{\.{\\fontname} primitive@>
+ @#
++primitive("expanded",convert,expanded_code);@/
++@!@:expanded_}{\.{\\expanded} primitive@>
++@#
+ primitive("pdftexrevision",convert,pdftex_revision_code);@/
+ @!@:pdftex_revision_}{\.{\\pdftexrevision} primitive@>
+ primitive("pdftexbanner",convert,pdftex_banner_code);@/
+@@ -10854,6 +10858,7 @@
+ meaning_code: print_esc("meaning");
+ font_name_code: print_esc("fontname");
+ eTeX_revision_code: print_esc("eTeXrevision");
++ expanded_code: print_esc("expanded");
+ pdftex_revision_code: print_esc("pdftexrevision");
+ pdftex_banner_code: print_esc("pdftexbanner");
+ pdf_font_name_code: print_esc("pdffontname");
+@@ -10926,6 +10931,20 @@
+ end;
+ font_name_code: scan_font_ident;
+ eTeX_revision_code: do_nothing;
++expanded_code:
++ begin
++ save_scanner_status := scanner_status;
++ save_warning_index := warning_index;
++ save_def_ref := def_ref;
++ save_cur_string;
++ scan_pdf_ext_toks;
++ warning_index := save_warning_index;
++ scanner_status := save_scanner_status;
++ ins_list(link(def_ref));
++ def_ref := save_def_ref;
++ restore_cur_string;
++ return;
++ end;
+ pdftex_revision_code: do_nothing;
+ pdftex_banner_code: do_nothing;
+ pdf_font_name_code, pdf_font_objnum_code, pdf_font_size_code: begin
+diff -ruN r47457/texk/web2c/pdftexdir/pdftoepdf-newpoppler.cc r49040/texk/web2c/pdftexdir/pdftoepdf-newpoppler.cc
+--- r47457/texk/web2c/pdftexdir/pdftoepdf-newpoppler.cc 2018-12-05 19:19:35.275778494 +0100
++++ r49040/texk/web2c/pdftexdir/pdftoepdf-newpoppler.cc 1970-01-01 01:00:00.000000000 +0100
+@@ -1,1113 +0,0 @@
+-/*
+-Copyright 1996-2017 Han The Thanh, <thanh@pdftex.org>
+-
+-This file is part of pdfTeX.
+-
+-pdfTeX 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.
+-
+-pdfTeX 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, see <http://www.gnu.org/licenses/>.
+-*/
+-
+-/*
+-This is based on the patch texlive-poppler-0.59.patch <2017-09-19> at
+-https://git.archlinux.org/svntogit/packages.git/plain/texlive-bin/trunk
+-by Arch Linux. A little modifications are made to avoid a crash for
+-some kind of pdf images, such as figure_missing.pdf in gnuplot.
+-The poppler should be 0.59.0 or newer versions.
+-POPPLER_VERSION should be defined.
+-*/
+-
+-/* Do this early in order to avoid a conflict between
+- MINGW32 <rpcndr.h> defining 'boolean' as 'unsigned char' and
+- <kpathsea/types.h> defining Pascal's boolean as 'int'.
+-*/
+-#include <w2c/config.h>
+-#include <kpathsea/lib.h>
+-
+-#include <stdlib.h>
+-#include <math.h>
+-#include <stddef.h>
+-#include <stdio.h>
+-#include <string.h>
+-#include <ctype.h>
+-
+-#ifdef POPPLER_VERSION
+-#include <dirent.h>
+-#include <poppler-config.h>
+-#include <goo/GooString.h>
+-#include <goo/gmem.h>
+-#include <goo/gfile.h>
+-#define GString GooString
+-#else
+-#error POPPLER_VERSION should be defined.
+-#endif
+-#include <assert.h>
+-
+-#include "Object.h"
+-#include "Stream.h"
+-#include "Array.h"
+-#include "Dict.h"
+-#include "XRef.h"
+-#include "Catalog.h"
+-#include "Link.h"
+-#include "Page.h"
+-#include "GfxFont.h"
+-#include "PDFDoc.h"
+-#include "GlobalParams.h"
+-#include "Error.h"
+-
+-// This file is mostly C and not very much C++; it's just used to interface
+-// the functions of xpdf, which are written in C++.
+-
+-extern "C" {
+-#include <pdftexdir/ptexmac.h>
+-#include <pdftexdir/pdftex-common.h>
+-
+-// These functions from pdftex.web gets declared in pdftexcoerce.h in the
+-// usual web2c way, but we cannot include that file here because C++
+-// does not allow it.
+-extern int getpdfsuppresswarningpagegroup(void);
+-extern integer getpdfsuppressptexinfo(void);
+-extern integer zround(double);
+-}
+-
+-// The prefix "PTEX" for the PDF keys is special to pdfTeX;
+-// this has been registered with Adobe by Hans Hagen.
+-
+-#define pdfkeyprefix "PTEX"
+-
+-#define MASK_SUPPRESS_PTEX_FULLBANNER 0x01
+-#define MASK_SUPPRESS_PTEX_FILENAME 0x02
+-#define MASK_SUPPRESS_PTEX_PAGENUMBER 0x04
+-#define MASK_SUPPRESS_PTEX_INFODICT 0x08
+-
+-// When copying the Resources of the selected page, all objects are copied
+-// recusively top-down. Indirect objects however are not fetched during
+-// copying, but get a new object number from pdfTeX and then will be
+-// appended into a linked list. Duplicates are checked and removed from the
+-// list of indirect objects during appending.
+-
+-enum InObjType {
+- objFont,
+- objFontDesc,
+- objOther
+-};
+-
+-struct InObj {
+- Ref ref; // ref in original PDF
+- InObjType type; // object type
+- InObj *next; // next entry in list of indirect objects
+- int num; // new object number in output PDF
+- fd_entry *fd; // pointer to /FontDescriptor object structure
+- int enc_objnum; // Encoding for objFont
+- int written; // has it been written to output PDF?
+-};
+-
+-struct UsedEncoding {
+- int enc_objnum;
+- GfxFont *font;
+- UsedEncoding *next;
+-};
+-
+-static InObj *inObjList;
+-static UsedEncoding *encodingList;
+-static GBool isInit = gFalse;
+-
+-// --------------------------------------------------------------------
+-// Maintain list of open embedded PDF files
+-// --------------------------------------------------------------------
+-
+-struct PdfDocument {
+- char *file_name;
+- PDFDoc *doc;
+- XRef *xref;
+- InObj *inObjList;
+- int occurences; // number of references to the document; the doc can be
+- // deleted when this is negative
+- PdfDocument *next;
+-};
+-
+-static PdfDocument *pdfDocuments = 0;
+-
+-static XRef *xref = 0;
+-
+-// Returns pointer to PdfDocument record for PDF file.
+-// Creates a new record if it doesn't exist yet.
+-// xref is made current for the document.
+-
+-static PdfDocument *find_add_document(char *file_name)
+-{
+- PdfDocument *p = pdfDocuments;
+- while (p && strcmp(p->file_name, file_name) != 0)
+- p = p->next;
+- if (p) {
+- xref = p->xref;
+- (p->occurences)++;
+- return p;
+- }
+- p = new PdfDocument;
+- p->file_name = xstrdup(file_name);
+- p->xref = xref = 0;
+- p->occurences = 0;
+- GString *docName = new GString(p->file_name);
+- p->doc = new PDFDoc(docName); // takes ownership of docName
+- if (!p->doc->isOk() || !p->doc->okToPrint()) {
+- pdftex_fail("xpdf: reading PDF image failed");
+- }
+- p->inObjList = 0;
+- p->next = pdfDocuments;
+- pdfDocuments = p;
+- return p;
+-}
+-
+-// Deallocate a PdfDocument with all its resources
+-
+-static void delete_document(PdfDocument * pdf_doc)
+-{
+- PdfDocument **p = &pdfDocuments;
+- while (*p && *p != pdf_doc)
+- p = &((*p)->next);
+- // should not happen:
+- if (!*p)
+- return;
+- // unlink from list
+- *p = pdf_doc->next;
+- // free pdf_doc's resources
+- InObj *r, *n;
+- for (r = pdf_doc->inObjList; r != 0; r = n) {
+- n = r->next;
+- delete r;
+- }
+- xref = pdf_doc->xref;
+- delete pdf_doc->doc;
+- xfree(pdf_doc->file_name);
+- delete pdf_doc;
+-}
+-
+-// --------------------------------------------------------------------
+-
+-static int addEncoding(GfxFont * gfont)
+-{
+- UsedEncoding *n;
+- n = new UsedEncoding;
+- n->next = encodingList;
+- encodingList = n;
+- n->font = gfont;
+- n->enc_objnum = pdfnewobjnum();
+- return n->enc_objnum;
+-}
+-
+-#define addFont(ref, fd, enc_objnum) \
+- addInObj(objFont, ref, fd, enc_objnum)
+-
+-// addFontDesc is only used to avoid writing the original FontDescriptor
+-// from the PDF file.
+-
+-#define addFontDesc(ref, fd) \
+- addInObj(objFontDesc, ref, fd, 0)
+-
+-#define addOther(ref) \
+- addInObj(objOther, ref, 0, 0)
+-
+-static int addInObj(InObjType type, Ref ref, fd_entry * fd, int e)
+-{
+- InObj *p, *q, *n = new InObj;
+- if (ref.num == 0)
+- pdftex_fail("PDF inclusion: invalid reference");
+- n->ref = ref;
+- n->type = type;
+- n->next = 0;
+- n->fd = fd;
+- n->enc_objnum = e;
+- n->written = 0;
+- if (inObjList == 0)
+- inObjList = n;
+- else {
+- for (p = inObjList; p != 0; p = p->next) {
+- if (p->ref.num == ref.num && p->ref.gen == ref.gen) {
+- delete n;
+- return p->num;
+- }
+- q = p;
+- }
+- // it is important to add new objects at the end of the list,
+- // because new objects are being added while the list is being
+- // written out.
+- q->next = n;
+- }
+- if (type == objFontDesc)
+- n->num = get_fd_objnum(fd);
+- else
+- n->num = pdfnewobjnum();
+- return n->num;
+-}
+-
+-#if 0 /* unusewd */
+-static int getNewObjectNumber(Ref ref)
+-{
+- InObj *p;
+- if (inObjList == 0) {
+- pdftex_fail("No objects copied yet");
+- } else {
+- for (p = inObjList; p != 0; p = p->next) {
+- if (p->ref.num == ref.num && p->ref.gen == ref.gen) {
+- return p->num;
+- }
+- }
+- pdftex_fail("Object not yet copied: %i %i", ref.num, ref.gen);
+- }
+-#ifdef _MSC_VER
+- /* Never reached, but without __attribute__((noreturn)) for pdftex_fail()
+- MSVC 5.0 requires an int return value. */
+- return -60000;
+-#endif
+-}
+-#endif
+-
+-static void copyObject(Object *);
+-
+-static void copyName(char *s)
+-{
+- pdf_puts("/");
+- for (; *s != 0; s++) {
+- if (isdigit(*s) || isupper(*s) || islower(*s) || *s == '_' ||
+- *s == '.' || *s == '-' || *s == '+')
+- pdfout(*s);
+- else
+- pdf_printf("#%.2X", *s & 0xFF);
+- }
+-}
+-
+-static void copyDictEntry(Object * obj, int i)
+-{
+- Object obj1;
+- copyName(obj->dictGetKey(i));
+- pdf_puts(" ");
+- obj1 = obj->dictGetValNF(i);
+- copyObject(&obj1);
+- pdf_puts("\n");
+-}
+-
+-static void copyDict(Object * obj)
+-{
+- int i, l;
+- if (!obj->isDict())
+- pdftex_fail("PDF inclusion: invalid dict type <%s>",
+- obj->getTypeName());
+- for (i = 0, l = obj->dictGetLength(); i < l; ++i)
+- copyDictEntry(obj, i);
+-}
+-
+-static void copyFontDict(Object * obj, InObj * r)
+-{
+- int i, l;
+- char *key;
+- if (!obj->isDict())
+- pdftex_fail("PDF inclusion: invalid dict type <%s>",
+- obj->getTypeName());
+- pdf_puts("<<\n");
+- assert(r->type == objFont); // FontDescriptor is in fd_tree
+- for (i = 0, l = obj->dictGetLength(); i < l; ++i) {
+- key = obj->dictGetKey(i);
+- if (strncmp("FontDescriptor", key, strlen("FontDescriptor")) == 0
+- || strncmp("BaseFont", key, strlen("BaseFont")) == 0
+- || strncmp("Encoding", key, strlen("Encoding")) == 0)
+- continue; // skip original values
+- copyDictEntry(obj, i);
+- }
+- // write new FontDescriptor, BaseFont, and Encoding
+- pdf_printf("/FontDescriptor %d 0 R\n", get_fd_objnum(r->fd));
+- pdf_printf("/BaseFont %d 0 R\n", get_fn_objnum(r->fd));
+- pdf_printf("/Encoding %d 0 R\n", r->enc_objnum);
+- pdf_puts(">>");
+-}
+-
+-static void copyStream(Stream * str)
+-{
+- int c, c2 = 0;
+- str->reset();
+- while ((c = str->getChar()) != EOF) {
+- pdfout(c);
+- c2 = c;
+- }
+- pdflastbyte = c2;
+-}
+-
+-static void copyProcSet(Object * obj)
+-{
+- int i, l;
+- Object procset;
+- if (!obj->isArray())
+- pdftex_fail("PDF inclusion: invalid ProcSet array type <%s>",
+- obj->getTypeName());
+- pdf_puts("/ProcSet [ ");
+- for (i = 0, l = obj->arrayGetLength(); i < l; ++i) {
+- procset = obj->arrayGetNF(i);
+- if (!procset.isName())
+- pdftex_fail("PDF inclusion: invalid ProcSet entry type <%s>",
+- procset.getTypeName());
+- copyName(procset.getName());
+- pdf_puts(" ");
+- }
+- pdf_puts("]\n");
+-}
+-
+-#define REPLACE_TYPE1C true
+-
+-static bool embeddableFont(Object * fontdesc)
+-{
+- Object fontfile, ffsubtype;
+-
+- if (!fontdesc->isDict())
+- return false;
+- fontfile = fontdesc->dictLookup("FontFile");
+- if (fontfile.isStream())
+- return true;
+- if (REPLACE_TYPE1C) {
+- fontfile = fontdesc->dictLookup("FontFile3");
+- if (!fontfile.isStream())
+- return false;
+- ffsubtype = fontfile.streamGetDict()->lookup("Subtype");
+- return ffsubtype.isName() && !strcmp(ffsubtype.getName(), "Type1C");
+- }
+- return false;
+-}
+-
+-static void copyFont(char *tag, Object * fontRef)
+-{
+- Object fontdict, subtype, basefont, fontdescRef, fontdesc, charset,
+- stemV;
+- GfxFont *gfont;
+- fd_entry *fd;
+- fm_entry *fontmap;
+- // Check whether the font has already been embedded before analysing it.
+- InObj *p;
+- Ref ref = fontRef->getRef();
+- for (p = inObjList; p; p = p->next) {
+- if (p->ref.num == ref.num && p->ref.gen == ref.gen) {
+- copyName(tag);
+- pdf_printf(" %d 0 R ", p->num);
+- return;
+- }
+- }
+- // Only handle included Type1 (and Type1C) fonts; anything else will be copied.
+- // Type1C fonts are replaced by Type1 fonts, if REPLACE_TYPE1C is true.
+- fontdict = fontRef->fetch(xref);
+- fontdesc = Object(objNull);
+- if (fontdict.isDict()) {
+- subtype = fontdict.dictLookup("Subtype");
+- basefont = fontdict.dictLookup("BaseFont");
+- fontdescRef = fontdict.dictLookupNF("FontDescriptor");
+- if (fontdescRef.isRef()) {
+- fontdesc = fontdescRef.fetch(xref);
+- }
+- }
+- if (!fixedinclusioncopyfont && fontdict.isDict()
+- && subtype.isName()
+- && !strcmp(subtype.getName(), "Type1")
+- && basefont.isName()
+- && fontdescRef.isRef()
+- && fontdesc.isDict()
+- && embeddableFont(&fontdesc)
+- && (fontmap = lookup_fontmap(basefont.getName())) != NULL) {
+- // round /StemV value, since the PDF input is a float
+- // (see Font Descriptors in PDF reference), but we only store an
+- // integer, since we don't want to change the struct.
+- stemV = fontdesc.dictLookup("StemV");
+- fd = epdf_create_fontdescriptor(fontmap, zround(stemV.getNum()));
+- charset = fontdesc.dictLookup("CharSet");
+- if (!charset.isNull() &&
+- charset.isString() && is_subsetable(fontmap))
+- epdf_mark_glyphs(fd, charset.getString()->getCString());
+- else
+- embed_whole_font(fd);
+- addFontDesc(fontdescRef.getRef(), fd);
+- copyName(tag);
+- gfont = GfxFont::makeFont(xref, tag, fontRef->getRef(),
+- fontdict.getDict());
+- pdf_printf(" %d 0 R ", addFont(fontRef->getRef(), fd,
+- addEncoding(gfont)));
+- } else {
+- copyName(tag);
+- pdf_puts(" ");
+- copyObject(fontRef);
+- }
+-}
+-
+-static void copyFontResources(Object * obj)
+-{
+- Object fontRef;
+- int i, l;
+- if (!obj->isDict())
+- pdftex_fail("PDF inclusion: invalid font resources dict type <%s>",
+- obj->getTypeName());
+- pdf_puts("/Font << ");
+- for (i = 0, l = obj->dictGetLength(); i < l; ++i) {
+- fontRef = obj->dictGetValNF(i);
+- if (fontRef.isRef())
+- copyFont(obj->dictGetKey(i), &fontRef);
+- else if (fontRef.isDict()) { // some programs generate pdf with embedded font object
+- copyName(obj->dictGetKey(i));
+- pdf_puts(" ");
+- copyObject(&fontRef);
+- }
+- else
+- pdftex_fail("PDF inclusion: invalid font in reference type <%s>",
+- fontRef.getTypeName());
+- }
+- pdf_puts(">>\n");
+-}
+-
+-static void copyOtherResources(Object * obj, char *key)
+-{
+- // copies all other resources (write_epdf handles Fonts and ProcSets),
+-
+- // if Subtype is present, it must be a name
+- if (strcmp("Subtype", key) == 0) {
+- if (!obj->isName()) {
+- pdftex_warn("PDF inclusion: Subtype in Resources dict is not a name"
+- " (key '%s', type <%s>); ignored.",
+- key, obj->getTypeName());
+- return;
+- }
+- } else if (!obj->isDict()) {
+- //FIXME: Write the message only to the log file
+- pdftex_warn("PDF inclusion: invalid other resource which is no dict"
+- " (key '%s', type <%s>); ignored.",
+- key, obj->getTypeName());
+- return;
+- }
+- copyName(key);
+- pdf_puts(" ");
+- copyObject(obj);
+-}
+-
+-// Function onverts double to string; very small and very large numbers
+-// are NOT converted to scientific notation.
+-// n must be a number or real conforming to the implementation limits
+-// of PDF as specified in appendix C.1 of the PDF Ref.
+-// These are:
+-// maximum value of ints is +2^32
+-// maximum value of reals is +2^15
+-// smalles values of reals is 1/(2^16)
+-
+-static char *convertNumToPDF(double n)
+-{
+- static const int precision = 6;
+- static const int fact = (int) 1E6; // must be 10^precision
+- static const double epsilon = 0.5E-6; // 2epsilon must be 10^-precision
+- static char buf[64];
+- // handle very small values: return 0
+- if (fabs(n) < epsilon) {
+- buf[0] = '0';
+- buf[1] = '\0';
+- } else {
+- char ints[64];
+- int bindex = 0, sindex = 0;
+- int ival, fval;
+- // handle the sign part if n is negative
+- if (n < 0) {
+- buf[bindex++] = '-';
+- n = -n;
+- }
+- n += epsilon; // for rounding
+- // handle the integer part, simply with sprintf
+- ival = (int) floor(n);
+- n -= ival;
+- sprintf(ints, "%d", ival);
+- while (ints[sindex] != 0)
+- buf[bindex++] = ints[sindex++];
+- // handle the fractional part up to 'precision' digits
+- fval = (int) floor(n * fact);
+- if (fval) {
+- // set a dot
+- buf[bindex++] = '.';
+- sindex = bindex + precision;
+- buf[sindex--] = '\0';
+- // fill up trailing zeros with the string terminator NULL
+- while (((fval % 10) == 0) && (sindex >= bindex)) {
+- buf[sindex--] = '\0';
+- fval /= 10;
+- }
+- // fill up the fractional part back to front
+- while (sindex >= bindex) {
+- buf[sindex--] = (fval % 10) + '0';
+- fval /= 10;
+- }
+- } else
+- buf[bindex++] = 0;
+- }
+- return (char *) buf;
+-}
+-
+-static void copyObject(Object * obj)
+-{
+- Object obj1;
+- int i, l, c;
+- Ref ref;
+- char *p;
+- GString *s;
+- if (obj->isBool()) {
+- pdf_printf("%s", obj->getBool()? "true" : "false");
+- } else if (obj->isInt()) {
+- pdf_printf("%i", obj->getInt());
+- } else if (obj->isReal()) {
+- pdf_printf("%s", convertNumToPDF(obj->getReal()));
+- } else if (obj->isNum()) {
+- pdf_printf("%s", convertNumToPDF(obj->getNum()));
+- } else if (obj->isString()) {
+- s = obj->getString();
+- p = s->getCString();
+- l = s->getLength();
+- if (strlen(p) == (unsigned int) l) {
+- pdf_puts("(");
+- for (; *p != 0; p++) {
+- c = (unsigned char) *p;
+- if (c == '(' || c == ')' || c == '\\')
+- pdf_printf("\\%c", c);
+- else if (c < 0x20 || c > 0x7F)
+- pdf_printf("\\%03o", c);
+- else
+- pdfout(c);
+- }
+- pdf_puts(")");
+- } else {
+- pdf_puts("<");
+- for (i = 0; i < l; i++) {
+- c = s->getChar(i) & 0xFF;
+- pdf_printf("%.2x", c);
+- }
+- pdf_puts(">");
+- }
+- } else if (obj->isName()) {
+- copyName(obj->getName());
+- } else if (obj->isNull()) {
+- pdf_puts("null");
+- } else if (obj->isArray()) {
+- pdf_puts("[");
+- for (i = 0, l = obj->arrayGetLength(); i < l; ++i) {
+- obj1 = obj->arrayGetNF(i);
+- if (!obj1.isName())
+- pdf_puts(" ");
+- copyObject(&obj1);
+- }
+- pdf_puts("]");
+- } else if (obj->isDict()) {
+- pdf_puts("<<\n");
+- copyDict(obj);
+- pdf_puts(">>");
+- } else if (obj->isStream()) {
+- pdf_puts("<<\n");
+- copyDict(obj->getStream()->getDictObject());
+- pdf_puts(">>\n");
+- pdf_puts("stream\n");
+- copyStream(obj->getStream()->getUndecodedStream());
+- pdf_puts("\nendstream");
+- } else if (obj->isRef()) {
+- ref = obj->getRef();
+- if (ref.num == 0) {
+- pdftex_fail
+- ("PDF inclusion: reference to invalid object"
+- " (is the included pdf broken?)");
+- } else
+- pdf_printf("%d 0 R", addOther(ref));
+- } else {
+- pdftex_fail("PDF inclusion: type <%s> cannot be copied",
+- obj->getTypeName());
+- }
+-}
+-
+-static void writeRefs()
+-{
+- InObj *r;
+- for (r = inObjList; r != 0; r = r->next) {
+- if (!r->written) {
+- r->written = 1;
+- Object obj1 = xref->fetch(r->ref.num, r->ref.gen);
+- if (r->type == objFont) {
+- assert(!obj1.isStream());
+- pdfbeginobj(r->num, 2); // \pdfobjcompresslevel = 2 is for this
+- copyFontDict(&obj1, r);
+- pdf_puts("\n");
+- pdfendobj();
+- } else if (r->type != objFontDesc) { // /FontDescriptor is written via write_fontdescriptor()
+- if (obj1.isStream())
+- pdfbeginobj(r->num, 0);
+- else
+- pdfbeginobj(r->num, 2); // \pdfobjcompresslevel = 2 is for this
+- copyObject(&obj1);
+- pdf_puts("\n");
+- pdfendobj();
+- }
+- }
+- }
+-}
+-
+-static void writeEncodings()
+-{
+- UsedEncoding *r, *n;
+- char *glyphNames[256], *s;
+- int i;
+- for (r = encodingList; r != 0; r = r->next) {
+- for (i = 0; i < 256; i++) {
+- if (r->font->isCIDFont()) {
+- pdftex_fail
+- ("PDF inclusion: CID fonts are not supported"
+- " (try to disable font replacement to fix this)");
+- }
+- if ((s = ((Gfx8BitFont *) r->font)->getCharName(i)) != 0)
+- glyphNames[i] = s;
+- else
+- glyphNames[i] = notdef;
+- }
+- epdf_write_enc(glyphNames, r->enc_objnum);
+- }
+- for (r = encodingList; r != 0; r = n) {
+- n = r->next;
+-#ifdef POPPLER_VERSION
+- r->font->decRefCnt();
+-#else
+-#error POPPLER_VERSION should be defined.
+-#endif
+- delete r;
+- }
+-}
+-
+-// get the pagebox according to the pagebox_spec
+-static PDFRectangle *get_pagebox(Page * page, int pagebox_spec)
+-{
+- if (pagebox_spec == pdfboxspecmedia)
+- return page->getMediaBox();
+- else if (pagebox_spec == pdfboxspeccrop)
+- return page->getCropBox();
+- else if (pagebox_spec == pdfboxspecbleed)
+- return page->getBleedBox();
+- else if (pagebox_spec == pdfboxspectrim)
+- return page->getTrimBox();
+- else if (pagebox_spec == pdfboxspecart)
+- return page->getArtBox();
+- else
+- pdftex_fail("PDF inclusion: unknown value of pagebox spec (%i)",
+- (int) pagebox_spec);
+- return page->getMediaBox(); // to make the compiler happy
+-}
+-
+-
+-// Reads various information about the PDF and sets it up for later inclusion.
+-// This will fail if the PDF version of the PDF is higher than
+-// minor_pdf_version_wanted or page_name is given and can not be found.
+-// It makes no sense to give page_name _and_ page_num.
+-// Returns the page number.
+-
+-int
+-read_pdf_info(char *image_name, char *page_name, int page_num,
+- int pagebox_spec, int minor_pdf_version_wanted,
+- int pdf_inclusion_errorlevel)
+-{
+- PdfDocument *pdf_doc;
+- Page *page;
+- PDFRectangle *pagebox;
+-#ifdef POPPLER_VERSION
+- int pdf_major_version_found, pdf_minor_version_found;
+-#else
+-#error POPPLER_VERSION should be defined.
+-#endif
+- // initialize
+- if (!isInit) {
+- globalParams = new GlobalParams();
+- globalParams->setErrQuiet(gFalse);
+- isInit = gTrue;
+- }
+- // open PDF file
+- pdf_doc = find_add_document(image_name);
+- epdf_doc = (void *) pdf_doc;
+-
+- // check PDF version
+- // this works only for PDF 1.x -- but since any versions of PDF newer
+- // than 1.x will not be backwards compatible to PDF 1.x, pdfTeX will
+- // then have to changed drastically anyway.
+-#ifdef POPPLER_VERSION
+- pdf_major_version_found = pdf_doc->doc->getPDFMajorVersion();
+- pdf_minor_version_found = pdf_doc->doc->getPDFMinorVersion();
+- if ((pdf_major_version_found > 1)
+- || (pdf_minor_version_found > minor_pdf_version_wanted)) {
+- const char *msg =
+- "PDF inclusion: found PDF version <%d.%d>, but at most version <1.%d> allowed";
+- if (pdf_inclusion_errorlevel > 0) {
+- pdftex_fail(msg, pdf_major_version_found, pdf_minor_version_found, minor_pdf_version_wanted);
+- } else if (pdf_inclusion_errorlevel < 0) {
+- ; /* do nothing */
+- } else { /* = 0, give warning */
+- pdftex_warn(msg, pdf_major_version_found, pdf_minor_version_found, minor_pdf_version_wanted);
+- }
+- }
+-#else
+-#error POPPLER_VERSION should be defined.
+-#endif
+- epdf_num_pages = pdf_doc->doc->getCatalog()->getNumPages();
+- if (page_name) {
+- // get page by name
+- GString name(page_name);
+- LinkDest *link = pdf_doc->doc->findDest(&name);
+- if (link == 0 || !link->isOk())
+- pdftex_fail("PDF inclusion: invalid destination <%s>", page_name);
+- Ref ref = link->getPageRef();
+- page_num = pdf_doc->doc->getCatalog()->findPage(ref.num, ref.gen);
+- if (page_num == 0)
+- pdftex_fail("PDF inclusion: destination is not a page <%s>",
+- page_name);
+- delete link;
+- } else {
+- // get page by number
+- if (page_num <= 0 || page_num > epdf_num_pages)
+- pdftex_fail("PDF inclusion: required page does not exist <%i>",
+- epdf_num_pages);
+- }
+- // get the required page
+- page = pdf_doc->doc->getCatalog()->getPage(page_num);
+-
+- // get the pagebox (media, crop...) to use.
+- pagebox = get_pagebox(page, pagebox_spec);
+- if (pagebox->x2 > pagebox->x1) {
+- epdf_orig_x = pagebox->x1;
+- epdf_width = pagebox->x2 - pagebox->x1;
+- } else {
+- epdf_orig_x = pagebox->x2;
+- epdf_width = pagebox->x1 - pagebox->x2;
+- }
+- if (pagebox->y2 > pagebox->y1) {
+- epdf_orig_y = pagebox->y1;
+- epdf_height = pagebox->y2 - pagebox->y1;
+- } else {
+- epdf_orig_y = pagebox->y2;
+- epdf_height = pagebox->y1 - pagebox->y2;
+- }
+-
+- // get page rotation
+- epdf_rotate = page->getRotate() % 360;
+- if (epdf_rotate < 0)
+- epdf_rotate += 360;
+-
+- // page group
+- if (page->getGroup() != NULL)
+- epdf_has_page_group = 1; // only flag that page group is present;
+- // the actual object number will be
+- // generated in pdftex.web
+- else
+- epdf_has_page_group = 0; // no page group present
+-
+- pdf_doc->xref = pdf_doc->doc->getXRef();
+- return page_num;
+-}
+-
+-// writes the current epf_doc.
+-// Here the included PDF is copied, so most errors that can happen during PDF
+-// inclusion will arise here.
+-
+-void write_epdf(void)
+-{
+- Page *page;
+- Ref *pageRef;
+- Dict *pageDict;
+- Object contents, obj1, obj2, pageObj, dictObj;
+- Object groupDict;
+- bool writeSepGroup = false;
+- Object info;
+- char *key;
+- char s[256];
+- int i, l;
+- int rotate;
+- double scale[6] = { 0, 0, 0, 0, 0, 0 };
+- bool writematrix = false;
+- int suppress_ptex_info = getpdfsuppressptexinfo();
+- static const char *pageDictKeys[] = {
+- "LastModified",
+- "Metadata",
+- "PieceInfo",
+- "SeparationInfo",
+-// "Group",
+-// "Resources",
+- NULL
+- };
+-
+- PdfDocument *pdf_doc = (PdfDocument *) epdf_doc;
+- (pdf_doc->occurences)--;
+- xref = pdf_doc->xref;
+- inObjList = pdf_doc->inObjList;
+- encodingList = 0;
+- page = pdf_doc->doc->getCatalog()->getPage(epdf_selected_page);
+- pageRef = pdf_doc->doc->getCatalog()->getPageRef(epdf_selected_page);
+- pageObj = xref->fetch(pageRef->num, pageRef->gen);
+- pageDict = pageObj.getDict();
+- rotate = page->getRotate();
+- PDFRectangle *pagebox;
+- // write the Page header
+- pdf_puts("/Type /XObject\n");
+- pdf_puts("/Subtype /Form\n");
+- pdf_puts("/FormType 1\n");
+-
+- // write additional information
+- if ((suppress_ptex_info & MASK_SUPPRESS_PTEX_FILENAME) == 0) {
+- pdf_printf("/%s.FileName (%s)\n", pdfkeyprefix,
+- convertStringToPDFString(pdf_doc->file_name,
+- strlen(pdf_doc->file_name)));
+- }
+- if ((suppress_ptex_info & MASK_SUPPRESS_PTEX_PAGENUMBER) == 0) {
+- pdf_printf("/%s.PageNumber %i\n", pdfkeyprefix, (int) epdf_selected_page);
+- }
+- if ((suppress_ptex_info & MASK_SUPPRESS_PTEX_INFODICT) == 0) {
+- info = pdf_doc->doc->getDocInfoNF();
+- if (info.isRef()) {
+- // the info dict must be indirect (PDF Ref p. 61)
+- pdf_printf("/%s.InfoDict ", pdfkeyprefix);
+- pdf_printf("%d 0 R\n", addOther(info.getRef()));
+- }
+- }
+- // get the pagebox (media, crop...) to use.
+- pagebox = get_pagebox(page, epdf_page_box);
+-
+- // handle page rotation
+- if (rotate != 0) {
+- if (rotate % 90 == 0) {
+- // this handles only the simple case: multiple of 90s but these
+- // are the only values allowed according to the reference
+- // (v1.3, p. 78).
+- // the image is rotated around its center.
+- // the /Rotate key is clockwise while the matrix is
+- // counterclockwise :-%
+- tex_printf(", page is rotated %d degrees", rotate);
+- switch (rotate) {
+- case 90:
+- scale[1] = -1;
+- scale[2] = 1;
+- scale[4] = pagebox->x1 - pagebox->y1;
+- scale[5] = pagebox->y1 + pagebox->x2;
+- writematrix = true;
+- break;
+- case 180:
+- scale[0] = scale[3] = -1;
+- scale[4] = pagebox->x1 + pagebox->x2;
+- scale[5] = pagebox->y1 + pagebox->y2;
+- writematrix = true;
+- break; // width and height are exchanged
+- case 270:
+- scale[1] = 1;
+- scale[2] = -1;
+- scale[4] = pagebox->x1 + pagebox->y2;
+- scale[5] = pagebox->y1 - pagebox->x1;
+- writematrix = true;
+- break;
+- }
+- if (writematrix) { // The matrix is only written if the image is rotated.
+- sprintf(s, "/Matrix [%.8f %.8f %.8f %.8f %.8f %.8f]\n",
+- scale[0],
+- scale[1], scale[2], scale[3], scale[4], scale[5]);
+- pdf_puts(stripzeros(s));
+- }
+- }
+- }
+-
+- sprintf(s, "/BBox [%.8f %.8f %.8f %.8f]\n",
+- pagebox->x1, pagebox->y1, pagebox->x2, pagebox->y2);
+- pdf_puts(stripzeros(s));
+-
+- // Metadata validity check (as a stream it must be indirect)
+- dictObj = pageDict->lookupNF("Metadata");
+- if (!dictObj.isNull() && !dictObj.isRef())
+- pdftex_warn("PDF inclusion: /Metadata must be indirect object");
+-
+- // copy selected items in Page dictionary except Resources & Group
+- for (i = 0; pageDictKeys[i] != NULL; i++) {
+- dictObj = pageDict->lookupNF(pageDictKeys[i]);
+- if (!dictObj.isNull()) {
+- pdf_newline();
+- pdf_printf("/%s ", pageDictKeys[i]);
+- copyObject(&dictObj); // preserves indirection
+- }
+- }
+-
+- // handle page group
+- dictObj = pageDict->lookupNF("Group");
+- if (!dictObj.isNull()) {
+- if (pdfpagegroupval == 0) {
+- // another pdf with page group was included earlier on the
+- // same page; copy the Group entry as is. See manual for
+- // info on why this is a warning.
+- if (getpdfsuppresswarningpagegroup() == 0) {
+- pdftex_warn
+- ("PDF inclusion: multiple pdfs with page group included in a single page");
+- }
+- pdf_newline();
+- pdf_puts("/Group ");
+- copyObject(&dictObj);
+- } else {
+- // write Group dict as a separate object, since the Page dict also refers to it
+- dictObj = pageDict->lookup("Group");
+- if (!dictObj.isDict())
+- pdftex_fail("PDF inclusion: /Group dict missing");
+- writeSepGroup = true;
+-/*
+-This part is only a single line
+- groupDict = Object(page->getGroup());
+-in the original patch. In this case, however, pdftex crashes at
+-"delete pdf_doc->doc" in "delete_document()" for inclusion of some
+-kind of pdf images, for example, figure_missing.pdf in gnuplot.
+-A change
+- groupDict = Object(page->getGroup()).copy();
+-does not improve the situation.
+-The changes below seem to work fine.
+-*/
+-// begin modification
+- groupDict = pageDict->lookup("Group");
+- const Dict& dic1 = page->getGroup();
+- const Dict& dic2 = groupDict.getDict();
+- // replace dic2 in groupDict with dic1
+- l = dic2.getLength();
+- for (i = 0; i < l; i++) {
+- groupDict.dictRemove(dic2.getKey(i));
+- }
+- l = dic1.getLength();
+- for (i = 0; i < l; i++) {
+- groupDict.dictAdd(copyString(dic1.getKey(i)),
+- dic1.getValNF(i));
+- }
+-// end modification
+- pdf_printf("/Group %ld 0 R\n", (long)pdfpagegroupval);
+- }
+- }
+-
+- // write the Resources dictionary
+- if (page->getResourceDict() == NULL) {
+- // Resources can be missing (files without them have been spotted
+- // in the wild); in which case the /Resouces of the /Page will be used.
+- // "This practice is not recommended".
+- pdftex_warn
+- ("PDF inclusion: /Resources missing. 'This practice is not recommended' (PDF Ref)");
+- } else {
+- Object *obj1 = page->getResourceDictObject();
+- if (!obj1->isDict())
+- pdftex_fail("PDF inclusion: invalid resources dict type <%s>",
+- obj1->getTypeName());
+- pdf_newline();
+- pdf_puts("/Resources <<\n");
+- for (i = 0, l = obj1->dictGetLength(); i < l; ++i) {
+- obj2 = obj1->dictGetVal(i);
+- key = obj1->dictGetKey(i);
+- if (strcmp("Font", key) == 0)
+- copyFontResources(&obj2);
+- else if (strcmp("ProcSet", key) == 0)
+- copyProcSet(&obj2);
+- else
+- copyOtherResources(&obj2, key);
+- }
+- pdf_puts(">>\n");
+- }
+-
+- // write the page contents
+- contents = page->getContents();
+- if (contents.isStream()) {
+-
+- // Variant A: get stream and recompress under control
+- // of \pdfcompresslevel
+- //
+- // pdfbeginstream();
+- // copyStream(contents->getStream());
+- // pdfendstream();
+-
+- // Variant B: copy stream without recompressing
+- //
+- obj1 = contents.streamGetDict()->lookup("F");
+- if (!obj1.isNull()) {
+- pdftex_fail("PDF inclusion: Unsupported external stream");
+- }
+- obj1 = contents.streamGetDict()->lookup("Length");
+- assert(!obj1.isNull());
+- pdf_puts("/Length ");
+- copyObject(&obj1);
+- pdf_puts("\n");
+- obj1 = contents.streamGetDict()->lookup("Filter");
+- if (!obj1.isNull()) {
+- pdf_puts("/Filter ");
+- copyObject(&obj1);
+- pdf_puts("\n");
+- obj1 = contents.streamGetDict()->lookup("DecodeParms");
+- if (!obj1.isNull()) {
+- pdf_puts("/DecodeParms ");
+- copyObject(&obj1);
+- pdf_puts("\n");
+- }
+- }
+- pdf_puts(">>\nstream\n");
+- copyStream(contents.getStream()->getUndecodedStream());
+- pdfendstream();
+- } else if (contents.isArray()) {
+- pdfbeginstream();
+- for (i = 0, l = contents.arrayGetLength(); i < l; ++i) {
+- Object contentsobj = contents.arrayGet(i);
+- copyStream(contentsobj.getStream());
+- if (i < l - 1)
+- pdf_newline(); // add a newline after each stream except the last
+- }
+- pdfendstream();
+- } else { // the contents are optional, but we need to include an empty stream
+- pdfbeginstream();
+- pdfendstream();
+- }
+-
+- // write out all indirect objects
+- writeRefs();
+-
+- // write out all used encodings (and delete list)
+- writeEncodings();
+-
+- // write the Group dict if needed
+- if (writeSepGroup) {
+- pdfbeginobj(pdfpagegroupval, 2);
+- copyObject(&groupDict);
+- pdf_puts("\n");
+- pdfendobj();
+- pdfpagegroupval = 0; // only the 1st included pdf on a page gets its
+- // Group included in the Page dict
+- }
+-
+- // save object list, xref
+- pdf_doc->inObjList = inObjList;
+- pdf_doc->xref = xref;
+-}
+-
+-// Called when an image has been written and it's resources in image_tab are
+-// freed and it's not referenced anymore.
+-
+-void epdf_delete()
+-{
+- PdfDocument *pdf_doc = (PdfDocument *) epdf_doc;
+- xref = pdf_doc->xref;
+- if (pdf_doc->occurences < 0) {
+- delete_document(pdf_doc);
+- }
+-}
+-
+-// Called when PDF embedding system is finalized.
+-// Now deallocate all remaining PdfDocuments.
+-
+-void epdf_check_mem()
+-{
+- if (isInit) {
+- PdfDocument *p, *n;
+- for (p = pdfDocuments; p; p = n) {
+- n = p->next;
+- delete_document(p);
+- }
+- // see above for globalParams
+- delete globalParams;
+- }
+-}
+diff -ruN r47457/texk/web2c/pdftexdir/pdftoepdf-poppler0.68.0.cc r49040/texk/web2c/pdftexdir/pdftoepdf-poppler0.68.0.cc
+--- r47457/texk/web2c/pdftexdir/pdftoepdf-poppler0.68.0.cc 1970-01-01 01:00:00.000000000 +0100
++++ r49040/texk/web2c/pdftexdir/pdftoepdf-poppler0.68.0.cc 2018-12-05 19:19:35.385778486 +0100
+@@ -0,0 +1,1114 @@
++/*
++Copyright 1996-2017 Han The Thanh, <thanh@pdftex.org>
++
++This file is part of pdfTeX.
++
++pdfTeX 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.
++
++pdfTeX 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, see <http://www.gnu.org/licenses/>.
++*/
++
++/*
++This is based on the patch texlive-poppler-0.59.patch <2017-09-19> at
++https://git.archlinux.org/svntogit/packages.git/plain/texlive-bin/trunk
++by Arch Linux. A little modifications are made to avoid a crash for
++some kind of pdf images, such as figure_missing.pdf in gnuplot.
++The poppler should be 0.59.0, ..., 0.68.0. For the poppler-0.69.0 or
++newer versions, a similar file pdftoepdf-poppler0.69.0 is given.
++POPPLER_VERSION should be defined.
++*/
++
++/* Do this early in order to avoid a conflict between
++ MINGW32 <rpcndr.h> defining 'boolean' as 'unsigned char' and
++ <kpathsea/types.h> defining Pascal's boolean as 'int'.
++*/
++#include <w2c/config.h>
++#include <kpathsea/lib.h>
++
++#include <stdlib.h>
++#include <math.h>
++#include <stddef.h>
++#include <stdio.h>
++#include <string.h>
++#include <ctype.h>
++
++#ifdef POPPLER_VERSION
++#include <dirent.h>
++#include <poppler-config.h>
++#include <goo/GooString.h>
++#include <goo/gmem.h>
++#include <goo/gfile.h>
++#define GString GooString
++#else
++#error POPPLER_VERSION should be defined.
++#endif
++#include <assert.h>
++
++#include "Object.h"
++#include "Stream.h"
++#include "Array.h"
++#include "Dict.h"
++#include "XRef.h"
++#include "Catalog.h"
++#include "Link.h"
++#include "Page.h"
++#include "GfxFont.h"
++#include "PDFDoc.h"
++#include "GlobalParams.h"
++#include "Error.h"
++
++// This file is mostly C and not very much C++; it's just used to interface
++// the functions of xpdf, which are written in C++.
++
++extern "C" {
++#include <pdftexdir/ptexmac.h>
++#include <pdftexdir/pdftex-common.h>
++
++// These functions from pdftex.web gets declared in pdftexcoerce.h in the
++// usual web2c way, but we cannot include that file here because C++
++// does not allow it.
++extern int getpdfsuppresswarningpagegroup(void);
++extern integer getpdfsuppressptexinfo(void);
++extern integer zround(double);
++}
++
++// The prefix "PTEX" for the PDF keys is special to pdfTeX;
++// this has been registered with Adobe by Hans Hagen.
++
++#define pdfkeyprefix "PTEX"
++
++#define MASK_SUPPRESS_PTEX_FULLBANNER 0x01
++#define MASK_SUPPRESS_PTEX_FILENAME 0x02
++#define MASK_SUPPRESS_PTEX_PAGENUMBER 0x04
++#define MASK_SUPPRESS_PTEX_INFODICT 0x08
++
++// When copying the Resources of the selected page, all objects are copied
++// recusively top-down. Indirect objects however are not fetched during
++// copying, but get a new object number from pdfTeX and then will be
++// appended into a linked list. Duplicates are checked and removed from the
++// list of indirect objects during appending.
++
++enum InObjType {
++ objFont,
++ objFontDesc,
++ objOther
++};
++
++struct InObj {
++ Ref ref; // ref in original PDF
++ InObjType type; // object type
++ InObj *next; // next entry in list of indirect objects
++ int num; // new object number in output PDF
++ fd_entry *fd; // pointer to /FontDescriptor object structure
++ int enc_objnum; // Encoding for objFont
++ int written; // has it been written to output PDF?
++};
++
++struct UsedEncoding {
++ int enc_objnum;
++ GfxFont *font;
++ UsedEncoding *next;
++};
++
++static InObj *inObjList;
++static UsedEncoding *encodingList;
++static GBool isInit = gFalse;
++
++// --------------------------------------------------------------------
++// Maintain list of open embedded PDF files
++// --------------------------------------------------------------------
++
++struct PdfDocument {
++ char *file_name;
++ PDFDoc *doc;
++ XRef *xref;
++ InObj *inObjList;
++ int occurences; // number of references to the document; the doc can be
++ // deleted when this is negative
++ PdfDocument *next;
++};
++
++static PdfDocument *pdfDocuments = 0;
++
++static XRef *xref = 0;
++
++// Returns pointer to PdfDocument record for PDF file.
++// Creates a new record if it doesn't exist yet.
++// xref is made current for the document.
++
++static PdfDocument *find_add_document(char *file_name)
++{
++ PdfDocument *p = pdfDocuments;
++ while (p && strcmp(p->file_name, file_name) != 0)
++ p = p->next;
++ if (p) {
++ xref = p->xref;
++ (p->occurences)++;
++ return p;
++ }
++ p = new PdfDocument;
++ p->file_name = xstrdup(file_name);
++ p->xref = xref = 0;
++ p->occurences = 0;
++ GString *docName = new GString(p->file_name);
++ p->doc = new PDFDoc(docName); // takes ownership of docName
++ if (!p->doc->isOk() || !p->doc->okToPrint()) {
++ pdftex_fail("xpdf: reading PDF image failed");
++ }
++ p->inObjList = 0;
++ p->next = pdfDocuments;
++ pdfDocuments = p;
++ return p;
++}
++
++// Deallocate a PdfDocument with all its resources
++
++static void delete_document(PdfDocument * pdf_doc)
++{
++ PdfDocument **p = &pdfDocuments;
++ while (*p && *p != pdf_doc)
++ p = &((*p)->next);
++ // should not happen:
++ if (!*p)
++ return;
++ // unlink from list
++ *p = pdf_doc->next;
++ // free pdf_doc's resources
++ InObj *r, *n;
++ for (r = pdf_doc->inObjList; r != 0; r = n) {
++ n = r->next;
++ delete r;
++ }
++ xref = pdf_doc->xref;
++ delete pdf_doc->doc;
++ xfree(pdf_doc->file_name);
++ delete pdf_doc;
++}
++
++// --------------------------------------------------------------------
++
++static int addEncoding(GfxFont * gfont)
++{
++ UsedEncoding *n;
++ n = new UsedEncoding;
++ n->next = encodingList;
++ encodingList = n;
++ n->font = gfont;
++ n->enc_objnum = pdfnewobjnum();
++ return n->enc_objnum;
++}
++
++#define addFont(ref, fd, enc_objnum) \
++ addInObj(objFont, ref, fd, enc_objnum)
++
++// addFontDesc is only used to avoid writing the original FontDescriptor
++// from the PDF file.
++
++#define addFontDesc(ref, fd) \
++ addInObj(objFontDesc, ref, fd, 0)
++
++#define addOther(ref) \
++ addInObj(objOther, ref, 0, 0)
++
++static int addInObj(InObjType type, Ref ref, fd_entry * fd, int e)
++{
++ InObj *p, *q, *n = new InObj;
++ if (ref.num == 0)
++ pdftex_fail("PDF inclusion: invalid reference");
++ n->ref = ref;
++ n->type = type;
++ n->next = 0;
++ n->fd = fd;
++ n->enc_objnum = e;
++ n->written = 0;
++ if (inObjList == 0)
++ inObjList = n;
++ else {
++ for (p = inObjList; p != 0; p = p->next) {
++ if (p->ref.num == ref.num && p->ref.gen == ref.gen) {
++ delete n;
++ return p->num;
++ }
++ q = p;
++ }
++ // it is important to add new objects at the end of the list,
++ // because new objects are being added while the list is being
++ // written out.
++ q->next = n;
++ }
++ if (type == objFontDesc)
++ n->num = get_fd_objnum(fd);
++ else
++ n->num = pdfnewobjnum();
++ return n->num;
++}
++
++#if 0 /* unusewd */
++static int getNewObjectNumber(Ref ref)
++{
++ InObj *p;
++ if (inObjList == 0) {
++ pdftex_fail("No objects copied yet");
++ } else {
++ for (p = inObjList; p != 0; p = p->next) {
++ if (p->ref.num == ref.num && p->ref.gen == ref.gen) {
++ return p->num;
++ }
++ }
++ pdftex_fail("Object not yet copied: %i %i", ref.num, ref.gen);
++ }
++#ifdef _MSC_VER
++ /* Never reached, but without __attribute__((noreturn)) for pdftex_fail()
++ MSVC 5.0 requires an int return value. */
++ return -60000;
++#endif
++}
++#endif
++
++static void copyObject(Object *);
++
++static void copyName(char *s)
++{
++ pdf_puts("/");
++ for (; *s != 0; s++) {
++ if (isdigit(*s) || isupper(*s) || islower(*s) || *s == '_' ||
++ *s == '.' || *s == '-' || *s == '+')
++ pdfout(*s);
++ else
++ pdf_printf("#%.2X", *s & 0xFF);
++ }
++}
++
++static void copyDictEntry(Object * obj, int i)
++{
++ Object obj1;
++ copyName((char *)obj->dictGetKey(i));
++ pdf_puts(" ");
++ obj1 = obj->dictGetValNF(i);
++ copyObject(&obj1);
++ pdf_puts("\n");
++}
++
++static void copyDict(Object * obj)
++{
++ int i, l;
++ if (!obj->isDict())
++ pdftex_fail("PDF inclusion: invalid dict type <%s>",
++ obj->getTypeName());
++ for (i = 0, l = obj->dictGetLength(); i < l; ++i)
++ copyDictEntry(obj, i);
++}
++
++static void copyFontDict(Object * obj, InObj * r)
++{
++ int i, l;
++ char *key;
++ if (!obj->isDict())
++ pdftex_fail("PDF inclusion: invalid dict type <%s>",
++ obj->getTypeName());
++ pdf_puts("<<\n");
++ assert(r->type == objFont); // FontDescriptor is in fd_tree
++ for (i = 0, l = obj->dictGetLength(); i < l; ++i) {
++ key = obj->dictGetKey(i);
++ if (strncmp("FontDescriptor", key, strlen("FontDescriptor")) == 0
++ || strncmp("BaseFont", key, strlen("BaseFont")) == 0
++ || strncmp("Encoding", key, strlen("Encoding")) == 0)
++ continue; // skip original values
++ copyDictEntry(obj, i);
++ }
++ // write new FontDescriptor, BaseFont, and Encoding
++ pdf_printf("/FontDescriptor %d 0 R\n", get_fd_objnum(r->fd));
++ pdf_printf("/BaseFont %d 0 R\n", get_fn_objnum(r->fd));
++ pdf_printf("/Encoding %d 0 R\n", r->enc_objnum);
++ pdf_puts(">>");
++}
++
++static void copyStream(Stream * str)
++{
++ int c, c2 = 0;
++ str->reset();
++ while ((c = str->getChar()) != EOF) {
++ pdfout(c);
++ c2 = c;
++ }
++ pdflastbyte = c2;
++}
++
++static void copyProcSet(Object * obj)
++{
++ int i, l;
++ Object procset;
++ if (!obj->isArray())
++ pdftex_fail("PDF inclusion: invalid ProcSet array type <%s>",
++ obj->getTypeName());
++ pdf_puts("/ProcSet [ ");
++ for (i = 0, l = obj->arrayGetLength(); i < l; ++i) {
++ procset = obj->arrayGetNF(i);
++ if (!procset.isName())
++ pdftex_fail("PDF inclusion: invalid ProcSet entry type <%s>",
++ procset.getTypeName());
++ copyName((char *)procset.getName());
++ pdf_puts(" ");
++ }
++ pdf_puts("]\n");
++}
++
++#define REPLACE_TYPE1C true
++
++static bool embeddableFont(Object * fontdesc)
++{
++ Object fontfile, ffsubtype;
++
++ if (!fontdesc->isDict())
++ return false;
++ fontfile = fontdesc->dictLookup("FontFile");
++ if (fontfile.isStream())
++ return true;
++ if (REPLACE_TYPE1C) {
++ fontfile = fontdesc->dictLookup("FontFile3");
++ if (!fontfile.isStream())
++ return false;
++ ffsubtype = fontfile.streamGetDict()->lookup("Subtype");
++ return ffsubtype.isName() && !strcmp(ffsubtype.getName(), "Type1C");
++ }
++ return false;
++}
++
++static void copyFont(char *tag, Object * fontRef)
++{
++ Object fontdict, subtype, basefont, fontdescRef, fontdesc, charset,
++ stemV;
++ GfxFont *gfont;
++ fd_entry *fd;
++ fm_entry *fontmap;
++ // Check whether the font has already been embedded before analysing it.
++ InObj *p;
++ Ref ref = fontRef->getRef();
++ for (p = inObjList; p; p = p->next) {
++ if (p->ref.num == ref.num && p->ref.gen == ref.gen) {
++ copyName(tag);
++ pdf_printf(" %d 0 R ", p->num);
++ return;
++ }
++ }
++ // Only handle included Type1 (and Type1C) fonts; anything else will be copied.
++ // Type1C fonts are replaced by Type1 fonts, if REPLACE_TYPE1C is true.
++ fontdict = fontRef->fetch(xref);
++ fontdesc = Object(objNull);
++ if (fontdict.isDict()) {
++ subtype = fontdict.dictLookup("Subtype");
++ basefont = fontdict.dictLookup("BaseFont");
++ fontdescRef = fontdict.dictLookupNF("FontDescriptor");
++ if (fontdescRef.isRef()) {
++ fontdesc = fontdescRef.fetch(xref);
++ }
++ }
++ if (!fixedinclusioncopyfont && fontdict.isDict()
++ && subtype.isName()
++ && !strcmp(subtype.getName(), "Type1")
++ && basefont.isName()
++ && fontdescRef.isRef()
++ && fontdesc.isDict()
++ && embeddableFont(&fontdesc)
++ && (fontmap = lookup_fontmap((char *)basefont.getName())) != NULL) {
++ // round /StemV value, since the PDF input is a float
++ // (see Font Descriptors in PDF reference), but we only store an
++ // integer, since we don't want to change the struct.
++ stemV = fontdesc.dictLookup("StemV");
++ fd = epdf_create_fontdescriptor(fontmap, zround(stemV.getNum()));
++ charset = fontdesc.dictLookup("CharSet");
++ if (!charset.isNull() &&
++ charset.isString() && is_subsetable(fontmap))
++ epdf_mark_glyphs(fd, (char *)charset.getString()->getCString());
++ else
++ embed_whole_font(fd);
++ addFontDesc(fontdescRef.getRef(), fd);
++ copyName(tag);
++ gfont = GfxFont::makeFont(xref, tag, fontRef->getRef(),
++ fontdict.getDict());
++ pdf_printf(" %d 0 R ", addFont(fontRef->getRef(), fd,
++ addEncoding(gfont)));
++ } else {
++ copyName(tag);
++ pdf_puts(" ");
++ copyObject(fontRef);
++ }
++}
++
++static void copyFontResources(Object * obj)
++{
++ Object fontRef;
++ int i, l;
++ if (!obj->isDict())
++ pdftex_fail("PDF inclusion: invalid font resources dict type <%s>",
++ obj->getTypeName());
++ pdf_puts("/Font << ");
++ for (i = 0, l = obj->dictGetLength(); i < l; ++i) {
++ fontRef = obj->dictGetValNF(i);
++ if (fontRef.isRef())
++ copyFont(obj->dictGetKey(i), &fontRef);
++ else if (fontRef.isDict()) { // some programs generate pdf with embedded font object
++ copyName((char *)obj->dictGetKey(i));
++ pdf_puts(" ");
++ copyObject(&fontRef);
++ }
++ else
++ pdftex_fail("PDF inclusion: invalid font in reference type <%s>",
++ fontRef.getTypeName());
++ }
++ pdf_puts(">>\n");
++}
++
++static void copyOtherResources(Object * obj, char *key)
++{
++ // copies all other resources (write_epdf handles Fonts and ProcSets),
++
++ // if Subtype is present, it must be a name
++ if (strcmp("Subtype", key) == 0) {
++ if (!obj->isName()) {
++ pdftex_warn("PDF inclusion: Subtype in Resources dict is not a name"
++ " (key '%s', type <%s>); ignored.",
++ key, obj->getTypeName());
++ return;
++ }
++ } else if (!obj->isDict()) {
++ //FIXME: Write the message only to the log file
++ pdftex_warn("PDF inclusion: invalid other resource which is no dict"
++ " (key '%s', type <%s>); ignored.",
++ key, obj->getTypeName());
++ return;
++ }
++ copyName(key);
++ pdf_puts(" ");
++ copyObject(obj);
++}
++
++// Function onverts double to string; very small and very large numbers
++// are NOT converted to scientific notation.
++// n must be a number or real conforming to the implementation limits
++// of PDF as specified in appendix C.1 of the PDF Ref.
++// These are:
++// maximum value of ints is +2^32
++// maximum value of reals is +2^15
++// smalles values of reals is 1/(2^16)
++
++static char *convertNumToPDF(double n)
++{
++ static const int precision = 6;
++ static const int fact = (int) 1E6; // must be 10^precision
++ static const double epsilon = 0.5E-6; // 2epsilon must be 10^-precision
++ static char buf[64];
++ // handle very small values: return 0
++ if (fabs(n) < epsilon) {
++ buf[0] = '0';
++ buf[1] = '\0';
++ } else {
++ char ints[64];
++ int bindex = 0, sindex = 0;
++ int ival, fval;
++ // handle the sign part if n is negative
++ if (n < 0) {
++ buf[bindex++] = '-';
++ n = -n;
++ }
++ n += epsilon; // for rounding
++ // handle the integer part, simply with sprintf
++ ival = (int) floor(n);
++ n -= ival;
++ sprintf(ints, "%d", ival);
++ while (ints[sindex] != 0)
++ buf[bindex++] = ints[sindex++];
++ // handle the fractional part up to 'precision' digits
++ fval = (int) floor(n * fact);
++ if (fval) {
++ // set a dot
++ buf[bindex++] = '.';
++ sindex = bindex + precision;
++ buf[sindex--] = '\0';
++ // fill up trailing zeros with the string terminator NULL
++ while (((fval % 10) == 0) && (sindex >= bindex)) {
++ buf[sindex--] = '\0';
++ fval /= 10;
++ }
++ // fill up the fractional part back to front
++ while (sindex >= bindex) {
++ buf[sindex--] = (fval % 10) + '0';
++ fval /= 10;
++ }
++ } else
++ buf[bindex++] = 0;
++ }
++ return (char *) buf;
++}
++
++static void copyObject(Object * obj)
++{
++ Object obj1;
++ int i, l, c;
++ Ref ref;
++ char *p;
++ GString *s;
++ if (obj->isBool()) {
++ pdf_printf("%s", obj->getBool()? "true" : "false");
++ } else if (obj->isInt()) {
++ pdf_printf("%i", obj->getInt());
++ } else if (obj->isReal()) {
++ pdf_printf("%s", convertNumToPDF(obj->getReal()));
++ } else if (obj->isNum()) {
++ pdf_printf("%s", convertNumToPDF(obj->getNum()));
++ } else if (obj->isString()) {
++ s = (GooString *)obj->getString();
++ p = s->getCString();
++ l = s->getLength();
++ if (strlen(p) == (unsigned int) l) {
++ pdf_puts("(");
++ for (; *p != 0; p++) {
++ c = (unsigned char) *p;
++ if (c == '(' || c == ')' || c == '\\')
++ pdf_printf("\\%c", c);
++ else if (c < 0x20 || c > 0x7F)
++ pdf_printf("\\%03o", c);
++ else
++ pdfout(c);
++ }
++ pdf_puts(")");
++ } else {
++ pdf_puts("<");
++ for (i = 0; i < l; i++) {
++ c = s->getChar(i) & 0xFF;
++ pdf_printf("%.2x", c);
++ }
++ pdf_puts(">");
++ }
++ } else if (obj->isName()) {
++ copyName((char *)obj->getName());
++ } else if (obj->isNull()) {
++ pdf_puts("null");
++ } else if (obj->isArray()) {
++ pdf_puts("[");
++ for (i = 0, l = obj->arrayGetLength(); i < l; ++i) {
++ obj1 = obj->arrayGetNF(i);
++ if (!obj1.isName())
++ pdf_puts(" ");
++ copyObject(&obj1);
++ }
++ pdf_puts("]");
++ } else if (obj->isDict()) {
++ pdf_puts("<<\n");
++ copyDict(obj);
++ pdf_puts(">>");
++ } else if (obj->isStream()) {
++ pdf_puts("<<\n");
++ copyDict(obj->getStream()->getDictObject());
++ pdf_puts(">>\n");
++ pdf_puts("stream\n");
++ copyStream(obj->getStream()->getUndecodedStream());
++ pdf_puts("\nendstream");
++ } else if (obj->isRef()) {
++ ref = obj->getRef();
++ if (ref.num == 0) {
++ pdftex_fail
++ ("PDF inclusion: reference to invalid object"
++ " (is the included pdf broken?)");
++ } else
++ pdf_printf("%d 0 R", addOther(ref));
++ } else {
++ pdftex_fail("PDF inclusion: type <%s> cannot be copied",
++ obj->getTypeName());
++ }
++}
++
++static void writeRefs()
++{
++ InObj *r;
++ for (r = inObjList; r != 0; r = r->next) {
++ if (!r->written) {
++ r->written = 1;
++ Object obj1 = xref->fetch(r->ref.num, r->ref.gen);
++ if (r->type == objFont) {
++ assert(!obj1.isStream());
++ pdfbeginobj(r->num, 2); // \pdfobjcompresslevel = 2 is for this
++ copyFontDict(&obj1, r);
++ pdf_puts("\n");
++ pdfendobj();
++ } else if (r->type != objFontDesc) { // /FontDescriptor is written via write_fontdescriptor()
++ if (obj1.isStream())
++ pdfbeginobj(r->num, 0);
++ else
++ pdfbeginobj(r->num, 2); // \pdfobjcompresslevel = 2 is for this
++ copyObject(&obj1);
++ pdf_puts("\n");
++ pdfendobj();
++ }
++ }
++ }
++}
++
++static void writeEncodings()
++{
++ UsedEncoding *r, *n;
++ char *glyphNames[256], *s;
++ int i;
++ for (r = encodingList; r != 0; r = r->next) {
++ for (i = 0; i < 256; i++) {
++ if (r->font->isCIDFont()) {
++ pdftex_fail
++ ("PDF inclusion: CID fonts are not supported"
++ " (try to disable font replacement to fix this)");
++ }
++ if ((s = ((Gfx8BitFont *) r->font)->getCharName(i)) != 0)
++ glyphNames[i] = s;
++ else
++ glyphNames[i] = notdef;
++ }
++ epdf_write_enc(glyphNames, r->enc_objnum);
++ }
++ for (r = encodingList; r != 0; r = n) {
++ n = r->next;
++#ifdef POPPLER_VERSION
++ r->font->decRefCnt();
++#else
++#error POPPLER_VERSION should be defined.
++#endif
++ delete r;
++ }
++}
++
++// get the pagebox according to the pagebox_spec
++static PDFRectangle *get_pagebox(Page * page, int pagebox_spec)
++{
++ if (pagebox_spec == pdfboxspecmedia)
++ return page->getMediaBox();
++ else if (pagebox_spec == pdfboxspeccrop)
++ return page->getCropBox();
++ else if (pagebox_spec == pdfboxspecbleed)
++ return page->getBleedBox();
++ else if (pagebox_spec == pdfboxspectrim)
++ return page->getTrimBox();
++ else if (pagebox_spec == pdfboxspecart)
++ return page->getArtBox();
++ else
++ pdftex_fail("PDF inclusion: unknown value of pagebox spec (%i)",
++ (int) pagebox_spec);
++ return page->getMediaBox(); // to make the compiler happy
++}
++
++
++// Reads various information about the PDF and sets it up for later inclusion.
++// This will fail if the PDF version of the PDF is higher than
++// minor_pdf_version_wanted or page_name is given and can not be found.
++// It makes no sense to give page_name _and_ page_num.
++// Returns the page number.
++
++int
++read_pdf_info(char *image_name, char *page_name, int page_num,
++ int pagebox_spec, int minor_pdf_version_wanted,
++ int pdf_inclusion_errorlevel)
++{
++ PdfDocument *pdf_doc;
++ Page *page;
++ PDFRectangle *pagebox;
++#ifdef POPPLER_VERSION
++ int pdf_major_version_found, pdf_minor_version_found;
++#else
++#error POPPLER_VERSION should be defined.
++#endif
++ // initialize
++ if (!isInit) {
++ globalParams = new GlobalParams();
++ globalParams->setErrQuiet(gFalse);
++ isInit = gTrue;
++ }
++ // open PDF file
++ pdf_doc = find_add_document(image_name);
++ epdf_doc = (void *) pdf_doc;
++
++ // check PDF version
++ // this works only for PDF 1.x -- but since any versions of PDF newer
++ // than 1.x will not be backwards compatible to PDF 1.x, pdfTeX will
++ // then have to changed drastically anyway.
++#ifdef POPPLER_VERSION
++ pdf_major_version_found = pdf_doc->doc->getPDFMajorVersion();
++ pdf_minor_version_found = pdf_doc->doc->getPDFMinorVersion();
++ if ((pdf_major_version_found > 1)
++ || (pdf_minor_version_found > minor_pdf_version_wanted)) {
++ const char *msg =
++ "PDF inclusion: found PDF version <%d.%d>, but at most version <1.%d> allowed";
++ if (pdf_inclusion_errorlevel > 0) {
++ pdftex_fail(msg, pdf_major_version_found, pdf_minor_version_found, minor_pdf_version_wanted);
++ } else if (pdf_inclusion_errorlevel < 0) {
++ ; /* do nothing */
++ } else { /* = 0, give warning */
++ pdftex_warn(msg, pdf_major_version_found, pdf_minor_version_found, minor_pdf_version_wanted);
++ }
++ }
++#else
++#error POPPLER_VERSION should be defined.
++#endif
++ epdf_num_pages = pdf_doc->doc->getCatalog()->getNumPages();
++ if (page_name) {
++ // get page by name
++ GString name(page_name);
++ LinkDest *link = pdf_doc->doc->findDest(&name);
++ if (link == 0 || !link->isOk())
++ pdftex_fail("PDF inclusion: invalid destination <%s>", page_name);
++ Ref ref = link->getPageRef();
++ page_num = pdf_doc->doc->getCatalog()->findPage(ref.num, ref.gen);
++ if (page_num == 0)
++ pdftex_fail("PDF inclusion: destination is not a page <%s>",
++ page_name);
++ delete link;
++ } else {
++ // get page by number
++ if (page_num <= 0 || page_num > epdf_num_pages)
++ pdftex_fail("PDF inclusion: required page does not exist <%i>",
++ epdf_num_pages);
++ }
++ // get the required page
++ page = pdf_doc->doc->getCatalog()->getPage(page_num);
++
++ // get the pagebox (media, crop...) to use.
++ pagebox = get_pagebox(page, pagebox_spec);
++ if (pagebox->x2 > pagebox->x1) {
++ epdf_orig_x = pagebox->x1;
++ epdf_width = pagebox->x2 - pagebox->x1;
++ } else {
++ epdf_orig_x = pagebox->x2;
++ epdf_width = pagebox->x1 - pagebox->x2;
++ }
++ if (pagebox->y2 > pagebox->y1) {
++ epdf_orig_y = pagebox->y1;
++ epdf_height = pagebox->y2 - pagebox->y1;
++ } else {
++ epdf_orig_y = pagebox->y2;
++ epdf_height = pagebox->y1 - pagebox->y2;
++ }
++
++ // get page rotation
++ epdf_rotate = page->getRotate() % 360;
++ if (epdf_rotate < 0)
++ epdf_rotate += 360;
++
++ // page group
++ if (page->getGroup() != NULL)
++ epdf_has_page_group = 1; // only flag that page group is present;
++ // the actual object number will be
++ // generated in pdftex.web
++ else
++ epdf_has_page_group = 0; // no page group present
++
++ pdf_doc->xref = pdf_doc->doc->getXRef();
++ return page_num;
++}
++
++// writes the current epf_doc.
++// Here the included PDF is copied, so most errors that can happen during PDF
++// inclusion will arise here.
++
++void write_epdf(void)
++{
++ Page *page;
++ Ref *pageRef;
++ Dict *pageDict;
++ Object contents, obj1, obj2, pageObj, dictObj;
++ Object groupDict;
++ bool writeSepGroup = false;
++ Object info;
++ char *key;
++ char s[256];
++ int i, l;
++ int rotate;
++ double scale[6] = { 0, 0, 0, 0, 0, 0 };
++ bool writematrix = false;
++ int suppress_ptex_info = getpdfsuppressptexinfo();
++ static const char *pageDictKeys[] = {
++ "LastModified",
++ "Metadata",
++ "PieceInfo",
++ "SeparationInfo",
++// "Group",
++// "Resources",
++ NULL
++ };
++
++ PdfDocument *pdf_doc = (PdfDocument *) epdf_doc;
++ (pdf_doc->occurences)--;
++ xref = pdf_doc->xref;
++ inObjList = pdf_doc->inObjList;
++ encodingList = 0;
++ page = pdf_doc->doc->getCatalog()->getPage(epdf_selected_page);
++ pageRef = pdf_doc->doc->getCatalog()->getPageRef(epdf_selected_page);
++ pageObj = xref->fetch(pageRef->num, pageRef->gen);
++ pageDict = pageObj.getDict();
++ rotate = page->getRotate();
++ PDFRectangle *pagebox;
++ // write the Page header
++ pdf_puts("/Type /XObject\n");
++ pdf_puts("/Subtype /Form\n");
++ pdf_puts("/FormType 1\n");
++
++ // write additional information
++ if ((suppress_ptex_info & MASK_SUPPRESS_PTEX_FILENAME) == 0) {
++ pdf_printf("/%s.FileName (%s)\n", pdfkeyprefix,
++ convertStringToPDFString(pdf_doc->file_name,
++ strlen(pdf_doc->file_name)));
++ }
++ if ((suppress_ptex_info & MASK_SUPPRESS_PTEX_PAGENUMBER) == 0) {
++ pdf_printf("/%s.PageNumber %i\n", pdfkeyprefix, (int) epdf_selected_page);
++ }
++ if ((suppress_ptex_info & MASK_SUPPRESS_PTEX_INFODICT) == 0) {
++ info = pdf_doc->doc->getDocInfoNF();
++ if (info.isRef()) {
++ // the info dict must be indirect (PDF Ref p. 61)
++ pdf_printf("/%s.InfoDict ", pdfkeyprefix);
++ pdf_printf("%d 0 R\n", addOther(info.getRef()));
++ }
++ }
++ // get the pagebox (media, crop...) to use.
++ pagebox = get_pagebox(page, epdf_page_box);
++
++ // handle page rotation
++ if (rotate != 0) {
++ if (rotate % 90 == 0) {
++ // this handles only the simple case: multiple of 90s but these
++ // are the only values allowed according to the reference
++ // (v1.3, p. 78).
++ // the image is rotated around its center.
++ // the /Rotate key is clockwise while the matrix is
++ // counterclockwise :-%
++ tex_printf(", page is rotated %d degrees", rotate);
++ switch (rotate) {
++ case 90:
++ scale[1] = -1;
++ scale[2] = 1;
++ scale[4] = pagebox->x1 - pagebox->y1;
++ scale[5] = pagebox->y1 + pagebox->x2;
++ writematrix = true;
++ break;
++ case 180:
++ scale[0] = scale[3] = -1;
++ scale[4] = pagebox->x1 + pagebox->x2;
++ scale[5] = pagebox->y1 + pagebox->y2;
++ writematrix = true;
++ break; // width and height are exchanged
++ case 270:
++ scale[1] = 1;
++ scale[2] = -1;
++ scale[4] = pagebox->x1 + pagebox->y2;
++ scale[5] = pagebox->y1 - pagebox->x1;
++ writematrix = true;
++ break;
++ }
++ if (writematrix) { // The matrix is only written if the image is rotated.
++ sprintf(s, "/Matrix [%.8f %.8f %.8f %.8f %.8f %.8f]\n",
++ scale[0],
++ scale[1], scale[2], scale[3], scale[4], scale[5]);
++ pdf_puts(stripzeros(s));
++ }
++ }
++ }
++
++ sprintf(s, "/BBox [%.8f %.8f %.8f %.8f]\n",
++ pagebox->x1, pagebox->y1, pagebox->x2, pagebox->y2);
++ pdf_puts(stripzeros(s));
++
++ // Metadata validity check (as a stream it must be indirect)
++ dictObj = pageDict->lookupNF("Metadata");
++ if (!dictObj.isNull() && !dictObj.isRef())
++ pdftex_warn("PDF inclusion: /Metadata must be indirect object");
++
++ // copy selected items in Page dictionary except Resources & Group
++ for (i = 0; pageDictKeys[i] != NULL; i++) {
++ dictObj = pageDict->lookupNF(pageDictKeys[i]);
++ if (!dictObj.isNull()) {
++ pdf_newline();
++ pdf_printf("/%s ", pageDictKeys[i]);
++ copyObject(&dictObj); // preserves indirection
++ }
++ }
++
++ // handle page group
++ dictObj = pageDict->lookupNF("Group");
++ if (!dictObj.isNull()) {
++ if (pdfpagegroupval == 0) {
++ // another pdf with page group was included earlier on the
++ // same page; copy the Group entry as is. See manual for
++ // info on why this is a warning.
++ if (getpdfsuppresswarningpagegroup() == 0) {
++ pdftex_warn
++ ("PDF inclusion: multiple pdfs with page group included in a single page");
++ }
++ pdf_newline();
++ pdf_puts("/Group ");
++ copyObject(&dictObj);
++ } else {
++ // write Group dict as a separate object, since the Page dict also refers to it
++ dictObj = pageDict->lookup("Group");
++ if (!dictObj.isDict())
++ pdftex_fail("PDF inclusion: /Group dict missing");
++ writeSepGroup = true;
++/*
++This part is only a single line
++ groupDict = Object(page->getGroup());
++in the original patch. In this case, however, pdftex crashes at
++"delete pdf_doc->doc" in "delete_document()" for inclusion of some
++kind of pdf images, for example, figure_missing.pdf in gnuplot.
++A change
++ groupDict = Object(page->getGroup()).copy();
++does not improve the situation.
++The changes below seem to work fine.
++*/
++// begin modification
++ groupDict = pageDict->lookup("Group");
++ const Dict& dic1 = page->getGroup();
++ const Dict& dic2 = groupDict.getDict();
++ // replace dic2 in groupDict with dic1
++ l = dic2.getLength();
++ for (i = 0; i < l; i++) {
++ groupDict.dictRemove(dic2.getKey(i));
++ }
++ l = dic1.getLength();
++ for (i = 0; i < l; i++) {
++ groupDict.dictAdd(copyString(dic1.getKey(i)),
++ dic1.getValNF(i));
++ }
++// end modification
++ pdf_printf("/Group %ld 0 R\n", (long)pdfpagegroupval);
++ }
++ }
++
++ // write the Resources dictionary
++ if (page->getResourceDict() == NULL) {
++ // Resources can be missing (files without them have been spotted
++ // in the wild); in which case the /Resouces of the /Page will be used.
++ // "This practice is not recommended".
++ pdftex_warn
++ ("PDF inclusion: /Resources missing. 'This practice is not recommended' (PDF Ref)");
++ } else {
++ Object *obj1 = page->getResourceDictObject();
++ if (!obj1->isDict())
++ pdftex_fail("PDF inclusion: invalid resources dict type <%s>",
++ obj1->getTypeName());
++ pdf_newline();
++ pdf_puts("/Resources <<\n");
++ for (i = 0, l = obj1->dictGetLength(); i < l; ++i) {
++ obj2 = obj1->dictGetVal(i);
++ key = obj1->dictGetKey(i);
++ if (strcmp("Font", key) == 0)
++ copyFontResources(&obj2);
++ else if (strcmp("ProcSet", key) == 0)
++ copyProcSet(&obj2);
++ else
++ copyOtherResources(&obj2, key);
++ }
++ pdf_puts(">>\n");
++ }
++
++ // write the page contents
++ contents = page->getContents();
++ if (contents.isStream()) {
++
++ // Variant A: get stream and recompress under control
++ // of \pdfcompresslevel
++ //
++ // pdfbeginstream();
++ // copyStream(contents->getStream());
++ // pdfendstream();
++
++ // Variant B: copy stream without recompressing
++ //
++ obj1 = contents.streamGetDict()->lookup("F");
++ if (!obj1.isNull()) {
++ pdftex_fail("PDF inclusion: Unsupported external stream");
++ }
++ obj1 = contents.streamGetDict()->lookup("Length");
++ assert(!obj1.isNull());
++ pdf_puts("/Length ");
++ copyObject(&obj1);
++ pdf_puts("\n");
++ obj1 = contents.streamGetDict()->lookup("Filter");
++ if (!obj1.isNull()) {
++ pdf_puts("/Filter ");
++ copyObject(&obj1);
++ pdf_puts("\n");
++ obj1 = contents.streamGetDict()->lookup("DecodeParms");
++ if (!obj1.isNull()) {
++ pdf_puts("/DecodeParms ");
++ copyObject(&obj1);
++ pdf_puts("\n");
++ }
++ }
++ pdf_puts(">>\nstream\n");
++ copyStream(contents.getStream()->getUndecodedStream());
++ pdfendstream();
++ } else if (contents.isArray()) {
++ pdfbeginstream();
++ for (i = 0, l = contents.arrayGetLength(); i < l; ++i) {
++ Object contentsobj = contents.arrayGet(i);
++ copyStream(contentsobj.getStream());
++ if (i < l - 1)
++ pdf_newline(); // add a newline after each stream except the last
++ }
++ pdfendstream();
++ } else { // the contents are optional, but we need to include an empty stream
++ pdfbeginstream();
++ pdfendstream();
++ }
++
++ // write out all indirect objects
++ writeRefs();
++
++ // write out all used encodings (and delete list)
++ writeEncodings();
++
++ // write the Group dict if needed
++ if (writeSepGroup) {
++ pdfbeginobj(pdfpagegroupval, 2);
++ copyObject(&groupDict);
++ pdf_puts("\n");
++ pdfendobj();
++ pdfpagegroupval = 0; // only the 1st included pdf on a page gets its
++ // Group included in the Page dict
++ }
++
++ // save object list, xref
++ pdf_doc->inObjList = inObjList;
++ pdf_doc->xref = xref;
++}
++
++// Called when an image has been written and it's resources in image_tab are
++// freed and it's not referenced anymore.
++
++void epdf_delete()
++{
++ PdfDocument *pdf_doc = (PdfDocument *) epdf_doc;
++ xref = pdf_doc->xref;
++ if (pdf_doc->occurences < 0) {
++ delete_document(pdf_doc);
++ }
++}
++
++// Called when PDF embedding system is finalized.
++// Now deallocate all remaining PdfDocuments.
++
++void epdf_check_mem()
++{
++ if (isInit) {
++ PdfDocument *p, *n;
++ for (p = pdfDocuments; p; p = n) {
++ n = p->next;
++ delete_document(p);
++ }
++ // see above for globalParams
++ delete globalParams;
++ }
++}
+diff -ruN r47457/texk/web2c/pdftexdir/pdftoepdf-poppler0.69.0.cc r49040/texk/web2c/pdftexdir/pdftoepdf-poppler0.69.0.cc
+--- r47457/texk/web2c/pdftexdir/pdftoepdf-poppler0.69.0.cc 1970-01-01 01:00:00.000000000 +0100
++++ r49040/texk/web2c/pdftexdir/pdftoepdf-poppler0.69.0.cc 2018-12-05 19:19:35.402778485 +0100
+@@ -0,0 +1,1113 @@
++/*
++Copyright 1996-2017 Han The Thanh, <thanh@pdftex.org>
++
++This file is part of pdfTeX.
++
++pdfTeX 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.
++
++pdfTeX 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, see <http://www.gnu.org/licenses/>.
++*/
++
++/*
++This is based on the patch texlive-poppler-0.59.patch <2017-09-19> at
++https://git.archlinux.org/svntogit/packages.git/plain/texlive-bin/trunk
++by Arch Linux. A little modifications are made to avoid a crash for
++some kind of pdf images, such as figure_missing.pdf in gnuplot.
++The poppler should be 0.69.0 or newer versions.
++POPPLER_VERSION should be defined.
++*/
++
++/* Do this early in order to avoid a conflict between
++ MINGW32 <rpcndr.h> defining 'boolean' as 'unsigned char' and
++ <kpathsea/types.h> defining Pascal's boolean as 'int'.
++*/
++#include <w2c/config.h>
++#include <kpathsea/lib.h>
++
++#include <stdlib.h>
++#include <math.h>
++#include <stddef.h>
++#include <stdio.h>
++#include <string.h>
++#include <ctype.h>
++
++#ifdef POPPLER_VERSION
++#include <dirent.h>
++#include <poppler-config.h>
++#include <goo/GooString.h>
++#include <goo/gmem.h>
++#include <goo/gfile.h>
++#define GString GooString
++#else
++#error POPPLER_VERSION should be defined.
++#endif
++#include <assert.h>
++
++#include "Object.h"
++#include "Stream.h"
++#include "Array.h"
++#include "Dict.h"
++#include "XRef.h"
++#include "Catalog.h"
++#include "Link.h"
++#include "Page.h"
++#include "GfxFont.h"
++#include "PDFDoc.h"
++#include "GlobalParams.h"
++#include "Error.h"
++
++// This file is mostly C and not very much C++; it's just used to interface
++// the functions of xpdf, which are written in C++.
++
++extern "C" {
++#include <pdftexdir/ptexmac.h>
++#include <pdftexdir/pdftex-common.h>
++
++// These functions from pdftex.web gets declared in pdftexcoerce.h in the
++// usual web2c way, but we cannot include that file here because C++
++// does not allow it.
++extern int getpdfsuppresswarningpagegroup(void);
++extern integer getpdfsuppressptexinfo(void);
++extern integer zround(double);
++}
++
++// The prefix "PTEX" for the PDF keys is special to pdfTeX;
++// this has been registered with Adobe by Hans Hagen.
++
++#define pdfkeyprefix "PTEX"
++
++#define MASK_SUPPRESS_PTEX_FULLBANNER 0x01
++#define MASK_SUPPRESS_PTEX_FILENAME 0x02
++#define MASK_SUPPRESS_PTEX_PAGENUMBER 0x04
++#define MASK_SUPPRESS_PTEX_INFODICT 0x08
++
++// When copying the Resources of the selected page, all objects are copied
++// recusively top-down. Indirect objects however are not fetched during
++// copying, but get a new object number from pdfTeX and then will be
++// appended into a linked list. Duplicates are checked and removed from the
++// list of indirect objects during appending.
++
++enum InObjType {
++ objFont,
++ objFontDesc,
++ objOther
++};
++
++struct InObj {
++ Ref ref; // ref in original PDF
++ InObjType type; // object type
++ InObj *next; // next entry in list of indirect objects
++ int num; // new object number in output PDF
++ fd_entry *fd; // pointer to /FontDescriptor object structure
++ int enc_objnum; // Encoding for objFont
++ int written; // has it been written to output PDF?
++};
++
++struct UsedEncoding {
++ int enc_objnum;
++ GfxFont *font;
++ UsedEncoding *next;
++};
++
++static InObj *inObjList;
++static UsedEncoding *encodingList;
++static GBool isInit = gFalse;
++
++// --------------------------------------------------------------------
++// Maintain list of open embedded PDF files
++// --------------------------------------------------------------------
++
++struct PdfDocument {
++ char *file_name;
++ PDFDoc *doc;
++ XRef *xref;
++ InObj *inObjList;
++ int occurences; // number of references to the document; the doc can be
++ // deleted when this is negative
++ PdfDocument *next;
++};
++
++static PdfDocument *pdfDocuments = 0;
++
++static XRef *xref = 0;
++
++// Returns pointer to PdfDocument record for PDF file.
++// Creates a new record if it doesn't exist yet.
++// xref is made current for the document.
++
++static PdfDocument *find_add_document(char *file_name)
++{
++ PdfDocument *p = pdfDocuments;
++ while (p && strcmp(p->file_name, file_name) != 0)
++ p = p->next;
++ if (p) {
++ xref = p->xref;
++ (p->occurences)++;
++ return p;
++ }
++ p = new PdfDocument;
++ p->file_name = xstrdup(file_name);
++ p->xref = xref = 0;
++ p->occurences = 0;
++ GString *docName = new GString(p->file_name);
++ p->doc = new PDFDoc(docName); // takes ownership of docName
++ if (!p->doc->isOk() || !p->doc->okToPrint()) {
++ pdftex_fail("xpdf: reading PDF image failed");
++ }
++ p->inObjList = 0;
++ p->next = pdfDocuments;
++ pdfDocuments = p;
++ return p;
++}
++
++// Deallocate a PdfDocument with all its resources
++
++static void delete_document(PdfDocument * pdf_doc)
++{
++ PdfDocument **p = &pdfDocuments;
++ while (*p && *p != pdf_doc)
++ p = &((*p)->next);
++ // should not happen:
++ if (!*p)
++ return;
++ // unlink from list
++ *p = pdf_doc->next;
++ // free pdf_doc's resources
++ InObj *r, *n;
++ for (r = pdf_doc->inObjList; r != 0; r = n) {
++ n = r->next;
++ delete r;
++ }
++ xref = pdf_doc->xref;
++ delete pdf_doc->doc;
++ xfree(pdf_doc->file_name);
++ delete pdf_doc;
++}
++
++// --------------------------------------------------------------------
++
++static int addEncoding(GfxFont * gfont)
++{
++ UsedEncoding *n;
++ n = new UsedEncoding;
++ n->next = encodingList;
++ encodingList = n;
++ n->font = gfont;
++ n->enc_objnum = pdfnewobjnum();
++ return n->enc_objnum;
++}
++
++#define addFont(ref, fd, enc_objnum) \
++ addInObj(objFont, ref, fd, enc_objnum)
++
++// addFontDesc is only used to avoid writing the original FontDescriptor
++// from the PDF file.
++
++#define addFontDesc(ref, fd) \
++ addInObj(objFontDesc, ref, fd, 0)
++
++#define addOther(ref) \
++ addInObj(objOther, ref, 0, 0)
++
++static int addInObj(InObjType type, Ref ref, fd_entry * fd, int e)
++{
++ InObj *p, *q, *n = new InObj;
++ if (ref.num == 0)
++ pdftex_fail("PDF inclusion: invalid reference");
++ n->ref = ref;
++ n->type = type;
++ n->next = 0;
++ n->fd = fd;
++ n->enc_objnum = e;
++ n->written = 0;
++ if (inObjList == 0)
++ inObjList = n;
++ else {
++ for (p = inObjList; p != 0; p = p->next) {
++ if (p->ref.num == ref.num && p->ref.gen == ref.gen) {
++ delete n;
++ return p->num;
++ }
++ q = p;
++ }
++ // it is important to add new objects at the end of the list,
++ // because new objects are being added while the list is being
++ // written out.
++ q->next = n;
++ }
++ if (type == objFontDesc)
++ n->num = get_fd_objnum(fd);
++ else
++ n->num = pdfnewobjnum();
++ return n->num;
++}
++
++#if 0 /* unusewd */
++static int getNewObjectNumber(Ref ref)
++{
++ InObj *p;
++ if (inObjList == 0) {
++ pdftex_fail("No objects copied yet");
++ } else {
++ for (p = inObjList; p != 0; p = p->next) {
++ if (p->ref.num == ref.num && p->ref.gen == ref.gen) {
++ return p->num;
++ }
++ }
++ pdftex_fail("Object not yet copied: %i %i", ref.num, ref.gen);
++ }
++#ifdef _MSC_VER
++ /* Never reached, but without __attribute__((noreturn)) for pdftex_fail()
++ MSVC 5.0 requires an int return value. */
++ return -60000;
++#endif
++}
++#endif
++
++static void copyObject(Object *);
++
++static void copyName(char *s)
++{
++ pdf_puts("/");
++ for (; *s != 0; s++) {
++ if (isdigit(*s) || isupper(*s) || islower(*s) || *s == '_' ||
++ *s == '.' || *s == '-' || *s == '+')
++ pdfout(*s);
++ else
++ pdf_printf("#%.2X", *s & 0xFF);
++ }
++}
++
++static void copyDictEntry(Object * obj, int i)
++{
++ Object obj1;
++ copyName((char *)obj->dictGetKey(i));
++ pdf_puts(" ");
++ obj1 = obj->dictGetValNF(i);
++ copyObject(&obj1);
++ pdf_puts("\n");
++}
++
++static void copyDict(Object * obj)
++{
++ int i, l;
++ if (!obj->isDict())
++ pdftex_fail("PDF inclusion: invalid dict type <%s>",
++ obj->getTypeName());
++ for (i = 0, l = obj->dictGetLength(); i < l; ++i)
++ copyDictEntry(obj, i);
++}
++
++static void copyFontDict(Object * obj, InObj * r)
++{
++ int i, l;
++ char *key;
++ if (!obj->isDict())
++ pdftex_fail("PDF inclusion: invalid dict type <%s>",
++ obj->getTypeName());
++ pdf_puts("<<\n");
++ assert(r->type == objFont); // FontDescriptor is in fd_tree
++ for (i = 0, l = obj->dictGetLength(); i < l; ++i) {
++ key = (char *)obj->dictGetKey(i);
++ if (strncmp("FontDescriptor", key, strlen("FontDescriptor")) == 0
++ || strncmp("BaseFont", key, strlen("BaseFont")) == 0
++ || strncmp("Encoding", key, strlen("Encoding")) == 0)
++ continue; // skip original values
++ copyDictEntry(obj, i);
++ }
++ // write new FontDescriptor, BaseFont, and Encoding
++ pdf_printf("/FontDescriptor %d 0 R\n", get_fd_objnum(r->fd));
++ pdf_printf("/BaseFont %d 0 R\n", get_fn_objnum(r->fd));
++ pdf_printf("/Encoding %d 0 R\n", r->enc_objnum);
++ pdf_puts(">>");
++}
++
++static void copyStream(Stream * str)
++{
++ int c, c2 = 0;
++ str->reset();
++ while ((c = str->getChar()) != EOF) {
++ pdfout(c);
++ c2 = c;
++ }
++ pdflastbyte = c2;
++}
++
++static void copyProcSet(Object * obj)
++{
++ int i, l;
++ Object procset;
++ if (!obj->isArray())
++ pdftex_fail("PDF inclusion: invalid ProcSet array type <%s>",
++ obj->getTypeName());
++ pdf_puts("/ProcSet [ ");
++ for (i = 0, l = obj->arrayGetLength(); i < l; ++i) {
++ procset = obj->arrayGetNF(i);
++ if (!procset.isName())
++ pdftex_fail("PDF inclusion: invalid ProcSet entry type <%s>",
++ procset.getTypeName());
++ copyName((char *)procset.getName());
++ pdf_puts(" ");
++ }
++ pdf_puts("]\n");
++}
++
++#define REPLACE_TYPE1C true
++
++static bool embeddableFont(Object * fontdesc)
++{
++ Object fontfile, ffsubtype;
++
++ if (!fontdesc->isDict())
++ return false;
++ fontfile = fontdesc->dictLookup("FontFile");
++ if (fontfile.isStream())
++ return true;
++ if (REPLACE_TYPE1C) {
++ fontfile = fontdesc->dictLookup("FontFile3");
++ if (!fontfile.isStream())
++ return false;
++ ffsubtype = fontfile.streamGetDict()->lookup("Subtype");
++ return ffsubtype.isName() && !strcmp(ffsubtype.getName(), "Type1C");
++ }
++ return false;
++}
++
++static void copyFont(char *tag, Object * fontRef)
++{
++ Object fontdict, subtype, basefont, fontdescRef, fontdesc, charset,
++ stemV;
++ GfxFont *gfont;
++ fd_entry *fd;
++ fm_entry *fontmap;
++ // Check whether the font has already been embedded before analysing it.
++ InObj *p;
++ Ref ref = fontRef->getRef();
++ for (p = inObjList; p; p = p->next) {
++ if (p->ref.num == ref.num && p->ref.gen == ref.gen) {
++ copyName(tag);
++ pdf_printf(" %d 0 R ", p->num);
++ return;
++ }
++ }
++ // Only handle included Type1 (and Type1C) fonts; anything else will be copied.
++ // Type1C fonts are replaced by Type1 fonts, if REPLACE_TYPE1C is true.
++ fontdict = fontRef->fetch(xref);
++ fontdesc = Object(objNull);
++ if (fontdict.isDict()) {
++ subtype = fontdict.dictLookup("Subtype");
++ basefont = fontdict.dictLookup("BaseFont");
++ fontdescRef = fontdict.dictLookupNF("FontDescriptor");
++ if (fontdescRef.isRef()) {
++ fontdesc = fontdescRef.fetch(xref);
++ }
++ }
++ if (!fixedinclusioncopyfont && fontdict.isDict()
++ && subtype.isName()
++ && !strcmp(subtype.getName(), "Type1")
++ && basefont.isName()
++ && fontdescRef.isRef()
++ && fontdesc.isDict()
++ && embeddableFont(&fontdesc)
++ && (fontmap = lookup_fontmap((char *)basefont.getName())) != NULL) {
++ // round /StemV value, since the PDF input is a float
++ // (see Font Descriptors in PDF reference), but we only store an
++ // integer, since we don't want to change the struct.
++ stemV = fontdesc.dictLookup("StemV");
++ fd = epdf_create_fontdescriptor(fontmap, zround(stemV.getNum()));
++ charset = fontdesc.dictLookup("CharSet");
++ if (!charset.isNull() &&
++ charset.isString() && is_subsetable(fontmap))
++ epdf_mark_glyphs(fd, (char *)charset.getString()->getCString());
++ else
++ embed_whole_font(fd);
++ addFontDesc(fontdescRef.getRef(), fd);
++ copyName(tag);
++ gfont = GfxFont::makeFont(xref, tag, fontRef->getRef(),
++ fontdict.getDict());
++ pdf_printf(" %d 0 R ", addFont(fontRef->getRef(), fd,
++ addEncoding(gfont)));
++ } else {
++ copyName(tag);
++ pdf_puts(" ");
++ copyObject(fontRef);
++ }
++}
++
++static void copyFontResources(Object * obj)
++{
++ Object fontRef;
++ int i, l;
++ if (!obj->isDict())
++ pdftex_fail("PDF inclusion: invalid font resources dict type <%s>",
++ obj->getTypeName());
++ pdf_puts("/Font << ");
++ for (i = 0, l = obj->dictGetLength(); i < l; ++i) {
++ fontRef = obj->dictGetValNF(i);
++ if (fontRef.isRef())
++ copyFont((char *)obj->dictGetKey(i), &fontRef);
++ else if (fontRef.isDict()) { // some programs generate pdf with embedded font object
++ copyName((char *)obj->dictGetKey(i));
++ pdf_puts(" ");
++ copyObject(&fontRef);
++ }
++ else
++ pdftex_fail("PDF inclusion: invalid font in reference type <%s>",
++ fontRef.getTypeName());
++ }
++ pdf_puts(">>\n");
++}
++
++static void copyOtherResources(Object * obj, char *key)
++{
++ // copies all other resources (write_epdf handles Fonts and ProcSets),
++
++ // if Subtype is present, it must be a name
++ if (strcmp("Subtype", key) == 0) {
++ if (!obj->isName()) {
++ pdftex_warn("PDF inclusion: Subtype in Resources dict is not a name"
++ " (key '%s', type <%s>); ignored.",
++ key, obj->getTypeName());
++ return;
++ }
++ } else if (!obj->isDict()) {
++ //FIXME: Write the message only to the log file
++ pdftex_warn("PDF inclusion: invalid other resource which is no dict"
++ " (key '%s', type <%s>); ignored.",
++ key, obj->getTypeName());
++ return;
++ }
++ copyName(key);
++ pdf_puts(" ");
++ copyObject(obj);
++}
++
++// Function onverts double to string; very small and very large numbers
++// are NOT converted to scientific notation.
++// n must be a number or real conforming to the implementation limits
++// of PDF as specified in appendix C.1 of the PDF Ref.
++// These are:
++// maximum value of ints is +2^32
++// maximum value of reals is +2^15
++// smalles values of reals is 1/(2^16)
++
++static char *convertNumToPDF(double n)
++{
++ static const int precision = 6;
++ static const int fact = (int) 1E6; // must be 10^precision
++ static const double epsilon = 0.5E-6; // 2epsilon must be 10^-precision
++ static char buf[64];
++ // handle very small values: return 0
++ if (fabs(n) < epsilon) {
++ buf[0] = '0';
++ buf[1] = '\0';
++ } else {
++ char ints[64];
++ int bindex = 0, sindex = 0;
++ int ival, fval;
++ // handle the sign part if n is negative
++ if (n < 0) {
++ buf[bindex++] = '-';
++ n = -n;
++ }
++ n += epsilon; // for rounding
++ // handle the integer part, simply with sprintf
++ ival = (int) floor(n);
++ n -= ival;
++ sprintf(ints, "%d", ival);
++ while (ints[sindex] != 0)
++ buf[bindex++] = ints[sindex++];
++ // handle the fractional part up to 'precision' digits
++ fval = (int) floor(n * fact);
++ if (fval) {
++ // set a dot
++ buf[bindex++] = '.';
++ sindex = bindex + precision;
++ buf[sindex--] = '\0';
++ // fill up trailing zeros with the string terminator NULL
++ while (((fval % 10) == 0) && (sindex >= bindex)) {
++ buf[sindex--] = '\0';
++ fval /= 10;
++ }
++ // fill up the fractional part back to front
++ while (sindex >= bindex) {
++ buf[sindex--] = (fval % 10) + '0';
++ fval /= 10;
++ }
++ } else
++ buf[bindex++] = 0;
++ }
++ return (char *) buf;
++}
++
++static void copyObject(Object * obj)
++{
++ Object obj1;
++ int i, l, c;
++ Ref ref;
++ char *p;
++ GString *s;
++ if (obj->isBool()) {
++ pdf_printf("%s", obj->getBool()? "true" : "false");
++ } else if (obj->isInt()) {
++ pdf_printf("%i", obj->getInt());
++ } else if (obj->isReal()) {
++ pdf_printf("%s", convertNumToPDF(obj->getReal()));
++ } else if (obj->isNum()) {
++ pdf_printf("%s", convertNumToPDF(obj->getNum()));
++ } else if (obj->isString()) {
++ s = (GooString *)obj->getString();
++ p = s->getCString();
++ l = s->getLength();
++ if (strlen(p) == (unsigned int) l) {
++ pdf_puts("(");
++ for (; *p != 0; p++) {
++ c = (unsigned char) *p;
++ if (c == '(' || c == ')' || c == '\\')
++ pdf_printf("\\%c", c);
++ else if (c < 0x20 || c > 0x7F)
++ pdf_printf("\\%03o", c);
++ else
++ pdfout(c);
++ }
++ pdf_puts(")");
++ } else {
++ pdf_puts("<");
++ for (i = 0; i < l; i++) {
++ c = s->getChar(i) & 0xFF;
++ pdf_printf("%.2x", c);
++ }
++ pdf_puts(">");
++ }
++ } else if (obj->isName()) {
++ copyName((char *)obj->getName());
++ } else if (obj->isNull()) {
++ pdf_puts("null");
++ } else if (obj->isArray()) {
++ pdf_puts("[");
++ for (i = 0, l = obj->arrayGetLength(); i < l; ++i) {
++ obj1 = obj->arrayGetNF(i);
++ if (!obj1.isName())
++ pdf_puts(" ");
++ copyObject(&obj1);
++ }
++ pdf_puts("]");
++ } else if (obj->isDict()) {
++ pdf_puts("<<\n");
++ copyDict(obj);
++ pdf_puts(">>");
++ } else if (obj->isStream()) {
++ pdf_puts("<<\n");
++ copyDict(obj->getStream()->getDictObject());
++ pdf_puts(">>\n");
++ pdf_puts("stream\n");
++ copyStream(obj->getStream()->getUndecodedStream());
++ pdf_puts("\nendstream");
++ } else if (obj->isRef()) {
++ ref = obj->getRef();
++ if (ref.num == 0) {
++ pdftex_fail
++ ("PDF inclusion: reference to invalid object"
++ " (is the included pdf broken?)");
++ } else
++ pdf_printf("%d 0 R", addOther(ref));
++ } else {
++ pdftex_fail("PDF inclusion: type <%s> cannot be copied",
++ obj->getTypeName());
++ }
++}
++
++static void writeRefs()
++{
++ InObj *r;
++ for (r = inObjList; r != 0; r = r->next) {
++ if (!r->written) {
++ r->written = 1;
++ Object obj1 = xref->fetch(r->ref.num, r->ref.gen);
++ if (r->type == objFont) {
++ assert(!obj1.isStream());
++ pdfbeginobj(r->num, 2); // \pdfobjcompresslevel = 2 is for this
++ copyFontDict(&obj1, r);
++ pdf_puts("\n");
++ pdfendobj();
++ } else if (r->type != objFontDesc) { // /FontDescriptor is written via write_fontdescriptor()
++ if (obj1.isStream())
++ pdfbeginobj(r->num, 0);
++ else
++ pdfbeginobj(r->num, 2); // \pdfobjcompresslevel = 2 is for this
++ copyObject(&obj1);
++ pdf_puts("\n");
++ pdfendobj();
++ }
++ }
++ }
++}
++
++static void writeEncodings()
++{
++ UsedEncoding *r, *n;
++ char *glyphNames[256], *s;
++ int i;
++ for (r = encodingList; r != 0; r = r->next) {
++ for (i = 0; i < 256; i++) {
++ if (r->font->isCIDFont()) {
++ pdftex_fail
++ ("PDF inclusion: CID fonts are not supported"
++ " (try to disable font replacement to fix this)");
++ }
++ if ((s = ((Gfx8BitFont *) r->font)->getCharName(i)) != 0)
++ glyphNames[i] = s;
++ else
++ glyphNames[i] = notdef;
++ }
++ epdf_write_enc(glyphNames, r->enc_objnum);
++ }
++ for (r = encodingList; r != 0; r = n) {
++ n = r->next;
++#ifdef POPPLER_VERSION
++ r->font->decRefCnt();
++#else
++#error POPPLER_VERSION should be defined.
++#endif
++ delete r;
++ }
++}
++
++// get the pagebox according to the pagebox_spec
++static PDFRectangle *get_pagebox(Page * page, int pagebox_spec)
++{
++ if (pagebox_spec == pdfboxspecmedia)
++ return page->getMediaBox();
++ else if (pagebox_spec == pdfboxspeccrop)
++ return page->getCropBox();
++ else if (pagebox_spec == pdfboxspecbleed)
++ return page->getBleedBox();
++ else if (pagebox_spec == pdfboxspectrim)
++ return page->getTrimBox();
++ else if (pagebox_spec == pdfboxspecart)
++ return page->getArtBox();
++ else
++ pdftex_fail("PDF inclusion: unknown value of pagebox spec (%i)",
++ (int) pagebox_spec);
++ return page->getMediaBox(); // to make the compiler happy
++}
++
++
++// Reads various information about the PDF and sets it up for later inclusion.
++// This will fail if the PDF version of the PDF is higher than
++// minor_pdf_version_wanted or page_name is given and can not be found.
++// It makes no sense to give page_name _and_ page_num.
++// Returns the page number.
++
++int
++read_pdf_info(char *image_name, char *page_name, int page_num,
++ int pagebox_spec, int minor_pdf_version_wanted,
++ int pdf_inclusion_errorlevel)
++{
++ PdfDocument *pdf_doc;
++ Page *page;
++ PDFRectangle *pagebox;
++#ifdef POPPLER_VERSION
++ int pdf_major_version_found, pdf_minor_version_found;
++#else
++#error POPPLER_VERSION should be defined.
++#endif
++ // initialize
++ if (!isInit) {
++ globalParams = new GlobalParams();
++ globalParams->setErrQuiet(gFalse);
++ isInit = gTrue;
++ }
++ // open PDF file
++ pdf_doc = find_add_document(image_name);
++ epdf_doc = (void *) pdf_doc;
++
++ // check PDF version
++ // this works only for PDF 1.x -- but since any versions of PDF newer
++ // than 1.x will not be backwards compatible to PDF 1.x, pdfTeX will
++ // then have to changed drastically anyway.
++#ifdef POPPLER_VERSION
++ pdf_major_version_found = pdf_doc->doc->getPDFMajorVersion();
++ pdf_minor_version_found = pdf_doc->doc->getPDFMinorVersion();
++ if ((pdf_major_version_found > 1)
++ || (pdf_minor_version_found > minor_pdf_version_wanted)) {
++ const char *msg =
++ "PDF inclusion: found PDF version <%d.%d>, but at most version <1.%d> allowed";
++ if (pdf_inclusion_errorlevel > 0) {
++ pdftex_fail(msg, pdf_major_version_found, pdf_minor_version_found, minor_pdf_version_wanted);
++ } else if (pdf_inclusion_errorlevel < 0) {
++ ; /* do nothing */
++ } else { /* = 0, give warning */
++ pdftex_warn(msg, pdf_major_version_found, pdf_minor_version_found, minor_pdf_version_wanted);
++ }
++ }
++#else
++#error POPPLER_VERSION should be defined.
++#endif
++ epdf_num_pages = pdf_doc->doc->getCatalog()->getNumPages();
++ if (page_name) {
++ // get page by name
++ GString name(page_name);
++ LinkDest *link = pdf_doc->doc->findDest(&name);
++ if (link == 0 || !link->isOk())
++ pdftex_fail("PDF inclusion: invalid destination <%s>", page_name);
++ Ref ref = link->getPageRef();
++ page_num = pdf_doc->doc->getCatalog()->findPage(ref.num, ref.gen);
++ if (page_num == 0)
++ pdftex_fail("PDF inclusion: destination is not a page <%s>",
++ page_name);
++ delete link;
++ } else {
++ // get page by number
++ if (page_num <= 0 || page_num > epdf_num_pages)
++ pdftex_fail("PDF inclusion: required page does not exist <%i>",
++ epdf_num_pages);
++ }
++ // get the required page
++ page = pdf_doc->doc->getCatalog()->getPage(page_num);
++
++ // get the pagebox (media, crop...) to use.
++ pagebox = get_pagebox(page, pagebox_spec);
++ if (pagebox->x2 > pagebox->x1) {
++ epdf_orig_x = pagebox->x1;
++ epdf_width = pagebox->x2 - pagebox->x1;
++ } else {
++ epdf_orig_x = pagebox->x2;
++ epdf_width = pagebox->x1 - pagebox->x2;
++ }
++ if (pagebox->y2 > pagebox->y1) {
++ epdf_orig_y = pagebox->y1;
++ epdf_height = pagebox->y2 - pagebox->y1;
++ } else {
++ epdf_orig_y = pagebox->y2;
++ epdf_height = pagebox->y1 - pagebox->y2;
++ }
++
++ // get page rotation
++ epdf_rotate = page->getRotate() % 360;
++ if (epdf_rotate < 0)
++ epdf_rotate += 360;
++
++ // page group
++ if (page->getGroup() != NULL)
++ epdf_has_page_group = 1; // only flag that page group is present;
++ // the actual object number will be
++ // generated in pdftex.web
++ else
++ epdf_has_page_group = 0; // no page group present
++
++ pdf_doc->xref = pdf_doc->doc->getXRef();
++ return page_num;
++}
++
++// writes the current epf_doc.
++// Here the included PDF is copied, so most errors that can happen during PDF
++// inclusion will arise here.
++
++void write_epdf(void)
++{
++ Page *page;
++ Ref *pageRef;
++ Dict *pageDict;
++ Object contents, obj1, obj2, pageObj, dictObj;
++ Object groupDict;
++ bool writeSepGroup = false;
++ Object info;
++ char *key;
++ char s[256];
++ int i, l;
++ int rotate;
++ double scale[6] = { 0, 0, 0, 0, 0, 0 };
++ bool writematrix = false;
++ int suppress_ptex_info = getpdfsuppressptexinfo();
++ static const char *pageDictKeys[] = {
++ "LastModified",
++ "Metadata",
++ "PieceInfo",
++ "SeparationInfo",
++// "Group",
++// "Resources",
++ NULL
++ };
++
++ PdfDocument *pdf_doc = (PdfDocument *) epdf_doc;
++ (pdf_doc->occurences)--;
++ xref = pdf_doc->xref;
++ inObjList = pdf_doc->inObjList;
++ encodingList = 0;
++ page = pdf_doc->doc->getCatalog()->getPage(epdf_selected_page);
++ pageRef = pdf_doc->doc->getCatalog()->getPageRef(epdf_selected_page);
++ pageObj = xref->fetch(pageRef->num, pageRef->gen);
++ pageDict = pageObj.getDict();
++ rotate = page->getRotate();
++ PDFRectangle *pagebox;
++ // write the Page header
++ pdf_puts("/Type /XObject\n");
++ pdf_puts("/Subtype /Form\n");
++ pdf_puts("/FormType 1\n");
++
++ // write additional information
++ if ((suppress_ptex_info & MASK_SUPPRESS_PTEX_FILENAME) == 0) {
++ pdf_printf("/%s.FileName (%s)\n", pdfkeyprefix,
++ convertStringToPDFString(pdf_doc->file_name,
++ strlen(pdf_doc->file_name)));
++ }
++ if ((suppress_ptex_info & MASK_SUPPRESS_PTEX_PAGENUMBER) == 0) {
++ pdf_printf("/%s.PageNumber %i\n", pdfkeyprefix, (int) epdf_selected_page);
++ }
++ if ((suppress_ptex_info & MASK_SUPPRESS_PTEX_INFODICT) == 0) {
++ info = pdf_doc->doc->getDocInfoNF();
++ if (info.isRef()) {
++ // the info dict must be indirect (PDF Ref p. 61)
++ pdf_printf("/%s.InfoDict ", pdfkeyprefix);
++ pdf_printf("%d 0 R\n", addOther(info.getRef()));
++ }
++ }
++ // get the pagebox (media, crop...) to use.
++ pagebox = get_pagebox(page, epdf_page_box);
++
++ // handle page rotation
++ if (rotate != 0) {
++ if (rotate % 90 == 0) {
++ // this handles only the simple case: multiple of 90s but these
++ // are the only values allowed according to the reference
++ // (v1.3, p. 78).
++ // the image is rotated around its center.
++ // the /Rotate key is clockwise while the matrix is
++ // counterclockwise :-%
++ tex_printf(", page is rotated %d degrees", rotate);
++ switch (rotate) {
++ case 90:
++ scale[1] = -1;
++ scale[2] = 1;
++ scale[4] = pagebox->x1 - pagebox->y1;
++ scale[5] = pagebox->y1 + pagebox->x2;
++ writematrix = true;
++ break;
++ case 180:
++ scale[0] = scale[3] = -1;
++ scale[4] = pagebox->x1 + pagebox->x2;
++ scale[5] = pagebox->y1 + pagebox->y2;
++ writematrix = true;
++ break; // width and height are exchanged
++ case 270:
++ scale[1] = 1;
++ scale[2] = -1;
++ scale[4] = pagebox->x1 + pagebox->y2;
++ scale[5] = pagebox->y1 - pagebox->x1;
++ writematrix = true;
++ break;
++ }
++ if (writematrix) { // The matrix is only written if the image is rotated.
++ sprintf(s, "/Matrix [%.8f %.8f %.8f %.8f %.8f %.8f]\n",
++ scale[0],
++ scale[1], scale[2], scale[3], scale[4], scale[5]);
++ pdf_puts(stripzeros(s));
++ }
++ }
++ }
++
++ sprintf(s, "/BBox [%.8f %.8f %.8f %.8f]\n",
++ pagebox->x1, pagebox->y1, pagebox->x2, pagebox->y2);
++ pdf_puts(stripzeros(s));
++
++ // Metadata validity check (as a stream it must be indirect)
++ dictObj = pageDict->lookupNF("Metadata");
++ if (!dictObj.isNull() && !dictObj.isRef())
++ pdftex_warn("PDF inclusion: /Metadata must be indirect object");
++
++ // copy selected items in Page dictionary except Resources & Group
++ for (i = 0; pageDictKeys[i] != NULL; i++) {
++ dictObj = pageDict->lookupNF(pageDictKeys[i]);
++ if (!dictObj.isNull()) {
++ pdf_newline();
++ pdf_printf("/%s ", pageDictKeys[i]);
++ copyObject(&dictObj); // preserves indirection
++ }
++ }
++
++ // handle page group
++ dictObj = pageDict->lookupNF("Group");
++ if (!dictObj.isNull()) {
++ if (pdfpagegroupval == 0) {
++ // another pdf with page group was included earlier on the
++ // same page; copy the Group entry as is. See manual for
++ // info on why this is a warning.
++ if (getpdfsuppresswarningpagegroup() == 0) {
++ pdftex_warn
++ ("PDF inclusion: multiple pdfs with page group included in a single page");
++ }
++ pdf_newline();
++ pdf_puts("/Group ");
++ copyObject(&dictObj);
++ } else {
++ // write Group dict as a separate object, since the Page dict also refers to it
++ dictObj = pageDict->lookup("Group");
++ if (!dictObj.isDict())
++ pdftex_fail("PDF inclusion: /Group dict missing");
++ writeSepGroup = true;
++/*
++This part is only a single line
++ groupDict = Object(page->getGroup());
++in the original patch. In this case, however, pdftex crashes at
++"delete pdf_doc->doc" in "delete_document()" for inclusion of some
++kind of pdf images, for example, figure_missing.pdf in gnuplot.
++A change
++ groupDict = Object(page->getGroup()).copy();
++does not improve the situation.
++The changes below seem to work fine.
++*/
++// begin modification
++ groupDict = pageDict->lookup("Group");
++ const Dict& dic1 = page->getGroup();
++ const Dict& dic2 = groupDict.getDict();
++ // replace dic2 in groupDict with dic1
++ l = dic2.getLength();
++ for (i = 0; i < l; i++) {
++ groupDict.dictRemove(dic2.getKey(i));
++ }
++ l = dic1.getLength();
++ for (i = 0; i < l; i++) {
++ groupDict.dictAdd((const char *)copyString(dic1.getKey(i)),
++ dic1.getValNF(i));
++ }
++// end modification
++ pdf_printf("/Group %ld 0 R\n", (long)pdfpagegroupval);
++ }
++ }
++
++ // write the Resources dictionary
++ if (page->getResourceDict() == NULL) {
++ // Resources can be missing (files without them have been spotted
++ // in the wild); in which case the /Resouces of the /Page will be used.
++ // "This practice is not recommended".
++ pdftex_warn
++ ("PDF inclusion: /Resources missing. 'This practice is not recommended' (PDF Ref)");
++ } else {
++ Object *obj1 = page->getResourceDictObject();
++ if (!obj1->isDict())
++ pdftex_fail("PDF inclusion: invalid resources dict type <%s>",
++ obj1->getTypeName());
++ pdf_newline();
++ pdf_puts("/Resources <<\n");
++ for (i = 0, l = obj1->dictGetLength(); i < l; ++i) {
++ obj2 = obj1->dictGetVal(i);
++ key = (char *)obj1->dictGetKey(i);
++ if (strcmp("Font", key) == 0)
++ copyFontResources(&obj2);
++ else if (strcmp("ProcSet", key) == 0)
++ copyProcSet(&obj2);
++ else
++ copyOtherResources(&obj2, (char *)key);
++ }
++ pdf_puts(">>\n");
++ }
++
++ // write the page contents
++ contents = page->getContents();
++ if (contents.isStream()) {
++
++ // Variant A: get stream and recompress under control
++ // of \pdfcompresslevel
++ //
++ // pdfbeginstream();
++ // copyStream(contents->getStream());
++ // pdfendstream();
++
++ // Variant B: copy stream without recompressing
++ //
++ obj1 = contents.streamGetDict()->lookup("F");
++ if (!obj1.isNull()) {
++ pdftex_fail("PDF inclusion: Unsupported external stream");
++ }
++ obj1 = contents.streamGetDict()->lookup("Length");
++ assert(!obj1.isNull());
++ pdf_puts("/Length ");
++ copyObject(&obj1);
++ pdf_puts("\n");
++ obj1 = contents.streamGetDict()->lookup("Filter");
++ if (!obj1.isNull()) {
++ pdf_puts("/Filter ");
++ copyObject(&obj1);
++ pdf_puts("\n");
++ obj1 = contents.streamGetDict()->lookup("DecodeParms");
++ if (!obj1.isNull()) {
++ pdf_puts("/DecodeParms ");
++ copyObject(&obj1);
++ pdf_puts("\n");
++ }
++ }
++ pdf_puts(">>\nstream\n");
++ copyStream(contents.getStream()->getUndecodedStream());
++ pdfendstream();
++ } else if (contents.isArray()) {
++ pdfbeginstream();
++ for (i = 0, l = contents.arrayGetLength(); i < l; ++i) {
++ Object contentsobj = contents.arrayGet(i);
++ copyStream(contentsobj.getStream());
++ if (i < l - 1)
++ pdf_newline(); // add a newline after each stream except the last
++ }
++ pdfendstream();
++ } else { // the contents are optional, but we need to include an empty stream
++ pdfbeginstream();
++ pdfendstream();
++ }
++
++ // write out all indirect objects
++ writeRefs();
++
++ // write out all used encodings (and delete list)
++ writeEncodings();
++
++ // write the Group dict if needed
++ if (writeSepGroup) {
++ pdfbeginobj(pdfpagegroupval, 2);
++ copyObject(&groupDict);
++ pdf_puts("\n");
++ pdfendobj();
++ pdfpagegroupval = 0; // only the 1st included pdf on a page gets its
++ // Group included in the Page dict
++ }
++
++ // save object list, xref
++ pdf_doc->inObjList = inObjList;
++ pdf_doc->xref = xref;
++}
++
++// Called when an image has been written and it's resources in image_tab are
++// freed and it's not referenced anymore.
++
++void epdf_delete()
++{
++ PdfDocument *pdf_doc = (PdfDocument *) epdf_doc;
++ xref = pdf_doc->xref;
++ if (pdf_doc->occurences < 0) {
++ delete_document(pdf_doc);
++ }
++}
++
++// Called when PDF embedding system is finalized.
++// Now deallocate all remaining PdfDocuments.
++
++void epdf_check_mem()
++{
++ if (isInit) {
++ PdfDocument *p, *n;
++ for (p = pdfDocuments; p; p = n) {
++ n = p->next;
++ delete_document(p);
++ }
++ // see above for globalParams
++ delete globalParams;
++ }
++}
+diff -ruN r47457/texk/web2c/pdftexdir/pdftoepdf-poppler0.70.0.cc r49040/texk/web2c/pdftexdir/pdftoepdf-poppler0.70.0.cc
+--- r47457/texk/web2c/pdftexdir/pdftoepdf-poppler0.70.0.cc 1970-01-01 01:00:00.000000000 +0100
++++ r49040/texk/web2c/pdftexdir/pdftoepdf-poppler0.70.0.cc 2018-12-05 19:19:35.399778485 +0100
+@@ -0,0 +1,1113 @@
++/*
++Copyright 1996-2017 Han The Thanh, <thanh@pdftex.org>
++
++This file is part of pdfTeX.
++
++pdfTeX 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.
++
++pdfTeX 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, see <http://www.gnu.org/licenses/>.
++*/
++
++/*
++This is based on the patch texlive-poppler-0.59.patch <2017-09-19> at
++https://git.archlinux.org/svntogit/packages.git/plain/texlive-bin/trunk
++by Arch Linux. A little modifications are made to avoid a crash for
++some kind of pdf images, such as figure_missing.pdf in gnuplot.
++The poppler should be 0.69.0 or newer versions.
++POPPLER_VERSION should be defined.
++*/
++
++/* Do this early in order to avoid a conflict between
++ MINGW32 <rpcndr.h> defining 'boolean' as 'unsigned char' and
++ <kpathsea/types.h> defining Pascal's boolean as 'int'.
++*/
++#include <w2c/config.h>
++#include <kpathsea/lib.h>
++
++#include <stdlib.h>
++#include <math.h>
++#include <stddef.h>
++#include <stdio.h>
++#include <string.h>
++#include <ctype.h>
++
++#ifdef POPPLER_VERSION
++#include <dirent.h>
++#include <poppler-config.h>
++#include <goo/GooString.h>
++#include <goo/gmem.h>
++#include <goo/gfile.h>
++#define GString GooString
++#else
++#error POPPLER_VERSION should be defined.
++#endif
++#include <assert.h>
++
++#include "Object.h"
++#include "Stream.h"
++#include "Array.h"
++#include "Dict.h"
++#include "XRef.h"
++#include "Catalog.h"
++#include "Link.h"
++#include "Page.h"
++#include "GfxFont.h"
++#include "PDFDoc.h"
++#include "GlobalParams.h"
++#include "Error.h"
++
++// This file is mostly C and not very much C++; it's just used to interface
++// the functions of xpdf, which are written in C++.
++
++extern "C" {
++#include <pdftexdir/ptexmac.h>
++#include <pdftexdir/pdftex-common.h>
++
++// These functions from pdftex.web gets declared in pdftexcoerce.h in the
++// usual web2c way, but we cannot include that file here because C++
++// does not allow it.
++extern int getpdfsuppresswarningpagegroup(void);
++extern integer getpdfsuppressptexinfo(void);
++extern integer zround(double);
++}
++
++// The prefix "PTEX" for the PDF keys is special to pdfTeX;
++// this has been registered with Adobe by Hans Hagen.
++
++#define pdfkeyprefix "PTEX"
++
++#define MASK_SUPPRESS_PTEX_FULLBANNER 0x01
++#define MASK_SUPPRESS_PTEX_FILENAME 0x02
++#define MASK_SUPPRESS_PTEX_PAGENUMBER 0x04
++#define MASK_SUPPRESS_PTEX_INFODICT 0x08
++
++// When copying the Resources of the selected page, all objects are copied
++// recusively top-down. Indirect objects however are not fetched during
++// copying, but get a new object number from pdfTeX and then will be
++// appended into a linked list. Duplicates are checked and removed from the
++// list of indirect objects during appending.
++
++enum InObjType {
++ objFont,
++ objFontDesc,
++ objOther
++};
++
++struct InObj {
++ Ref ref; // ref in original PDF
++ InObjType type; // object type
++ InObj *next; // next entry in list of indirect objects
++ int num; // new object number in output PDF
++ fd_entry *fd; // pointer to /FontDescriptor object structure
++ int enc_objnum; // Encoding for objFont
++ int written; // has it been written to output PDF?
++};
++
++struct UsedEncoding {
++ int enc_objnum;
++ GfxFont *font;
++ UsedEncoding *next;
++};
++
++static InObj *inObjList;
++static UsedEncoding *encodingList;
++static GBool isInit = gFalse;
++
++// --------------------------------------------------------------------
++// Maintain list of open embedded PDF files
++// --------------------------------------------------------------------
++
++struct PdfDocument {
++ char *file_name;
++ PDFDoc *doc;
++ XRef *xref;
++ InObj *inObjList;
++ int occurences; // number of references to the document; the doc can be
++ // deleted when this is negative
++ PdfDocument *next;
++};
++
++static PdfDocument *pdfDocuments = 0;
++
++static XRef *xref = 0;
++
++// Returns pointer to PdfDocument record for PDF file.
++// Creates a new record if it doesn't exist yet.
++// xref is made current for the document.
++
++static PdfDocument *find_add_document(char *file_name)
++{
++ PdfDocument *p = pdfDocuments;
++ while (p && strcmp(p->file_name, file_name) != 0)
++ p = p->next;
++ if (p) {
++ xref = p->xref;
++ (p->occurences)++;
++ return p;
++ }
++ p = new PdfDocument;
++ p->file_name = xstrdup(file_name);
++ p->xref = xref = 0;
++ p->occurences = 0;
++ GString *docName = new GString(p->file_name);
++ p->doc = new PDFDoc(docName); // takes ownership of docName
++ if (!p->doc->isOk() || !p->doc->okToPrint()) {
++ pdftex_fail("xpdf: reading PDF image failed");
++ }
++ p->inObjList = 0;
++ p->next = pdfDocuments;
++ pdfDocuments = p;
++ return p;
++}
++
++// Deallocate a PdfDocument with all its resources
++
++static void delete_document(PdfDocument * pdf_doc)
++{
++ PdfDocument **p = &pdfDocuments;
++ while (*p && *p != pdf_doc)
++ p = &((*p)->next);
++ // should not happen:
++ if (!*p)
++ return;
++ // unlink from list
++ *p = pdf_doc->next;
++ // free pdf_doc's resources
++ InObj *r, *n;
++ for (r = pdf_doc->inObjList; r != 0; r = n) {
++ n = r->next;
++ delete r;
++ }
++ xref = pdf_doc->xref;
++ delete pdf_doc->doc;
++ xfree(pdf_doc->file_name);
++ delete pdf_doc;
++}
++
++// --------------------------------------------------------------------
++
++static int addEncoding(GfxFont * gfont)
++{
++ UsedEncoding *n;
++ n = new UsedEncoding;
++ n->next = encodingList;
++ encodingList = n;
++ n->font = gfont;
++ n->enc_objnum = pdfnewobjnum();
++ return n->enc_objnum;
++}
++
++#define addFont(ref, fd, enc_objnum) \
++ addInObj(objFont, ref, fd, enc_objnum)
++
++// addFontDesc is only used to avoid writing the original FontDescriptor
++// from the PDF file.
++
++#define addFontDesc(ref, fd) \
++ addInObj(objFontDesc, ref, fd, 0)
++
++#define addOther(ref) \
++ addInObj(objOther, ref, 0, 0)
++
++static int addInObj(InObjType type, Ref ref, fd_entry * fd, int e)
++{
++ InObj *p, *q, *n = new InObj;
++ if (ref.num == 0)
++ pdftex_fail("PDF inclusion: invalid reference");
++ n->ref = ref;
++ n->type = type;
++ n->next = 0;
++ n->fd = fd;
++ n->enc_objnum = e;
++ n->written = 0;
++ if (inObjList == 0)
++ inObjList = n;
++ else {
++ for (p = inObjList; p != 0; p = p->next) {
++ if (p->ref.num == ref.num && p->ref.gen == ref.gen) {
++ delete n;
++ return p->num;
++ }
++ q = p;
++ }
++ // it is important to add new objects at the end of the list,
++ // because new objects are being added while the list is being
++ // written out.
++ q->next = n;
++ }
++ if (type == objFontDesc)
++ n->num = get_fd_objnum(fd);
++ else
++ n->num = pdfnewobjnum();
++ return n->num;
++}
++
++#if 0 /* unusewd */
++static int getNewObjectNumber(Ref ref)
++{
++ InObj *p;
++ if (inObjList == 0) {
++ pdftex_fail("No objects copied yet");
++ } else {
++ for (p = inObjList; p != 0; p = p->next) {
++ if (p->ref.num == ref.num && p->ref.gen == ref.gen) {
++ return p->num;
++ }
++ }
++ pdftex_fail("Object not yet copied: %i %i", ref.num, ref.gen);
++ }
++#ifdef _MSC_VER
++ /* Never reached, but without __attribute__((noreturn)) for pdftex_fail()
++ MSVC 5.0 requires an int return value. */
++ return -60000;
++#endif
++}
++#endif
++
++static void copyObject(Object *);
++
++static void copyName(char *s)
++{
++ pdf_puts("/");
++ for (; *s != 0; s++) {
++ if (isdigit(*s) || isupper(*s) || islower(*s) || *s == '_' ||
++ *s == '.' || *s == '-' || *s == '+')
++ pdfout(*s);
++ else
++ pdf_printf("#%.2X", *s & 0xFF);
++ }
++}
++
++static void copyDictEntry(Object * obj, int i)
++{
++ Object obj1;
++ copyName((char *)obj->dictGetKey(i));
++ pdf_puts(" ");
++ obj1 = obj->dictGetValNF(i);
++ copyObject(&obj1);
++ pdf_puts("\n");
++}
++
++static void copyDict(Object * obj)
++{
++ int i, l;
++ if (!obj->isDict())
++ pdftex_fail("PDF inclusion: invalid dict type <%s>",
++ obj->getTypeName());
++ for (i = 0, l = obj->dictGetLength(); i < l; ++i)
++ copyDictEntry(obj, i);
++}
++
++static void copyFontDict(Object * obj, InObj * r)
++{
++ int i, l;
++ char *key;
++ if (!obj->isDict())
++ pdftex_fail("PDF inclusion: invalid dict type <%s>",
++ obj->getTypeName());
++ pdf_puts("<<\n");
++ assert(r->type == objFont); // FontDescriptor is in fd_tree
++ for (i = 0, l = obj->dictGetLength(); i < l; ++i) {
++ key = (char *)obj->dictGetKey(i);
++ if (strncmp("FontDescriptor", key, strlen("FontDescriptor")) == 0
++ || strncmp("BaseFont", key, strlen("BaseFont")) == 0
++ || strncmp("Encoding", key, strlen("Encoding")) == 0)
++ continue; // skip original values
++ copyDictEntry(obj, i);
++ }
++ // write new FontDescriptor, BaseFont, and Encoding
++ pdf_printf("/FontDescriptor %d 0 R\n", get_fd_objnum(r->fd));
++ pdf_printf("/BaseFont %d 0 R\n", get_fn_objnum(r->fd));
++ pdf_printf("/Encoding %d 0 R\n", r->enc_objnum);
++ pdf_puts(">>");
++}
++
++static void copyStream(Stream * str)
++{
++ int c, c2 = 0;
++ str->reset();
++ while ((c = str->getChar()) != EOF) {
++ pdfout(c);
++ c2 = c;
++ }
++ pdflastbyte = c2;
++}
++
++static void copyProcSet(Object * obj)
++{
++ int i, l;
++ Object procset;
++ if (!obj->isArray())
++ pdftex_fail("PDF inclusion: invalid ProcSet array type <%s>",
++ obj->getTypeName());
++ pdf_puts("/ProcSet [ ");
++ for (i = 0, l = obj->arrayGetLength(); i < l; ++i) {
++ procset = obj->arrayGetNF(i);
++ if (!procset.isName())
++ pdftex_fail("PDF inclusion: invalid ProcSet entry type <%s>",
++ procset.getTypeName());
++ copyName((char *)procset.getName());
++ pdf_puts(" ");
++ }
++ pdf_puts("]\n");
++}
++
++#define REPLACE_TYPE1C true
++
++static bool embeddableFont(Object * fontdesc)
++{
++ Object fontfile, ffsubtype;
++
++ if (!fontdesc->isDict())
++ return false;
++ fontfile = fontdesc->dictLookup("FontFile");
++ if (fontfile.isStream())
++ return true;
++ if (REPLACE_TYPE1C) {
++ fontfile = fontdesc->dictLookup("FontFile3");
++ if (!fontfile.isStream())
++ return false;
++ ffsubtype = fontfile.streamGetDict()->lookup("Subtype");
++ return ffsubtype.isName() && !strcmp(ffsubtype.getName(), "Type1C");
++ }
++ return false;
++}
++
++static void copyFont(char *tag, Object * fontRef)
++{
++ Object fontdict, subtype, basefont, fontdescRef, fontdesc, charset,
++ stemV;
++ GfxFont *gfont;
++ fd_entry *fd;
++ fm_entry *fontmap;
++ // Check whether the font has already been embedded before analysing it.
++ InObj *p;
++ Ref ref = fontRef->getRef();
++ for (p = inObjList; p; p = p->next) {
++ if (p->ref.num == ref.num && p->ref.gen == ref.gen) {
++ copyName(tag);
++ pdf_printf(" %d 0 R ", p->num);
++ return;
++ }
++ }
++ // Only handle included Type1 (and Type1C) fonts; anything else will be copied.
++ // Type1C fonts are replaced by Type1 fonts, if REPLACE_TYPE1C is true.
++ fontdict = fontRef->fetch(xref);
++ fontdesc = Object(objNull);
++ if (fontdict.isDict()) {
++ subtype = fontdict.dictLookup("Subtype");
++ basefont = fontdict.dictLookup("BaseFont");
++ fontdescRef = fontdict.dictLookupNF("FontDescriptor");
++ if (fontdescRef.isRef()) {
++ fontdesc = fontdescRef.fetch(xref);
++ }
++ }
++ if (!fixedinclusioncopyfont && fontdict.isDict()
++ && subtype.isName()
++ && !strcmp(subtype.getName(), "Type1")
++ && basefont.isName()
++ && fontdescRef.isRef()
++ && fontdesc.isDict()
++ && embeddableFont(&fontdesc)
++ && (fontmap = lookup_fontmap((char *)basefont.getName())) != NULL) {
++ // round /StemV value, since the PDF input is a float
++ // (see Font Descriptors in PDF reference), but we only store an
++ // integer, since we don't want to change the struct.
++ stemV = fontdesc.dictLookup("StemV");
++ fd = epdf_create_fontdescriptor(fontmap, zround(stemV.getNum()));
++ charset = fontdesc.dictLookup("CharSet");
++ if (!charset.isNull() &&
++ charset.isString() && is_subsetable(fontmap))
++ epdf_mark_glyphs(fd, (char *)charset.getString()->getCString());
++ else
++ embed_whole_font(fd);
++ addFontDesc(fontdescRef.getRef(), fd);
++ copyName(tag);
++ gfont = GfxFont::makeFont(xref, tag, fontRef->getRef(),
++ fontdict.getDict());
++ pdf_printf(" %d 0 R ", addFont(fontRef->getRef(), fd,
++ addEncoding(gfont)));
++ } else {
++ copyName(tag);
++ pdf_puts(" ");
++ copyObject(fontRef);
++ }
++}
++
++static void copyFontResources(Object * obj)
++{
++ Object fontRef;
++ int i, l;
++ if (!obj->isDict())
++ pdftex_fail("PDF inclusion: invalid font resources dict type <%s>",
++ obj->getTypeName());
++ pdf_puts("/Font << ");
++ for (i = 0, l = obj->dictGetLength(); i < l; ++i) {
++ fontRef = obj->dictGetValNF(i);
++ if (fontRef.isRef())
++ copyFont((char *)obj->dictGetKey(i), &fontRef);
++ else if (fontRef.isDict()) { // some programs generate pdf with embedded font object
++ copyName((char *)obj->dictGetKey(i));
++ pdf_puts(" ");
++ copyObject(&fontRef);
++ }
++ else
++ pdftex_fail("PDF inclusion: invalid font in reference type <%s>",
++ fontRef.getTypeName());
++ }
++ pdf_puts(">>\n");
++}
++
++static void copyOtherResources(Object * obj, char *key)
++{
++ // copies all other resources (write_epdf handles Fonts and ProcSets),
++
++ // if Subtype is present, it must be a name
++ if (strcmp("Subtype", key) == 0) {
++ if (!obj->isName()) {
++ pdftex_warn("PDF inclusion: Subtype in Resources dict is not a name"
++ " (key '%s', type <%s>); ignored.",
++ key, obj->getTypeName());
++ return;
++ }
++ } else if (!obj->isDict()) {
++ //FIXME: Write the message only to the log file
++ pdftex_warn("PDF inclusion: invalid other resource which is no dict"
++ " (key '%s', type <%s>); ignored.",
++ key, obj->getTypeName());
++ return;
++ }
++ copyName(key);
++ pdf_puts(" ");
++ copyObject(obj);
++}
++
++// Function onverts double to string; very small and very large numbers
++// are NOT converted to scientific notation.
++// n must be a number or real conforming to the implementation limits
++// of PDF as specified in appendix C.1 of the PDF Ref.
++// These are:
++// maximum value of ints is +2^32
++// maximum value of reals is +2^15
++// smalles values of reals is 1/(2^16)
++
++static char *convertNumToPDF(double n)
++{
++ static const int precision = 6;
++ static const int fact = (int) 1E6; // must be 10^precision
++ static const double epsilon = 0.5E-6; // 2epsilon must be 10^-precision
++ static char buf[64];
++ // handle very small values: return 0
++ if (fabs(n) < epsilon) {
++ buf[0] = '0';
++ buf[1] = '\0';
++ } else {
++ char ints[64];
++ int bindex = 0, sindex = 0;
++ int ival, fval;
++ // handle the sign part if n is negative
++ if (n < 0) {
++ buf[bindex++] = '-';
++ n = -n;
++ }
++ n += epsilon; // for rounding
++ // handle the integer part, simply with sprintf
++ ival = (int) floor(n);
++ n -= ival;
++ sprintf(ints, "%d", ival);
++ while (ints[sindex] != 0)
++ buf[bindex++] = ints[sindex++];
++ // handle the fractional part up to 'precision' digits
++ fval = (int) floor(n * fact);
++ if (fval) {
++ // set a dot
++ buf[bindex++] = '.';
++ sindex = bindex + precision;
++ buf[sindex--] = '\0';
++ // fill up trailing zeros with the string terminator NULL
++ while (((fval % 10) == 0) && (sindex >= bindex)) {
++ buf[sindex--] = '\0';
++ fval /= 10;
++ }
++ // fill up the fractional part back to front
++ while (sindex >= bindex) {
++ buf[sindex--] = (fval % 10) + '0';
++ fval /= 10;
++ }
++ } else
++ buf[bindex++] = 0;
++ }
++ return (char *) buf;
++}
++
++static void copyObject(Object * obj)
++{
++ Object obj1;
++ int i, l, c;
++ Ref ref;
++ char *p;
++ GString *s;
++ if (obj->isBool()) {
++ pdf_printf("%s", obj->getBool()? "true" : "false");
++ } else if (obj->isInt()) {
++ pdf_printf("%i", obj->getInt());
++ } else if (obj->isReal()) {
++ pdf_printf("%s", convertNumToPDF(obj->getReal()));
++ } else if (obj->isNum()) {
++ pdf_printf("%s", convertNumToPDF(obj->getNum()));
++ } else if (obj->isString()) {
++ s = (GooString *)obj->getString();
++ p = (char *)s->getCString();
++ l = s->getLength();
++ if (strlen(p) == (unsigned int) l) {
++ pdf_puts("(");
++ for (; *p != 0; p++) {
++ c = (unsigned char) *p;
++ if (c == '(' || c == ')' || c == '\\')
++ pdf_printf("\\%c", c);
++ else if (c < 0x20 || c > 0x7F)
++ pdf_printf("\\%03o", c);
++ else
++ pdfout(c);
++ }
++ pdf_puts(")");
++ } else {
++ pdf_puts("<");
++ for (i = 0; i < l; i++) {
++ c = s->getChar(i) & 0xFF;
++ pdf_printf("%.2x", c);
++ }
++ pdf_puts(">");
++ }
++ } else if (obj->isName()) {
++ copyName((char *)obj->getName());
++ } else if (obj->isNull()) {
++ pdf_puts("null");
++ } else if (obj->isArray()) {
++ pdf_puts("[");
++ for (i = 0, l = obj->arrayGetLength(); i < l; ++i) {
++ obj1 = obj->arrayGetNF(i);
++ if (!obj1.isName())
++ pdf_puts(" ");
++ copyObject(&obj1);
++ }
++ pdf_puts("]");
++ } else if (obj->isDict()) {
++ pdf_puts("<<\n");
++ copyDict(obj);
++ pdf_puts(">>");
++ } else if (obj->isStream()) {
++ pdf_puts("<<\n");
++ copyDict(obj->getStream()->getDictObject());
++ pdf_puts(">>\n");
++ pdf_puts("stream\n");
++ copyStream(obj->getStream()->getUndecodedStream());
++ pdf_puts("\nendstream");
++ } else if (obj->isRef()) {
++ ref = obj->getRef();
++ if (ref.num == 0) {
++ pdftex_fail
++ ("PDF inclusion: reference to invalid object"
++ " (is the included pdf broken?)");
++ } else
++ pdf_printf("%d 0 R", addOther(ref));
++ } else {
++ pdftex_fail("PDF inclusion: type <%s> cannot be copied",
++ obj->getTypeName());
++ }
++}
++
++static void writeRefs()
++{
++ InObj *r;
++ for (r = inObjList; r != 0; r = r->next) {
++ if (!r->written) {
++ r->written = 1;
++ Object obj1 = xref->fetch(r->ref.num, r->ref.gen);
++ if (r->type == objFont) {
++ assert(!obj1.isStream());
++ pdfbeginobj(r->num, 2); // \pdfobjcompresslevel = 2 is for this
++ copyFontDict(&obj1, r);
++ pdf_puts("\n");
++ pdfendobj();
++ } else if (r->type != objFontDesc) { // /FontDescriptor is written via write_fontdescriptor()
++ if (obj1.isStream())
++ pdfbeginobj(r->num, 0);
++ else
++ pdfbeginobj(r->num, 2); // \pdfobjcompresslevel = 2 is for this
++ copyObject(&obj1);
++ pdf_puts("\n");
++ pdfendobj();
++ }
++ }
++ }
++}
++
++static void writeEncodings()
++{
++ UsedEncoding *r, *n;
++ char *glyphNames[256], *s;
++ int i;
++ for (r = encodingList; r != 0; r = r->next) {
++ for (i = 0; i < 256; i++) {
++ if (r->font->isCIDFont()) {
++ pdftex_fail
++ ("PDF inclusion: CID fonts are not supported"
++ " (try to disable font replacement to fix this)");
++ }
++ if ((s = (char *)((Gfx8BitFont *) r->font)->getCharName(i)) != 0)
++ glyphNames[i] = s;
++ else
++ glyphNames[i] = notdef;
++ }
++ epdf_write_enc(glyphNames, r->enc_objnum);
++ }
++ for (r = encodingList; r != 0; r = n) {
++ n = r->next;
++#ifdef POPPLER_VERSION
++ r->font->decRefCnt();
++#else
++#error POPPLER_VERSION should be defined.
++#endif
++ delete r;
++ }
++}
++
++// get the pagebox according to the pagebox_spec
++static const PDFRectangle *get_pagebox(Page * page, int pagebox_spec)
++{
++ if (pagebox_spec == pdfboxspecmedia)
++ return page->getMediaBox();
++ else if (pagebox_spec == pdfboxspeccrop)
++ return page->getCropBox();
++ else if (pagebox_spec == pdfboxspecbleed)
++ return page->getBleedBox();
++ else if (pagebox_spec == pdfboxspectrim)
++ return page->getTrimBox();
++ else if (pagebox_spec == pdfboxspecart)
++ return page->getArtBox();
++ else
++ pdftex_fail("PDF inclusion: unknown value of pagebox spec (%i)",
++ (int) pagebox_spec);
++ return page->getMediaBox(); // to make the compiler happy
++}
++
++
++// Reads various information about the PDF and sets it up for later inclusion.
++// This will fail if the PDF version of the PDF is higher than
++// minor_pdf_version_wanted or page_name is given and can not be found.
++// It makes no sense to give page_name _and_ page_num.
++// Returns the page number.
++
++int
++read_pdf_info(char *image_name, char *page_name, int page_num,
++ int pagebox_spec, int minor_pdf_version_wanted,
++ int pdf_inclusion_errorlevel)
++{
++ PdfDocument *pdf_doc;
++ Page *page;
++ const PDFRectangle *pagebox;
++#ifdef POPPLER_VERSION
++ int pdf_major_version_found, pdf_minor_version_found;
++#else
++#error POPPLER_VERSION should be defined.
++#endif
++ // initialize
++ if (!isInit) {
++ globalParams = new GlobalParams();
++ globalParams->setErrQuiet(gFalse);
++ isInit = gTrue;
++ }
++ // open PDF file
++ pdf_doc = find_add_document(image_name);
++ epdf_doc = (void *) pdf_doc;
++
++ // check PDF version
++ // this works only for PDF 1.x -- but since any versions of PDF newer
++ // than 1.x will not be backwards compatible to PDF 1.x, pdfTeX will
++ // then have to changed drastically anyway.
++#ifdef POPPLER_VERSION
++ pdf_major_version_found = pdf_doc->doc->getPDFMajorVersion();
++ pdf_minor_version_found = pdf_doc->doc->getPDFMinorVersion();
++ if ((pdf_major_version_found > 1)
++ || (pdf_minor_version_found > minor_pdf_version_wanted)) {
++ const char *msg =
++ "PDF inclusion: found PDF version <%d.%d>, but at most version <1.%d> allowed";
++ if (pdf_inclusion_errorlevel > 0) {
++ pdftex_fail(msg, pdf_major_version_found, pdf_minor_version_found, minor_pdf_version_wanted);
++ } else if (pdf_inclusion_errorlevel < 0) {
++ ; /* do nothing */
++ } else { /* = 0, give warning */
++ pdftex_warn(msg, pdf_major_version_found, pdf_minor_version_found, minor_pdf_version_wanted);
++ }
++ }
++#else
++#error POPPLER_VERSION should be defined.
++#endif
++ epdf_num_pages = pdf_doc->doc->getCatalog()->getNumPages();
++ if (page_name) {
++ // get page by name
++ GString name(page_name);
++ LinkDest *link = pdf_doc->doc->findDest(&name);
++ if (link == 0 || !link->isOk())
++ pdftex_fail("PDF inclusion: invalid destination <%s>", page_name);
++ Ref ref = link->getPageRef();
++ page_num = pdf_doc->doc->getCatalog()->findPage(ref.num, ref.gen);
++ if (page_num == 0)
++ pdftex_fail("PDF inclusion: destination is not a page <%s>",
++ page_name);
++ delete link;
++ } else {
++ // get page by number
++ if (page_num <= 0 || page_num > epdf_num_pages)
++ pdftex_fail("PDF inclusion: required page does not exist <%i>",
++ epdf_num_pages);
++ }
++ // get the required page
++ page = pdf_doc->doc->getCatalog()->getPage(page_num);
++
++ // get the pagebox (media, crop...) to use.
++ pagebox = get_pagebox(page, pagebox_spec);
++ if (pagebox->x2 > pagebox->x1) {
++ epdf_orig_x = pagebox->x1;
++ epdf_width = pagebox->x2 - pagebox->x1;
++ } else {
++ epdf_orig_x = pagebox->x2;
++ epdf_width = pagebox->x1 - pagebox->x2;
++ }
++ if (pagebox->y2 > pagebox->y1) {
++ epdf_orig_y = pagebox->y1;
++ epdf_height = pagebox->y2 - pagebox->y1;
++ } else {
++ epdf_orig_y = pagebox->y2;
++ epdf_height = pagebox->y1 - pagebox->y2;
++ }
++
++ // get page rotation
++ epdf_rotate = page->getRotate() % 360;
++ if (epdf_rotate < 0)
++ epdf_rotate += 360;
++
++ // page group
++ if (page->getGroup() != NULL)
++ epdf_has_page_group = 1; // only flag that page group is present;
++ // the actual object number will be
++ // generated in pdftex.web
++ else
++ epdf_has_page_group = 0; // no page group present
++
++ pdf_doc->xref = pdf_doc->doc->getXRef();
++ return page_num;
++}
++
++// writes the current epf_doc.
++// Here the included PDF is copied, so most errors that can happen during PDF
++// inclusion will arise here.
++
++void write_epdf(void)
++{
++ Page *page;
++ Ref *pageRef;
++ Dict *pageDict;
++ Object contents, obj1, obj2, pageObj, dictObj;
++ Object groupDict;
++ bool writeSepGroup = false;
++ Object info;
++ char *key;
++ char s[256];
++ int i, l;
++ int rotate;
++ double scale[6] = { 0, 0, 0, 0, 0, 0 };
++ bool writematrix = false;
++ int suppress_ptex_info = getpdfsuppressptexinfo();
++ static const char *pageDictKeys[] = {
++ "LastModified",
++ "Metadata",
++ "PieceInfo",
++ "SeparationInfo",
++// "Group",
++// "Resources",
++ NULL
++ };
++
++ PdfDocument *pdf_doc = (PdfDocument *) epdf_doc;
++ (pdf_doc->occurences)--;
++ xref = pdf_doc->xref;
++ inObjList = pdf_doc->inObjList;
++ encodingList = 0;
++ page = pdf_doc->doc->getCatalog()->getPage(epdf_selected_page);
++ pageRef = pdf_doc->doc->getCatalog()->getPageRef(epdf_selected_page);
++ pageObj = xref->fetch(pageRef->num, pageRef->gen);
++ pageDict = pageObj.getDict();
++ rotate = page->getRotate();
++ const PDFRectangle *pagebox;
++ // write the Page header
++ pdf_puts("/Type /XObject\n");
++ pdf_puts("/Subtype /Form\n");
++ pdf_puts("/FormType 1\n");
++
++ // write additional information
++ if ((suppress_ptex_info & MASK_SUPPRESS_PTEX_FILENAME) == 0) {
++ pdf_printf("/%s.FileName (%s)\n", pdfkeyprefix,
++ convertStringToPDFString(pdf_doc->file_name,
++ strlen(pdf_doc->file_name)));
++ }
++ if ((suppress_ptex_info & MASK_SUPPRESS_PTEX_PAGENUMBER) == 0) {
++ pdf_printf("/%s.PageNumber %i\n", pdfkeyprefix, (int) epdf_selected_page);
++ }
++ if ((suppress_ptex_info & MASK_SUPPRESS_PTEX_INFODICT) == 0) {
++ info = pdf_doc->doc->getDocInfoNF();
++ if (info.isRef()) {
++ // the info dict must be indirect (PDF Ref p. 61)
++ pdf_printf("/%s.InfoDict ", pdfkeyprefix);
++ pdf_printf("%d 0 R\n", addOther(info.getRef()));
++ }
++ }
++ // get the pagebox (media, crop...) to use.
++ pagebox = get_pagebox(page, epdf_page_box);
++
++ // handle page rotation
++ if (rotate != 0) {
++ if (rotate % 90 == 0) {
++ // this handles only the simple case: multiple of 90s but these
++ // are the only values allowed according to the reference
++ // (v1.3, p. 78).
++ // the image is rotated around its center.
++ // the /Rotate key is clockwise while the matrix is
++ // counterclockwise :-%
++ tex_printf(", page is rotated %d degrees", rotate);
++ switch (rotate) {
++ case 90:
++ scale[1] = -1;
++ scale[2] = 1;
++ scale[4] = pagebox->x1 - pagebox->y1;
++ scale[5] = pagebox->y1 + pagebox->x2;
++ writematrix = true;
++ break;
++ case 180:
++ scale[0] = scale[3] = -1;
++ scale[4] = pagebox->x1 + pagebox->x2;
++ scale[5] = pagebox->y1 + pagebox->y2;
++ writematrix = true;
++ break; // width and height are exchanged
++ case 270:
++ scale[1] = 1;
++ scale[2] = -1;
++ scale[4] = pagebox->x1 + pagebox->y2;
++ scale[5] = pagebox->y1 - pagebox->x1;
++ writematrix = true;
++ break;
++ }
++ if (writematrix) { // The matrix is only written if the image is rotated.
++ sprintf(s, "/Matrix [%.8f %.8f %.8f %.8f %.8f %.8f]\n",
++ scale[0],
++ scale[1], scale[2], scale[3], scale[4], scale[5]);
++ pdf_puts(stripzeros(s));
++ }
++ }
++ }
++
++ sprintf(s, "/BBox [%.8f %.8f %.8f %.8f]\n",
++ pagebox->x1, pagebox->y1, pagebox->x2, pagebox->y2);
++ pdf_puts(stripzeros(s));
++
++ // Metadata validity check (as a stream it must be indirect)
++ dictObj = pageDict->lookupNF("Metadata");
++ if (!dictObj.isNull() && !dictObj.isRef())
++ pdftex_warn("PDF inclusion: /Metadata must be indirect object");
++
++ // copy selected items in Page dictionary except Resources & Group
++ for (i = 0; pageDictKeys[i] != NULL; i++) {
++ dictObj = pageDict->lookupNF(pageDictKeys[i]);
++ if (!dictObj.isNull()) {
++ pdf_newline();
++ pdf_printf("/%s ", pageDictKeys[i]);
++ copyObject(&dictObj); // preserves indirection
++ }
++ }
++
++ // handle page group
++ dictObj = pageDict->lookupNF("Group");
++ if (!dictObj.isNull()) {
++ if (pdfpagegroupval == 0) {
++ // another pdf with page group was included earlier on the
++ // same page; copy the Group entry as is. See manual for
++ // info on why this is a warning.
++ if (getpdfsuppresswarningpagegroup() == 0) {
++ pdftex_warn
++ ("PDF inclusion: multiple pdfs with page group included in a single page");
++ }
++ pdf_newline();
++ pdf_puts("/Group ");
++ copyObject(&dictObj);
++ } else {
++ // write Group dict as a separate object, since the Page dict also refers to it
++ dictObj = pageDict->lookup("Group");
++ if (!dictObj.isDict())
++ pdftex_fail("PDF inclusion: /Group dict missing");
++ writeSepGroup = true;
++/*
++This part is only a single line
++ groupDict = Object(page->getGroup());
++in the original patch. In this case, however, pdftex crashes at
++"delete pdf_doc->doc" in "delete_document()" for inclusion of some
++kind of pdf images, for example, figure_missing.pdf in gnuplot.
++A change
++ groupDict = Object(page->getGroup()).copy();
++does not improve the situation.
++The changes below seem to work fine.
++*/
++// begin modification
++ groupDict = pageDict->lookup("Group");
++ const Dict& dic1 = page->getGroup();
++ const Dict& dic2 = groupDict.getDict();
++ // replace dic2 in groupDict with dic1
++ l = dic2.getLength();
++ for (i = 0; i < l; i++) {
++ groupDict.dictRemove(dic2.getKey(i));
++ }
++ l = dic1.getLength();
++ for (i = 0; i < l; i++) {
++ groupDict.dictAdd((const char *)copyString(dic1.getKey(i)),
++ dic1.getValNF(i));
++ }
++// end modification
++ pdf_printf("/Group %ld 0 R\n", (long)pdfpagegroupval);
++ }
++ }
++
++ // write the Resources dictionary
++ if (page->getResourceDict() == NULL) {
++ // Resources can be missing (files without them have been spotted
++ // in the wild); in which case the /Resouces of the /Page will be used.
++ // "This practice is not recommended".
++ pdftex_warn
++ ("PDF inclusion: /Resources missing. 'This practice is not recommended' (PDF Ref)");
++ } else {
++ Object *obj1 = page->getResourceDictObject();
++ if (!obj1->isDict())
++ pdftex_fail("PDF inclusion: invalid resources dict type <%s>",
++ obj1->getTypeName());
++ pdf_newline();
++ pdf_puts("/Resources <<\n");
++ for (i = 0, l = obj1->dictGetLength(); i < l; ++i) {
++ obj2 = obj1->dictGetVal(i);
++ key = (char *)obj1->dictGetKey(i);
++ if (strcmp("Font", key) == 0)
++ copyFontResources(&obj2);
++ else if (strcmp("ProcSet", key) == 0)
++ copyProcSet(&obj2);
++ else
++ copyOtherResources(&obj2, (char *)key);
++ }
++ pdf_puts(">>\n");
++ }
++
++ // write the page contents
++ contents = page->getContents();
++ if (contents.isStream()) {
++
++ // Variant A: get stream and recompress under control
++ // of \pdfcompresslevel
++ //
++ // pdfbeginstream();
++ // copyStream(contents->getStream());
++ // pdfendstream();
++
++ // Variant B: copy stream without recompressing
++ //
++ obj1 = contents.streamGetDict()->lookup("F");
++ if (!obj1.isNull()) {
++ pdftex_fail("PDF inclusion: Unsupported external stream");
++ }
++ obj1 = contents.streamGetDict()->lookup("Length");
++ assert(!obj1.isNull());
++ pdf_puts("/Length ");
++ copyObject(&obj1);
++ pdf_puts("\n");
++ obj1 = contents.streamGetDict()->lookup("Filter");
++ if (!obj1.isNull()) {
++ pdf_puts("/Filter ");
++ copyObject(&obj1);
++ pdf_puts("\n");
++ obj1 = contents.streamGetDict()->lookup("DecodeParms");
++ if (!obj1.isNull()) {
++ pdf_puts("/DecodeParms ");
++ copyObject(&obj1);
++ pdf_puts("\n");
++ }
++ }
++ pdf_puts(">>\nstream\n");
++ copyStream(contents.getStream()->getUndecodedStream());
++ pdfendstream();
++ } else if (contents.isArray()) {
++ pdfbeginstream();
++ for (i = 0, l = contents.arrayGetLength(); i < l; ++i) {
++ Object contentsobj = contents.arrayGet(i);
++ copyStream(contentsobj.getStream());
++ if (i < l - 1)
++ pdf_newline(); // add a newline after each stream except the last
++ }
++ pdfendstream();
++ } else { // the contents are optional, but we need to include an empty stream
++ pdfbeginstream();
++ pdfendstream();
++ }
++
++ // write out all indirect objects
++ writeRefs();
++
++ // write out all used encodings (and delete list)
++ writeEncodings();
++
++ // write the Group dict if needed
++ if (writeSepGroup) {
++ pdfbeginobj(pdfpagegroupval, 2);
++ copyObject(&groupDict);
++ pdf_puts("\n");
++ pdfendobj();
++ pdfpagegroupval = 0; // only the 1st included pdf on a page gets its
++ // Group included in the Page dict
++ }
++
++ // save object list, xref
++ pdf_doc->inObjList = inObjList;
++ pdf_doc->xref = xref;
++}
++
++// Called when an image has been written and it's resources in image_tab are
++// freed and it's not referenced anymore.
++
++void epdf_delete()
++{
++ PdfDocument *pdf_doc = (PdfDocument *) epdf_doc;
++ xref = pdf_doc->xref;
++ if (pdf_doc->occurences < 0) {
++ delete_document(pdf_doc);
++ }
++}
++
++// Called when PDF embedding system is finalized.
++// Now deallocate all remaining PdfDocuments.
++
++void epdf_check_mem()
++{
++ if (isInit) {
++ PdfDocument *p, *n;
++ for (p = pdfDocuments; p; p = n) {
++ n = p->next;
++ delete_document(p);
++ }
++ // see above for globalParams
++ delete globalParams;
++ }
++}
+diff -ruN r47457/texk/web2c/pdftexdir/pdftoepdf-poppler0.71.0.cc r49040/texk/web2c/pdftexdir/pdftoepdf-poppler0.71.0.cc
+--- r47457/texk/web2c/pdftexdir/pdftoepdf-poppler0.71.0.cc 1970-01-01 01:00:00.000000000 +0100
++++ r49040/texk/web2c/pdftexdir/pdftoepdf-poppler0.71.0.cc 2018-12-05 19:19:35.404778485 +0100
+@@ -0,0 +1,1113 @@
++/*
++Copyright 1996-2017 Han The Thanh, <thanh@pdftex.org>
++
++This file is part of pdfTeX.
++
++pdfTeX 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.
++
++pdfTeX 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, see <http://www.gnu.org/licenses/>.
++*/
++
++/*
++This is based on the patch texlive-poppler-0.59.patch <2017-09-19> at
++https://git.archlinux.org/svntogit/packages.git/plain/texlive-bin/trunk
++by Arch Linux. A little modifications are made to avoid a crash for
++some kind of pdf images, such as figure_missing.pdf in gnuplot.
++The poppler should be 0.69.0 or newer versions.
++POPPLER_VERSION should be defined.
++*/
++
++/* Do this early in order to avoid a conflict between
++ MINGW32 <rpcndr.h> defining 'boolean' as 'unsigned char' and
++ <kpathsea/types.h> defining Pascal's boolean as 'int'.
++*/
++#include <w2c/config.h>
++#include <kpathsea/lib.h>
++
++#include <stdlib.h>
++#include <math.h>
++#include <stddef.h>
++#include <stdio.h>
++#include <string.h>
++#include <ctype.h>
++
++#ifdef POPPLER_VERSION
++#include <dirent.h>
++#include <poppler-config.h>
++#include <goo/GooString.h>
++#include <goo/gmem.h>
++#include <goo/gfile.h>
++#define GString GooString
++#else
++#error POPPLER_VERSION should be defined.
++#endif
++#include <assert.h>
++
++#include "Object.h"
++#include "Stream.h"
++#include "Array.h"
++#include "Dict.h"
++#include "XRef.h"
++#include "Catalog.h"
++#include "Link.h"
++#include "Page.h"
++#include "GfxFont.h"
++#include "PDFDoc.h"
++#include "GlobalParams.h"
++#include "Error.h"
++
++// This file is mostly C and not very much C++; it's just used to interface
++// the functions of xpdf, which are written in C++.
++
++extern "C" {
++#include <pdftexdir/ptexmac.h>
++#include <pdftexdir/pdftex-common.h>
++
++// These functions from pdftex.web gets declared in pdftexcoerce.h in the
++// usual web2c way, but we cannot include that file here because C++
++// does not allow it.
++extern int getpdfsuppresswarningpagegroup(void);
++extern integer getpdfsuppressptexinfo(void);
++extern integer zround(double);
++}
++
++// The prefix "PTEX" for the PDF keys is special to pdfTeX;
++// this has been registered with Adobe by Hans Hagen.
++
++#define pdfkeyprefix "PTEX"
++
++#define MASK_SUPPRESS_PTEX_FULLBANNER 0x01
++#define MASK_SUPPRESS_PTEX_FILENAME 0x02
++#define MASK_SUPPRESS_PTEX_PAGENUMBER 0x04
++#define MASK_SUPPRESS_PTEX_INFODICT 0x08
++
++// When copying the Resources of the selected page, all objects are copied
++// recusively top-down. Indirect objects however are not fetched during
++// copying, but get a new object number from pdfTeX and then will be
++// appended into a linked list. Duplicates are checked and removed from the
++// list of indirect objects during appending.
++
++enum InObjType {
++ objFont,
++ objFontDesc,
++ objOther
++};
++
++struct InObj {
++ Ref ref; // ref in original PDF
++ InObjType type; // object type
++ InObj *next; // next entry in list of indirect objects
++ int num; // new object number in output PDF
++ fd_entry *fd; // pointer to /FontDescriptor object structure
++ int enc_objnum; // Encoding for objFont
++ int written; // has it been written to output PDF?
++};
++
++struct UsedEncoding {
++ int enc_objnum;
++ GfxFont *font;
++ UsedEncoding *next;
++};
++
++static InObj *inObjList;
++static UsedEncoding *encodingList;
++static bool isInit = false;
++
++// --------------------------------------------------------------------
++// Maintain list of open embedded PDF files
++// --------------------------------------------------------------------
++
++struct PdfDocument {
++ char *file_name;
++ PDFDoc *doc;
++ XRef *xref;
++ InObj *inObjList;
++ int occurences; // number of references to the document; the doc can be
++ // deleted when this is negative
++ PdfDocument *next;
++};
++
++static PdfDocument *pdfDocuments = 0;
++
++static XRef *xref = 0;
++
++// Returns pointer to PdfDocument record for PDF file.
++// Creates a new record if it doesn't exist yet.
++// xref is made current for the document.
++
++static PdfDocument *find_add_document(char *file_name)
++{
++ PdfDocument *p = pdfDocuments;
++ while (p && strcmp(p->file_name, file_name) != 0)
++ p = p->next;
++ if (p) {
++ xref = p->xref;
++ (p->occurences)++;
++ return p;
++ }
++ p = new PdfDocument;
++ p->file_name = xstrdup(file_name);
++ p->xref = xref = 0;
++ p->occurences = 0;
++ GString *docName = new GString(p->file_name);
++ p->doc = new PDFDoc(docName); // takes ownership of docName
++ if (!p->doc->isOk() || !p->doc->okToPrint()) {
++ pdftex_fail("xpdf: reading PDF image failed");
++ }
++ p->inObjList = 0;
++ p->next = pdfDocuments;
++ pdfDocuments = p;
++ return p;
++}
++
++// Deallocate a PdfDocument with all its resources
++
++static void delete_document(PdfDocument * pdf_doc)
++{
++ PdfDocument **p = &pdfDocuments;
++ while (*p && *p != pdf_doc)
++ p = &((*p)->next);
++ // should not happen:
++ if (!*p)
++ return;
++ // unlink from list
++ *p = pdf_doc->next;
++ // free pdf_doc's resources
++ InObj *r, *n;
++ for (r = pdf_doc->inObjList; r != 0; r = n) {
++ n = r->next;
++ delete r;
++ }
++ xref = pdf_doc->xref;
++ delete pdf_doc->doc;
++ xfree(pdf_doc->file_name);
++ delete pdf_doc;
++}
++
++// --------------------------------------------------------------------
++
++static int addEncoding(GfxFont * gfont)
++{
++ UsedEncoding *n;
++ n = new UsedEncoding;
++ n->next = encodingList;
++ encodingList = n;
++ n->font = gfont;
++ n->enc_objnum = pdfnewobjnum();
++ return n->enc_objnum;
++}
++
++#define addFont(ref, fd, enc_objnum) \
++ addInObj(objFont, ref, fd, enc_objnum)
++
++// addFontDesc is only used to avoid writing the original FontDescriptor
++// from the PDF file.
++
++#define addFontDesc(ref, fd) \
++ addInObj(objFontDesc, ref, fd, 0)
++
++#define addOther(ref) \
++ addInObj(objOther, ref, 0, 0)
++
++static int addInObj(InObjType type, Ref ref, fd_entry * fd, int e)
++{
++ InObj *p, *q, *n = new InObj;
++ if (ref.num == 0)
++ pdftex_fail("PDF inclusion: invalid reference");
++ n->ref = ref;
++ n->type = type;
++ n->next = 0;
++ n->fd = fd;
++ n->enc_objnum = e;
++ n->written = 0;
++ if (inObjList == 0)
++ inObjList = n;
++ else {
++ for (p = inObjList; p != 0; p = p->next) {
++ if (p->ref.num == ref.num && p->ref.gen == ref.gen) {
++ delete n;
++ return p->num;
++ }
++ q = p;
++ }
++ // it is important to add new objects at the end of the list,
++ // because new objects are being added while the list is being
++ // written out.
++ q->next = n;
++ }
++ if (type == objFontDesc)
++ n->num = get_fd_objnum(fd);
++ else
++ n->num = pdfnewobjnum();
++ return n->num;
++}
++
++#if 0 /* unusewd */
++static int getNewObjectNumber(Ref ref)
++{
++ InObj *p;
++ if (inObjList == 0) {
++ pdftex_fail("No objects copied yet");
++ } else {
++ for (p = inObjList; p != 0; p = p->next) {
++ if (p->ref.num == ref.num && p->ref.gen == ref.gen) {
++ return p->num;
++ }
++ }
++ pdftex_fail("Object not yet copied: %i %i", ref.num, ref.gen);
++ }
++#ifdef _MSC_VER
++ /* Never reached, but without __attribute__((noreturn)) for pdftex_fail()
++ MSVC 5.0 requires an int return value. */
++ return -60000;
++#endif
++}
++#endif
++
++static void copyObject(Object *);
++
++static void copyName(char *s)
++{
++ pdf_puts("/");
++ for (; *s != 0; s++) {
++ if (isdigit(*s) || isupper(*s) || islower(*s) || *s == '_' ||
++ *s == '.' || *s == '-' || *s == '+')
++ pdfout(*s);
++ else
++ pdf_printf("#%.2X", *s & 0xFF);
++ }
++}
++
++static void copyDictEntry(Object * obj, int i)
++{
++ Object obj1;
++ copyName((char *)obj->dictGetKey(i));
++ pdf_puts(" ");
++ obj1 = obj->dictGetValNF(i);
++ copyObject(&obj1);
++ pdf_puts("\n");
++}
++
++static void copyDict(Object * obj)
++{
++ int i, l;
++ if (!obj->isDict())
++ pdftex_fail("PDF inclusion: invalid dict type <%s>",
++ obj->getTypeName());
++ for (i = 0, l = obj->dictGetLength(); i < l; ++i)
++ copyDictEntry(obj, i);
++}
++
++static void copyFontDict(Object * obj, InObj * r)
++{
++ int i, l;
++ char *key;
++ if (!obj->isDict())
++ pdftex_fail("PDF inclusion: invalid dict type <%s>",
++ obj->getTypeName());
++ pdf_puts("<<\n");
++ assert(r->type == objFont); // FontDescriptor is in fd_tree
++ for (i = 0, l = obj->dictGetLength(); i < l; ++i) {
++ key = (char *)obj->dictGetKey(i);
++ if (strncmp("FontDescriptor", key, strlen("FontDescriptor")) == 0
++ || strncmp("BaseFont", key, strlen("BaseFont")) == 0
++ || strncmp("Encoding", key, strlen("Encoding")) == 0)
++ continue; // skip original values
++ copyDictEntry(obj, i);
++ }
++ // write new FontDescriptor, BaseFont, and Encoding
++ pdf_printf("/FontDescriptor %d 0 R\n", get_fd_objnum(r->fd));
++ pdf_printf("/BaseFont %d 0 R\n", get_fn_objnum(r->fd));
++ pdf_printf("/Encoding %d 0 R\n", r->enc_objnum);
++ pdf_puts(">>");
++}
++
++static void copyStream(Stream * str)
++{
++ int c, c2 = 0;
++ str->reset();
++ while ((c = str->getChar()) != EOF) {
++ pdfout(c);
++ c2 = c;
++ }
++ pdflastbyte = c2;
++}
++
++static void copyProcSet(Object * obj)
++{
++ int i, l;
++ Object procset;
++ if (!obj->isArray())
++ pdftex_fail("PDF inclusion: invalid ProcSet array type <%s>",
++ obj->getTypeName());
++ pdf_puts("/ProcSet [ ");
++ for (i = 0, l = obj->arrayGetLength(); i < l; ++i) {
++ procset = obj->arrayGetNF(i);
++ if (!procset.isName())
++ pdftex_fail("PDF inclusion: invalid ProcSet entry type <%s>",
++ procset.getTypeName());
++ copyName((char *)procset.getName());
++ pdf_puts(" ");
++ }
++ pdf_puts("]\n");
++}
++
++#define REPLACE_TYPE1C true
++
++static bool embeddableFont(Object * fontdesc)
++{
++ Object fontfile, ffsubtype;
++
++ if (!fontdesc->isDict())
++ return false;
++ fontfile = fontdesc->dictLookup("FontFile");
++ if (fontfile.isStream())
++ return true;
++ if (REPLACE_TYPE1C) {
++ fontfile = fontdesc->dictLookup("FontFile3");
++ if (!fontfile.isStream())
++ return false;
++ ffsubtype = fontfile.streamGetDict()->lookup("Subtype");
++ return ffsubtype.isName() && !strcmp(ffsubtype.getName(), "Type1C");
++ }
++ return false;
++}
++
++static void copyFont(char *tag, Object * fontRef)
++{
++ Object fontdict, subtype, basefont, fontdescRef, fontdesc, charset,
++ stemV;
++ GfxFont *gfont;
++ fd_entry *fd;
++ fm_entry *fontmap;
++ // Check whether the font has already been embedded before analysing it.
++ InObj *p;
++ Ref ref = fontRef->getRef();
++ for (p = inObjList; p; p = p->next) {
++ if (p->ref.num == ref.num && p->ref.gen == ref.gen) {
++ copyName(tag);
++ pdf_printf(" %d 0 R ", p->num);
++ return;
++ }
++ }
++ // Only handle included Type1 (and Type1C) fonts; anything else will be copied.
++ // Type1C fonts are replaced by Type1 fonts, if REPLACE_TYPE1C is true.
++ fontdict = fontRef->fetch(xref);
++ fontdesc = Object(objNull);
++ if (fontdict.isDict()) {
++ subtype = fontdict.dictLookup("Subtype");
++ basefont = fontdict.dictLookup("BaseFont");
++ fontdescRef = fontdict.dictLookupNF("FontDescriptor");
++ if (fontdescRef.isRef()) {
++ fontdesc = fontdescRef.fetch(xref);
++ }
++ }
++ if (!fixedinclusioncopyfont && fontdict.isDict()
++ && subtype.isName()
++ && !strcmp(subtype.getName(), "Type1")
++ && basefont.isName()
++ && fontdescRef.isRef()
++ && fontdesc.isDict()
++ && embeddableFont(&fontdesc)
++ && (fontmap = lookup_fontmap((char *)basefont.getName())) != NULL) {
++ // round /StemV value, since the PDF input is a float
++ // (see Font Descriptors in PDF reference), but we only store an
++ // integer, since we don't want to change the struct.
++ stemV = fontdesc.dictLookup("StemV");
++ fd = epdf_create_fontdescriptor(fontmap, zround(stemV.getNum()));
++ charset = fontdesc.dictLookup("CharSet");
++ if (!charset.isNull() &&
++ charset.isString() && is_subsetable(fontmap))
++ epdf_mark_glyphs(fd, (char *)charset.getString()->getCString());
++ else
++ embed_whole_font(fd);
++ addFontDesc(fontdescRef.getRef(), fd);
++ copyName(tag);
++ gfont = GfxFont::makeFont(xref, tag, fontRef->getRef(),
++ fontdict.getDict());
++ pdf_printf(" %d 0 R ", addFont(fontRef->getRef(), fd,
++ addEncoding(gfont)));
++ } else {
++ copyName(tag);
++ pdf_puts(" ");
++ copyObject(fontRef);
++ }
++}
++
++static void copyFontResources(Object * obj)
++{
++ Object fontRef;
++ int i, l;
++ if (!obj->isDict())
++ pdftex_fail("PDF inclusion: invalid font resources dict type <%s>",
++ obj->getTypeName());
++ pdf_puts("/Font << ");
++ for (i = 0, l = obj->dictGetLength(); i < l; ++i) {
++ fontRef = obj->dictGetValNF(i);
++ if (fontRef.isRef())
++ copyFont((char *)obj->dictGetKey(i), &fontRef);
++ else if (fontRef.isDict()) { // some programs generate pdf with embedded font object
++ copyName((char *)obj->dictGetKey(i));
++ pdf_puts(" ");
++ copyObject(&fontRef);
++ }
++ else
++ pdftex_fail("PDF inclusion: invalid font in reference type <%s>",
++ fontRef.getTypeName());
++ }
++ pdf_puts(">>\n");
++}
++
++static void copyOtherResources(Object * obj, char *key)
++{
++ // copies all other resources (write_epdf handles Fonts and ProcSets),
++
++ // if Subtype is present, it must be a name
++ if (strcmp("Subtype", key) == 0) {
++ if (!obj->isName()) {
++ pdftex_warn("PDF inclusion: Subtype in Resources dict is not a name"
++ " (key '%s', type <%s>); ignored.",
++ key, obj->getTypeName());
++ return;
++ }
++ } else if (!obj->isDict()) {
++ //FIXME: Write the message only to the log file
++ pdftex_warn("PDF inclusion: invalid other resource which is no dict"
++ " (key '%s', type <%s>); ignored.",
++ key, obj->getTypeName());
++ return;
++ }
++ copyName(key);
++ pdf_puts(" ");
++ copyObject(obj);
++}
++
++// Function onverts double to string; very small and very large numbers
++// are NOT converted to scientific notation.
++// n must be a number or real conforming to the implementation limits
++// of PDF as specified in appendix C.1 of the PDF Ref.
++// These are:
++// maximum value of ints is +2^32
++// maximum value of reals is +2^15
++// smalles values of reals is 1/(2^16)
++
++static char *convertNumToPDF(double n)
++{
++ static const int precision = 6;
++ static const int fact = (int) 1E6; // must be 10^precision
++ static const double epsilon = 0.5E-6; // 2epsilon must be 10^-precision
++ static char buf[64];
++ // handle very small values: return 0
++ if (fabs(n) < epsilon) {
++ buf[0] = '0';
++ buf[1] = '\0';
++ } else {
++ char ints[64];
++ int bindex = 0, sindex = 0;
++ int ival, fval;
++ // handle the sign part if n is negative
++ if (n < 0) {
++ buf[bindex++] = '-';
++ n = -n;
++ }
++ n += epsilon; // for rounding
++ // handle the integer part, simply with sprintf
++ ival = (int) floor(n);
++ n -= ival;
++ sprintf(ints, "%d", ival);
++ while (ints[sindex] != 0)
++ buf[bindex++] = ints[sindex++];
++ // handle the fractional part up to 'precision' digits
++ fval = (int) floor(n * fact);
++ if (fval) {
++ // set a dot
++ buf[bindex++] = '.';
++ sindex = bindex + precision;
++ buf[sindex--] = '\0';
++ // fill up trailing zeros with the string terminator NULL
++ while (((fval % 10) == 0) && (sindex >= bindex)) {
++ buf[sindex--] = '\0';
++ fval /= 10;
++ }
++ // fill up the fractional part back to front
++ while (sindex >= bindex) {
++ buf[sindex--] = (fval % 10) + '0';
++ fval /= 10;
++ }
++ } else
++ buf[bindex++] = 0;
++ }
++ return (char *) buf;
++}
++
++static void copyObject(Object * obj)
++{
++ Object obj1;
++ int i, l, c;
++ Ref ref;
++ char *p;
++ GString *s;
++ if (obj->isBool()) {
++ pdf_printf("%s", obj->getBool()? "true" : "false");
++ } else if (obj->isInt()) {
++ pdf_printf("%i", obj->getInt());
++ } else if (obj->isReal()) {
++ pdf_printf("%s", convertNumToPDF(obj->getReal()));
++ } else if (obj->isNum()) {
++ pdf_printf("%s", convertNumToPDF(obj->getNum()));
++ } else if (obj->isString()) {
++ s = (GooString *)obj->getString();
++ p = (char *)s->getCString();
++ l = s->getLength();
++ if (strlen(p) == (unsigned int) l) {
++ pdf_puts("(");
++ for (; *p != 0; p++) {
++ c = (unsigned char) *p;
++ if (c == '(' || c == ')' || c == '\\')
++ pdf_printf("\\%c", c);
++ else if (c < 0x20 || c > 0x7F)
++ pdf_printf("\\%03o", c);
++ else
++ pdfout(c);
++ }
++ pdf_puts(")");
++ } else {
++ pdf_puts("<");
++ for (i = 0; i < l; i++) {
++ c = s->getChar(i) & 0xFF;
++ pdf_printf("%.2x", c);
++ }
++ pdf_puts(">");
++ }
++ } else if (obj->isName()) {
++ copyName((char *)obj->getName());
++ } else if (obj->isNull()) {
++ pdf_puts("null");
++ } else if (obj->isArray()) {
++ pdf_puts("[");
++ for (i = 0, l = obj->arrayGetLength(); i < l; ++i) {
++ obj1 = obj->arrayGetNF(i);
++ if (!obj1.isName())
++ pdf_puts(" ");
++ copyObject(&obj1);
++ }
++ pdf_puts("]");
++ } else if (obj->isDict()) {
++ pdf_puts("<<\n");
++ copyDict(obj);
++ pdf_puts(">>");
++ } else if (obj->isStream()) {
++ pdf_puts("<<\n");
++ copyDict(obj->getStream()->getDictObject());
++ pdf_puts(">>\n");
++ pdf_puts("stream\n");
++ copyStream(obj->getStream()->getUndecodedStream());
++ pdf_puts("\nendstream");
++ } else if (obj->isRef()) {
++ ref = obj->getRef();
++ if (ref.num == 0) {
++ pdftex_fail
++ ("PDF inclusion: reference to invalid object"
++ " (is the included pdf broken?)");
++ } else
++ pdf_printf("%d 0 R", addOther(ref));
++ } else {
++ pdftex_fail("PDF inclusion: type <%s> cannot be copied",
++ obj->getTypeName());
++ }
++}
++
++static void writeRefs()
++{
++ InObj *r;
++ for (r = inObjList; r != 0; r = r->next) {
++ if (!r->written) {
++ r->written = 1;
++ Object obj1 = xref->fetch(r->ref.num, r->ref.gen);
++ if (r->type == objFont) {
++ assert(!obj1.isStream());
++ pdfbeginobj(r->num, 2); // \pdfobjcompresslevel = 2 is for this
++ copyFontDict(&obj1, r);
++ pdf_puts("\n");
++ pdfendobj();
++ } else if (r->type != objFontDesc) { // /FontDescriptor is written via write_fontdescriptor()
++ if (obj1.isStream())
++ pdfbeginobj(r->num, 0);
++ else
++ pdfbeginobj(r->num, 2); // \pdfobjcompresslevel = 2 is for this
++ copyObject(&obj1);
++ pdf_puts("\n");
++ pdfendobj();
++ }
++ }
++ }
++}
++
++static void writeEncodings()
++{
++ UsedEncoding *r, *n;
++ char *glyphNames[256], *s;
++ int i;
++ for (r = encodingList; r != 0; r = r->next) {
++ for (i = 0; i < 256; i++) {
++ if (r->font->isCIDFont()) {
++ pdftex_fail
++ ("PDF inclusion: CID fonts are not supported"
++ " (try to disable font replacement to fix this)");
++ }
++ if ((s = (char *)((Gfx8BitFont *) r->font)->getCharName(i)) != 0)
++ glyphNames[i] = s;
++ else
++ glyphNames[i] = notdef;
++ }
++ epdf_write_enc(glyphNames, r->enc_objnum);
++ }
++ for (r = encodingList; r != 0; r = n) {
++ n = r->next;
++#ifdef POPPLER_VERSION
++ r->font->decRefCnt();
++#else
++#error POPPLER_VERSION should be defined.
++#endif
++ delete r;
++ }
++}
++
++// get the pagebox according to the pagebox_spec
++static const PDFRectangle *get_pagebox(Page * page, int pagebox_spec)
++{
++ if (pagebox_spec == pdfboxspecmedia)
++ return page->getMediaBox();
++ else if (pagebox_spec == pdfboxspeccrop)
++ return page->getCropBox();
++ else if (pagebox_spec == pdfboxspecbleed)
++ return page->getBleedBox();
++ else if (pagebox_spec == pdfboxspectrim)
++ return page->getTrimBox();
++ else if (pagebox_spec == pdfboxspecart)
++ return page->getArtBox();
++ else
++ pdftex_fail("PDF inclusion: unknown value of pagebox spec (%i)",
++ (int) pagebox_spec);
++ return page->getMediaBox(); // to make the compiler happy
++}
++
++
++// Reads various information about the PDF and sets it up for later inclusion.
++// This will fail if the PDF version of the PDF is higher than
++// minor_pdf_version_wanted or page_name is given and can not be found.
++// It makes no sense to give page_name _and_ page_num.
++// Returns the page number.
++
++int
++read_pdf_info(char *image_name, char *page_name, int page_num,
++ int pagebox_spec, int minor_pdf_version_wanted,
++ int pdf_inclusion_errorlevel)
++{
++ PdfDocument *pdf_doc;
++ Page *page;
++ const PDFRectangle *pagebox;
++#ifdef POPPLER_VERSION
++ int pdf_major_version_found, pdf_minor_version_found;
++#else
++#error POPPLER_VERSION should be defined.
++#endif
++ // initialize
++ if (!isInit) {
++ globalParams = new GlobalParams();
++ globalParams->setErrQuiet(false);
++ isInit = true;
++ }
++ // open PDF file
++ pdf_doc = find_add_document(image_name);
++ epdf_doc = (void *) pdf_doc;
++
++ // check PDF version
++ // this works only for PDF 1.x -- but since any versions of PDF newer
++ // than 1.x will not be backwards compatible to PDF 1.x, pdfTeX will
++ // then have to changed drastically anyway.
++#ifdef POPPLER_VERSION
++ pdf_major_version_found = pdf_doc->doc->getPDFMajorVersion();
++ pdf_minor_version_found = pdf_doc->doc->getPDFMinorVersion();
++ if ((pdf_major_version_found > 1)
++ || (pdf_minor_version_found > minor_pdf_version_wanted)) {
++ const char *msg =
++ "PDF inclusion: found PDF version <%d.%d>, but at most version <1.%d> allowed";
++ if (pdf_inclusion_errorlevel > 0) {
++ pdftex_fail(msg, pdf_major_version_found, pdf_minor_version_found, minor_pdf_version_wanted);
++ } else if (pdf_inclusion_errorlevel < 0) {
++ ; /* do nothing */
++ } else { /* = 0, give warning */
++ pdftex_warn(msg, pdf_major_version_found, pdf_minor_version_found, minor_pdf_version_wanted);
++ }
++ }
++#else
++#error POPPLER_VERSION should be defined.
++#endif
++ epdf_num_pages = pdf_doc->doc->getCatalog()->getNumPages();
++ if (page_name) {
++ // get page by name
++ GString name(page_name);
++ LinkDest *link = pdf_doc->doc->findDest(&name);
++ if (link == 0 || !link->isOk())
++ pdftex_fail("PDF inclusion: invalid destination <%s>", page_name);
++ Ref ref = link->getPageRef();
++ page_num = pdf_doc->doc->getCatalog()->findPage(ref.num, ref.gen);
++ if (page_num == 0)
++ pdftex_fail("PDF inclusion: destination is not a page <%s>",
++ page_name);
++ delete link;
++ } else {
++ // get page by number
++ if (page_num <= 0 || page_num > epdf_num_pages)
++ pdftex_fail("PDF inclusion: required page does not exist <%i>",
++ epdf_num_pages);
++ }
++ // get the required page
++ page = pdf_doc->doc->getCatalog()->getPage(page_num);
++
++ // get the pagebox (media, crop...) to use.
++ pagebox = get_pagebox(page, pagebox_spec);
++ if (pagebox->x2 > pagebox->x1) {
++ epdf_orig_x = pagebox->x1;
++ epdf_width = pagebox->x2 - pagebox->x1;
++ } else {
++ epdf_orig_x = pagebox->x2;
++ epdf_width = pagebox->x1 - pagebox->x2;
++ }
++ if (pagebox->y2 > pagebox->y1) {
++ epdf_orig_y = pagebox->y1;
++ epdf_height = pagebox->y2 - pagebox->y1;
++ } else {
++ epdf_orig_y = pagebox->y2;
++ epdf_height = pagebox->y1 - pagebox->y2;
++ }
++
++ // get page rotation
++ epdf_rotate = page->getRotate() % 360;
++ if (epdf_rotate < 0)
++ epdf_rotate += 360;
++
++ // page group
++ if (page->getGroup() != NULL)
++ epdf_has_page_group = 1; // only flag that page group is present;
++ // the actual object number will be
++ // generated in pdftex.web
++ else
++ epdf_has_page_group = 0; // no page group present
++
++ pdf_doc->xref = pdf_doc->doc->getXRef();
++ return page_num;
++}
++
++// writes the current epf_doc.
++// Here the included PDF is copied, so most errors that can happen during PDF
++// inclusion will arise here.
++
++void write_epdf(void)
++{
++ Page *page;
++ Ref *pageRef;
++ Dict *pageDict;
++ Object contents, obj1, obj2, pageObj, dictObj;
++ Object groupDict;
++ bool writeSepGroup = false;
++ Object info;
++ char *key;
++ char s[256];
++ int i, l;
++ int rotate;
++ double scale[6] = { 0, 0, 0, 0, 0, 0 };
++ bool writematrix = false;
++ int suppress_ptex_info = getpdfsuppressptexinfo();
++ static const char *pageDictKeys[] = {
++ "LastModified",
++ "Metadata",
++ "PieceInfo",
++ "SeparationInfo",
++// "Group",
++// "Resources",
++ NULL
++ };
++
++ PdfDocument *pdf_doc = (PdfDocument *) epdf_doc;
++ (pdf_doc->occurences)--;
++ xref = pdf_doc->xref;
++ inObjList = pdf_doc->inObjList;
++ encodingList = 0;
++ page = pdf_doc->doc->getCatalog()->getPage(epdf_selected_page);
++ pageRef = pdf_doc->doc->getCatalog()->getPageRef(epdf_selected_page);
++ pageObj = xref->fetch(pageRef->num, pageRef->gen);
++ pageDict = pageObj.getDict();
++ rotate = page->getRotate();
++ const PDFRectangle *pagebox;
++ // write the Page header
++ pdf_puts("/Type /XObject\n");
++ pdf_puts("/Subtype /Form\n");
++ pdf_puts("/FormType 1\n");
++
++ // write additional information
++ if ((suppress_ptex_info & MASK_SUPPRESS_PTEX_FILENAME) == 0) {
++ pdf_printf("/%s.FileName (%s)\n", pdfkeyprefix,
++ convertStringToPDFString(pdf_doc->file_name,
++ strlen(pdf_doc->file_name)));
++ }
++ if ((suppress_ptex_info & MASK_SUPPRESS_PTEX_PAGENUMBER) == 0) {
++ pdf_printf("/%s.PageNumber %i\n", pdfkeyprefix, (int) epdf_selected_page);
++ }
++ if ((suppress_ptex_info & MASK_SUPPRESS_PTEX_INFODICT) == 0) {
++ info = pdf_doc->doc->getDocInfoNF();
++ if (info.isRef()) {
++ // the info dict must be indirect (PDF Ref p. 61)
++ pdf_printf("/%s.InfoDict ", pdfkeyprefix);
++ pdf_printf("%d 0 R\n", addOther(info.getRef()));
++ }
++ }
++ // get the pagebox (media, crop...) to use.
++ pagebox = get_pagebox(page, epdf_page_box);
++
++ // handle page rotation
++ if (rotate != 0) {
++ if (rotate % 90 == 0) {
++ // this handles only the simple case: multiple of 90s but these
++ // are the only values allowed according to the reference
++ // (v1.3, p. 78).
++ // the image is rotated around its center.
++ // the /Rotate key is clockwise while the matrix is
++ // counterclockwise :-%
++ tex_printf(", page is rotated %d degrees", rotate);
++ switch (rotate) {
++ case 90:
++ scale[1] = -1;
++ scale[2] = 1;
++ scale[4] = pagebox->x1 - pagebox->y1;
++ scale[5] = pagebox->y1 + pagebox->x2;
++ writematrix = true;
++ break;
++ case 180:
++ scale[0] = scale[3] = -1;
++ scale[4] = pagebox->x1 + pagebox->x2;
++ scale[5] = pagebox->y1 + pagebox->y2;
++ writematrix = true;
++ break; // width and height are exchanged
++ case 270:
++ scale[1] = 1;
++ scale[2] = -1;
++ scale[4] = pagebox->x1 + pagebox->y2;
++ scale[5] = pagebox->y1 - pagebox->x1;
++ writematrix = true;
++ break;
++ }
++ if (writematrix) { // The matrix is only written if the image is rotated.
++ sprintf(s, "/Matrix [%.8f %.8f %.8f %.8f %.8f %.8f]\n",
++ scale[0],
++ scale[1], scale[2], scale[3], scale[4], scale[5]);
++ pdf_puts(stripzeros(s));
++ }
++ }
++ }
++
++ sprintf(s, "/BBox [%.8f %.8f %.8f %.8f]\n",
++ pagebox->x1, pagebox->y1, pagebox->x2, pagebox->y2);
++ pdf_puts(stripzeros(s));
++
++ // Metadata validity check (as a stream it must be indirect)
++ dictObj = pageDict->lookupNF("Metadata");
++ if (!dictObj.isNull() && !dictObj.isRef())
++ pdftex_warn("PDF inclusion: /Metadata must be indirect object");
++
++ // copy selected items in Page dictionary except Resources & Group
++ for (i = 0; pageDictKeys[i] != NULL; i++) {
++ dictObj = pageDict->lookupNF(pageDictKeys[i]);
++ if (!dictObj.isNull()) {
++ pdf_newline();
++ pdf_printf("/%s ", pageDictKeys[i]);
++ copyObject(&dictObj); // preserves indirection
++ }
++ }
++
++ // handle page group
++ dictObj = pageDict->lookupNF("Group");
++ if (!dictObj.isNull()) {
++ if (pdfpagegroupval == 0) {
++ // another pdf with page group was included earlier on the
++ // same page; copy the Group entry as is. See manual for
++ // info on why this is a warning.
++ if (getpdfsuppresswarningpagegroup() == 0) {
++ pdftex_warn
++ ("PDF inclusion: multiple pdfs with page group included in a single page");
++ }
++ pdf_newline();
++ pdf_puts("/Group ");
++ copyObject(&dictObj);
++ } else {
++ // write Group dict as a separate object, since the Page dict also refers to it
++ dictObj = pageDict->lookup("Group");
++ if (!dictObj.isDict())
++ pdftex_fail("PDF inclusion: /Group dict missing");
++ writeSepGroup = true;
++/*
++This part is only a single line
++ groupDict = Object(page->getGroup());
++in the original patch. In this case, however, pdftex crashes at
++"delete pdf_doc->doc" in "delete_document()" for inclusion of some
++kind of pdf images, for example, figure_missing.pdf in gnuplot.
++A change
++ groupDict = Object(page->getGroup()).copy();
++does not improve the situation.
++The changes below seem to work fine.
++*/
++// begin modification
++ groupDict = pageDict->lookup("Group");
++ const Dict& dic1 = page->getGroup();
++ const Dict& dic2 = groupDict.getDict();
++ // replace dic2 in groupDict with dic1
++ l = dic2.getLength();
++ for (i = 0; i < l; i++) {
++ groupDict.dictRemove(dic2.getKey(i));
++ }
++ l = dic1.getLength();
++ for (i = 0; i < l; i++) {
++ groupDict.dictAdd((const char *)copyString(dic1.getKey(i)),
++ dic1.getValNF(i));
++ }
++// end modification
++ pdf_printf("/Group %ld 0 R\n", (long)pdfpagegroupval);
++ }
++ }
++
++ // write the Resources dictionary
++ if (page->getResourceDict() == NULL) {
++ // Resources can be missing (files without them have been spotted
++ // in the wild); in which case the /Resouces of the /Page will be used.
++ // "This practice is not recommended".
++ pdftex_warn
++ ("PDF inclusion: /Resources missing. 'This practice is not recommended' (PDF Ref)");
++ } else {
++ Object *obj1 = page->getResourceDictObject();
++ if (!obj1->isDict())
++ pdftex_fail("PDF inclusion: invalid resources dict type <%s>",
++ obj1->getTypeName());
++ pdf_newline();
++ pdf_puts("/Resources <<\n");
++ for (i = 0, l = obj1->dictGetLength(); i < l; ++i) {
++ obj2 = obj1->dictGetVal(i);
++ key = (char *)obj1->dictGetKey(i);
++ if (strcmp("Font", key) == 0)
++ copyFontResources(&obj2);
++ else if (strcmp("ProcSet", key) == 0)
++ copyProcSet(&obj2);
++ else
++ copyOtherResources(&obj2, (char *)key);
++ }
++ pdf_puts(">>\n");
++ }
++
++ // write the page contents
++ contents = page->getContents();
++ if (contents.isStream()) {
++
++ // Variant A: get stream and recompress under control
++ // of \pdfcompresslevel
++ //
++ // pdfbeginstream();
++ // copyStream(contents->getStream());
++ // pdfendstream();
++
++ // Variant B: copy stream without recompressing
++ //
++ obj1 = contents.streamGetDict()->lookup("F");
++ if (!obj1.isNull()) {
++ pdftex_fail("PDF inclusion: Unsupported external stream");
++ }
++ obj1 = contents.streamGetDict()->lookup("Length");
++ assert(!obj1.isNull());
++ pdf_puts("/Length ");
++ copyObject(&obj1);
++ pdf_puts("\n");
++ obj1 = contents.streamGetDict()->lookup("Filter");
++ if (!obj1.isNull()) {
++ pdf_puts("/Filter ");
++ copyObject(&obj1);
++ pdf_puts("\n");
++ obj1 = contents.streamGetDict()->lookup("DecodeParms");
++ if (!obj1.isNull()) {
++ pdf_puts("/DecodeParms ");
++ copyObject(&obj1);
++ pdf_puts("\n");
++ }
++ }
++ pdf_puts(">>\nstream\n");
++ copyStream(contents.getStream()->getUndecodedStream());
++ pdfendstream();
++ } else if (contents.isArray()) {
++ pdfbeginstream();
++ for (i = 0, l = contents.arrayGetLength(); i < l; ++i) {
++ Object contentsobj = contents.arrayGet(i);
++ copyStream(contentsobj.getStream());
++ if (i < l - 1)
++ pdf_newline(); // add a newline after each stream except the last
++ }
++ pdfendstream();
++ } else { // the contents are optional, but we need to include an empty stream
++ pdfbeginstream();
++ pdfendstream();
++ }
++
++ // write out all indirect objects
++ writeRefs();
++
++ // write out all used encodings (and delete list)
++ writeEncodings();
++
++ // write the Group dict if needed
++ if (writeSepGroup) {
++ pdfbeginobj(pdfpagegroupval, 2);
++ copyObject(&groupDict);
++ pdf_puts("\n");
++ pdfendobj();
++ pdfpagegroupval = 0; // only the 1st included pdf on a page gets its
++ // Group included in the Page dict
++ }
++
++ // save object list, xref
++ pdf_doc->inObjList = inObjList;
++ pdf_doc->xref = xref;
++}
++
++// Called when an image has been written and it's resources in image_tab are
++// freed and it's not referenced anymore.
++
++void epdf_delete()
++{
++ PdfDocument *pdf_doc = (PdfDocument *) epdf_doc;
++ xref = pdf_doc->xref;
++ if (pdf_doc->occurences < 0) {
++ delete_document(pdf_doc);
++ }
++}
++
++// Called when PDF embedding system is finalized.
++// Now deallocate all remaining PdfDocuments.
++
++void epdf_check_mem()
++{
++ if (isInit) {
++ PdfDocument *p, *n;
++ for (p = pdfDocuments; p; p = n) {
++ n = p->next;
++ delete_document(p);
++ }
++ // see above for globalParams
++ delete globalParams;
++ }
++}
+diff -ruN r47457/texk/web2c/pdftexdir/pdftosrc-newpoppler.cc r49040/texk/web2c/pdftexdir/pdftosrc-newpoppler.cc
+--- r47457/texk/web2c/pdftexdir/pdftosrc-newpoppler.cc 2018-12-05 19:19:35.367778487 +0100
++++ r49040/texk/web2c/pdftexdir/pdftosrc-newpoppler.cc 2018-12-05 19:19:35.398778485 +0100
+@@ -21,6 +21,8 @@
+ This is based on the patch texlive-poppler-0.59.patch <2017-09-19> at
+ https://git.archlinux.org/svntogit/packages.git/plain/texlive-bin/trunk
+ by Arch Linux. The poppler should be 0.59.0 or newer versions.
++It is tested up to the poppler 0.70.1. The poppler 0.71.0 and newer
++ones require pdftosrc-poppler0.71.0.
+ POPPLER_VERSION should be defined.
+ */
+
+@@ -109,7 +111,7 @@
+ fprintf(stderr, "No SourceName found\n");
+ exit(1);
+ }
+- outname = srcName.getString()->getCString();
++ outname = (char *)srcName.getString()->getCString();
+ // We cannot free srcName, as objname shares its string.
+ // srcName.free();
+ } else if (objnum > 0) {
+diff -ruN r47457/texk/web2c/pdftexdir/pdftosrc-poppler0.71.0.cc r49040/texk/web2c/pdftexdir/pdftosrc-poppler0.71.0.cc
+--- r47457/texk/web2c/pdftexdir/pdftosrc-poppler0.71.0.cc 1970-01-01 01:00:00.000000000 +0100
++++ r49040/texk/web2c/pdftexdir/pdftosrc-poppler0.71.0.cc 2018-12-05 19:19:35.386778486 +0100
+@@ -0,0 +1,208 @@
++/*
++Copyright 1996-2017 Han The Thanh, <thanh@pdftex.org>
++
++This file is part of pdfTeX.
++
++pdfTeX 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.
++
++pdfTeX 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, see <http://www.gnu.org/licenses/>.
++*/
++
++/*
++This is based on the patch texlive-poppler-0.59.patch <2017-09-19> at
++https://git.archlinux.org/svntogit/packages.git/plain/texlive-bin/trunk
++by Arch Linux. The poppler should be 0.59.0 or newer versions.
++It is tested up to the poppler 0.70.0.
++POPPLER_VERSION should be defined.
++*/
++
++#include <w2c/config.h>
++
++#include <stdlib.h>
++#include <stddef.h>
++#include <stdio.h>
++#include <string.h>
++#include <ctype.h>
++
++#ifdef POPPLER_VERSION
++#define GString GooString
++#define xpdfVersion POPPLER_VERSION
++#include <dirent.h>
++#include <goo/GooString.h>
++#include <goo/gmem.h>
++#include <goo/gfile.h>
++#else
++#error POPPLER_VERSION should be defined.
++#endif
++#include <assert.h>
++
++#include "Object.h"
++#include "Stream.h"
++#include "Lexer.h"
++#include "Parser.h"
++#include "Array.h"
++#include "Dict.h"
++#include "XRef.h"
++#include "Catalog.h"
++#include "Page.h"
++#include "GfxFont.h"
++#include "PDFDoc.h"
++#include "GlobalParams.h"
++#include "Error.h"
++
++static XRef *xref = 0;
++
++int main(int argc, char *argv[])
++{
++ char *p, buf[1024];
++ PDFDoc *doc;
++ GString *fileName;
++ Stream *s;
++ Object srcStream, srcName, catalogDict;
++ FILE *outfile;
++ char *outname;
++ int objnum = 0, objgen = 0;
++ bool extract_xref_table = false;
++ int c;
++ fprintf(stderr, "pdftosrc version %s\n", xpdfVersion);
++ if (argc < 2) {
++ fprintf(stderr,
++ "Usage: pdftosrc <PDF-file> [<stream-object-number>]\n");
++ exit(1);
++ }
++ fileName = new GString(argv[1]);
++ globalParams = new GlobalParams();
++ doc = new PDFDoc(fileName);
++ if (!doc->isOk()) {
++ fprintf(stderr, "Invalid PDF file\n");
++ exit(1);
++ }
++ if (argc >= 3) {
++ objnum = atoi(argv[2]);
++ if (argc >= 4)
++ objgen = atoi(argv[3]);
++ }
++ xref = doc->getXRef();
++ catalogDict = xref->getCatalog();
++ if (!catalogDict.isDict("Catalog")) {
++ fprintf(stderr, "No Catalog found\n");
++ exit(1);
++ }
++ srcStream = Object(objNull);
++ if (objnum == 0) {
++ srcStream = catalogDict.dictLookup("SourceObject");
++ static char const_SourceFile[] = "SourceFile";
++ if (!srcStream.isStream(const_SourceFile)) {
++ fprintf(stderr, "No SourceObject found\n");
++ exit(1);
++ }
++ srcName = srcStream.getStream()->getDict()->lookup("SourceName");
++ if (!srcName.isString()) {
++ fprintf(stderr, "No SourceName found\n");
++ exit(1);
++ }
++ outname = (char *)srcName.getString()->getCString();
++ // We cannot free srcName, as objname shares its string.
++ // srcName.free();
++ } else if (objnum > 0) {
++ srcStream = xref->fetch(objnum, objgen);
++ if (!srcStream.isStream()) {
++ fprintf(stderr, "Not a Stream object\n");
++ exit(1);
++ }
++ sprintf(buf, "%s", fileName->getCString());
++ if ((p = strrchr(buf, '.')) == 0)
++ p = strchr(buf, 0);
++ if (objgen == 0)
++ sprintf(p, ".%i", objnum);
++ else
++ sprintf(p, ".%i+%i", objnum, objgen);
++ outname = buf;
++ } else { // objnum < 0 means we are extracting the XRef table
++ extract_xref_table = true;
++ sprintf(buf, "%s", fileName->getCString());
++ if ((p = strrchr(buf, '.')) == 0)
++ p = strchr(buf, 0);
++ sprintf(p, ".xref");
++ outname = buf;
++ }
++ if (!(outfile = fopen(outname, "wb"))) {
++ fprintf(stderr, "Cannot open file \"%s\" for writing\n", outname);
++ exit(1);
++ }
++ if (extract_xref_table) {
++ int size = xref->getNumObjects();
++ int i;
++ for (i = 0; i < size; i++) {
++ if (xref->getEntry(i)->offset == 0xffffffff)
++ break;
++ }
++ size = i;
++ fprintf(outfile, "xref\n");
++ fprintf(outfile, "0 %i\n", size);
++ for (i = 0; i < size; i++) {
++ XRefEntry *e = xref->getEntry(i);
++ if (e->type != xrefEntryCompressed)
++ fprintf(outfile, "%.10lu %.5i %s\n",
++ (long unsigned) e->offset, e->gen,
++ (e->type == xrefEntryFree ? "f" : "n"));
++ else { // e->offset is the object number of the object stream
++ Stream *str;
++ Lexer *lexer;
++ Parser *parser;
++ Object objStr, obj1, obj2;
++ int nObjects, first, n;
++ int localOffset = 0;
++ Guint firstOffset;
++
++ objStr = xref->fetch(e->offset, 0);
++ assert(objStr.isStream());
++ obj1 = objStr.streamGetDict()->lookup("N");
++ nObjects = obj1.getInt();
++ obj1 = objStr.streamGetDict()->lookup("First");
++ first = obj1.getInt();
++ firstOffset = objStr.getStream()->getBaseStream()->getStart() + first;
++
++ // parse the header: object numbers and offsets
++ objStr.streamReset();
++ str = new EmbedStream(objStr.getStream(), Object(objNull), true, first);
++ lexer = new Lexer(xref, str);
++ parser = new Parser(xref, lexer, false);
++ for (n = 0; n < nObjects; ++n) {
++ obj1 = parser->getObj();
++ obj2 = parser->getObj();
++ if (n == e->gen)
++ localOffset = obj2.getInt();
++ }
++ while (str->getChar() != EOF) ;
++ delete parser;
++
++ fprintf(outfile, "%.10lu 00000 n\n",
++ (long unsigned)(firstOffset + localOffset));
++ }
++ }
++ } else {
++ s = srcStream.getStream();
++ s->reset();
++ while ((c = s->getChar()) != EOF)
++ fputc(c, outfile);
++ }
++ if (objnum == 0)
++ fprintf(stderr, "Source file extracted to %s\n", outname);
++ else if (objnum > 0)
++ fprintf(stderr, "Stream object extracted to %s\n", outname);
++ else
++ fprintf(stderr, "Cross-reference table extracted to %s\n", outname);
++ fclose(outfile);
++ delete doc;
++ delete globalParams;
++}
+diff -ruN r47457/texk/web2c/pdftexdir/ptexlib.h r49040/texk/web2c/pdftexdir/ptexlib.h
+--- r47457/texk/web2c/pdftexdir/ptexlib.h 2018-12-05 19:19:35.368778487 +0100
++++ r49040/texk/web2c/pdftexdir/ptexlib.h 2018-12-05 19:19:35.399778485 +0100
+@@ -20,6 +20,17 @@
+ #ifndef PDFTEXLIB
+ # define PDFTEXLIB
+
++#ifdef _WIN32
++#undef fopen
++#undef xfopen
++#undef fputs
++#undef putc
++#define fopen fsyscp_fopen
++#define xfopen fsyscp_xfopen
++#define fputs win32_fputs
++#define putc win32_putc
++#endif
++
+ /* WEB2C macros and prototypes */
+ # if !defined(PDFTEXCOERCE) && !defined(PDFETEXCOERCE)
+ # ifdef pdfTeX
+diff -ruN r47457/texk/web2c/pdftexdir/tests/expanded.tex r49040/texk/web2c/pdftexdir/tests/expanded.tex
+--- r47457/texk/web2c/pdftexdir/tests/expanded.tex 1970-01-01 01:00:00.000000000 +0100
++++ r49040/texk/web2c/pdftexdir/tests/expanded.tex 2018-12-05 19:19:35.403778485 +0100
+@@ -0,0 +1,46 @@
++% $Id$
++% Public domain.
++% Originally written 2018 by David Carlisle, Bruno Le Floch.
++
++\catcode`\{=1 \catcode`\}=2 \catcode`\#=6
++\def\typ#1{\immediate\write-1 {#1}}
++\def\space{ }
++\let\bgroup{ \let\egroup}
++
++\typ{START}
++\typ{EXPANDED TEST 1}
++% Check the primitive exists
++\show\expanded
++
++\typ{EXPANDED TEST 2}
++% Simple expansion test
++\def\aaa{x}
++\def\bbb{\aaa\aaa}
++\expandafter\def\expandafter\ccc\expandafter{\expanded{\bbb,\aaa}}
++\show\ccc
++
++\typ{EXPANDED TEST 3: the}
++% Expanding \the
++\typ{\expanded{\bbb,\the\numexpr100+20+3\relax}}
++
++\typ{EXPANDED TEST 4: macro param}
++% Constructed #1 is still #1
++\expandafter\def\expandafter\ddd\expandafter#\expanded{1{#\number--1}}
++\show\ddd
++
++\typ{EXPANDED TEST 5: torture}
++% Torture test from Bruno Le Floch testing various tricky interactions
++\expanded\relax\space\ifincsname \BOOM\fi{\ifincsname \BOOM\fi}
++\showtokens\expandafter{\expanded{#,\noexpand\aaa,\unexpanded{\aaa}}}
++\showtokens\expandafter{\expanded{#,\unexpanded{#}}}
++\showtokens\expandafter{\expanded\expandafter{\noexpand\aaa}}
++\showtokens\expandafter{\expanded\expandafter{\unexpanded{\aaa}}}
++\showtokens\expanded{{\expanded{\aaa\noexpand\aaa\noexpand\noexpand\noexpand\aaa}}}
++\toks0{\aaa}
++\showtokens\expanded{{\the\toks0}}
++\expanded\bgroup\show\egroup}
++\edef\foo{\expanded{##}}
++\show\foo
++
++\typ{END}
++\end
+diff -ruN r47457/texk/web2c/pdftexdir/tests/expanded.txt r49040/texk/web2c/pdftexdir/tests/expanded.txt
+--- r47457/texk/web2c/pdftexdir/tests/expanded.txt 1970-01-01 01:00:00.000000000 +0100
++++ r49040/texk/web2c/pdftexdir/tests/expanded.txt 2018-12-05 19:19:35.403778485 +0100
+@@ -0,0 +1,61 @@
++START
++EXPANDED TEST 1
++> \expanded=\expanded.
++l.13 \show\expanded
++
++
++EXPANDED TEST 2
++> \ccc=macro:
++->xx,x.
++l.20 \show\ccc
++
++
++EXPANDED TEST 3: the
++xx,123
++EXPANDED TEST 4: macro param
++> \ddd=macro:
++#1->#1.
++l.29 \show\ddd
++
++
++EXPANDED TEST 5: torture
++> ##,\aaa ,\aaa .
++l.34 ...panded{#,\noexpand\aaa,\unexpanded{\aaa}}}
++
++
++> ##,##.
++l.35 ...s\expandafter{\expanded{#,\unexpanded{#}}}
++
++
++> \aaa .
++l.36 ...fter{\expanded\expandafter{\noexpand\aaa}}
++
++
++> x.
++l.37 ...{\expanded\expandafter{\unexpanded{\aaa}}}
++
++
++> xx\aaa .
++<inserted text> {xx\aaa }
++
++l.38 ...pand\aaa\noexpand\noexpand\noexpand\aaa}}}
++
++
++> \aaa .
++<inserted text> {\aaa }
++
++l.40 \showtokens\expanded{{\the\toks0}}
++
++
++> \egroup=end-group character }.
++<inserted text> \show \egroup
++
++l.41 \expanded\bgroup\show\egroup}
++
++
++> \foo=macro:
++->##.
++l.43 \show\foo
++
++
++END
+diff -ruN r47457/texk/web2c/pdftexdir/ttf2afm.test r49040/texk/web2c/pdftexdir/ttf2afm.test
+--- r47457/texk/web2c/pdftexdir/ttf2afm.test 2018-12-05 19:19:35.277778494 +0100
++++ r49040/texk/web2c/pdftexdir/ttf2afm.test 2018-12-05 19:19:35.385778486 +0100
+@@ -3,11 +3,12 @@
+-# Copyright 2017 Karl Berry <tex-live@tug.org>#
++# Copyright 2017-2018 Karl Berry <tex-live@tug.org>#
+ # Copyright 2013 Peter Breitenlohner <tex-live@tug.org>
+ # You may freely use, modify and/or distribute this file.
+
+-TEXMFCNF=$srcdir/../kpathsea
+-TEXINPUTS=$srcdir/pdftexdir/tests:$srcdir/tests
+-TEXFONTS=$srcdir/pdftexdir/tests
+-export TEXMFCNF TEXINPUTS TEXFONTS
++LC_ALL=C; export LC_ALL; LANGUAGE=C; export LANGUAGE
++
++TEXMFCNF=$srcdir/../kpathsea; export TEXMFCNF
++TEXINPUTS=$srcdir/pdftexdir/tests:$srcdir/tests; export TEXINPUTS;
++TEXFONTS=$srcdir/pdftexdir/tests; export TEXFONTS
+
+ testsrc=$srcdir/pdftexdir/tests
+
+diff -ruN r47457/texk/web2c/pdftexdir/wprob.test r49040/texk/web2c/pdftexdir/wprob.test
+--- r47457/texk/web2c/pdftexdir/wprob.test 2018-12-05 19:19:35.384778486 +0100
++++ r49040/texk/web2c/pdftexdir/wprob.test 2018-12-05 19:19:35.410778484 +0100
+@@ -3,13 +3,17 @@
+-# Copyright 2017 Karl Berry <tex-live@tug.org>
++# Copyright 2017-2018 Karl Berry <tex-live@tug.org>
+ # Copyright 2011-2013 Peter Breitenlohner <tex-live@tug.org>
+ # You may freely use, modify and/or distribute this file.
+
+ rm -rf pwprob.*
+-cp $srcdir/tests/wprob.tex ./pwprob.tex
++cp "$srcdir/tests/wprob.tex" ./pwprob.tex || exit 1
+
+-TEXMFCNF=$srcdir/../kpathsea \
+- ./pdftex --ini --etex --file-line-error --interaction=nonstopmode pwprob.tex
++TEXMFCNF=$srcdir/../kpathsea; export TEXMFCNF
++
++# this command is expected to fail.
++./pdftex --ini --etex --file-line-error --interaction=nonstopmode pwprob.tex \
++&& exit 1
+
+ grep '^\./pwprob\.tex:12: Could not open file NoSuchFile\.eps\.$' \
+- pwprob.log || exit 1
++ pwprob.log || exit 1
+
++exit 0
+diff -ruN r47457/texk/web2c/pdftexdir/writefont.c r49040/texk/web2c/pdftexdir/writefont.c
+--- r47457/texk/web2c/pdftexdir/writefont.c 2018-12-05 19:19:35.370778487 +0100
++++ r49040/texk/web2c/pdftexdir/writefont.c 2018-12-05 19:19:35.400778485 +0100
+@@ -484,16 +484,26 @@
+ pdf_printf("/Flags %i\n", fd_flags);
+ write_fontmetrics(fd);
+ if (fd->ff_found) {
++#ifdef ENABLE_PDF_CHARSET /* just in case a builder wants it */
+ if (is_subsetted(fd->fm) && is_type1(fd->fm)) {
+- /* /CharSet is optional; names may appear in any order */
++ /* CharSet is optional, but if it appears, it must be
++ correct. Unfortunately, there is no practical way we can
++ guarantee correctness with precomposed accent characters
++ in our usual fonts (EC, TX, etc.):
++ https://mailman.ntg.nl/pipermail/ntg-pdftex/2018-June/004251.html
++ Therefore, we disable its output. The code is left in
++ just in case it turns out that something important was
++ relying on the (incorrect) CharSet. */
+ assert(fd->gl_tree != NULL);
+ avl_t_init(&t, fd->gl_tree);
++ /* Names may appear in any order. */
+ pdf_puts("/CharSet (");
+ for (glyph = (char *) avl_t_first(&t, fd->gl_tree); glyph != NULL;
+ glyph = (char *) avl_t_next(&t))
+ pdf_printf("/%s", glyph);
+ pdf_puts(")\n");
+ }
++#endif /* ENABLE_PDF_CHARSET */
+ if (is_type1(fd->fm))
+ pdf_printf("/FontFile %i 0 R\n", (int) fd->ff_objnum);
+ else if (is_truetype(fd->fm))
+diff -ruN r47457/texk/web2c/pdftexdir/writet1.c r49040/texk/web2c/pdftexdir/writet1.c
+--- r47457/texk/web2c/pdftexdir/writet1.c 2018-12-05 19:19:35.372778487 +0100
++++ r49040/texk/web2c/pdftexdir/writet1.c 2018-12-05 19:19:35.401778485 +0100
+@@ -1,5 +1,5 @@
+ /*
+-Copyright 1996-2014 Han The Thanh <thanh@pdftex.org>
++Copyright 1996-2018 Han The Thanh <thanh@pdftex.org>
+
+ 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
+@@ -1598,7 +1598,11 @@
+ *(strend(t1_buf_array) - 1) = ' ';
+
+ t1_getline();
++ alloc_array(t1_buf, strlen(t1_line_array)
++ + (t1_buf_array ? strlen(t1_buf_array) + 1 : 0),
++ T1_BUF_SIZE);
+ strcat(t1_buf_array, t1_line_array);
++ alloc_array(t1_line, strlen(t1_buf_array) + 1, T1_BUF_SIZE);
+ strcpy(t1_line_array, t1_buf_array);
+ t1_line_ptr = eol(t1_line_array);
+ }