diff options
author | Thomas Orgis | 2018-12-05 20:56:25 +0100 |
---|---|---|
committer | Thomas Orgis | 2018-12-05 21:29:30 +0100 |
commit | d759aa768517a934c81d9b4f7a27a2a8126f92da (patch) | |
tree | bfca8b3fc9f7a4b2fd17f16f4a8cb0b04067c24e /latex | |
parent | 9d6d134df923742978089313f9057b54f60832dc (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-x | latex/texlive/DEPENDS | 1 | ||||
-rw-r--r-- | latex/texlive/HISTORY | 8 | ||||
-rwxr-xr-x | latex/texlive/PRE_BUILD | 26 | ||||
-rw-r--r-- | latex/texlive/patches/texlive-20180414-source-upstream_fixes-1.patch | 119 | ||||
-rw-r--r-- | latex/texlive/patches/texlive-20180414-source-upstream_fixes-2.patch | 6350 |
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); + } |