From c44cc0e342ab0ab537882d1f6b312a770c519f18 Mon Sep 17 00:00:00 2001 From: Akira Kakuto Date: Sat, 25 Jul 2020 22:06:35 +0000 Subject: Place static variables into a single struct. Various minor improvements (S. Hirata). git-svn-id: svn://tug.org/texlive/trunk@55945 c570f23f-e606-0410-a88d-b1316a301751 --- Build/source/texk/dvipdfm-x/ChangeLog | 16 + Build/source/texk/dvipdfm-x/cmap_write.c | 18 +- Build/source/texk/dvipdfm-x/configure | 22 +- Build/source/texk/dvipdfm-x/configure.ac | 2 +- Build/source/texk/dvipdfm-x/dpxconf.c | 4 +- Build/source/texk/dvipdfm-x/dpxconf.h | 3 +- Build/source/texk/dvipdfm-x/dpxutil.c | 88 +- Build/source/texk/dvipdfm-x/dpxutil.h | 5 +- Build/source/texk/dvipdfm-x/dvi.c | 90 +- Build/source/texk/dvipdfm-x/dvipdfmx.c | 246 ++--- Build/source/texk/dvipdfm-x/pdfdev.c | 1484 ++++++++++++++++-------------- Build/source/texk/dvipdfm-x/pdfdev.h | 67 +- Build/source/texk/dvipdfm-x/pdfdoc.c | 80 +- Build/source/texk/dvipdfm-x/pdfdoc.h | 6 +- Build/source/texk/dvipdfm-x/pdfencrypt.c | 385 ++++---- Build/source/texk/dvipdfm-x/pdfencrypt.h | 21 +- Build/source/texk/dvipdfm-x/pdfobj.c | 1216 ++++++++++++++---------- Build/source/texk/dvipdfm-x/pdfobj.h | 33 +- Build/source/texk/dvipdfm-x/pdfparse.c | 146 ++- Build/source/texk/dvipdfm-x/pdfparse.h | 13 +- Build/source/texk/dvipdfm-x/pdfximage.c | 1 - Build/source/texk/dvipdfm-x/spc_pdfm.c | 98 +- Build/source/texk/dvipdfm-x/xbb.c | 2 +- 23 files changed, 2170 insertions(+), 1876 deletions(-) (limited to 'Build/source/texk/dvipdfm-x') diff --git a/Build/source/texk/dvipdfm-x/ChangeLog b/Build/source/texk/dvipdfm-x/ChangeLog index d6d4bec2d8b..9a3ee71ebcc 100644 --- a/Build/source/texk/dvipdfm-x/ChangeLog +++ b/Build/source/texk/dvipdfm-x/ChangeLog @@ -1,3 +1,19 @@ +2020-07-26 Shunsaku Hirata + + * cmap_write.c: Change ariable names. + * dvipdfmx.c: Remove unused variables. Modify init sequence. + Page size specified as a command line option overwrites + settings specified by pagesize specials. + * pdfdev.[ch], pdfdoc.[ch], pdfencrypt.[ch], pdfobj.[ch]: + File static variables are now placed in a single struct. + * pdfparse.[ch], spc_pdfm.c: PDF parse object function is + called with a callback function to be called when an object of + unknown type is encountered. + * pdfximage.c: Do not include an unnecessary file. + * dpxconf.[ch], xbb.c: Add is_xbb in dpx_conf. + * dpxutil.[ch], dvi.c, dvipdfmx.c: Add dpx_util_read_length(). + * configure.ac: Version 20200726. + 2020-07-24 Shunsaku Hirata * cidtype0.c: Fix a bug introduced in rev.37144 that generated diff --git a/Build/source/texk/dvipdfm-x/cmap_write.c b/Build/source/texk/dvipdfm-x/cmap_write.c index 314a9e9526a..3af5f9acbe7 100644 --- a/Build/source/texk/dvipdfm-x/cmap_write.c +++ b/Build/source/texk/dvipdfm-x/cmap_write.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2020 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -240,14 +240,14 @@ write_map (mapDef *mtab, int count, /* duplicated from pdfobj.c */ static void -write_string (char **outptr, char *endptr, const char *strptr) +write_string (char **outptr, char *endptr, const char *string_data) { - const char *s; char *p; + const char *s; int i, length; - s = strptr; - length = strptr ? strlen(strptr) : 0; + s = string_data; + length = string_data ? strlen(string_data) : 0; p = *outptr; *p++ = '('; @@ -275,14 +275,14 @@ write_string (char **outptr, char *endptr, const char *strptr) } static void -write_name (char **outptr, char *endptr, const char *name) +write_name (char **outptr, char *endptr, const char *name_data) { - const char *s; char *p; + const char *s; int i, length; - s = name; - length = name ? strlen(name) : 0; + s = name_data; + length = name_data ? strlen(name_data) : 0; p = *outptr; #ifndef is_delim /* Avoid '{' and '}' for PostScript compatibility? */ diff --git a/Build/source/texk/dvipdfm-x/configure b/Build/source/texk/dvipdfm-x/configure index 90c88272bd3..1ff118c0dd1 100755 --- a/Build/source/texk/dvipdfm-x/configure +++ b/Build/source/texk/dvipdfm-x/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for dvipdfm-x (TeX Live) 20200721. +# Generated by GNU Autoconf 2.69 for dvipdfm-x (TeX Live) 20200726. # # Report bugs to . # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='dvipdfm-x (TeX Live)' PACKAGE_TARNAME='dvipdfm-x--tex-live-' -PACKAGE_VERSION='20200721' -PACKAGE_STRING='dvipdfm-x (TeX Live) 20200721' +PACKAGE_VERSION='20200726' +PACKAGE_STRING='dvipdfm-x (TeX Live) 20200726' PACKAGE_BUGREPORT='dvipdfmx@tug.org' PACKAGE_URL='' @@ -1350,7 +1350,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures dvipdfm-x (TeX Live) 20200721 to adapt to many kinds of systems. +\`configure' configures dvipdfm-x (TeX Live) 20200726 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1421,7 +1421,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of dvipdfm-x (TeX Live) 20200721:";; + short | recursive ) echo "Configuration of dvipdfm-x (TeX Live) 20200726:";; esac cat <<\_ACEOF @@ -1551,7 +1551,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -dvipdfm-x (TeX Live) configure 20200721 +dvipdfm-x (TeX Live) configure 20200726 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2390,7 +2390,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by dvipdfm-x (TeX Live) $as_me 20200721, which was +It was created by dvipdfm-x (TeX Live) $as_me 20200726, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -8077,7 +8077,7 @@ fi # Define the identity of the package. PACKAGE='dvipdfm-x--tex-live-' - VERSION='20200721' + VERSION='20200726' cat >>confdefs.h <<_ACEOF @@ -14746,7 +14746,7 @@ Usage: $0 [OPTIONS] Report bugs to ." lt_cl_version="\ -dvipdfm-x (TeX Live) config.lt 20200721 +dvipdfm-x (TeX Live) config.lt 20200726 configured by $0, generated by GNU Autoconf 2.69. Copyright (C) 2011 Free Software Foundation, Inc. @@ -16636,7 +16636,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by dvipdfm-x (TeX Live) $as_me 20200721, which was +This file was extended by dvipdfm-x (TeX Live) $as_me 20200726, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -16706,7 +16706,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -dvipdfm-x (TeX Live) config.status 20200721 +dvipdfm-x (TeX Live) config.status 20200726 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/Build/source/texk/dvipdfm-x/configure.ac b/Build/source/texk/dvipdfm-x/configure.ac index eea48de57cc..aa3acacecf5 100644 --- a/Build/source/texk/dvipdfm-x/configure.ac +++ b/Build/source/texk/dvipdfm-x/configure.ac @@ -8,7 +8,7 @@ dnl This file is free software; the copyright holder dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl -AC_INIT([dvipdfm-x (TeX Live)], [20200721], [dvipdfmx@tug.org]) +AC_INIT([dvipdfm-x (TeX Live)], [20200726], [dvipdfmx@tug.org]) AC_PREREQ([2.65]) AC_CONFIG_SRCDIR([agl.c]) AC_CONFIG_AUX_DIR([../../build-aux]) diff --git a/Build/source/texk/dvipdfm-x/dpxconf.c b/Build/source/texk/dvipdfm-x/dpxconf.c index d8279489b2b..ab7f6693ac8 100644 --- a/Build/source/texk/dvipdfm-x/dpxconf.c +++ b/Build/source/texk/dvipdfm-x/dpxconf.c @@ -1,6 +1,6 @@ /* This is DVIPDFMx, an eXtended version of DVIPDFM by Mark A. Wicks. - Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2020 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -30,7 +30,7 @@ #include "dpxconf.h" -struct _dpx_conf dpx_conf = {0, dpx_mode_normal_mode, 0, {0}}; +struct _dpx_conf dpx_conf = {0, 0, dpx_mode_normal_mode, 0, {0}}; #ifndef HAVE_LIBPAPER const struct paper paperspecs[] = { diff --git a/Build/source/texk/dvipdfm-x/dpxconf.h b/Build/source/texk/dvipdfm-x/dpxconf.h index 8a6b775692d..e0785a1e42d 100644 --- a/Build/source/texk/dvipdfm-x/dpxconf.h +++ b/Build/source/texk/dvipdfm-x/dpxconf.h @@ -1,6 +1,6 @@ /* This is DVIPDFMx, an eXtended version of DVIPDFM by Mark A. Wicks. - Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2020 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -31,6 +31,7 @@ enum dpx_mode { }; extern struct _dpx_conf { + int is_xbb; int verbose_level; enum dpx_mode compat_mode; int ignore_font_license; diff --git a/Build/source/texk/dvipdfm-x/dpxutil.c b/Build/source/texk/dvipdfm-x/dpxutil.c index bc21c86aeec..10a5387a4e8 100644 --- a/Build/source/texk/dvipdfm-x/dpxutil.c +++ b/Build/source/texk/dvipdfm-x/dpxutil.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2020 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -69,6 +69,92 @@ max4 (double x1, double x2, double x3, double x4) return v; } +/* Duplicate from pdfparse.c */ +static void +skip_white (const char **pp, const char *endptr) +{ + while (*pp < endptr && + (**pp == ' ' || **pp == '\t' || **pp == '\f' || + **pp == '\r' || **pp == '\n' || **pp == '\0')) { + (*pp)++; + } +} + +/* This need to allow 'true' prefix for unit and length value must be divided + * by current magnification. + */ +int +dpx_util_read_length (double *vp, double mag, const char **pp, const char *endptr) +{ + char *q; + const char *p = *pp; + double v, u = 1.0; + const char *_ukeys[] = { +#define K_UNIT__PT 0 +#define K_UNIT__IN 1 +#define K_UNIT__CM 2 +#define K_UNIT__MM 3 +#define K_UNIT__BP 4 +#define K_UNIT__PC 5 +#define K_UNIT__DD 6 +#define K_UNIT__CC 7 +#define K_UNIT__SP 8 + "pt", "in", "cm", "mm", "bp", "pc", "dd", "cc", "sp", + NULL + }; + int k, error = 0; + + q = parse_float_decimal(&p, endptr); + if (!q) { + *vp = 0.0; *pp = p; + return -1; + } + + v = atof(q); + RELEASE(q); + + skip_white(&p, endptr); + q = parse_c_ident(&p, endptr); + if (q) { + char *qq = q; /* remember this for RELEASE, because q may be advanced */ + if (strlen(q) >= strlen("true") && + !memcmp(q, "true", strlen("true"))) { + u /= mag != 0.0 ? mag : 1.0; /* inverse magnify */ + q += strlen("true"); + } + if (strlen(q) == 0) { /* "true" was a separate word from the units */ + RELEASE(qq); + skip_white(&p, endptr); + qq = q = parse_c_ident(&p, endptr); + } + if (q) { + for (k = 0; _ukeys[k] && strcmp(_ukeys[k], q); k++); + switch (k) { + case K_UNIT__PT: u *= 72.0 / 72.27; break; + case K_UNIT__IN: u *= 72.0; break; + case K_UNIT__CM: u *= 72.0 / 2.54 ; break; + case K_UNIT__MM: u *= 72.0 / 25.4 ; break; + case K_UNIT__BP: u *= 1.0 ; break; + case K_UNIT__PC: u *= 12.0 * 72.0 / 72.27 ; break; + case K_UNIT__DD: u *= 1238.0 / 1157.0 * 72.0 / 72.27 ; break; + case K_UNIT__CC: u *= 12.0 * 1238.0 / 1157.0 * 72.0 / 72.27 ; break; + case K_UNIT__SP: u *= 72.0 / (72.27 * 65536) ; break; + default: + WARN("Unknown unit of measure: %s", q); + error = -1; + break; + } + RELEASE(qq); + } + else { + WARN("Missing unit of measure after \"true\""); + error = -1; + } + } + + *vp = v * u; *pp = p; + return error; +} #if defined(_MSC_VER) #define strtoll _strtoi64 diff --git a/Build/source/texk/dvipdfm-x/dpxutil.h b/Build/source/texk/dvipdfm-x/dpxutil.h index 8268659917f..11aaa1f18d8 100644 --- a/Build/source/texk/dvipdfm-x/dpxutil.h +++ b/Build/source/texk/dvipdfm-x/dpxutil.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2020 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -35,6 +35,9 @@ extern double min4(double v1, double v2, double v3, double v4); extern double max4(double v1, double v2, double v3, double v4); +extern int dpx_util_read_length (double *vp, double mag, + const char **curptr, const char *endptr); + #define INVALID_EPOCH_VALUE ((time_t)-1) extern time_t dpx_util_get_unique_time_if_given (void); extern int dpx_util_format_asn_date (char *date_string, int need_timezone); diff --git a/Build/source/texk/dvipdfm-x/dvi.c b/Build/source/texk/dvipdfm-x/dvi.c index 5317bfb8182..a4afab61bdb 100644 --- a/Build/source/texk/dvipdfm-x/dvi.c +++ b/Build/source/texk/dvipdfm-x/dvi.c @@ -2249,83 +2249,7 @@ dvi_vf_finish (void) /* Scan various specials */ #include "dpxutil.h" - -/* This need to allow 'true' prefix for unit and - * length value must be divided by current magnification. - */ -static int -read_length (double *vp, double mag, const char **pp, const char *endptr) -{ - char *q; - const char *p = *pp; - double v, u = 1.0; - const char *_ukeys[] = { -#define K_UNIT__PT 0 -#define K_UNIT__IN 1 -#define K_UNIT__CM 2 -#define K_UNIT__MM 3 -#define K_UNIT__BP 4 -#define K_UNIT__PC 5 -#define K_UNIT__DD 6 -#define K_UNIT__CC 7 -#define K_UNIT__SP 8 - "pt", "in", "cm", "mm", "bp", "pc", "dd", "cc", "sp", - NULL - }; - int k, error = 0; - - q = parse_float_decimal(&p, endptr); - if (!q) { - *vp = 0.0; *pp = p; - return -1; - } - - v = atof(q); - RELEASE(q); - - skip_white(&p, endptr); - q = parse_c_ident(&p, endptr); - if (q) { - char *qq = q; /* remember this for RELEASE, because q may be advanced */ - if (strlen(q) >= strlen("true") && - !memcmp(q, "true", strlen("true"))) { - u /= mag != 0.0 ? mag : 1.0; /* inverse magnify */ - q += strlen("true"); - } - if (strlen(q) == 0) { /* "true" was a separate word from the units */ - RELEASE(qq); - skip_white(&p, endptr); - qq = q = parse_c_ident(&p, endptr); - } - if (q) { - for (k = 0; _ukeys[k] && strcmp(_ukeys[k], q); k++); - switch (k) { - case K_UNIT__PT: u *= 72.0 / 72.27; break; - case K_UNIT__IN: u *= 72.0; break; - case K_UNIT__CM: u *= 72.0 / 2.54 ; break; - case K_UNIT__MM: u *= 72.0 / 25.4 ; break; - case K_UNIT__BP: u *= 1.0 ; break; - case K_UNIT__PC: u *= 12.0 * 72.0 / 72.27 ; break; - case K_UNIT__DD: u *= 1238.0 / 1157.0 * 72.0 / 72.27 ; break; - case K_UNIT__CC: u *= 12.0 * 1238.0 / 1157.0 * 72.0 / 72.27 ; break; - case K_UNIT__SP: u *= 72.0 / (72.27 * 65536) ; break; - default: - WARN("Unknown unit of measure: %s", q); - error = -1; - break; - } - RELEASE(qq); - } - else { - WARN("Missing unit of measure after \"true\""); - error = -1; - } - } - - *vp = v * u; *pp = p; - return error; -} - +/* For MAX_PWD_LEN */ #include "pdfencrypt.h" static int @@ -2486,19 +2410,19 @@ scan_special (double *wd, double *ht, double *xo, double *yo, int *lm, else { skip_white(&p, endptr); if (!strcmp(kp, "width")) { - error = read_length(&tmp, dvi_tell_mag(), &p, endptr); + error = dpx_util_read_length(&tmp, dvi_tell_mag(), &p, endptr); if (!error) *wd = tmp * dvi_tell_mag(); } else if (!strcmp(kp, "height")) { - error = read_length(&tmp, dvi_tell_mag(), &p, endptr); + error = dpx_util_read_length(&tmp, dvi_tell_mag(), &p, endptr); if (!error) *ht = tmp * dvi_tell_mag(); } else if (!strcmp(kp, "xoffset")) { - error = read_length(&tmp, dvi_tell_mag(), &p, endptr); + error = dpx_util_read_length(&tmp, dvi_tell_mag(), &p, endptr); if (!error) *xo = tmp * dvi_tell_mag(); } else if (!strcmp(kp, "yoffset")) { - error = read_length(&tmp, dvi_tell_mag(), &p, endptr); + error = dpx_util_read_length(&tmp, dvi_tell_mag(), &p, endptr); if (!error) *yo = tmp * dvi_tell_mag(); } else if (!strcmp(kp, "default")) { @@ -2519,7 +2443,7 @@ scan_special (double *wd, double *ht, double *xo, double *yo, int *lm, qchr = *p; p++; skip_white(&p, endptr); } - error = read_length(&tmp, 1.0, &p, endptr); + error = dpx_util_read_length(&tmp, 1.0, &p, endptr); if (!error) { double tmp1; @@ -2527,7 +2451,7 @@ scan_special (double *wd, double *ht, double *xo, double *yo, int *lm, if (p < endptr && *p == ',') { p++; skip_white(&p, endptr); } - error = read_length(&tmp1, 1.0, &p, endptr); + error = dpx_util_read_length(&tmp1, 1.0, &p, endptr); if (!error) { *wd = tmp; *ht = tmp1; diff --git a/Build/source/texk/dvipdfm-x/dvipdfmx.c b/Build/source/texk/dvipdfm-x/dvipdfmx.c index f67c7deb7dd..32c9acf8b14 100644 --- a/Build/source/texk/dvipdfm-x/dvipdfmx.c +++ b/Build/source/texk/dvipdfm-x/dvipdfmx.c @@ -2,7 +2,7 @@ DVIPDFMx, an eXtended version of DVIPDFM by Mark A. Wicks. - Copyright (C) 2002-2020 by Jin-Hwan Cho, Matthias Franz, Shunsaku Hirata, + Copyright (C) 2002-2020 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, the DVIPDFMx project team. Copyright (c) 2006 SIL. (xdvipdfmx extensions for XeTeX support) @@ -70,8 +70,11 @@ const char *my_name = "ApTeX"; const char *my_name; #endif /* LIBDPX */ -static int verbose = 0; +/* Verbosity level */ +static int verbose = 0; +static int really_quiet = 0; +/* Compatibility option flags */ static int opt_flags = 0; #define OPT_TPIC_TRANSPARENT_FILL (1 << 1) #define OPT_CIDFONT_FIXEDPITCH (1 << 2) @@ -80,54 +83,54 @@ static int opt_flags = 0; #define OPT_PDFOBJ_NO_PREDICTOR (1 << 5) #define OPT_PDFOBJ_NO_OBJSTM (1 << 6) +/* Basic PDF output settings */ static int pdf_version_major = 1; static int pdf_version_minor = 5; static int compression_level = 9; -static char ignore_colors = 0; -static double annot_grow = 0.0; -static int bookmark_open = 0; -static double mag = 1.0; -static int font_dpi = 600; -static int enable_thumbnail = 0; -static int really_quiet = 0; -/* - * Precision is essentially limited to 0.01pt. - * See, dev_set_string() in pdfdev.c. - */ +/* PDF document navigation feature settings */ +static double annot_grow = 0.0; +static int bookmark_open = 0; +static double mag = 1.0; +static int enable_thumbnail = 0; + +static int font_dpi = 600; + +/* PDF output device settings */ static int pdfdecimaldigits = 3; +static char ignore_colors = 0; -/* Image cache life in hours */ -/* 0 means erase all old images and leave new images */ -/* -1 means erase all old images and also erase new images */ -/* -2 means ignore image cache (default) */ +/* Image cache life in hours + * 0 means erase all old images and leave new images + * -1 means erase all old images and also erase new images + * -2 means ignore image cache (default) + */ static int image_cache_life = -2; /* Image format conversion filter template */ static char *filter_template = NULL; /* Encryption */ -static int do_encryption = 0; -static int key_bits = 40; -static int32_t permission = 0x003C; +static int do_encryption = 0; +static int key_bits = 40; +static int32_t permission = 0x003C; /* Page device */ -double paper_width = 595.0; -double paper_height = 842.0; -static double x_offset = 72.0; -static double y_offset = 72.0; -int landscape_mode = 0; -static int translate_origin = 0; +double paper_width = 595.0; +double paper_height = 842.0; +static double x_offset = 72.0; +static double y_offset = 72.0; +int landscape_mode = 0; +static int translate_origin = 0; -/* Command line option takes precedence */ -static int has_paper_option = 0; -static int has_encrypt_option = 0; +static int has_paper_option = 0; -char *dvi_filename = NULL, *pdf_filename = NULL; +/* Input and output filenames */ +static char *dvi_filename = NULL, *pdf_filename = NULL; static void read_config_file (const char *config); static void -set_default_pdf_filename(void) +set_default_pdf_filename (void) { const char *dvi_base; const char *suffix; @@ -251,79 +254,6 @@ usage (void) exit(1); } - -static int -read_length (double *vp, const char **pp, const char *endptr) -{ - char *q; - const char *p = *pp; - double v, u = 1.0; - const char *_ukeys[] = { -#define K_UNIT__PT 0 -#define K_UNIT__IN 1 -#define K_UNIT__CM 2 -#define K_UNIT__MM 3 -#define K_UNIT__BP 4 -#define K_UNIT__PC 5 -#define K_UNIT__DD 6 -#define K_UNIT__CC 7 -#define K_UNIT__SP 8 - "pt", "in", "cm", "mm", "bp", "pc", "dd", "cc", "sp", - NULL - }; - int k, error = 0; - - q = parse_float_decimal(&p, endptr); - if (!q) { - *vp = 0.0; *pp = p; - return -1; - } - - v = atof(q); - RELEASE(q); - - skip_white(&p, endptr); - q = parse_c_ident(&p, endptr); - if (q) { - char *qq = q; - if (strlen(q) >= strlen("true") && - !memcmp(q, "true", strlen("true"))) { - q += strlen("true"); /* just skip "true" */ - } - if (strlen(q) == 0) { - RELEASE(qq); - skip_white(&p, endptr); - qq = q = parse_c_ident(&p, endptr); - } - if (q) { - for (k = 0; _ukeys[k] && strcmp(_ukeys[k], q); k++); - switch (k) { - case K_UNIT__PT: u *= 72.0 / 72.27; break; - case K_UNIT__IN: u *= 72.0; break; - case K_UNIT__CM: u *= 72.0 / 2.54 ; break; - case K_UNIT__MM: u *= 72.0 / 25.4 ; break; - case K_UNIT__BP: u *= 1.0 ; break; - case K_UNIT__PC: u *= 12.0 * 72.0 / 72.27 ; break; - case K_UNIT__DD: u *= 1238.0 / 1157.0 * 72.0 / 72.27 ; break; - case K_UNIT__CC: u *= 12.0 * 1238.0 / 1157.0 * 72.0 / 72.27 ; break; - case K_UNIT__SP: u *= 72.0 / (72.27 * 65536) ; break; - default: - WARN("Unknown unit of measure: %s", q); - error = -1; - break; - } - RELEASE(qq); - } - else { - WARN("Missing unit of measure after \"true\""); - error = -1; - } - } - - *vp = v * u; *pp = p; - return error; -} - static void select_paper (const char *paperspec) { @@ -340,9 +270,9 @@ select_paper (const char *paperspec) endptr = p + strlen(p); if (!comma) ERROR("Unrecognized paper format: %s", paperspec); - error = read_length(&paper_width, &p, comma); + error = dpx_util_read_length(&paper_width, 1.0, &p, comma); p = comma + 1; - error = read_length(&paper_height, &p, endptr); + error = dpx_util_read_length(&paper_height, 1.0, &p, endptr); } if (error || paper_width <= 0.0 || paper_height <= 0.0) ERROR("Invalid paper size: %s (%.2fx%.2f)", paperspec, paper_width, paper_height); @@ -618,17 +548,17 @@ do_args_second_pass (int argc, char *argv[], const char *source, int unsafe) case 'g': nnextptr = nextptr = optarg; - read_length(&annot_grow, &nnextptr, nextptr + strlen(nextptr)); + dpx_util_read_length(&annot_grow, 1.0, &nnextptr, nextptr + strlen(nextptr)); break; case 'x': nnextptr = nextptr = optarg; - read_length(&x_offset, &nnextptr, nextptr + strlen(nextptr)); + dpx_util_read_length(&x_offset, 1.0, &nnextptr, nextptr + strlen(nextptr)); break; case 'y': nnextptr = nextptr = optarg; - read_length(&y_offset, &nnextptr, nextptr + strlen(nextptr)); + dpx_util_read_length(&y_offset, 1.0, &nnextptr, nextptr + strlen(nextptr)); break; case 'o': @@ -699,7 +629,6 @@ do_args_second_pass (int argc, char *argv[], const char *source, int unsafe) case 'S': do_encryption = 1; - has_encrypt_option = 1; break; case 'K': @@ -935,20 +864,34 @@ do_dvi_pages (void) int lm; MESG("[%d", page_no+1); - /* Users want to change page size even after page is started! */ + /* FIXME: incompatibility here.... In older versions of dvipdfmx page sizes + * are inherited from the previous page but in the current implementation + * pagesize special only takes effect to the current page. + * The following line resets page sizes to the paper size... + */ page_width = paper_width; page_height = paper_height; w = page_width; h = page_height; lm = landscape_mode; xo = x_offset; yo = y_offset; dvi_scan_specials(page_no, &w, &h, &xo, &yo, &lm, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - if (lm != landscape_mode) { /* already swapped for the first page */ + /* No need for encryption options */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + /* No trailer IDs */ + NULL, NULL, NULL); + if (lm != landscape_mode) { + /* The first page was already scanned once and SWAP() was applied there. + * Do not apply SWAP() twice! + * FIXME: SWAP() not applied to paper_width and paper_height. Why? + */ SWAP(w, h); landscape_mode = lm; } - if (page_width != w || page_height != h) { - page_width = w; - page_height = h; + /* Specified as a command line option */ + if (!has_paper_option) { + if (page_width != w || page_height != h) { + page_width = w; + page_height = h; + } } if (x_offset != xo || y_offset != yo) { x_offset = xo; @@ -1095,27 +1038,26 @@ main (int argc, char *argv[]) STREQ (argv[1], "--ebb"))) { argc--; base = argv++[1]+2; - } else + } else { base = kpse_program_basename (argv[0]); - + } + if (FILESTRCASEEQ (base, "extractbb") || FILESTRCASEEQ (base, "xbb")) { my_name = "extractbb"; return extractbb (argc, argv); - } - if (FILESTRCASEEQ (base, "ebb")) { + } else if (FILESTRCASEEQ (base, "ebb")) { my_name = "ebb"; dpx_conf.compat_mode = dpx_mode_compat_mode; return extractbb (argc, argv); - } - if (FILESTRCASEEQ (base, "dvipdfm")) + } else if (FILESTRCASEEQ (base, "dvipdfm")) { dpx_conf.compat_mode = dpx_mode_compat_mode; - if (FILESTRCASEEQ (base, "dvipdfmx")) + } else if (FILESTRCASEEQ (base, "dvipdfmx")) { my_name = "dvipdfmx"; - else + } else { my_name = "xdvipdfmx"; - - opterr = 0; + } + opterr = 0; /* Special-case single option --mvorigin, --help, --showpaper, or --version, * to avoid possible diagnostics about config files, etc. * Also handle -q and -v that cannot be set in config file. @@ -1130,6 +1072,12 @@ main (int argc, char *argv[]) read_config_file(DPX_CONFIG_FILE); + /* Current implementation seems to be assuming that paper size read from config + * is for "default" and explicitly specified one via command-line option must be + * used for all pages regardless of papersize specials. + */ + has_paper_option = 0; + #ifndef MIKTEX kpse_init_prog("", font_dpi, NULL, NULL); kpse_set_program_enabled(kpse_pk_format, true, kpse_src_texmf_cnf); @@ -1157,7 +1105,6 @@ main (int argc, char *argv[]) y_offset = 0.0; dvi2pts = 0.01; /* dvi2pts controls accuracy. */ } else { - /* Dependency between DVI and PDF side is rather complicated... */ dvi2pts = dvi_init(dvi_filename, mag); if (dvi2pts == 0.0) ERROR("dvi_init() failed!"); @@ -1180,9 +1127,24 @@ main (int argc, char *argv[]) } } -/* moved to here because image caching was not effective */ + /* moved to here because image caching was not effective */ dpx_delete_old_cache(image_cache_life); + /* Setup Options */ + settings.ver_major = pdf_version_major; + settings.ver_minor = pdf_version_minor; + + /* PDF trailer ID. */ + if (!has_id) { +#define PRODUCER \ +"%s-%s, Copyright 2002-2020 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata" + char producer[256]; + + sprintf(producer, PRODUCER, my_name, VERSION); + compute_id_string(id1, producer, dvi_filename, pdf_filename); + memcpy(id2, id1, 16); + } + /* Encryption and Other Settings */ { memset(&settings.encrypt, 0, sizeof(struct pdf_enc_setting)); @@ -1195,6 +1157,8 @@ main (int argc, char *argv[]) settings.encrypt.oplain = oplain; } + /* PDF object settings */ + settings.object.compression_level = compression_level; if (opt_flags & OPT_PDFOBJ_NO_OBJSTM) { settings.object.enable_objstm = 0; } else { @@ -1205,7 +1169,9 @@ main (int argc, char *argv[]) } else { settings.object.enable_predictor = 1; } - /* Set default paper size here so that all page's can inherite it. + + /* PDF document settings + * Set default paper size here so that all page's can inherite it. * annot_grow: Margin of annotation. * bookmark_open: Miximal depth of open bookmarks. */ @@ -1217,32 +1183,14 @@ main (int argc, char *argv[]) settings.annot_grow_amount = annot_grow; settings.outline_open_depth = bookmark_open; settings.check_gotos = !(opt_flags & OPT_PDFDOC_NO_DEST_REMOVE); + settings.enable_manual_thumb = enable_thumbnail; + /* PDF page output settings */ settings.device.dvi2pts = dvi2pts; settings.device.precision = pdfdecimaldigits; settings.device.ignore_colors = ignore_colors; set_distiller_template(filter_template); - /* This must come before pdf_open_document where initialization - * of pdf_enc takes place. - */ - { - int version = pdf_version_major * 10 + pdf_version_minor; - pdf_set_version(version); - } - pdf_set_compression(compression_level); - if (enable_thumbnail) - pdf_doc_enable_manual_thumbnails(); - - if (!has_id) { -#define PRODUCER \ -"%s-%s, Copyright 2002-2015 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata" - char producer[256]; - - sprintf(producer, PRODUCER, my_name, VERSION); - compute_id_string(id1, producer, dvi_filename, pdf_filename); - memcpy(id2, id1, 16); - } /* Initialize PDF document creation routine. */ pdf_open_document(pdf_filename, creator, id1, id2, settings); diff --git a/Build/source/texk/dvipdfm-x/pdfdev.c b/Build/source/texk/dvipdfm-x/pdfdev.c index a8e19e5282e..27d7192f20f 100644 --- a/Build/source/texk/dvipdfm-x/pdfdev.c +++ b/Build/source/texk/dvipdfm-x/pdfdev.c @@ -53,33 +53,245 @@ #include "pdfdev.h" -/* Not working yet... */ -double -pdf_dev_scale (void) +struct dev_param { - return 1.0; -} + /* Text composition (direction) mode is ignored (always same + * as font's writing mode) if autorotate is unset (value zero). + */ + int autorotate; + + /* + * Ignore color migrated to here. This is device's capacity. + * colormode 0 for ignore colors + */ + int colormode; + +}; + +/* + * Text handling routines. + */ + +/* Motion state: + * GRAPHICS_MODE Initial state (not within BT/ET block nor in string) + * TEXT_MODE Text section is started via BT operator but not + * in string. + * STRING_MODE In string. A string or array of strings are currently + * in process. May started '[', '<' or '('. + */ +#define GRAPHICS_MODE 1 +#define TEXT_MODE 2 +#define STRING_MODE 3 + +/* + * In PDF, vertical text positioning is always applied when current font + * is vertical font. While ASCII pTeX manages current writing direction + * and font's WMode separately. + * + * 000/101 WMODE_HH/VV h(v) font, h(v) direction. + * 001 WMODE_HV -90 deg. rotated + * 100 WMODE_VH +90 deg. rotated + * 011 WMODE_HD +90 deg. rotated + * 111 WMODE_VD 180 deg. rotated + + * In MetaPost PostScript file processing (mp_mode = 1), only HH/VV mode + * is applied. + */ +#define TEXT_WMODE_HH 0 +#define TEXT_WMODE_HV 1 +#define TEXT_WMODE_VH 4 +#define TEXT_WMODE_VV 5 +#define TEXT_WMODE_HD 3 +#define TEXT_WMODE_VD 7 + +#define ANGLE_CHANGES(m1,m2) ((abs((m1)-(m2)) % 5) == 0 ? 0 : 1) +#define ROTATE_TEXT(m) ((m) != TEXT_WMODE_HH && (m) != TEXT_WMODE_VV) + +struct text_state { + + /* Current font. + * This is index within dev_fonts. + */ + int font_id; + + /* Dvipdfmx does compression of text by doing text positioning + * in relative motion and uses string array [(foo) -250 (bar)] + * with kerning (negative kern is used for white space as suited + * for TeX). This is offset within current string. + */ + spt_t offset; + + /* This is reference point of strings. + * It may include error correction induced by rounding. + */ + spt_t ref_x; + spt_t ref_y; + + /* Using text raise and leading is highly recommended for + * text extraction to work properly. But not implemented yet. + * We can't do consice output for \TeX without this. + */ + spt_t raise; /* unused */ + spt_t leading; /* unused */ + + /* This is not always text matrix but rather font matrix. + * We do not use horizontal scaling in PDF text state parameter + * since they always apply scaling in fixed direction regardless + * of writing mode. + */ + struct { + double slant; + double extend; + int rotate; /* TEXT_WMODE_XX */ + } matrix; + + /* Fake bold parameter: + * If bold_param is positive, use text rendering mode + * fill-then-stroke with stroking line width specified + * by bold_param. + */ + double bold_param; + + /* Text composition (direction) mode. */ + int dir_mode; + + /* internal */ + + /* Flag indicating text matrix to be forcibly reset. + * Enabled if synthetic font features (slant, extend, etc) + * are used for current font or when text rotation mode + * changes. + */ + int force_reset; + + /* This information is duplicated from dev[font_id].format. + * Set to 1 if font is composite (Type0) font. + */ + int is_mb; +}; + +#define PDF_FONTTYPE_SIMPLE 1 +#define PDF_FONTTYPE_BITMAP 2 +#define PDF_FONTTYPE_COMPOSITE 3 + +struct dev_font { + /* Needs to be big enough to hold name "Fxxx" + * where xxx is number of largest font + */ + char short_name[7]; /* Resource name */ + int used_on_this_page; + + char *tex_name; /* String identifier of this font */ + spt_t sptsize; /* Point size */ + + /* Returned values from font/encoding layer: + * + * The font_id and enc_id is font and encoding (CMap) identifier + * used in pdf_font or encoding/cmap layer. + * The PDF object "resource" is an indirect reference object + * pointing font resource of this font. The used_chars is somewhat + * misleading, this is actually used_glyphs in CIDFont for Type0 + * and is 65536/8 bytes binary data with each bits representing + * whether the glyph is in-use or not. It is 256 char array for + * simple font. + */ + int font_id; + int enc_id; + + /* if >= 0, index of a dev_font that really has the resource and used_chars */ + int real_font_index; + + pdf_obj *resource; + char *used_chars; + + /* Font format: + * simple, composite or bitmap. + */ + int format; + + /* Writing mode: + * Non-zero for vertical. Duplicated from CMap. + */ + int wmode; + + /* Syntetic Font: + * + * We use text matrix for creating extended or slanted font, + * but not with font's FontMatrix since TrueType and Type0 + * font don't support them. + */ + double extend; + double slant; + double bold; /* Boldness prameter */ + + /* Compatibility */ + int mapc; /* Nasty workaround for Omega */ + + /* There are no font metric format supporting four-bytes + * charcter code. So we should provide an option to specify + * UCS group and plane. + */ + int ucs_group; + int ucs_plane; + + int is_unicode; +}; /* * Unit conversion, formatting and others. */ #define TEX_ONE_HUNDRED_BP 6578176 -static struct { - double dvi2pts; +struct dev_unit { + double dvi2pts; /* multiplier for DVI unit to bpt conversion */ int min_bp_val; /* Shortest resolvable distance in the output PDF. */ int precision; /* Number of decimal digits (in fractional part) kept. */ -} dev_unit = { - 0.0, - 658, - 2 }; +#define FORMAT_BUF_SIZE 4096 +struct pdf_dev { + int motion_state; + struct dev_param param; + struct dev_unit unit; + struct text_state text_state; + struct dev_font *fonts; + int num_dev_fonts; + int max_dev_fonts; + int num_phys_fonts; + char format_buffer[FORMAT_BUF_SIZE+1]; + + /* Just to support pdf:bcontent special... + * Text position adjustment inside the pdf:bcontent and pdf:econtent. + */ + pdf_coord *dev_coords; + int num_dev_coords; + int max_dev_coords; +}; -double -dev_unit_dviunit (void) +/* + * For a moment declare as static variable here + * 2020/07/23 Most of the static variables put into single struct pdev + */ +static pdf_dev pdev; + +static pdf_dev * +current_device (void) +{ + return &pdev; +} + +static void +dev_out (pdf_dev *p, const char *str, size_t len) { - return (1.0/dev_unit.dvi2pts); + pdf_doc_add_page_content(str, len); +} + +static double +pdf_dev_unit_dviunit (pdf_dev *p) +{ + ASSERT(p); + + return (1.0 / p->unit.dvi2pts); } #define DEV_PRECISION_MAX 8 @@ -91,8 +303,8 @@ static double ten_pow_inv[10] = { 1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, 0.00000001, 0.000000001 }; -#define bpt2spt(b) ( (spt_t) round( (b) / dev_unit.dvi2pts ) ) -#define spt2bpt(s) ( (s) * dev_unit.dvi2pts ) +#define bpt2spt(p, b) ( (spt_t) round( (b) / (p)->unit.dvi2pts ) ) +#define spt2bpt(p, s) ( (s) * (p)->unit.dvi2pts ) #define dround_at(v,p) (ROUND( (v), ten_pow_inv[(p)] )) static int @@ -194,320 +406,128 @@ p_dtoa (double value, int prec, char *buf) } static int -dev_sprint_bp (char *buf, spt_t value, spt_t *error) +dev_sprint_bp (pdf_dev *p, char *buf, spt_t value, spt_t *error) { double value_in_bp; double error_in_bp; - int prec = dev_unit.precision; + int prec; + + ASSERT(p); + + prec = p->unit.precision; - value_in_bp = spt2bpt(value); + value_in_bp = spt2bpt(p, value); if (error) { error_in_bp = value_in_bp - dround_at(value_in_bp, prec); - *error = bpt2spt(error_in_bp); - } - - return p_dtoa(value_in_bp, prec, buf); -} - -/* They are affected by precision (set at device initialization). */ -int -pdf_sprint_matrix (char *buf, const pdf_tmatrix *M) -{ - int len; - int prec2 = MIN(dev_unit.precision + 2, DEV_PRECISION_MAX); - int prec0 = MAX(dev_unit.precision, 2); - - len = p_dtoa(M->a, prec2, buf); - buf[len++] = ' '; - len += p_dtoa(M->b, prec2, buf+len); - buf[len++] = ' '; - len += p_dtoa(M->c, prec2, buf+len); - buf[len++] = ' '; - len += p_dtoa(M->d, prec2, buf+len); - buf[len++] = ' '; - len += p_dtoa(M->e, prec0, buf+len); - buf[len++] = ' '; - len += p_dtoa(M->f, prec0, buf+len); - buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */ - - return len; -} - -int -pdf_sprint_rect (char *buf, const pdf_rect *rect) -{ - int len; - - len = p_dtoa(rect->llx, dev_unit.precision, buf); - buf[len++] = ' '; - len += p_dtoa(rect->lly, dev_unit.precision, buf+len); - buf[len++] = ' '; - len += p_dtoa(rect->urx, dev_unit.precision, buf+len); - buf[len++] = ' '; - len += p_dtoa(rect->ury, dev_unit.precision, buf+len); - buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */ - - return len; -} - -int -pdf_sprint_coord (char *buf, const pdf_coord *p) -{ - int len; - - len = p_dtoa(p->x, dev_unit.precision, buf); - buf[len++] = ' '; - len += p_dtoa(p->y, dev_unit.precision, buf+len); - buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */ - - return len; -} - -int -pdf_sprint_length (char *buf, double value) -{ - int len; - - len = p_dtoa(value, dev_unit.precision, buf); - buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */ - - return len; -} - - -int -pdf_sprint_number (char *buf, double value) -{ - int len; - - len = p_dtoa(value, DEV_PRECISION_MAX, buf); - buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */ - - return len; -} - - -static struct -{ - /* Text composition (direction) mode is ignored (always same - * as font's writing mode) if autorotate is unset (value zero). - */ - int autorotate; - - /* - * Ignore color migrated to here. This is device's capacity. - * colormode 0 for ignore colors - */ - int colormode; - -} dev_param = { - 1, /* autorotate */ - 1, /* colormode */ -}; - -/* - * Text handling routines. - */ - -/* Motion state: - * GRAPHICS_MODE Initial state (not within BT/ET block nor in string) - * TEXT_MODE Text section is started via BT operator but not - * in string. - * STRING_MODE In string. A string or array of strings are currently - * in process. May started '[', '<' or '('. - */ -#define GRAPHICS_MODE 1 -#define TEXT_MODE 2 -#define STRING_MODE 3 - -static int motion_state = GRAPHICS_MODE; - -#define FORMAT_BUF_SIZE 4096 -static char format_buffer[FORMAT_BUF_SIZE]; - -/* - * In PDF, vertical text positioning is always applied when current font - * is vertical font. While ASCII pTeX manages current writing direction - * and font's WMode separately. - * - * 000/101 WMODE_HH/VV h(v) font, h(v) direction. - * 001 WMODE_HV -90 deg. rotated - * 100 WMODE_VH +90 deg. rotated - * 011 WMODE_HD +90 deg. rotated - * 111 WMODE_VD 180 deg. rotated - - * In MetaPost PostScript file processing (mp_mode = 1), only HH/VV mode - * is applied. - */ -#define TEXT_WMODE_HH 0 -#define TEXT_WMODE_HV 1 -#define TEXT_WMODE_VH 4 -#define TEXT_WMODE_VV 5 -#define TEXT_WMODE_HD 3 -#define TEXT_WMODE_VD 7 - -#define ANGLE_CHANGES(m1,m2) ((abs((m1)-(m2)) % 5) == 0 ? 0 : 1) -#define ROTATE_TEXT(m) ((m) != TEXT_WMODE_HH && (m) != TEXT_WMODE_VV) - -static struct { - - /* Current font. - * This is index within dev_fonts. - */ - int font_id; - - /* Dvipdfmx does compression of text by doing text positioning - * in relative motion and uses string array [(foo) -250 (bar)] - * with kerning (negative kern is used for white space as suited - * for TeX). This is offset within current string. - */ - spt_t offset; - - /* This is reference point of strings. - * It may include error correction induced by rounding. - */ - spt_t ref_x; - spt_t ref_y; - - /* Using text raise and leading is highly recommended for - * text extraction to work properly. But not implemented yet. - * We can't do consice output for \TeX without this. - */ - spt_t raise; /* unused */ - spt_t leading; /* unused */ - - /* This is not always text matrix but rather font matrix. - * We do not use horizontal scaling in PDF text state parameter - * since they always apply scaling in fixed direction regardless - * of writing mode. - */ - struct { - double slant; - double extend; - int rotate; /* TEXT_WMODE_XX */ - } matrix; - - /* Fake bold parameter: - * If bold_param is positive, use text rendering mode - * fill-then-stroke with stroking line width specified - * by bold_param. - */ - double bold_param; + *error = bpt2spt(p, error_in_bp); + } - /* Text composition (direction) mode. */ - int dir_mode; + return p_dtoa(value_in_bp, prec, buf); +} - /* internal */ +/* They are affected by precision (set at device initialization). */ +static size_t +pdf_dev_sprint_matrix (pdf_dev *p, char *buf, const pdf_tmatrix *M) +{ + size_t len; + int prec0, prec2; - /* Flag indicating text matrix to be forcibly reset. - * Enabled if synthetic font features (slant, extend, etc) - * are used for current font or when text rotation mode - * changes. - */ - int force_reset; + ASSERT(p); - /* This information is duplicated from dev[font_id].format. - * Set to 1 if font is composite (Type0) font. - */ - int is_mb; -} text_state = { - -1, /* font */ - 0, /* offset */ - 0, 0, /* ref_x, ref_y */ - 0, 0, /* raise, leading */ - {0.0, 1.0, 0}, + prec2 = MIN(p->unit.precision + 2, DEV_PRECISION_MAX); + prec0 = MAX(p->unit.precision, 2); - 0.0, /* Experimental boldness param */ + len = p_dtoa(M->a, prec2, buf); + buf[len++] = ' '; + len += p_dtoa(M->b, prec2, buf+len); + buf[len++] = ' '; + len += p_dtoa(M->c, prec2, buf+len); + buf[len++] = ' '; + len += p_dtoa(M->d, prec2, buf+len); + buf[len++] = ' '; + len += p_dtoa(M->e, prec0, buf+len); + buf[len++] = ' '; + len += p_dtoa(M->f, prec0, buf+len); + buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */ - 0, /* dir_mode */ + return len; +} - /* internal */ - 0, /* force_reset */ - 0 /* is_mb */ -}; +static size_t +pdf_dev_sprint_rect (pdf_dev *p, char *buf, const pdf_rect *rect) +{ + size_t len; -#define PDF_FONTTYPE_SIMPLE 1 -#define PDF_FONTTYPE_BITMAP 2 -#define PDF_FONTTYPE_COMPOSITE 3 + ASSERT(p); -struct dev_font { - /* Needs to be big enough to hold name "Fxxx" - * where xxx is number of largest font - */ - char short_name[7]; /* Resource name */ - int used_on_this_page; + len = p_dtoa(rect->llx, p->unit.precision, buf); + buf[len++] = ' '; + len += p_dtoa(rect->lly, p->unit.precision, buf+len); + buf[len++] = ' '; + len += p_dtoa(rect->urx, p->unit.precision, buf+len); + buf[len++] = ' '; + len += p_dtoa(rect->ury, p->unit.precision, buf+len); + buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */ - char *tex_name; /* String identifier of this font */ - spt_t sptsize; /* Point size */ + return len; +} - /* Returned values from font/encoding layer: - * - * The font_id and enc_id is font and encoding (CMap) identifier - * used in pdf_font or encoding/cmap layer. - * The PDF object "resource" is an indirect reference object - * pointing font resource of this font. The used_chars is somewhat - * misleading, this is actually used_glyphs in CIDFont for Type0 - * and is 65536/8 bytes binary data with each bits representing - * whether the glyph is in-use or not. It is 256 char array for - * simple font. - */ - int font_id; - int enc_id; +static size_t +pdf_dev_sprint_coord (pdf_dev *p, char *buf, const pdf_coord *c) +{ + size_t len; - /* if >= 0, index of a dev_font that really has the resource and used_chars */ - int real_font_index; + ASSERT(p); - pdf_obj *resource; - char *used_chars; + len = p_dtoa(c->x, p->unit.precision, buf); + buf[len++] = ' '; + len += p_dtoa(c->y, p->unit.precision, buf+len); + buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */ - /* Font format: - * simple, composite or bitmap. - */ - int format; + return len; +} - /* Writing mode: - * Non-zero for vertical. Duplicated from CMap. - */ - int wmode; +static size_t +pdf_dev_sprint_length (pdf_dev *p, char *buf, double value) +{ + size_t len; - /* Syntetic Font: - * - * We use text matrix for creating extended or slanted font, - * but not with font's FontMatrix since TrueType and Type0 - * font don't support them. - */ - double extend; - double slant; - double bold; /* Boldness prameter */ + ASSERT(p); - /* Compatibility */ - int mapc; /* Nasty workaround for Omega */ + len = p_dtoa(value, p->unit.precision, buf); + buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */ - /* There are no font metric format supporting four-bytes - * charcter code. So we should provide an option to specify - * UCS group and plane. - */ - int ucs_group; - int ucs_plane; + return len; +} - int is_unicode; -}; -static struct dev_font *dev_fonts = NULL; +static size_t +pdf_dev_sprint_number (pdf_dev *p, char *buf, double value) +{ + size_t len; -static int num_dev_fonts = 0; -static int max_dev_fonts = 0; -static int num_phys_fonts = 0; + ASSERT(p); + + len = p_dtoa(value, DEV_PRECISION_MAX, buf); + buf[len] = '\0'; /* xxx_sprint_xxx NULL terminates strings. */ -#define CURRENTFONT() ((text_state.font_id < 0) ? NULL : &(dev_fonts[text_state.font_id])) -#define GET_FONT(n) (&(dev_fonts[(n)])) + return len; +} +/* Text handling */ +#define CURRENTFONT(p) (((p)->text_state.font_id < 0) ? \ + NULL : &((p)->fonts[(p)->text_state.font_id])) +#define GET_FONT(p, n) (&((p)->fonts[(n)])) static void -dev_set_text_matrix (spt_t xpos, spt_t ypos, double slant, double extend, int rotate) +dev_set_text_matrix (pdf_dev *p, + spt_t xpos, spt_t ypos, + double slant, double extend, int rotate) { pdf_tmatrix tm; int len = 0; + ASSERT(p); + /* slant is negated for vertical font so that right-side * is always lower. */ switch (rotate) { @@ -542,22 +562,22 @@ dev_set_text_matrix (spt_t xpos, spt_t ypos, double slant, double extend, int ro tm.c = 0.0; tm.d = -extend; break; } - tm.e = xpos * dev_unit.dvi2pts; - tm.f = ypos * dev_unit.dvi2pts; - - format_buffer[len++] = ' '; - len += pdf_sprint_matrix(format_buffer+len, &tm); - format_buffer[len++] = ' '; - format_buffer[len++] = 'T'; - format_buffer[len++] = 'm'; - - pdf_doc_add_page_content(format_buffer, len); /* op: Tm */ - - text_state.ref_x = xpos; - text_state.ref_y = ypos; - text_state.matrix.slant = slant; - text_state.matrix.extend = extend; - text_state.matrix.rotate = rotate; + tm.e = xpos * p->unit.dvi2pts; + tm.f = ypos * p->unit.dvi2pts; + + p->format_buffer[len++] = ' '; + len += pdf_dev_sprint_matrix(p, p->format_buffer+len, &tm); + p->format_buffer[len++] = ' '; + p->format_buffer[len++] = 'T'; + p->format_buffer[len++] = 'm'; + + dev_out(p, p->format_buffer, len); /* op: Tm */ + + p->text_state.ref_x = xpos; + p->text_state.ref_y = ypos; + p->text_state.matrix.slant = slant; + p->text_state.matrix.extend = extend; + p->text_state.matrix.rotate = rotate; } /* @@ -566,81 +586,88 @@ dev_set_text_matrix (spt_t xpos, spt_t ypos, double slant, double extend, int ro */ static void -reset_text_state (void) +reset_text_state (pdf_dev *p) { + ASSERT(p); + /* * We need to reset the line matrix to handle slanted fonts. */ - pdf_doc_add_page_content(" BT", 3); /* op: BT */ + dev_out(p, " BT", 3); /* op: BT */ /* * text_state.matrix is identity at top of page. * This sometimes write unnecessary "Tm"s when transition from * GRAPHICS_MODE to TEXT_MODE occurs. */ - if (text_state.force_reset || - text_state.matrix.slant != 0.0 || - text_state.matrix.extend != 1.0 || - ROTATE_TEXT(text_state.matrix.rotate)) { - dev_set_text_matrix(0, 0, - text_state.matrix.slant, - text_state.matrix.extend, - text_state.matrix.rotate); + if (p->text_state.force_reset || + p->text_state.matrix.slant != 0.0 || + p->text_state.matrix.extend != 1.0 || + ROTATE_TEXT(p->text_state.matrix.rotate)) { + dev_set_text_matrix(p, 0, 0, + p->text_state.matrix.slant, + p->text_state.matrix.extend, + p->text_state.matrix.rotate); } - text_state.ref_x = 0; - text_state.ref_y = 0; - text_state.offset = 0; - text_state.force_reset = 0; + p->text_state.ref_x = 0; + p->text_state.ref_y = 0; + p->text_state.offset = 0; + p->text_state.force_reset = 0; } static void -text_mode (void) +pdf_dev_text_mode (pdf_dev *p) { - switch (motion_state) { + ASSERT(p); + + switch (p->motion_state) { case TEXT_MODE: break; case STRING_MODE: - pdf_doc_add_page_content(text_state.is_mb ? ">]TJ" : ")]TJ", 4); /* op: TJ */ + dev_out(p, p->text_state.is_mb ? ">]TJ" : ")]TJ", 4); /* op: TJ */ break; case GRAPHICS_MODE: - reset_text_state(); + reset_text_state(p); break; } - motion_state = TEXT_MODE; - text_state.offset = 0; + p->motion_state = TEXT_MODE; + p->text_state.offset = 0; } -void -graphics_mode (void) +static void +pdf_dev_graphics_mode (pdf_dev *p) { - switch (motion_state) { + switch (p->motion_state) { case GRAPHICS_MODE: break; case STRING_MODE: - pdf_doc_add_page_content(text_state.is_mb ? ">]TJ" : ")]TJ", 4); /* op: TJ */ + dev_out(p, p->text_state.is_mb ? ">]TJ" : ")]TJ", 4); /* op: TJ */ /* continue */ case TEXT_MODE: - if (text_state.bold_param != 0.0) { + if (p->text_state.bold_param != 0.0) { /* fake-bold "2 Tr" is still active */ - pdf_doc_add_page_content(" 0 Tr", 5); /* op: Tr */ - text_state.bold_param = 0.0; - } - pdf_doc_add_page_content(" ET", 3); /* op: ET */ - text_state.force_reset = 0; - text_state.font_id = -1; + dev_out(p, " 0 Tr", 5); /* op: Tr */ + p->text_state.bold_param = 0.0; + } + dev_out(p, " ET", 3); /* op: ET */ + p->text_state.force_reset = 0; + p->text_state.font_id = -1; break; } - motion_state = GRAPHICS_MODE; + p->motion_state = GRAPHICS_MODE; } static void -start_string (spt_t xpos, spt_t ypos, double slant, double extend, int rotate) +start_string (pdf_dev *p, + spt_t xpos, spt_t ypos, double slant, double extend, int rotate) { spt_t delx, dely, error_delx, error_dely; spt_t desired_delx, desired_dely; int len = 0; - delx = xpos - text_state.ref_x; - dely = ypos - text_state.ref_y; + ASSERT(p); + + delx = xpos - p->text_state.ref_x; + dely = ypos - p->text_state.ref_y; /* * Precompensating for line transformation matrix. * @@ -697,10 +724,10 @@ start_string (spt_t xpos, spt_t ypos, double slant, double extend, int rotate) * We must care about rotation here but not extend/slant... * The extend and slant actually is font matrix. */ - format_buffer[len++] = ' '; - len += dev_sprint_bp(format_buffer+len, desired_delx, &error_dely); - format_buffer[len++] = ' '; - len += dev_sprint_bp(format_buffer+len, desired_dely, &error_delx); + p->format_buffer[len++] = ' '; + len += dev_sprint_bp(p, p->format_buffer+len, desired_delx, &error_dely); + p->format_buffer[len++] = ' '; + len += dev_sprint_bp(p, p->format_buffer+len, desired_dely, &error_delx); error_delx = -error_delx; break; case TEXT_WMODE_HV: @@ -716,10 +743,10 @@ start_string (spt_t xpos, spt_t ypos, double slant, double extend, int rotate) /* * e = (e_user_y, -e_user_x) */ - format_buffer[len++] = ' '; - len += dev_sprint_bp(format_buffer+len, desired_delx, &error_dely); - format_buffer[len++] = ' '; - len += dev_sprint_bp(format_buffer+len, desired_dely, &error_delx); + p->format_buffer[len++] = ' '; + len += dev_sprint_bp(p, p->format_buffer+len, desired_delx, &error_dely); + p->format_buffer[len++] = ' '; + len += dev_sprint_bp(p, p->format_buffer+len, desired_dely, &error_delx); error_dely = -error_dely; break; case TEXT_WMODE_HH: @@ -731,10 +758,10 @@ start_string (spt_t xpos, spt_t ypos, double slant, double extend, int rotate) desired_delx = (spt_t)((delx - dely*slant)/extend); desired_dely = dely; - format_buffer[len++] = ' '; - len += dev_sprint_bp(format_buffer+len, desired_delx, &error_delx); - format_buffer[len++] = ' '; - len += dev_sprint_bp(format_buffer+len, desired_dely, &error_dely); + p->format_buffer[len++] = ' '; + len += dev_sprint_bp(p, p->format_buffer+len, desired_delx, &error_delx); + p->format_buffer[len++] = ' '; + len += dev_sprint_bp(p, p->format_buffer+len, desired_dely, &error_dely); break; case TEXT_WMODE_VV: /* Vertical font in vertical mode: @@ -745,10 +772,10 @@ start_string (spt_t xpos, spt_t ypos, double slant, double extend, int rotate) desired_delx = delx; desired_dely = (spt_t)((dely + delx*slant)/extend); - format_buffer[len++] = ' '; - len += dev_sprint_bp(format_buffer+len, desired_delx, &error_delx); - format_buffer[len++] = ' '; - len += dev_sprint_bp(format_buffer+len, desired_dely, &error_dely); + p->format_buffer[len++] = ' '; + len += dev_sprint_bp(p, p->format_buffer+len, desired_delx, &error_delx); + p->format_buffer[len++] = ' '; + len += dev_sprint_bp(p, p->format_buffer+len, desired_dely, &error_dely); break; case TEXT_WMODE_HD: /* Horizontal font in down-to-up mode: rot = +90 @@ -760,10 +787,10 @@ start_string (spt_t xpos, spt_t ypos, double slant, double extend, int rotate) desired_delx = -(spt_t)(-(dely + delx*slant)/extend); desired_dely = -delx; - format_buffer[len++] = ' '; - len += dev_sprint_bp(format_buffer+len, desired_delx, &error_dely); - format_buffer[len++] = ' '; - len += dev_sprint_bp(format_buffer+len, desired_dely, &error_delx); + p->format_buffer[len++] = ' '; + len += dev_sprint_bp(p, p->format_buffer+len, desired_delx, &error_dely); + p->format_buffer[len++] = ' '; + len += dev_sprint_bp(p, p->format_buffer+len, desired_dely, &error_delx); error_delx = -error_delx; error_dely = -error_dely; break; @@ -776,48 +803,50 @@ start_string (spt_t xpos, spt_t ypos, double slant, double extend, int rotate) desired_delx = -delx; desired_dely = -(spt_t)((dely + delx*slant)/extend); - format_buffer[len++] = ' '; - len += dev_sprint_bp(format_buffer+len, desired_delx, &error_delx); - format_buffer[len++] = ' '; - len += dev_sprint_bp(format_buffer+len, desired_dely, &error_dely); + p->format_buffer[len++] = ' '; + len += dev_sprint_bp(p, p->format_buffer+len, desired_delx, &error_delx); + p->format_buffer[len++] = ' '; + len += dev_sprint_bp(p, p->format_buffer+len, desired_dely, &error_dely); error_delx = -error_delx; error_dely = -error_dely; break; } - pdf_doc_add_page_content(format_buffer, len); /* op: */ + dev_out(p, p->format_buffer, len); /* op: */ /* * dvipdfm wrongly using "TD" in place of "Td". * The TD operator set leading, but we are not using T* etc. */ - pdf_doc_add_page_content(text_state.is_mb ? " Td[<" : " Td[(", 5); /* op: Td */ + dev_out(p, p->text_state.is_mb ? " Td[<" : " Td[(", 5); /* op: Td */ /* Error correction */ - text_state.ref_x = xpos - error_delx; - text_state.ref_y = ypos - error_dely; + p->text_state.ref_x = xpos - error_delx; + p->text_state.ref_y = ypos - error_dely; - text_state.offset = 0; + p->text_state.offset = 0; } static void -string_mode (spt_t xpos, spt_t ypos, double slant, double extend, int rotate) +pdf_dev_string_mode (pdf_dev *p, spt_t xpos, spt_t ypos, double slant, double extend, int rotate) { - switch (motion_state) { + ASSERT(p); + + switch (p->motion_state) { case STRING_MODE: break; case GRAPHICS_MODE: - reset_text_state(); + reset_text_state(p); /* continue */ case TEXT_MODE: - if (text_state.force_reset) { - dev_set_text_matrix(xpos, ypos, slant, extend, rotate); - pdf_doc_add_page_content(text_state.is_mb ? "[<" : "[(", 2); /* op: */ - text_state.force_reset = 0; + if (p->text_state.force_reset) { + dev_set_text_matrix(p, xpos, ypos, slant, extend, rotate); + dev_out(p, p->text_state.is_mb ? "[<" : "[(", 2); /* op: */ + p->text_state.force_reset = 0; } else { - start_string(xpos, ypos, slant, extend, rotate); + start_string(p, xpos, ypos, slant, extend, rotate); } break; } - motion_state = STRING_MODE; + p->motion_state = STRING_MODE; } /* @@ -833,7 +862,7 @@ string_mode (spt_t xpos, spt_t ypos, double slant, double extend, int rotate) */ static int -dev_set_font (int font_id) +pdf_dev_set_font (pdf_dev *p, int font_id) { struct dev_font *font; struct dev_font *real_font; @@ -842,35 +871,37 @@ dev_set_font (int font_id) int len; int vert_dir, vert_font; + ASSERT(p); + /* text_mode() must come before text_state.is_mb is changed. */ - text_mode(); + pdf_dev_text_mode(p); - font = GET_FONT(font_id); + font = GET_FONT(p, font_id); ASSERT(font); /* Caller should check font_id. */ if (font->real_font_index >= 0) - real_font = GET_FONT(font->real_font_index); + real_font = GET_FONT(p, font->real_font_index); else real_font = font; - text_state.is_mb = (font->format == PDF_FONTTYPE_COMPOSITE) ? 1 : 0; + p->text_state.is_mb = (font->format == PDF_FONTTYPE_COMPOSITE) ? 1 : 0; vert_font = font->wmode ? 1 : 0; - if (dev_param.autorotate) { - vert_dir = text_state.dir_mode; + if (p->param.autorotate) { + vert_dir = p->text_state.dir_mode; } else { vert_dir = vert_font; } text_rotate = (vert_font << 2)|vert_dir; - if (font->slant != text_state.matrix.slant || - font->extend != text_state.matrix.extend || - ANGLE_CHANGES(text_rotate, text_state.matrix.rotate)) { - text_state.force_reset = 1; + if (font->slant != p->text_state.matrix.slant || + font->extend != p->text_state.matrix.extend || + ANGLE_CHANGES(text_rotate, p->text_state.matrix.rotate)) { + p->text_state.force_reset = 1; } - text_state.matrix.slant = font->slant; - text_state.matrix.extend = font->extend; - text_state.matrix.rotate = text_rotate; + p->text_state.matrix.slant = font->slant; + p->text_state.matrix.extend = font->extend; + p->text_state.matrix.rotate = text_rotate; if (!real_font->resource) { real_font->resource = pdf_get_font_reference(real_font->font_id); @@ -884,66 +915,33 @@ dev_set_font (int font_id) real_font->used_on_this_page = 1; } - font_scale = (double) font->sptsize * dev_unit.dvi2pts; - len = sprintf(format_buffer, " /%s", real_font->short_name); /* space not necessary. */ - format_buffer[len++] = ' '; - len += p_dtoa(font_scale, MIN(dev_unit.precision+1, DEV_PRECISION_MAX), format_buffer+len); - format_buffer[len++] = ' '; - format_buffer[len++] = 'T'; - format_buffer[len++] = 'f'; - pdf_doc_add_page_content(format_buffer, len); /* op: Tf */ - - if (font->bold > 0.0 || font->bold != text_state.bold_param) { + font_scale = (double) font->sptsize * p->unit.dvi2pts; + len = sprintf(p->format_buffer, " /%s", real_font->short_name); /* space not necessary. */ + p->format_buffer[len++] = ' '; + len += p_dtoa(font_scale, MIN(p->unit.precision+1, DEV_PRECISION_MAX), + p->format_buffer+len); + p->format_buffer[len++] = ' '; + p->format_buffer[len++] = 'T'; + p->format_buffer[len++] = 'f'; + dev_out(p, p->format_buffer, len); /* op: Tf */ + + if (font->bold > 0.0 || font->bold != p->text_state.bold_param) { if (font->bold <= 0.0) - len = sprintf(format_buffer, " 0 Tr"); + len = sprintf(p->format_buffer, " 0 Tr"); else - len = sprintf(format_buffer, " 2 Tr %.6f w", font->bold); /* _FIXME_ */ - pdf_doc_add_page_content(format_buffer, len); /* op: Tr w */ + len = sprintf(p->format_buffer, " 2 Tr %.6f w", font->bold); /* _FIXME_ */ + dev_out(p, p->format_buffer, len); /* op: Tr w */ } - text_state.bold_param = font->bold; + p->text_state.bold_param = font->bold; - text_state.font_id = font_id; + p->text_state.font_id = font_id; return 0; } - -/* Access text state parameters. +/* These tmp buffers can't be removed since the pointer to this can be + * used as the return value of handle_multibyte_string(): str_ptr can point these. */ -#if 0 -int -pdf_dev_currentfont (void) -{ - return text_state.font_id; -} - -double -pdf_dev_get_font_ptsize (int font_id) -{ - struct dev_font *font; - - font = GET_FONT(font_id); - if (font) { - return font->sptsize * dev_unit.dvi2pts; - } - - return 1.0; -} -#endif - -int -pdf_dev_get_font_wmode (int font_id) -{ - struct dev_font *font; - - font = GET_FONT(font_id); - if (font) { - return font->wmode; - } - - return 0; -} - static unsigned char sbuf0[FORMAT_BUF_SIZE]; static unsigned char sbuf1[FORMAT_BUF_SIZE]; @@ -1048,37 +1046,6 @@ handle_multibyte_string (struct dev_font *font, return 0; } - -static pdf_coord *dev_coords = NULL; -static int num_dev_coords = 0; -static int max_dev_coords = 0; - -void pdf_dev_get_coord(double *xpos, double *ypos) -{ - if (num_dev_coords > 0) { - *xpos = dev_coords[num_dev_coords-1].x; - *ypos = dev_coords[num_dev_coords-1].y; - } else { - *xpos = *ypos = 0.0; - } -} - -void pdf_dev_push_coord(double xpos, double ypos) -{ - if (num_dev_coords >= max_dev_coords) { - max_dev_coords += 4; - dev_coords = RENEW(dev_coords, max_dev_coords, pdf_coord); - } - dev_coords[num_dev_coords].x = xpos; - dev_coords[num_dev_coords].y = ypos; - num_dev_coords++; -} - -void pdf_dev_pop_coord(void) -{ - if (num_dev_coords > 0) num_dev_coords--; -} - /* * ctype: * -1 input string contains 2-byte Freetype glyph index values @@ -1097,35 +1064,36 @@ pdf_dev_set_string (spt_t xpos, spt_t ypos, spt_t width, int font_id, int ctype) { - struct dev_font *font; - struct dev_font *real_font; + pdf_dev *p = current_device(); + struct dev_font *font; + struct dev_font *real_font; const unsigned char *str_ptr; /* Pointer to the reencoded string. */ - int length, i, len = 0; - spt_t kern, delh, delv; - spt_t text_xorigin; - spt_t text_yorigin; + int length, i, len = 0; + spt_t kern, delh, delv; + spt_t text_xorigin; + spt_t text_yorigin; - if (font_id < 0 || font_id >= num_dev_fonts) { - ERROR("Invalid font: %d (%d)", font_id, num_dev_fonts); + if (font_id < 0 || font_id >= p->num_dev_fonts) { + ERROR("Invalid font: %d (%d)", font_id, p->num_dev_fonts); return; } - if (font_id != text_state.font_id) { - dev_set_font(font_id); + if (font_id != p->text_state.font_id) { + pdf_dev_set_font(p, font_id); } - font = CURRENTFONT(); + font = CURRENTFONT(p); if (!font) { ERROR("Currentfont not set."); return; } if (font->real_font_index >= 0) - real_font = GET_FONT(font->real_font_index); + real_font = GET_FONT(p, font->real_font_index); else real_font = font; - text_xorigin = text_state.ref_x; - text_yorigin = text_state.ref_y; + text_xorigin = p->text_state.ref_x; + text_yorigin = p->text_state.ref_y; str_ptr = instr_ptr; length = instr_len; @@ -1148,9 +1116,9 @@ pdf_dev_set_string (spt_t xpos, spt_t ypos, } } - if (num_dev_coords > 0) { - xpos -= bpt2spt(dev_coords[num_dev_coords-1].x); - ypos -= bpt2spt(dev_coords[num_dev_coords-1].y); + if (p->num_dev_coords > 0) { + xpos -= bpt2spt(p, p->dev_coords[p->num_dev_coords-1].x); + ypos -= bpt2spt(p, p->dev_coords[p->num_dev_coords-1].y); } /* @@ -1168,17 +1136,17 @@ pdf_dev_set_string (spt_t xpos, spt_t ypos, * (in 1000 units per em) but dvipdfmx does not take into account of this... */ - if (text_state.dir_mode==0) { + if (p->text_state.dir_mode==0) { /* Left-to-right */ - delh = text_xorigin + text_state.offset - xpos; + delh = text_xorigin + p->text_state.offset - xpos; delv = ypos - text_yorigin; - } else if (text_state.dir_mode==1) { + } else if (p->text_state.dir_mode==1) { /* Top-to-bottom */ - delh = ypos - text_yorigin + text_state.offset; + delh = ypos - text_yorigin + p->text_state.offset; delv = xpos - text_xorigin; } else { /* Bottom-to-top */ - delh = ypos + text_yorigin + text_state.offset; + delh = ypos + text_yorigin + p->text_state.offset; delv = xpos + text_xorigin; } @@ -1192,10 +1160,10 @@ pdf_dev_set_string (spt_t xpos, spt_t ypos, */ #define WORD_SPACE_MAX(f) (spt_t) (3.0 * (f)->extend * (f)->sptsize) - if (text_state.force_reset || - labs(delv) > dev_unit.min_bp_val || + if (p->text_state.force_reset || + labs(delv) > p->unit.min_bp_val || labs(delh) > WORD_SPACE_MAX(font)) { - text_mode(); + pdf_dev_text_mode(p); kern = 0; } else { kern = (spt_t) (1000.0 / font->extend * delh / font->sptsize); @@ -1205,28 +1173,28 @@ pdf_dev_set_string (spt_t xpos, spt_t ypos, * single text block. There are point_size/1000 rounding error per character. * If you really care about accuracy, you should compensate this here too. */ - if (motion_state != STRING_MODE) - string_mode(xpos, ypos, - font->slant, font->extend, text_state.matrix.rotate); + if (p->motion_state != STRING_MODE) + pdf_dev_string_mode(p, xpos, ypos, + font->slant, font->extend, p->text_state.matrix.rotate); else if (kern != 0) { /* * Same issues as earlier. Use floating point for simplicity. * This routine needs to be fast, so we don't call sprintf() or strcpy(). */ - text_state.offset -= + p->text_state.offset -= (spt_t) (kern * font->extend * (font->sptsize / 1000.0)); - format_buffer[len++] = text_state.is_mb ? '>' : ')'; + p->format_buffer[len++] = p->text_state.is_mb ? '>' : ')'; if (font->wmode) - len += p_itoa(-kern, format_buffer + len); + len += p_itoa(-kern, p->format_buffer + len); else { - len += p_itoa( kern, format_buffer + len); + len += p_itoa( kern, p->format_buffer + len); } - format_buffer[len++] = text_state.is_mb ? '<' : '('; - pdf_doc_add_page_content(format_buffer, len); /* op: */ + p->format_buffer[len++] = p->text_state.is_mb ? '<' : '('; + dev_out(p, p->format_buffer, len); /* op: */ len = 0; } - if (text_state.is_mb) { + if (p->text_state.is_mb) { if (FORMAT_BUF_SIZE - len < 2 * length) ERROR("Buffer overflow..."); for (i = 0; i < length; i++) { @@ -1234,68 +1202,94 @@ pdf_dev_set_string (spt_t xpos, spt_t ypos, first = (str_ptr[i] >> 4) & 0x0f; second = str_ptr[i] & 0x0f; - format_buffer[len++] = ((first >= 10) ? first + 'W' : first + '0'); - format_buffer[len++] = ((second >= 10) ? second + 'W' : second + '0'); + p->format_buffer[len++] = ((first >= 10) ? first + 'W' : first + '0'); + p->format_buffer[len++] = ((second >= 10) ? second + 'W' : second + '0'); } } else { - len += pdfobj_escape_str(format_buffer + len, + len += pdfobj_escape_str(p->format_buffer + len, FORMAT_BUF_SIZE - len, str_ptr, length); } /* I think if you really care about speed, you should avoid memcopy here. */ - pdf_doc_add_page_content(format_buffer, len); /* op: */ + dev_out(p, p->format_buffer, len); /* op: */ - text_state.offset += width; + p->text_state.offset += width; } void pdf_init_device (double dvi2pts, int precision, int black_and_white) { + pdf_dev *p = current_device(); + + p->motion_state = GRAPHICS_MODE; + p->unit.dvi2pts = 0.0; + p->unit.min_bp_val = 658; + p->unit.precision = 2; + p->param.autorotate = 1; + p->param.colormode = 1; + p->text_state.font_id = -1; + p->text_state.offset = 0; + p->text_state.matrix.slant = 0; + p->text_state.matrix.extend = 0; + p->text_state.matrix.rotate = 0; + p->text_state.bold_param = 0; + p->text_state.dir_mode = 0; + p->text_state.force_reset = 0; + p->text_state.is_mb = 0; + if (precision < 0 || precision > DEV_PRECISION_MAX) WARN("Number of decimal digits out of range [0-%d].", DEV_PRECISION_MAX); if (precision < 0) { - dev_unit.precision = 0; + p->unit.precision = 0; } else if (precision > DEV_PRECISION_MAX) { - dev_unit.precision = DEV_PRECISION_MAX; + p->unit.precision = DEV_PRECISION_MAX; } else { - dev_unit.precision = precision; + p->unit.precision = precision; } - dev_unit.dvi2pts = dvi2pts; - dev_unit.min_bp_val = (int) ROUND(1.0/(ten_pow[dev_unit.precision]*dvi2pts), 1); - if (dev_unit.min_bp_val < 0) - dev_unit.min_bp_val = -dev_unit.min_bp_val; + p->unit.dvi2pts = dvi2pts; + p->unit.min_bp_val = (int) ROUND(1.0/(ten_pow[p->unit.precision]*dvi2pts), 1); + if (p->unit.min_bp_val < 0) + p->unit.min_bp_val = -p->unit.min_bp_val; - dev_param.colormode = (black_and_white ? 0 : 1); + p->param.colormode = (black_and_white ? 0 : 1); - graphics_mode(); + pdf_dev_graphics_mode(p); pdf_color_clear_stack(); pdf_dev_init_gstates(); - num_dev_fonts = max_dev_fonts = 0; - dev_fonts = NULL; - num_dev_coords = max_dev_coords = 0; - dev_coords = NULL; + p->num_dev_fonts = p->max_dev_fonts = 0; + p->fonts = NULL; + p->num_dev_coords = 0; + p->max_dev_coords = 0; + p->dev_coords = NULL; + + return; } void pdf_close_device (void) { - if (dev_fonts) { + pdf_dev *p = current_device(); + + if (p->fonts) { int i; - for (i = 0; i < num_dev_fonts; i++) { - if (dev_fonts[i].tex_name) - RELEASE(dev_fonts[i].tex_name); - if (dev_fonts[i].resource) - pdf_release_obj(dev_fonts[i].resource); - dev_fonts[i].tex_name = NULL; - dev_fonts[i].resource = NULL; + for (i = 0; i < p->num_dev_fonts; i++) { + if (p->fonts[i].tex_name) + RELEASE(p->fonts[i].tex_name); + if (p->fonts[i].resource) + pdf_release_obj(p->fonts[i].resource); + p->fonts[i].tex_name = NULL; + p->fonts[i].resource = NULL; } - RELEASE(dev_fonts); + RELEASE(p->fonts); + p->fonts = NULL; } - if (dev_coords) RELEASE(dev_coords); + if (p->dev_coords) + RELEASE(p->dev_coords); + p->dev_coords = NULL; pdf_dev_clear_gstates(); } @@ -1307,22 +1301,23 @@ pdf_close_device (void) void pdf_dev_reset_fonts (int newpage) { - int i; + pdf_dev *p = current_device(); + int i; - for (i = 0; i < num_dev_fonts; i++) { - dev_fonts[i].used_on_this_page = 0; + for (i = 0; i < p->num_dev_fonts; i++) { + p->fonts[i].used_on_this_page = 0; } - text_state.font_id = -1; + p->text_state.font_id = -1; - text_state.matrix.slant = 0.0; - text_state.matrix.extend = 1.0; - text_state.matrix.rotate = TEXT_WMODE_HH; + p->text_state.matrix.slant = 0.0; + p->text_state.matrix.extend = 1.0; + p->text_state.matrix.rotate = TEXT_WMODE_HH; if (newpage) - text_state.bold_param = 0.0; + p->text_state.bold_param = 0.0; - text_state.is_mb = 0; + p->text_state.is_mb = 0; } void @@ -1335,29 +1330,14 @@ pdf_dev_reset_color (int force) pdf_dev_set_color(fc, 0x20, force); } -#if 0 -/* Not working */ -void -pdf_dev_set_origin (double phys_x, double phys_y) -{ - pdf_tmatrix M0, M1; - - pdf_dev_currentmatrix(&M0); - pdf_dev_currentmatrix(&M1); - pdf_invertmatrix(&M1); - M0.e = phys_x; M0.f = phys_y; - pdf_concatmatrix(&M1, &M0); - - pdf_dev_concat(&M1); -} -#endif - void pdf_dev_bop (const pdf_tmatrix *M) { - graphics_mode(); + pdf_dev *p = current_device(); + + pdf_dev_graphics_mode(p); - text_state.force_reset = 0; + p->text_state.force_reset = 0; pdf_dev_gsave(); pdf_dev_concat(M); @@ -1370,9 +1350,10 @@ pdf_dev_bop (const pdf_tmatrix *M) void pdf_dev_eop (void) { - int depth; + pdf_dev *p = current_device(); + int depth; - graphics_mode(); + pdf_dev_graphics_mode(p); depth = pdf_dev_current_depth(); if (depth != 1) { @@ -1433,6 +1414,7 @@ print_fontmap (const char *font_name, fontmap_rec *mrec) int pdf_dev_locate_font (const char *font_name, spt_t ptsize) { + pdf_dev *p = current_device(); int i; fontmap_rec *mrec; struct dev_font *font; @@ -1445,11 +1427,11 @@ pdf_dev_locate_font (const char *font_name, spt_t ptsize) return -1; } - for (i = 0; i < num_dev_fonts; i++) { - if (strcmp(font_name, dev_fonts[i].tex_name) == 0) { - if (ptsize == dev_fonts[i].sptsize) + for (i = 0; i < p->num_dev_fonts; i++) { + if (strcmp(font_name, p->fonts[i].tex_name) == 0) { + if (ptsize == p->fonts[i].sptsize) return i; /* found a dev_font that matches the request */ - if (dev_fonts[i].format != PDF_FONTTYPE_BITMAP) + if (p->fonts[i].format != PDF_FONTTYPE_BITMAP) break; /* new dev_font will share pdf resource with /i/ */ } } @@ -1458,12 +1440,12 @@ pdf_dev_locate_font (const char *font_name, spt_t ptsize) * Make sure we have room for a new one, even though we may not * actually create one. */ - if (num_dev_fonts >= max_dev_fonts) { - max_dev_fonts += 16; - dev_fonts = RENEW(dev_fonts, max_dev_fonts, struct dev_font); + if (p->num_dev_fonts >= p->max_dev_fonts) { + p->max_dev_fonts += 16; + p->fonts = RENEW(p->fonts, p->max_dev_fonts, struct dev_font); } - font = &dev_fonts[num_dev_fonts]; + font = &p->fonts[p->num_dev_fonts]; /* New font */ mrec = pdf_lookup_fontmap_record(font_name); @@ -1471,20 +1453,20 @@ pdf_dev_locate_font (const char *font_name, spt_t ptsize) if (dpx_conf.verbose_level > 1) print_fontmap(font_name, mrec); - font->font_id = pdf_font_findresource(font_name, ptsize * dev_unit.dvi2pts, mrec); + font->font_id = pdf_font_findresource(font_name, ptsize * p->unit.dvi2pts, mrec); if (font->font_id < 0) return -1; /* We found device font here. */ - if (i < num_dev_fonts) { + if (i < p->num_dev_fonts) { font->real_font_index = i; - strcpy(font->short_name, dev_fonts[i].short_name); + strcpy(font->short_name, p->fonts[i].short_name); } else { font->real_font_index = -1; font->short_name[0] = 'F'; - p_itoa(num_phys_fonts + 1, &font->short_name[1]); /* NULL terminated here */ - num_phys_fonts++; + p_itoa(p->num_phys_fonts + 1, &font->short_name[1]); /* NULL terminated here */ + p->num_phys_fonts++; } font->used_on_this_page = 0; @@ -1543,33 +1525,33 @@ pdf_dev_locate_font (const char *font_name, spt_t ptsize) } } - return num_dev_fonts++; + return p->num_dev_fonts++; } /* This does not remember current stroking width. */ static int -dev_sprint_line (char *buf, spt_t width, +dev_sprint_line (pdf_dev *p, char *buf, spt_t width, spt_t p0_x, spt_t p0_y, spt_t p1_x, spt_t p1_y) { int len = 0; double w; - w = width * dev_unit.dvi2pts; + w = width * p->unit.dvi2pts; - len += p_dtoa(w, MIN(dev_unit.precision+1, DEV_PRECISION_MAX), buf+len); + len += p_dtoa(w, MIN(p->unit.precision+1, DEV_PRECISION_MAX), buf+len); buf[len++] = ' '; buf[len++] = 'w'; buf[len++] = ' '; - len += dev_sprint_bp(buf+len, p0_x, NULL); + len += dev_sprint_bp(p, buf+len, p0_x, NULL); buf[len++] = ' '; - len += dev_sprint_bp(buf+len, p0_y, NULL); + len += dev_sprint_bp(p, buf+len, p0_y, NULL); buf[len++] = ' '; buf[len++] = 'm'; buf[len++] = ' '; - len += dev_sprint_bp(buf+len, p1_x, NULL); + len += dev_sprint_bp(p, buf+len, p1_x, NULL); buf[len++] = ' '; - len += dev_sprint_bp(buf+len, p1_y, NULL); + len += dev_sprint_bp(p, buf+len, p1_y, NULL); buf[len++] = ' '; buf[len++] = 'l'; buf[len++] = ' '; @@ -1583,35 +1565,36 @@ dev_sprint_line (char *buf, spt_t width, void pdf_dev_set_rule (spt_t xpos, spt_t ypos, spt_t width, spt_t height) { - int len = 0; - double width_in_bp; + pdf_dev *p = current_device(); + int len = 0; + double width_in_bp; - if (num_dev_coords > 0) { - xpos -= bpt2spt(dev_coords[num_dev_coords-1].x); - ypos -= bpt2spt(dev_coords[num_dev_coords-1].y); + if (p->num_dev_coords > 0) { + xpos -= bpt2spt(p, p->dev_coords[p->num_dev_coords-1].x); + ypos -= bpt2spt(p, p->dev_coords[p->num_dev_coords-1].y); } - graphics_mode(); + pdf_dev_graphics_mode(p); - format_buffer[len++] = ' '; - format_buffer[len++] = 'q'; - format_buffer[len++] = ' '; + p->format_buffer[len++] = ' '; + p->format_buffer[len++] = 'q'; + p->format_buffer[len++] = ' '; /* Don't use too thick line. */ - width_in_bp = ((width < height) ? width : height) * dev_unit.dvi2pts; + width_in_bp = ((width < height) ? width : height) * p->unit.dvi2pts; if (width_in_bp < 0.0 || /* Shouldn't happen */ width_in_bp > PDF_LINE_THICKNESS_MAX) { pdf_rect rect; - rect.llx = dev_unit.dvi2pts * xpos; - rect.lly = dev_unit.dvi2pts * ypos; - rect.urx = dev_unit.dvi2pts * width; - rect.ury = dev_unit.dvi2pts * height; - len += pdf_sprint_rect(format_buffer+len, &rect); - format_buffer[len++] = ' '; - format_buffer[len++] = 'r'; - format_buffer[len++] = 'e'; - format_buffer[len++] = ' '; - format_buffer[len++] = 'f'; + rect.llx = p->unit.dvi2pts * xpos; + rect.lly = p->unit.dvi2pts * ypos; + rect.urx = p->unit.dvi2pts * width; + rect.ury = p->unit.dvi2pts * height; + len += pdf_dev_sprint_rect(p, p->format_buffer+len, &rect); + p->format_buffer[len++] = ' '; + p->format_buffer[len++] = 'r'; + p->format_buffer[len++] = 'e'; + p->format_buffer[len++] = ' '; + p->format_buffer[len++] = 'f'; } else { if (width > height) { /* NOTE: @@ -1619,22 +1602,22 @@ pdf_dev_set_rule (spt_t xpos, spt_t ypos, spt_t width, spt_t height) * device resolution. See, PDF Reference Manual 4th ed., sec. 4.3.2, * "Details of Graphics State Parameters", p. 185. */ - if (height < dev_unit.min_bp_val) { + if (height < p->unit.min_bp_val) { WARN("Too thin line: height=%ld (%g bp)", height, width_in_bp); WARN("Please consider using \"-d\" option."); } - len += dev_sprint_line(format_buffer+len, + len += dev_sprint_line(p, p->format_buffer+len, height, xpos, ypos + height/2, xpos + width, ypos + height/2); } else { - if (width < dev_unit.min_bp_val) { + if (width < p->unit.min_bp_val) { WARN("Too thin line: width=%ld (%g bp)", width, width_in_bp); WARN("Please consider using \"-d\" option."); } - len += dev_sprint_line(format_buffer+len, + len += dev_sprint_line(p, p->format_buffer+len, width, xpos + width/2, ypos, @@ -1642,9 +1625,9 @@ pdf_dev_set_rule (spt_t xpos, spt_t ypos, spt_t width, spt_t height) ypos + height); } } - format_buffer[len++] = ' '; - format_buffer[len++] = 'Q'; - pdf_doc_add_page_content(format_buffer, len); /* op: q re f Q */ + p->format_buffer[len++] = ' '; + p->format_buffer[len++] = 'Q'; + dev_out(p, p->format_buffer, len); /* op: q re f Q */ } /* Rectangle in device space coordinate. */ @@ -1653,16 +1636,17 @@ pdf_dev_set_rect (pdf_rect *rect, spt_t x_user, spt_t y_user, spt_t width, spt_t height, spt_t depth) { + pdf_dev *p = current_device(); double dev_x, dev_y; pdf_coord p0, p1, p2, p3; double min_x, min_y, max_x, max_y; - dev_x = x_user * dev_unit.dvi2pts; - dev_y = y_user * dev_unit.dvi2pts; - if (text_state.dir_mode) { - p0.x = dev_x - dev_unit.dvi2pts * depth; - p0.y = dev_y - dev_unit.dvi2pts * width; - p1.x = dev_x + dev_unit.dvi2pts * height; + dev_x = x_user * p->unit.dvi2pts; + dev_y = y_user * p->unit.dvi2pts; + if (p->text_state.dir_mode) { + p0.x = dev_x - p->unit.dvi2pts * depth; + p0.y = dev_y - p->unit.dvi2pts * width; + p1.x = dev_x + p->unit.dvi2pts * height; p1.y = p0.y; p2.x = p1.x; p2.y = dev_y; @@ -1670,11 +1654,11 @@ pdf_dev_set_rect (pdf_rect *rect, p3.y = p2.y; } else { p0.x = dev_x; - p0.y = dev_y - dev_unit.dvi2pts * depth; - p1.x = dev_x + dev_unit.dvi2pts * width; + p0.y = dev_y - p->unit.dvi2pts * depth; + p1.x = dev_x + p->unit.dvi2pts * width; p1.y = p0.y; p2.x = p1.x; - p2.y = dev_y + dev_unit.dvi2pts * height; + p2.y = dev_y + p->unit.dvi2pts * height; p3.x = p0.x; p3.y = p2.y; } @@ -1711,20 +1695,22 @@ pdf_dev_set_rect (pdf_rect *rect, int pdf_dev_get_dirmode (void) { - return text_state.dir_mode; + pdf_dev *p = current_device(); + return p->text_state.dir_mode; } void pdf_dev_set_dirmode (int text_dir) { + pdf_dev *p = current_device(); struct dev_font *font; int text_rotate; int vert_dir, vert_font; - font = CURRENTFONT(); + font = CURRENTFONT(p); vert_font = (font && font->wmode) ? 1 : 0; - if (dev_param.autorotate) { + if (p->param.autorotate) { vert_dir = text_dir; } else { vert_dir = vert_font; @@ -1732,48 +1718,51 @@ pdf_dev_set_dirmode (int text_dir) text_rotate = (vert_font << 2)|vert_dir; if (font && - ANGLE_CHANGES(text_rotate, text_state.matrix.rotate)) { - text_state.force_reset = 1; + ANGLE_CHANGES(text_rotate, p->text_state.matrix.rotate)) { + p->text_state.force_reset = 1; } - text_state.matrix.rotate = text_rotate; - text_state.dir_mode = text_dir; + p->text_state.matrix.rotate = text_rotate; + p->text_state.dir_mode = text_dir; } static void -dev_set_param_autorotate (int auto_rotate) +dev_set_param_autorotate (pdf_dev *p, int auto_rotate) { struct dev_font *font; int text_rotate, vert_font, vert_dir; - font = CURRENTFONT(); + ASSERT(p); + + font = CURRENTFONT(p); vert_font = (font && font->wmode) ? 1 : 0; if (auto_rotate) { - vert_dir = text_state.dir_mode; + vert_dir = p->text_state.dir_mode; } else { vert_dir = vert_font; } text_rotate = (vert_font << 2)|vert_dir; - if (ANGLE_CHANGES(text_rotate, text_state.matrix.rotate)) { - text_state.force_reset = 1; + if (ANGLE_CHANGES(text_rotate, p->text_state.matrix.rotate)) { + p->text_state.force_reset = 1; } - text_state.matrix.rotate = text_rotate; - dev_param.autorotate = auto_rotate; + p->text_state.matrix.rotate = text_rotate; + p->param.autorotate = auto_rotate; } int pdf_dev_get_param (int param_type) { + pdf_dev *p = current_device(); int value = 0; switch (param_type) { case PDF_DEV_PARAM_AUTOROTATE: - value = dev_param.autorotate; + value = p->param.autorotate; break; case PDF_DEV_PARAM_COLORMODE: - value = dev_param.colormode; + value = p->param.colormode; break; default: ERROR("Unknown device parameter: %d", param_type); @@ -1785,12 +1774,14 @@ pdf_dev_get_param (int param_type) void pdf_dev_set_param (int param_type, int value) { + pdf_dev *p = current_device(); + switch (param_type) { case PDF_DEV_PARAM_AUTOROTATE: - dev_set_param_autorotate(value); + dev_set_param_autorotate(p, value); break; case PDF_DEV_PARAM_COLORMODE: - dev_param.colormode = value; /* 0 for B&W */ + p->param.colormode = value; /* 0 for B&W */ break; default: ERROR("Unknown device parameter: %d", param_type); @@ -1802,56 +1793,52 @@ pdf_dev_set_param (int param_type, int value) int pdf_dev_put_image (int id, - transform_info *p, + transform_info *ti, double ref_x, double ref_y) { + pdf_dev *p = current_device(); char *res_name; pdf_tmatrix M, M1; pdf_rect r; int len = 0; - if (num_dev_coords > 0) { - ref_x -= dev_coords[num_dev_coords-1].x; - ref_y -= dev_coords[num_dev_coords-1].y; + if (p->num_dev_coords > 0) { + ref_x -= p->dev_coords[p->num_dev_coords-1].x; + ref_y -= p->dev_coords[p->num_dev_coords-1].y; } - pdf_copymatrix(&M, &(p->matrix)); + pdf_copymatrix(&M, &(ti->matrix)); M.e += ref_x; M.f += ref_y; /* Just rotate by -90, but not tested yet. Any problem if M has scaling? */ - if (dev_param.autorotate && - text_state.dir_mode) { + if (p->param.autorotate && + p->text_state.dir_mode) { double tmp; tmp = -M.a; M.a = M.b; M.b = tmp; tmp = -M.c; M.c = M.d; M.d = tmp; } - graphics_mode(); + pdf_dev_graphics_mode(p); pdf_dev_gsave(); - pdf_ximage_scale_image(id, &M1, &r, p); + pdf_ximage_scale_image(id, &M1, &r, ti); pdf_concatmatrix(&M, &M1); pdf_dev_concat(&M); /* Clip */ - if (p->flags & INFO_DO_CLIP) { -#if 0 - pdf_dev_newpath(); - pdf_dev_moveto(r.llx, r.lly); - pdf_dev_lineto(r.urx, r.lly); - pdf_dev_lineto(r.urx, r.ury); - pdf_dev_lineto(r.llx, r.ury); - pdf_dev_closepath(); - pdf_dev_clip(); - pdf_dev_newpath(); -#else + if (ti->flags & INFO_DO_CLIP) { pdf_dev_rectclip(r.llx, r.lly, r.urx - r.llx, r.ury - r.lly); -#endif } res_name = pdf_ximage_get_resname(id); - len = sprintf(work_buffer, " /%s Do", res_name); - pdf_doc_add_page_content(work_buffer, len); /* op: Do */ + { + char *buf; + + buf = NEW(strlen(res_name)+6, char); + len = sprintf(buf, " /%s Do", res_name); + dev_out(p, buf, len); /* op: Do */ + RELEASE(buf); + } pdf_dev_grestore(); @@ -1861,19 +1848,19 @@ pdf_dev_put_image (int id, if (dvi_is_tracking_boxes()) { pdf_tmatrix P; - int i; - pdf_rect rect; - pdf_coord corner[4]; + int i; + pdf_rect rect; + pdf_coord corner[4]; pdf_dev_set_rect(&rect, 65536 * ref_x, 65536 * ref_y, - 65536 * (r.urx - r.llx), 65536 * (r.ury - r.lly), 0); + 65536 * (r.urx - r.llx), 65536 * (r.ury - r.lly), 0); corner[0].x = rect.llx; corner[0].y = rect.lly; corner[1].x = rect.llx; corner[1].y = rect.ury; corner[2].x = rect.urx; corner[2].y = rect.ury; corner[3].x = rect.urx; corner[3].y = rect.lly; - pdf_copymatrix(&P, &(p->matrix)); + pdf_copymatrix(&P, &(ti->matrix)); for (i = 0; i < 4; ++i) { corner[i].x -= rect.llx; corner[i].y -= rect.lly; @@ -1888,13 +1875,13 @@ pdf_dev_put_image (int id, rect.ury = corner[0].y; for (i = 0; i < 4; ++i) { if (corner[i].x < rect.llx) - rect.llx = corner[i].x; + rect.llx = corner[i].x; if (corner[i].x > rect.urx) - rect.urx = corner[i].x; + rect.urx = corner[i].x; if (corner[i].y < rect.lly) - rect.lly = corner[i].y; + rect.lly = corner[i].y; if (corner[i].y > rect.ury) - rect.ury = corner[i].y; + rect.ury = corner[i].y; } pdf_doc_expand_box(&rect); @@ -1903,7 +1890,6 @@ pdf_dev_put_image (int id, return 0; } - void transform_info_clear (transform_info *info) { @@ -1926,7 +1912,8 @@ transform_info_clear (transform_info *info) void pdf_dev_begin_actualtext (uint16_t *unicodes, int count) { - int len, i, pdf_doc_enc = 1; + pdf_dev *p = current_device(); + int len, i, pdf_doc_enc = 1; /* check whether we can use PDFDocEncoding for this string (we punt on the 0x80..0xA0 range that does not directly correspond to unicode) */ @@ -1937,41 +1924,144 @@ pdf_dev_begin_actualtext (uint16_t *unicodes, int count) } } - graphics_mode(); + pdf_dev_graphics_mode(p); - len = sprintf(work_buffer, "\n/Span< 0) { unsigned char s[2] = { *unicodes >> 8, *unicodes & 0xff }; + char buf[32]; i = pdf_doc_enc; /* if using PDFDocEncoding, we only care about the low 8 bits, so start with the second byte of our pair */ len = 0; for (; i < 2; i++) { unsigned char c = s[i]; if (c == '(' || c == ')' || c == '\\') { - len += sprintf(work_buffer + len, "\\%c", c); + len += sprintf(buf + len, "\\%c", c); } else if (c < ' ') { - len += sprintf(work_buffer + len, "\\%03o", c); + len += sprintf(buf + len, "\\%03o", c); } else { - len += sprintf(work_buffer + len, "%c", c); + len += sprintf(buf + len, "%c", c); } } - pdf_doc_add_page_content(work_buffer, len); + dev_out(p, buf, len); ++unicodes; } - len = sprintf(work_buffer, ")>>BDC"); - pdf_doc_add_page_content(work_buffer, len); + dev_out(p, ") >> BDC", 8); } void pdf_dev_end_actualtext (void) { - graphics_mode(); + pdf_dev *p = current_device(); + + pdf_dev_graphics_mode(p); + + dev_out(p, " EMC", 4); +} + +/* Compatibility functions.... For other files still using old interface */ +void +graphics_mode (void) +{ + pdf_dev *p = current_device(); + + pdf_dev_graphics_mode(p); +} + +double +dev_unit_dviunit (void) +{ + pdf_dev *p = current_device(); + return pdf_dev_unit_dviunit(p); +} + +int +pdf_sprint_matrix (char *buf, const pdf_tmatrix *M) +{ + pdf_dev *p = current_device(); + return (int) pdf_dev_sprint_matrix(p, buf, M); +} + +int +pdf_sprint_rect (char *buf, const pdf_rect *rect) +{ + pdf_dev *p = current_device(); + return (int) pdf_dev_sprint_rect(p, buf, rect); +} + +int +pdf_sprint_coord (char *buf, const pdf_coord *c) +{ + pdf_dev *p = current_device(); + return (int) pdf_dev_sprint_coord(p, buf, c); +} + +int +pdf_sprint_length (char *buf, double value) +{ + pdf_dev *p = current_device(); + return (int) pdf_dev_sprint_length(p, buf, value); +} + +int +pdf_sprint_number (char *buf, double value) +{ + pdf_dev *p = current_device(); + return (int) pdf_dev_sprint_number(p, buf, value); +} + +/* Access text state parameters. */ +int +pdf_dev_get_font_wmode (int font_id) +{ + pdf_dev *p = current_device(); + struct dev_font *font; + + font = GET_FONT(p, font_id); + if (font) { + return font->wmode; + } + + return 0; +} + +/* Saved text position compensation */ +void +pdf_dev_get_coord (double *xpos, double *ypos) +{ + pdf_dev *p = current_device(); + + if (p->num_dev_coords > 0) { + *xpos = p->dev_coords[p->num_dev_coords-1].x; + *ypos = p->dev_coords[p->num_dev_coords-1].y; + } else { + *xpos = *ypos = 0.0; + } +} + +void +pdf_dev_push_coord (double xpos, double ypos) +{ + pdf_dev *p = current_device(); + + if (p->num_dev_coords >= p->max_dev_coords) { + p->max_dev_coords += 4; + p->dev_coords = RENEW(p->dev_coords, p->max_dev_coords, pdf_coord); + } + p->dev_coords[p->num_dev_coords].x = xpos; + p->dev_coords[p->num_dev_coords].y = ypos; + p->num_dev_coords++; +} + +void +pdf_dev_pop_coord (void) +{ + pdf_dev *p = current_device(); - pdf_doc_add_page_content(" EMC", 4); + if (p->num_dev_coords > 0) + p->num_dev_coords--; } diff --git a/Build/source/texk/dvipdfm-x/pdfdev.h b/Build/source/texk/dvipdfm-x/pdfdev.h index 09124e2785f..f896be7850b 100644 --- a/Build/source/texk/dvipdfm-x/pdfdev.h +++ b/Build/source/texk/dvipdfm-x/pdfdev.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2020 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -27,6 +27,8 @@ #include "pdfobj.h" #include "pdfcolor.h" +typedef struct pdf_dev pdf_dev; + typedef int spt_t; typedef struct pdf_tmatrix @@ -89,39 +91,6 @@ extern void pdf_close_device (void); /* returns 1.0/unit_conv */ extern double dev_unit_dviunit (void); -#if 0 -/* DVI interpreter knows text positioning in relative motion. - * However, pdf_dev_set_string() recieves text string with placement - * in absolute position in user space, and it convert absolute - * positioning back to relative positioning. It is quite wasteful. - * - * TeX using DVI register stack operation to do CR and then use down - * command for LF. DVI interpreter knows hint for current leading - * and others (raised or lowered), but they are mostly lost in - * pdf_dev_set_string(). - */ - -typedef struct -{ - int argc; - - struct { - int is_kern; /* kern or string */ - - spt_t kern; /* negative kern means space */ - - int offset; /* offset to sbuf */ - int length; /* length of string */ - } args[]; - - unsigned char sbuf[PDF_STRING_LEN_MAX]; - -} pdf_text_string; - -/* Something for handling raise, leading, etc. here. */ - -#endif - /* Draw texts and rules: * * xpos, ypos, width, and height are all fixed-point numbers @@ -134,15 +103,12 @@ typedef struct * 2 - input string is in 16-bit encoding. */ extern void pdf_dev_set_string (spt_t xpos, spt_t ypos, - const void *instr_ptr, int instr_len, - spt_t text_width, - int font_id, int ctype); -extern void pdf_dev_set_rule (spt_t xpos, spt_t ypos, - spt_t width, spt_t height); + const void *instr_ptr, int instr_len, + spt_t text_width, int font_id, int ctype); +extern void pdf_dev_set_rule (spt_t xpos, spt_t ypos, spt_t width, spt_t height); /* Place XObject */ -extern int pdf_dev_put_image (int xobj_id, - transform_info *p, double ref_x, double ref_y); +extern int pdf_dev_put_image (int xobj_id, transform_info *p, double ref_x, double ref_y); /* The design_size and ptsize required by PK font support... */ @@ -151,18 +117,9 @@ extern int pdf_dev_locate_font (const char *font_name, spt_t ptsize); /* The following two routines are NOT WORKING. * Dvipdfmx doesn't manage gstate well.. */ -#if 0 -/* pdf_dev_translate() or pdf_dev_concat() should be used. */ -extern void pdf_dev_set_origin (double orig_x, double orig_y); -#endif -/* Always returns 1.0, please rename this. */ -extern double pdf_dev_scale (void); +#define pdf_dev_scale() (1.0) /* Access text state parameters. */ -#if 0 -extern int pdf_dev_currentfont (void); /* returns font_id */ -extern double pdf_dev_get_font_ptsize (int font_id); -#endif extern int pdf_dev_get_font_wmode (int font_id); /* ps: special support want this (pTeX). */ /* Text composition (direction) mode @@ -214,11 +171,11 @@ extern void pdf_dev_eop (void); */ extern void graphics_mode (void); -extern void pdf_dev_get_coord(double *xpos, double *ypos); -extern void pdf_dev_push_coord(double xpos, double ypos); -extern void pdf_dev_pop_coord(void); +extern void pdf_dev_get_coord (double *xpos, double *ypos); +extern void pdf_dev_push_coord (double xpos, double ypos); +extern void pdf_dev_pop_coord (void); extern void pdf_dev_begin_actualtext (uint16_t *unicodes, int len); -extern void pdf_dev_end_actualtext (void); +extern void pdf_dev_end_actualtext (void); #endif /* _PDFDEV_H_ */ diff --git a/Build/source/texk/dvipdfm-x/pdfdoc.c b/Build/source/texk/dvipdfm-x/pdfdoc.c index 98f8625cfd4..3da9f320c50 100644 --- a/Build/source/texk/dvipdfm-x/pdfdoc.c +++ b/Build/source/texk/dvipdfm-x/pdfdoc.c @@ -66,19 +66,6 @@ #define PDFDOC_ARTICLE_ALLOC_SIZE 16 #define PDFDOC_BEAD_ALLOC_SIZE 16 -static char manual_thumb_enabled = 0; -static char *thumb_basename = NULL; - -void -pdf_doc_enable_manual_thumbnails (void) -{ -#if HAVE_LIBPNG - manual_thumb_enabled = 1; -#else - WARN("Manual thumbnail is not supported without the libpng library."); -#endif -} - static pdf_obj * read_thumbnail (const char *thumb_filename) { @@ -234,10 +221,12 @@ typedef struct pdf_doc struct { int outline_open_depth; double annot_grow; - } opt; + int enable_manual_thumb; + } options; struct form_list_node *pending_forms; + char *thumb_basename; } pdf_doc; static pdf_doc pdoc; @@ -1257,7 +1246,7 @@ pdf_doc_init_bookmarks (pdf_doc *p, int bm_open_depth) pdf_olitem *item; #define MAX_OUTLINE_DEPTH 256u - p->opt.outline_open_depth = + p->options.outline_open_depth = ((bm_open_depth >= 0) ? bm_open_depth : MAX_OUTLINE_DEPTH - bm_open_depth); @@ -1470,7 +1459,7 @@ pdf_doc_bookmarks_add (pdf_obj *dict, int is_open) item = item->next; } -#define BMOPEN(b,p) (((b) < 0) ? (((p)->outlines.current_depth > (p)->opt.outline_open_depth) ? 0 : 1) : (b)) +#define BMOPEN(b,p) (((b) < 0) ? (((p)->outlines.current_depth > (p)->options.outline_open_depth) ? 0 : 1) : (b)) #if 0 item->dict = pdf_link_obj(dict); @@ -2381,13 +2370,13 @@ pdf_doc_finish_page (pdf_doc *p) currentpage->resources = NULL; } - if (manual_thumb_enabled) { + if (p->options.enable_manual_thumb) { char *thumb_filename; pdf_obj *thumb_ref; - thumb_filename = NEW(strlen(thumb_basename)+7, char); + thumb_filename = NEW(strlen(p->thumb_basename)+7, char); sprintf(thumb_filename, "%s.%ld", - thumb_basename, (p->pages.num_entries % 99999) + 1L); + p->thumb_basename, (p->pages.num_entries % 99999) + 1L); thumb_ref = read_thumbnail(thumb_filename); RELEASE(thumb_filename); if (thumb_ref) @@ -2494,22 +2483,29 @@ pdf_doc_add_page_content (const char *buffer, unsigned length) void pdf_open_document (const char *filename, - const char *creator, const unsigned char *id1, const unsigned char *id2, + const char *creator, + const unsigned char *id1, const unsigned char *id2, struct pdf_setting settings) { pdf_doc *p = &pdoc; - if (settings.enable_encrypt) - pdf_init_encryption(settings.encrypt, id1); - - pdf_out_init(filename, settings.enable_encrypt, + pdf_out_init(filename, id1, id2, + settings.ver_major, settings.ver_minor, settings.object.compression_level, + settings.enable_encrypt, settings.object.enable_objstm, settings.object.enable_predictor); pdf_files_init(); pdf_doc_init_catalog(p); - p->opt.annot_grow = settings.annot_grow_amount; - p->opt.outline_open_depth = settings.outline_open_depth; + /* After Catalog is created... */ + if (settings.enable_encrypt) { + pdf_out_set_encrypt(settings.encrypt.key_size, settings.encrypt.permission, + settings.encrypt.oplain, settings.encrypt.uplain, + 1, 1); + } + + p->options.annot_grow = settings.annot_grow_amount; + p->options.outline_open_depth = settings.outline_open_depth; pdf_init_resources(); pdf_init_colors(); @@ -2531,30 +2527,18 @@ pdf_open_document (const char *filename, pdf_doc_set_bgcolor(NULL); - if (settings.enable_encrypt) { - pdf_obj *encrypt = pdf_encrypt_obj(); - pdf_set_encrypt(encrypt); - pdf_release_obj(encrypt); - } - if (id1 && id2) { - pdf_obj *id_obj = pdf_new_array(); - - pdf_add_array(id_obj, pdf_new_string(id1, 16)); - pdf_add_array(id_obj, pdf_new_string(id2, 16)); - pdf_set_id(id_obj); - } - + p->options.enable_manual_thumb = settings.enable_manual_thumb; /* Create a default name for thumbnail image files */ - if (manual_thumb_enabled) { + if (p->options.enable_manual_thumb) { if (strlen(filename) > 4 && !strncmp(".pdf", filename + strlen(filename) - 4, 4)) { size_t len = strlen(filename) - strlen(".pdf"); - thumb_basename = NEW(len+1, char); - strncpy(thumb_basename, filename, len); - thumb_basename[len] = 0; + p->thumb_basename = NEW(len+1, char); + strncpy(p->thumb_basename, filename, len); + p->thumb_basename[len] = 0; } else { - thumb_basename = NEW(strlen(filename)+1, char); - strcpy(thumb_basename, filename); + p->thumb_basename = NEW(strlen(filename)+1, char); + strcpy(p->thumb_basename, filename); } } @@ -2598,8 +2582,8 @@ pdf_close_document (void) pdf_files_close(); pdf_out_flush(); - if (thumb_basename) - RELEASE(thumb_basename); + if (p->thumb_basename) + RELEASE(p->thumb_basename); return; } @@ -2817,7 +2801,7 @@ void pdf_doc_break_annot (void) { pdf_doc *p = &pdoc; - double g = p->opt.annot_grow; + double g = p->options.annot_grow; if (breaking_state.dirty) { pdf_obj *annot_dict, *annot_copy; diff --git a/Build/source/texk/dvipdfm-x/pdfdoc.h b/Build/source/texk/dvipdfm-x/pdfdoc.h index 855563d2d1c..2fbb0f8ae87 100644 --- a/Build/source/texk/dvipdfm-x/pdfdoc.h +++ b/Build/source/texk/dvipdfm-x/pdfdoc.h @@ -55,14 +55,17 @@ struct pdf_enc_setting { struct pdf_obj_setting { int enable_objstm; int enable_predictor; + int compression_level; }; struct pdf_setting { + int ver_major, ver_minor; double media_width, media_height; double annot_grow_amount; int outline_open_depth; int check_gotos; + int enable_manual_thumb; int enable_encrypt; struct pdf_enc_setting encrypt; struct pdf_dev_setting device; @@ -71,7 +74,8 @@ struct pdf_setting extern void pdf_open_document (const char *filename, const char *creator, - const unsigned char *id1, const unsigned char *id2, + const unsigned char *id1, + const unsigned char *id2, struct pdf_setting settings); extern void pdf_close_document(void); diff --git a/Build/source/texk/dvipdfm-x/pdfencrypt.c b/Build/source/texk/dvipdfm-x/pdfencrypt.c index a1c02561da4..524181b084f 100644 --- a/Build/source/texk/dvipdfm-x/pdfencrypt.c +++ b/Build/source/texk/dvipdfm-x/pdfencrypt.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2020 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -45,20 +45,13 @@ * TODO: Convert password to PDFDocEncoding. SASLPrep stringpref for AESV3. */ -static void pdf_enc_set_passwd (unsigned int bits, unsigned int perm, - const char *oplain, const char *uplain); -/* PDF-2.0 is not published yet. */ #define USE_ADOBE_EXTENSION 1 -#ifdef USE_ADOBE_EXTENSION -#include "pdfdoc.h" -#endif - #include "dvipdfmx.h" #include "pdfencrypt.h" -static struct pdf_sec { +struct pdf_sec { unsigned char key[32]; int key_size; @@ -78,7 +71,10 @@ static struct pdf_sec { uint64_t objnum; uint16_t gennum; } label; -} sec_data; +}; + +static void pdf_enc_set_password (pdf_sec *p_sec, unsigned int bits, unsigned int perm, + const char *oplain, const char *uplain); static const unsigned char padding_bytes[32] = { 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, @@ -87,29 +83,38 @@ static const unsigned char padding_bytes[32] = { 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a }; -int -pdf_init_encryption (struct pdf_enc_setting settings, const unsigned char *trailer_id) +pdf_sec * +pdf_enc_init (const unsigned char *id, + int keybits, uint32_t permission, + const char *opasswd, const char *upasswd, + int use_aes, int encrypt_metadata) { - time_t current_time; - struct pdf_sec *p = &sec_data; + time_t current_time; + pdf_sec *p_sec; - if (trailer_id) { - memcpy(p->ID, trailer_id, 16); - } else { - memset(p->ID, 0, 16); - } + p_sec = NEW(1, pdf_sec); + memset(p_sec, 0, sizeof(pdf_sec)); current_time = dpx_util_get_unique_time_if_given(); if (current_time == INVALID_EPOCH_VALUE) current_time = time(NULL); srand(current_time); /* For AES IV */ - p->setting.use_aes = settings.use_aes; - p->setting.encrypt_metadata = settings.encrypt_metadata; - p->setting.need_adobe_extension = 0; + p_sec->setting.use_aes = use_aes; + p_sec->setting.encrypt_metadata = encrypt_metadata; + p_sec->setting.need_adobe_extension = 0; + + memcpy(p_sec->ID, id, 16); + pdf_enc_set_password(p_sec, keybits, permission, opasswd, upasswd); - pdf_enc_set_passwd(settings.key_size, settings.permission, - settings.oplain, settings.uplain); + return p_sec; +} - return 0; +void +pdf_enc_close (pdf_sec **p_sec) +{ + if (p_sec && *p_sec) { + RELEASE(*p_sec); + *p_sec = NULL; + } } static void @@ -124,10 +129,10 @@ passwd_padding (const char *src, unsigned char *dst) } static void -compute_owner_password (struct pdf_sec *p, +compute_owner_password (pdf_sec *p_sec, const char *opasswd, const char *upasswd) { - int i, j; + int i, j; unsigned char padded[32]; MD5_CONTEXT md5; ARC4_CONTEXT arc4; @@ -138,39 +143,39 @@ compute_owner_password (struct pdf_sec *p, MD5_init (&md5); MD5_write(&md5, padded, 32); MD5_final(hash, &md5); - if (p->R >= 3) { + if (p_sec->R >= 3) { for (i = 0; i < 50; i++) { /* * NOTE: We truncate each MD5 hash as in the following step. * Otherwise Adobe Reader won't decrypt the PDF file. */ MD5_init (&md5); - MD5_write(&md5, hash, p->key_size); + MD5_write(&md5, hash, p_sec->key_size); MD5_final(hash, &md5); } } - ARC4_set_key(&arc4, p->key_size, hash); + ARC4_set_key(&arc4, p_sec->key_size, hash); passwd_padding(upasswd, padded); { unsigned char tmp1[32], tmp2[32]; unsigned char key[16]; ARC4(&arc4, 32, padded, tmp1); - if (p->R >= 3) { + if (p_sec->R >= 3) { for (i = 1; i <= 19; i++) { memcpy(tmp2, tmp1, 32); - for (j = 0; j < p->key_size; j++) + for (j = 0; j < p_sec->key_size; j++) key[j] = hash[j] ^ i; - ARC4_set_key(&arc4, p->key_size, key); + ARC4_set_key(&arc4, p_sec->key_size, key); ARC4(&arc4, 32, tmp2, tmp1); } } - memcpy(p->O, tmp1, 32); + memcpy(p_sec->O, tmp1, 32); } } static void -compute_encryption_key (struct pdf_sec *p, const char *passwd) +compute_encryption_key (pdf_sec *p_sec, const char *passwd) { int i; unsigned char hash[32], padded[32]; @@ -179,53 +184,53 @@ compute_encryption_key (struct pdf_sec *p, const char *passwd) passwd_padding(passwd, padded); MD5_init (&md5); MD5_write(&md5, padded, 32); - MD5_write(&md5, p->O, 32); + MD5_write(&md5, p_sec->O, 32); { unsigned char tmp[4]; - tmp[0] = (unsigned char)(p->P) & 0xFF; - tmp[1] = (unsigned char)(p->P >> 8) & 0xFF; - tmp[2] = (unsigned char)(p->P >> 16) & 0xFF; - tmp[3] = (unsigned char)(p->P >> 24) & 0xFF; + tmp[0] = (unsigned char)(p_sec->P) & 0xFF; + tmp[1] = (unsigned char)(p_sec->P >> 8) & 0xFF; + tmp[2] = (unsigned char)(p_sec->P >> 16) & 0xFF; + tmp[3] = (unsigned char)(p_sec->P >> 24) & 0xFF; MD5_write(&md5, tmp, 4); } - MD5_write(&md5, p->ID, 16); + MD5_write(&md5, p_sec->ID, 16); #if 0 /* Not Supported Yet */ - if (!p->setting.encrypt_metadata) { + if (!p_sec->setting.encrypt_metadata) { unsigned char tmp[4] = {0xff, 0xff, 0xff, 0xff}; MD5_write(&md5, tmp, 4); } #endif MD5_final(hash, &md5); - if (p->R >= 3) { + if (p_sec->R >= 3) { for (i = 0; i < 50; i++) { /* * NOTE: We truncate each MD5 hash as in the following step. * Otherwise Adobe Reader won't decrypt the PDF file. */ MD5_init (&md5); - MD5_write(&md5, hash, p->key_size); + MD5_write(&md5, hash, p_sec->key_size); MD5_final(hash, &md5); } } - memcpy(p->key, hash, p->key_size); + memcpy(p_sec->key, hash, p_sec->key_size); } static void -compute_user_password (struct pdf_sec *p, const char *uplain) +compute_user_password (pdf_sec *p_sec, const char *uplain) { int i, j; ARC4_CONTEXT arc4; MD5_CONTEXT md5; unsigned char upasswd[32]; - compute_encryption_key(p, uplain); + compute_encryption_key(p_sec, uplain); - switch (p->R) { + switch (p_sec->R) { case 2: - ARC4_set_key(&arc4, p->key_size, p->key); + ARC4_set_key(&arc4, p_sec->key_size, p_sec->key); ARC4(&arc4, 32, padding_bytes, upasswd); break; case 3: case 4: @@ -236,19 +241,19 @@ compute_user_password (struct pdf_sec *p, const char *uplain) MD5_init (&md5); MD5_write(&md5, padding_bytes, 32); - MD5_write(&md5, p->ID, 16); + MD5_write(&md5, p_sec->ID, 16); MD5_final(hash, &md5); - ARC4_set_key(&arc4, p->key_size, p->key); + ARC4_set_key(&arc4, p_sec->key_size, p_sec->key); ARC4(&arc4, 16, hash, tmp1); - for (i = 1; i <= 19; i++) { + for (i = 1; i <= 19; i++) { unsigned char key[16]; memcpy(tmp2, tmp1, 16); - for (j = 0; j < p->key_size; j++) - key[j] = p->key[j] ^ i; - ARC4_set_key(&arc4, p->key_size, key); + for (j = 0; j < p_sec->key_size; j++) + key[j] = p_sec->key[j] ^ i; + ARC4_set_key(&arc4, p_sec->key_size, key); ARC4(&arc4, 16, tmp2, tmp1); } memcpy(upasswd, tmp1, 32); @@ -258,7 +263,7 @@ compute_user_password (struct pdf_sec *p, const char *uplain) ERROR("Invalid revision number."); } - memcpy(p->U, upasswd, 32); + memcpy(p_sec->U, upasswd, 32); } /* Algorithm 2.B from ISO 32000-1 chapter 7 */ @@ -352,7 +357,7 @@ compute_hash_V5 (unsigned char *hash, } static void -compute_owner_password_V5 (struct pdf_sec *p, const char *oplain) +compute_owner_password_V5 (pdf_sec *p_sec, const char *oplain) { unsigned char vsalt[8], ksalt[8], hash[32]; unsigned char *OE, iv[AES_BLOCKSIZE]; @@ -364,20 +369,20 @@ compute_owner_password_V5 (struct pdf_sec *p, const char *oplain) ksalt[i] = rand() % 256; } - compute_hash_V5(hash, oplain, vsalt, p->U, p->R); - memcpy(p->O, hash, 32); - memcpy(p->O + 32, vsalt, 8); - memcpy(p->O + 40, ksalt, 8); + compute_hash_V5(hash, oplain, vsalt, p_sec->U, p_sec->R); + memcpy(p_sec->O, hash, 32); + memcpy(p_sec->O + 32, vsalt, 8); + memcpy(p_sec->O + 40, ksalt, 8); - compute_hash_V5(hash, oplain, ksalt, p->U, p->R); + compute_hash_V5(hash, oplain, ksalt, p_sec->U, p_sec->R); memset(iv, 0, AES_BLOCKSIZE); - AES_cbc_encrypt(hash, 32, iv, 0, p->key, p->key_size, &OE, &OE_len); - memcpy(p->OE, OE, 32); + AES_cbc_encrypt(hash, 32, iv, 0, p_sec->key, p_sec->key_size, &OE, &OE_len); + memcpy(p_sec->OE, OE, 32); RELEASE(OE); } static void -compute_user_password_V5 (struct pdf_sec *p, const char *uplain) +compute_user_password_V5 (pdf_sec *p_sec, const char *uplain) { unsigned char vsalt[8], ksalt[8], hash[32]; unsigned char *UE, iv[AES_BLOCKSIZE]; @@ -389,36 +394,36 @@ compute_user_password_V5 (struct pdf_sec *p, const char *uplain) ksalt[i] = rand() % 256; } - compute_hash_V5(hash, uplain, vsalt, NULL, p->R); - memcpy(p->U, hash, 32); - memcpy(p->U + 32, vsalt, 8); - memcpy(p->U + 40, ksalt, 8); + compute_hash_V5(hash, uplain, vsalt, NULL, p_sec->R); + memcpy(p_sec->U, hash, 32); + memcpy(p_sec->U + 32, vsalt, 8); + memcpy(p_sec->U + 40, ksalt, 8); - compute_hash_V5(hash, uplain, ksalt, NULL, p->R); + compute_hash_V5(hash, uplain, ksalt, NULL, p_sec->R); memset(iv, 0, AES_BLOCKSIZE); - AES_cbc_encrypt(hash, 32, iv, 0, p->key, p->key_size, &UE, &UE_len); - memcpy(p->UE, UE, 32); + AES_cbc_encrypt(hash, 32, iv, 0, p_sec->key, p_sec->key_size, &UE, &UE_len); + memcpy(p_sec->UE, UE, 32); RELEASE(UE); } static void -check_version (struct pdf_sec *p, int version) +check_version (pdf_sec *p_sec, int version) { - if (p->V > 2 && version < 14) { + if (p_sec->V > 2 && version < 14) { WARN("Current encryption setting requires PDF version >= 1.4."); - p->V = 1; - p->key_size = 5; - } else if (p->V == 4 && version < 15) { + p_sec->V = 1; + p_sec->key_size = 5; + } else if (p_sec->V == 4 && version < 15) { WARN("Current encryption setting requires PDF version >= 1.5."); - p->V = 2; - } else if (p->V ==5 && version < 17) { + p_sec->V = 2; + } else if (p_sec->V ==5 && version < 17) { WARN("Current encryption setting requires PDF version >= 1.7" \ " (plus Adobe Extension Level 3)."); - p->V = 4; - p->key_size = 16; + p_sec->V = 4; + p_sec->key_size = 16; } - if (p->V == 5 && version < 20) { - p->setting.need_adobe_extension = 1; + if (p_sec->V == 5 && version < 20) { + p_sec->setting.need_adobe_extension = 1; } } @@ -493,54 +498,55 @@ preproc_password (const char *passwd, char *outbuf, int V) } static void -pdf_enc_set_passwd (unsigned int bits, unsigned int perm, - const char *oplain, const char *uplain) +pdf_enc_set_password (pdf_sec *p_sec, unsigned int bits, unsigned int perm, + const char *oplain, const char *uplain) { - struct pdf_sec *p = &sec_data; - char opasswd[128], upasswd[128]; - int version; - char empty_passwd[1] = "\0"; + char opasswd[128], upasswd[128]; + int version; + char empty_passwd[1] = "\0"; version = pdf_get_version(); - p->key_size = (int) (bits / 8); - if (p->key_size == 5) /* 40bit */ - p->V = 1; - else if (p->key_size <= 16) { - p->V = p->setting.use_aes ? 4 : 2; - } else if (p->key_size == 32) { - p->V = 5; + p_sec->key_size = (int) (bits / 8); + if (p_sec->key_size == 5) { /* 40bit */ + p_sec->V = 1; + } else if (p_sec->key_size < 16) { + p_sec->V = 2; + } else if (p_sec->key_size == 16) { + p_sec->V = p_sec->setting.use_aes ? 4 : 2; + } else if (p_sec->key_size == 32) { + p_sec->V = 5; } else { WARN("Key length %d unsupported.", bits); - p->key_size = 5; - p->V = 2; + p_sec->key_size = 5; + p_sec->V = 2; } - check_version(p, version); + check_version(p_sec, version); - p->P = (int32_t) (perm | 0xC0U); + p_sec->P = (int32_t) (perm | 0xC0U); /* Bit position 10 shall be always set to 1 for PDF >= 2.0. */ if (version >= 20) - p->P |= (1 << 9); - switch (p->V) { + p_sec->P |= (1 << 9); + switch (p_sec->V) { case 1: - p->R = (p->P < 0x100L) ? 2 : 3; + p_sec->R = (p_sec->P < 0x100L) ? 2 : 3; break; case 2: case 3: - p->R = 3; + p_sec->R = 3; break; case 4: - p->R = 4; + p_sec->R = 4; break; case 5: #if USE_ADOBE_EXTENSION - p->R = 6; + p_sec->R = 6; #else WARN("Encryption V 5 unsupported."); - p->R = 4; p->V = 4; + p_sec->R = 4; p_sec->V = 4; #endif break; default: - p->R = 3; + p_sec->R = 3; break; } @@ -548,54 +554,54 @@ pdf_enc_set_passwd (unsigned int bits, unsigned int perm, memset(upasswd, 0, 128); /* Password must be preprocessed. */ if (oplain) { - if (preproc_password(oplain, opasswd, p->V) < 0) + if (preproc_password(oplain, opasswd, p_sec->V) < 0) WARN("Invaid UTF-8 string for password."); } else { - preproc_password(empty_passwd, opasswd, p->V); + preproc_password(empty_passwd, opasswd, p_sec->V); } if (uplain) { - if (preproc_password(uplain, upasswd, p->V) < 0) + if (preproc_password(uplain, upasswd, p_sec->V) < 0) WARN("Invalid UTF-8 string for passowrd."); } else { - preproc_password(empty_passwd, upasswd, p->V); + preproc_password(empty_passwd, upasswd, p_sec->V); } - if (p->R >= 3) - p->P |= 0xFFFFF000U; + if (p_sec->R >= 3) + p_sec->P |= 0xFFFFF000U; - if (p->V < 5) { - compute_owner_password(p, opasswd, upasswd); - compute_user_password (p, upasswd); - } else if (p->V == 5) { + if (p_sec->V < 5) { + compute_owner_password(p_sec, opasswd, upasswd); + compute_user_password (p_sec, upasswd); + } else if (p_sec->V == 5) { int i; for (i = 0; i < 32; i++) - p->key[i] = rand() % 256; - p->key_size = 32; + p_sec->key[i] = rand() % 256; + p_sec->key_size = 32; /* Order is important here */ - compute_user_password_V5 (p, upasswd); - compute_owner_password_V5(p, opasswd); /* uses p->U */ + compute_user_password_V5 (p_sec, upasswd); + compute_owner_password_V5(p_sec, opasswd); /* uses p_sec->U */ } } static void -calculate_key (struct pdf_sec *p, unsigned char *key) +calculate_key (pdf_sec *p_sec, unsigned char *key) { - int len = p->key_size + 5; + int len = p_sec->key_size + 5; unsigned char tmp[25]; MD5_CONTEXT md5; - memcpy(tmp, p->key, p->key_size); - tmp[p->key_size ] = (unsigned char) p->label.objnum & 0xFF; - tmp[p->key_size+1] = (unsigned char)(p->label.objnum >> 8) & 0xFF; - tmp[p->key_size+2] = (unsigned char)(p->label.objnum >> 16) & 0xFF; - tmp[p->key_size+3] = (unsigned char)(p->label.gennum) & 0xFF; - tmp[p->key_size+4] = (unsigned char)(p->label.gennum >> 8) & 0xFF; - if (p->V >= 4) { - tmp[p->key_size + 5] = 0x73; - tmp[p->key_size + 6] = 0x41; - tmp[p->key_size + 7] = 0x6c; - tmp[p->key_size + 8] = 0x54; + memcpy(tmp, p_sec->key, p_sec->key_size); + tmp[p_sec->key_size ] = (unsigned char) p_sec->label.objnum & 0xFF; + tmp[p_sec->key_size+1] = (unsigned char)(p_sec->label.objnum >> 8) & 0xFF; + tmp[p_sec->key_size+2] = (unsigned char)(p_sec->label.objnum >> 16) & 0xFF; + tmp[p_sec->key_size+3] = (unsigned char)(p_sec->label.gennum) & 0xFF; + tmp[p_sec->key_size+4] = (unsigned char)(p_sec->label.gennum >> 8) & 0xFF; + if (p_sec->V >= 4) { + tmp[p_sec->key_size + 5] = 0x73; + tmp[p_sec->key_size + 6] = 0x41; + tmp[p_sec->key_size + 7] = 0x6c; + tmp[p_sec->key_size + 8] = 0x54; len += 4; } MD5_init (&md5); @@ -604,49 +610,52 @@ calculate_key (struct pdf_sec *p, unsigned char *key) } void -pdf_encrypt_data (const unsigned char *plain, size_t plain_len, +pdf_encrypt_data (pdf_sec *p_sec, + const unsigned char *plain, size_t plain_len, unsigned char **cipher, size_t *cipher_len) { - struct pdf_sec *p = &sec_data; - unsigned char key[32]; + unsigned char key[32]; + + ASSERT(p_sec); - switch (p->V) { + switch (p_sec->V) { case 1: case 2: - calculate_key(p, key); + calculate_key(p_sec, key); { ARC4_CONTEXT arc4; *cipher_len = plain_len; *cipher = NEW(*cipher_len, unsigned char); - ARC4_set_key(&arc4, MIN(16, p->key_size + 5), key); + ARC4_set_key(&arc4, MIN(16, p_sec->key_size + 5), key); ARC4(&arc4, plain_len, plain, *cipher); } break; case 4: - calculate_key(p, key); - AES_cbc_encrypt(key, MIN(16, p->key_size + 5), NULL, 1, + calculate_key(p_sec, key); + AES_cbc_encrypt(key, MIN(16, p_sec->key_size + 5), NULL, 1, plain, plain_len, cipher, cipher_len); break; case 5: - AES_cbc_encrypt(p->key, p->key_size, NULL, 1, + AES_cbc_encrypt(p_sec->key, p_sec->key_size, NULL, 1, plain, plain_len, cipher, cipher_len); break; default: - ERROR("pdfencrypt: Unexpected V value: %d", p->V); + ERROR("pdfencrypt: Unexpected V value: %d", p_sec->V); break; } } pdf_obj * -pdf_encrypt_obj (void) +pdf_enc_get_encrypt_dict (pdf_sec *p_sec) { - struct pdf_sec *p = &sec_data; pdf_obj *doc_encrypt; + ASSERT(p_sec); + doc_encrypt = pdf_new_dict(); pdf_add_dict(doc_encrypt, pdf_new_name("Filter"), pdf_new_name("Standard")); - pdf_add_dict(doc_encrypt, pdf_new_name("V"), pdf_new_number(p->V)); + pdf_add_dict(doc_encrypt, pdf_new_name("V"), pdf_new_number(p_sec->V)); #if 0 /* PDF reference describes it as: * @@ -654,54 +663,54 @@ pdf_encrypt_obj (void) * * but Acrobat *requires* this even for V 5! */ - if (p->V > 1 && p->V < 4) + if (p_sec->V > 1 && p_sec->V < 4) #endif pdf_add_dict(doc_encrypt, - pdf_new_name("Length"), pdf_new_number(p->key_size * 8)); - if (p->V >= 4) { + pdf_new_name("Length"), pdf_new_number(p_sec->key_size * 8)); + if (p_sec->V >= 4) { pdf_obj *CF, *StdCF; CF = pdf_new_dict(); StdCF = pdf_new_dict(); pdf_add_dict(StdCF, pdf_new_name("CFM"), - pdf_new_name( (p->V == 4) ? "AESV2" : "AESV3" )); + pdf_new_name( (p_sec->V == 4) ? "AESV2" : "AESV3" )); pdf_add_dict(StdCF, pdf_new_name("AuthEvent"), pdf_new_name("DocOpen")); - pdf_add_dict(StdCF, pdf_new_name("Length"), pdf_new_number(p->key_size)); + pdf_add_dict(StdCF, pdf_new_name("Length"), pdf_new_number(p_sec->key_size)); pdf_add_dict(CF, pdf_new_name("StdCF"), StdCF); pdf_add_dict(doc_encrypt, pdf_new_name("CF"), CF); pdf_add_dict(doc_encrypt, pdf_new_name("StmF"), pdf_new_name("StdCF")); pdf_add_dict(doc_encrypt, pdf_new_name("StrF"), pdf_new_name("StdCF")); #if 0 /* NOT SUPPORTED YET */ - if (!p->setting.encrypt_metadata) + if (!p_sec->setting.encrypt_metadata) pdf_add_dict(doc_encrypt, pdf_new_name("EncryptMetadata"), pdf_new_boolean(false)); #endif } - pdf_add_dict(doc_encrypt, pdf_new_name("R"), pdf_new_number(p->R)); - if (p->V < 5) { - pdf_add_dict(doc_encrypt, pdf_new_name("O"), pdf_new_string(p->O, 32)); - pdf_add_dict(doc_encrypt, pdf_new_name("U"), pdf_new_string(p->U, 32)); - } else if (p->V == 5) { - pdf_add_dict(doc_encrypt, pdf_new_name("O"), pdf_new_string(p->O, 48)); - pdf_add_dict(doc_encrypt, pdf_new_name("U"), pdf_new_string(p->U, 48)); + pdf_add_dict(doc_encrypt, pdf_new_name("R"), pdf_new_number(p_sec->R)); + if (p_sec->V < 5) { + pdf_add_dict(doc_encrypt, pdf_new_name("O"), pdf_new_string(p_sec->O, 32)); + pdf_add_dict(doc_encrypt, pdf_new_name("U"), pdf_new_string(p_sec->U, 32)); + } else if (p_sec->V == 5) { + pdf_add_dict(doc_encrypt, pdf_new_name("O"), pdf_new_string(p_sec->O, 48)); + pdf_add_dict(doc_encrypt, pdf_new_name("U"), pdf_new_string(p_sec->U, 48)); } - pdf_add_dict(doc_encrypt, pdf_new_name("P"), pdf_new_number(p->P)); + pdf_add_dict(doc_encrypt, pdf_new_name("P"), pdf_new_number(p_sec->P)); - if (p->V == 5) { + if (p_sec->V == 5) { unsigned char perms[16], *cipher = NULL; size_t cipher_len = 0; - pdf_add_dict(doc_encrypt, pdf_new_name("OE"), pdf_new_string(p->OE, 32)); - pdf_add_dict(doc_encrypt, pdf_new_name("UE"), pdf_new_string(p->UE, 32)); - perms[0] = p->P & 0xff; - perms[1] = (p->P >> 8) & 0xff; - perms[2] = (p->P >> 16) & 0xff; - perms[3] = (p->P >> 24) & 0xff; + pdf_add_dict(doc_encrypt, pdf_new_name("OE"), pdf_new_string(p_sec->OE, 32)); + pdf_add_dict(doc_encrypt, pdf_new_name("UE"), pdf_new_string(p_sec->UE, 32)); + perms[0] = p_sec->P & 0xff; + perms[1] = (p_sec->P >> 8) & 0xff; + perms[2] = (p_sec->P >> 16) & 0xff; + perms[3] = (p_sec->P >> 24) & 0xff; perms[4] = 0xff; perms[5] = 0xff; perms[6] = 0xff; perms[7] = 0xff; - perms[8] = p->setting.encrypt_metadata ? 'T' : 'F'; + perms[8] = p_sec->setting.encrypt_metadata ? 'T' : 'F'; perms[9] = 'a'; perms[10] = 'd'; perms[11] = 'b'; @@ -709,39 +718,47 @@ pdf_encrypt_obj (void) perms[13] = 0; perms[14] = 0; perms[15] = 0; - AES_ecb_encrypt(p->key, p->key_size, perms, 16, &cipher, &cipher_len); + AES_ecb_encrypt(p_sec->key, p_sec->key_size, perms, 16, &cipher, &cipher_len); pdf_add_dict(doc_encrypt, pdf_new_name("Perms"), pdf_new_string(cipher, cipher_len)); RELEASE(cipher); } + + return doc_encrypt; +} + +pdf_obj * +pdf_enc_get_extension_dict (pdf_sec *p_sec) +{ + pdf_obj *ext = NULL, *adbe; + + ASSERT(p_sec); #ifdef USE_ADOBE_EXTENSION - if (p->R > 5 && p->setting.need_adobe_extension != 0) { - pdf_obj *catalog = pdf_doc_catalog(); - pdf_obj *ext = pdf_new_dict(); - pdf_obj *adbe = pdf_new_dict(); + if (p_sec->setting.need_adobe_extension) { + ext = pdf_new_dict(); + adbe = pdf_new_dict(); pdf_add_dict(adbe, pdf_new_name("BaseVersion"), pdf_new_name("1.7")); pdf_add_dict(adbe, pdf_new_name("ExtensionLevel"), - pdf_new_number(p->R == 5 ? 3 : 8)); + pdf_new_number(p_sec->R == 5 ? 3 : 8)); pdf_add_dict(ext, pdf_new_name("ADBE"), adbe); - pdf_add_dict(catalog, pdf_new_name("Extensions"), ext); } #endif - return doc_encrypt; + return ext; } -void pdf_enc_set_label (unsigned label) +void pdf_enc_set_label (pdf_sec *p_sec, unsigned label) { - struct pdf_sec *p = &sec_data; + ASSERT(p_sec); - p->label.objnum = label; + p_sec->label.objnum = label; } -void pdf_enc_set_generation (unsigned generation) +void pdf_enc_set_generation (pdf_sec *p_sec, unsigned generation) { - struct pdf_sec *p = &sec_data; + ASSERT(p_sec); - p->label.gennum = generation; + p_sec->label.gennum = generation; } diff --git a/Build/source/texk/dvipdfm-x/pdfencrypt.h b/Build/source/texk/dvipdfm-x/pdfencrypt.h index 98e4b48e31b..885cdc6d0b6 100644 --- a/Build/source/texk/dvipdfm-x/pdfencrypt.h +++ b/Build/source/texk/dvipdfm-x/pdfencrypt.h @@ -2,7 +2,7 @@ This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2020 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -28,11 +28,18 @@ #define MAX_PWD_LEN 127 -extern int pdf_init_encryption (struct pdf_enc_setting, const unsigned char *trailer_id); -extern void pdf_enc_set_label (unsigned label); -extern void pdf_enc_set_generation (unsigned generation); -extern void pdf_encrypt_data (const unsigned char *plain, size_t plain_len, - unsigned char **cipher, size_t *cipher_len); -extern pdf_obj *pdf_encrypt_obj (void); +typedef struct pdf_sec pdf_sec; +extern pdf_sec *pdf_enc_init (const unsigned char *id, + int keybits, uint32_t permission, + const char *opasswd, const char *upasswd, + int use_aes, int encrypt_metadata); +extern void pdf_enc_close (pdf_sec **p_sec); + +extern void pdf_enc_set_label (pdf_sec *p_sec, unsigned label); +extern void pdf_enc_set_generation (pdf_sec *p_sec, unsigned generation); +extern void pdf_encrypt_data (pdf_sec *p_sec, const unsigned char *plain, size_t plain_len, + unsigned char **cipher, size_t *cipher_len); +extern pdf_obj *pdf_enc_get_encrypt_dict (pdf_sec *p_sec); +extern pdf_obj *pdf_enc_get_extension_dict (pdf_sec *p_sec); #endif /* _PDFENCRYPT_H_ */ diff --git a/Build/source/texk/dvipdfm-x/pdfobj.c b/Build/source/texk/dvipdfm-x/pdfobj.c index 7cae7295356..9be1744ba2d 100644 --- a/Build/source/texk/dvipdfm-x/pdfobj.c +++ b/Build/source/texk/dvipdfm-x/pdfobj.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2020 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2020 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -35,6 +35,7 @@ #include "mfileio.h" #include "dpxconf.h" #include "dpxutil.h" + #include "pdflimits.h" #include "pdfencrypt.h" #include "pdfparse.h" @@ -60,13 +61,12 @@ /* Any of these types can be represented as follows */ struct pdf_obj { - int type; + int type; - unsigned int label; /* Only used for indirect objects - all other "label" to zero */ - unsigned short generation; /* Only used if "label" is used */ - unsigned refcount; /* Number of links to this object */ - int flags; + uint32_t label; /* Only used for indirect objects all other "label" to zero */ + uint16_t generation; /* Only used if "label" is used */ + int refcount; /* Number of links to this object */ + int32_t flags; void *data; #if defined(PDFOBJ_DEBUG) @@ -81,7 +81,7 @@ static int cur_obj_id = 0; struct pdf_boolean { - char value; + char value; }; struct pdf_number @@ -92,7 +92,7 @@ struct pdf_number struct pdf_string { unsigned char *string; - unsigned short length; + size_t length; }; struct pdf_name @@ -102,8 +102,8 @@ struct pdf_name struct pdf_array { - unsigned int max; - unsigned int size; + size_t max; + size_t size; struct pdf_obj **values; }; @@ -138,18 +138,18 @@ struct pdf_stream struct pdf_obj *dict; unsigned char *stream; int *objstm_data; /* used for object streams */ - unsigned int stream_length; - unsigned int max_length; + size_t stream_length; + size_t max_length; int32_t _flags; struct decode_parms decodeparms; }; struct pdf_indirect { - pdf_file *pf; - pdf_obj *obj; /* used when PF == NULL */ - unsigned label; - unsigned short generation; + pdf_file *pf; + pdf_obj *obj; /* used when PF == NULL */ + uint32_t label; + uint16_t generation; }; typedef void pdf_null; @@ -162,101 +162,182 @@ typedef struct pdf_dict pdf_dict; typedef struct pdf_stream pdf_stream; typedef struct pdf_indirect pdf_indirect; -static FILE *pdf_output_file = NULL; - -static int pdf_output_file_position = 0; -static int pdf_output_line_position = 0; -static int compression_saved = 0; - -#define FORMAT_BUF_SIZE 4096 -static char format_buffer[FORMAT_BUF_SIZE]; - typedef struct xref_entry { - unsigned char type; /* object storage type */ - unsigned int field2; /* offset in file or object stream */ - unsigned short field3; /* generation or index */ - pdf_obj *direct; /* used for imported objects */ - pdf_obj *indirect; /* used for imported objects */ + uint8_t type; /* object storage type */ + uint32_t field2; /* offset in file or object stream */ + uint16_t field3; /* generation or index */ + pdf_obj *direct; /* used for imported objects */ + pdf_obj *indirect; /* used for imported objects */ } xref_entry; -static xref_entry *output_xref; - -static unsigned int pdf_max_ind_objects; -static unsigned int next_label; - -static unsigned int startxref; - struct pdf_file { - FILE *file; - pdf_obj *trailer; - xref_entry *xref_table; - pdf_obj *catalog; - int num_obj; - int file_size; - int version; + FILE *file; + pdf_obj *trailer; + xref_entry *xref_table; + pdf_obj *catalog; + int num_obj; + int file_size; + int version; }; -static pdf_obj *output_stream; +static int error_out = 0; #define OBJSTM_MAX_OBJS 200 /* the limit is only 100 for linearized PDF */ -static int enc_mode; -static int doc_enc_mode; +struct pdf_out { + struct { + int enc_mode; /* boolean */ + } state; + + unsigned char id1[16]; + unsigned char id2[16]; + + struct { + int major; + int minor; + } version; + + struct { + struct { + int level; + int use_predictor; + } compression; + + int enable_encrypt; + int use_objstm; + } options; + + struct { + FILE *file; + size_t file_position; + int line_position; + size_t compression_saved; +#if defined(LIBDPX) + size_t file_stats; +#endif /* LIBDPX */ + } output; -static pdf_obj *trailer_dict; -static pdf_obj *xref_stream; + struct { + uint32_t next_label; + uint32_t max_ind_objects; + } obj; -/* Internal static routines */ + pdf_sec *sec_data; -static int check_for_pdf_version (FILE *file); + pdf_obj *trailer; + uint32_t startxref; + xref_entry * xref_table; -static void pdf_flush_obj (pdf_obj *object, FILE *file); -static void pdf_label_obj (pdf_obj *object); -static void pdf_write_obj (pdf_obj *object, FILE *file); + pdf_obj *xref_stream; + pdf_obj *output_stream; + pdf_obj *current_objstm; +}; -static void set_objstm_data (pdf_obj *objstm, int *data); -static int *get_objstm_data (pdf_obj *objstm); -static void release_objstm (pdf_obj *objstm); +/* Underway to reform PDF related code... For a moment place pdf_out + * object as a static variable. */ +static pdf_out pout; -static void pdf_out_char (FILE *file, char c); -static void pdf_out (FILE *file, const void *buffer, int length); +static pdf_out * +current_output (void) +{ + return &pout; +} -static pdf_obj *pdf_new_ref (pdf_obj *object); -static void release_indirect (pdf_indirect *data); -static void write_indirect (pdf_indirect *indirect, FILE *file); +static void +init_pdf_out_struct (pdf_out *p) +{ + ASSERT(p); -static void release_boolean (pdf_obj *data); -static void write_boolean (pdf_boolean *data, FILE *file); + p->state.enc_mode = 0; -static void write_null (FILE *file); + memset(p->id1, 0, 16); + memset(p->id2, 0, 16); -static void release_number (pdf_number *number); -static void write_number (pdf_number *number, FILE *file); + p->version.major = 1; + p->version.minor = PDF_VERSION_DEFAULT; -static void write_string (pdf_string *str, FILE *file); -static void release_string (pdf_string *str); + p->options.compression.level = 9; + p->options.compression.use_predictor = 1; + p->options.enable_encrypt = 0; + p->options.use_objstm = 1; -static void write_name (pdf_name *name, FILE *file); -static void release_name (pdf_name *name); + p->output.file = NULL; + p->output.file_position = 0; + p->output.line_position = 0; + p->output.compression_saved = 0; +#if defined(LIBDPX) + p->output.file_stats = 0; +#endif /* LIBDPX */ -static void write_array (pdf_array *array, FILE *file); -static void release_array (pdf_array *array); + p->obj.next_label = 1; + p->obj.max_ind_objects = 0; -static void write_dict (pdf_dict *dict, FILE *file); -static void release_dict (pdf_dict *dict); + p->sec_data = NULL; + p->trailer = NULL; + p->startxref = 0; + p->xref_table = NULL; -static void write_stream (pdf_stream *stream, FILE *file); -static void release_stream (pdf_stream *stream); + p->xref_stream = NULL; + p->output_stream = NULL; + p->current_objstm = NULL; +} -static char compression_level = 9; -static char compression_use_predictor = 1; +static void +clean_pdf_out_struct (pdf_out *p) +{ + memset(p, 0, sizeof(pdf_out)); +} -void -pdf_set_compression (int level) +/* Internal static routines */ + +static int check_for_pdf_version (FILE *file); + +static void pdf_flush_obj (pdf_out *p, pdf_obj *object); +static void pdf_label_obj (pdf_out *p, pdf_obj *object); +static void pdf_write_obj (pdf_out *p, pdf_obj *object); + +static void set_objstm_data (pdf_obj *objstm, int *data); +static int *get_objstm_data (pdf_obj *objstm); +static void release_objstm (pdf_obj *objstm); + +static void pdf_out_char (pdf_out *p, char c); +static void pdf_out_str (pdf_out *p, const void *buffer, size_t length); + +static pdf_obj *pdf_new_ref (pdf_out *p, pdf_obj *object); +static void release_indirect (pdf_indirect *data); +static void write_indirect (pdf_out *p, pdf_indirect *indirect); + +static void release_boolean (pdf_obj *data); +static void write_boolean (pdf_out *p, pdf_boolean *data); + +static void write_null (pdf_out *p); + +static void release_number (pdf_number *number); +static void write_number (pdf_out *p, pdf_number *number); + +static void write_string (pdf_out *p, pdf_string *str); +static void release_string (pdf_string *str); + +static void write_name (pdf_out *p, pdf_name *name); +static void release_name (pdf_name *name); + +static void write_array (pdf_out *p, pdf_array *array); +static void release_array (pdf_array *array); + +static void write_dict (pdf_out *p, pdf_dict *dict); +static void release_dict (pdf_dict *dict); + +static void write_stream (pdf_out *p, pdf_stream *stream); +static void release_stream (pdf_stream *stream); + +static void +pdf_out_set_compression (pdf_out *p, int level) { + ASSERT(p); + #ifndef HAVE_ZLIB ERROR("You don't have compression compiled in. Possibly libz wasn't found by configure."); #else @@ -265,7 +346,7 @@ pdf_set_compression (int level) WARN("Unable to set compression level -- your zlib doesn't have compress2()."); #endif if (level >= 0 && level <= 9) - compression_level = level; + p->options.compression.level = level; else { ERROR("set_compression: invalid compression level: %d", level); } @@ -277,156 +358,233 @@ pdf_set_compression (int level) FILE * pdf_get_output_file (void) { - return pdf_output_file; + pdf_out *p = current_output(); + return p->output.file; } -static int pdf_version = PDF_VERSION_DEFAULT; - -void -pdf_set_version (int version) +static void +pdf_out_set_version (pdf_out *p, int ver_major, int ver_minor) { + int version; + + ASSERT(p); + + version = ver_major * 10 + ver_minor; /* Don't forget to update CIDFont_stdcc_def[] in cid.c too! */ if (version >= PDF_VERSION_MIN && version <= PDF_VERSION_MAX) { - pdf_version = version; + p->version.major = ver_major; + p->version.minor = ver_minor; + } else { + WARN("Unsupported PDF version %d.%d ... Ignoring.", ver_major, ver_minor); } } int pdf_get_version (void) { - return pdf_version; + pdf_out *p = current_output(); + return (p->version.major * 10 + p->version.minor); } int pdf_get_version_major (void) { - return pdf_version/10; + pdf_out *p = current_output(); + return p->version.major; } int pdf_get_version_minor (void) { - return pdf_version%10; + pdf_out *p = current_output(); + return p->version.minor; } int pdf_check_version (int major, int minor) { - return (pdf_version >= major*10+minor) ? 0 : -1; -} + pdf_out *p = current_output(); + if (p->version.major > major) + return 0; + else if (p->version.major < major) + return -1; + else { + return (p->version.minor >= minor) ? 0 : -1; + } -static pdf_obj *current_objstm = NULL; -static int do_objstm; + return -1; +} static void -add_xref_entry (unsigned label, unsigned char type, unsigned int field2, unsigned short field3) +add_xref_entry (pdf_out *p, + uint32_t label, uint8_t type, uint32_t field2, uint16_t field3) { - if (label >= pdf_max_ind_objects) { - pdf_max_ind_objects = (label/IND_OBJECTS_ALLOC_SIZE+1)*IND_OBJECTS_ALLOC_SIZE; - output_xref = RENEW(output_xref, pdf_max_ind_objects, xref_entry); + ASSERT(p); + + if (label >= p->obj.max_ind_objects) { + p->obj.max_ind_objects = (label/IND_OBJECTS_ALLOC_SIZE+1)*IND_OBJECTS_ALLOC_SIZE; + p->xref_table = RENEW(p->xref_table, p->obj.max_ind_objects, xref_entry); } - output_xref[label].type = type; - output_xref[label].field2 = field2; - output_xref[label].field3 = field3; - output_xref[label].direct = NULL; - output_xref[label].indirect = NULL; + p->xref_table[label].type = type; + p->xref_table[label].field2 = field2; + p->xref_table[label].field3 = field3; + p->xref_table[label].direct = NULL; + p->xref_table[label].indirect = NULL; } #define BINARY_MARKER "%\344\360\355\370\n" -void +pdf_out * pdf_out_init (const char *filename, - int do_encryption, int enable_objstm, int enable_predictor) + const unsigned char *id1, + const unsigned char *id2, + int ver_major, int ver_minor, int compression_level, + int enable_encrypt, + int enable_objstm, + int enable_predictor) { - char v; + pdf_out *p = current_output(); + char v; + + init_pdf_out_struct(p); + + pdf_out_set_version(p, ver_major, ver_minor); + pdf_out_set_compression(p, compression_level); - output_xref = NULL; - pdf_max_ind_objects = 0; - add_xref_entry(0, 0, 0, 0xffff); - next_label = 1; + add_xref_entry(p, 0, 0, 0, 0xffff); - if (pdf_version >= 15) { + /* This must be set before pdf_set_root() is called */ + p->options.enable_encrypt = enable_encrypt; + if (pdf_check_version(1, 5) == 0) { if (enable_objstm) { - xref_stream = pdf_new_stream(STREAM_COMPRESS); - xref_stream->flags |= OBJ_NO_ENCRYPT; - trailer_dict = pdf_stream_dict(xref_stream); - pdf_add_dict(trailer_dict, pdf_new_name("Type"), pdf_new_name("XRef")); - do_objstm = 1; + p->xref_stream = pdf_new_stream(STREAM_COMPRESS); + p->xref_stream->flags |= OBJ_NO_ENCRYPT; + p->trailer = pdf_stream_dict(p->xref_stream); + pdf_add_dict(p->trailer, pdf_new_name("Type"), pdf_new_name("XRef")); + p->options.use_objstm = 1; } else { - trailer_dict = pdf_new_dict(); - do_objstm = 0; + p->xref_stream = NULL; + p->trailer = pdf_new_dict(); + p->options.use_objstm = 0; } } else { - xref_stream = NULL; - trailer_dict = pdf_new_dict(); - do_objstm = 0; + p->xref_stream = NULL; + p->trailer = pdf_new_dict(); + p->options.use_objstm = 0; } - output_stream = NULL; + p->output_stream = NULL; if (filename == NULL) { /* no filename: writing to stdout */ #ifdef WIN32 setmode(fileno(stdout), _O_BINARY); #endif - pdf_output_file = stdout; + p->output.file = stdout; } else { - pdf_output_file = MFOPEN(filename, FOPEN_WBIN_MODE); - if (!pdf_output_file) { + p->output.file = MFOPEN(filename, FOPEN_WBIN_MODE); + if (!p->output.file) { if (strlen(filename) < 128) ERROR("Unable to open \"%s\".", filename); else ERROR("Unable to open file."); } } - pdf_out(pdf_output_file, "%PDF-", strlen("%PDF-")); - v = '0' + (pdf_version / 10); - pdf_out(pdf_output_file, &v, 1); - pdf_out(pdf_output_file, ".", 1); - v = '0' + (pdf_version % 10); - pdf_out(pdf_output_file, &v, 1); - pdf_out(pdf_output_file, "\n", 1); - pdf_out(pdf_output_file, BINARY_MARKER, strlen(BINARY_MARKER)); + pdf_out_str(p, "%PDF-", strlen("%PDF-")); + v = '0' + p->version.major; + pdf_out_str(p, &v, 1); + pdf_out_str(p, ".", 1); + v = '0' + p->version.minor; + pdf_out_str(p, &v, 1); + pdf_out_str(p, "\n", 1); + pdf_out_str(p, BINARY_MARKER, strlen(BINARY_MARKER)); + + /* Set trailer ID and setup security handler */ + { + pdf_obj *id_array; + + memcpy(p->id1, id1, 16); + memcpy(p->id2, id2, 16); + id_array = pdf_new_array(); + pdf_add_array(id_array, pdf_new_string(p->id1, 16)); + pdf_add_array(id_array, pdf_new_string(p->id2, 16)); + pdf_add_dict(p->trailer, pdf_new_name("ID"), id_array); + } + p->state.enc_mode = 0; + p->options.compression.use_predictor = enable_predictor; - enc_mode = 0; - doc_enc_mode = do_encryption; - compression_use_predictor = enable_predictor; + return p; +} + +void +pdf_out_set_encrypt (int keybits, int32_t permission, + const char *opasswd, const char *upasswd, + int use_aes, int encrypt_metadata) +{ + pdf_out *p = current_output(); + + pdf_obj *encrypt, *extension, *catalog; + + p->sec_data = pdf_enc_init(p->id1, keybits, permission, + opasswd, upasswd, use_aes, encrypt_metadata); + if (!p->sec_data) { + p->options.enable_encrypt = 0; + return; + } + + encrypt = pdf_enc_get_encrypt_dict(p->sec_data); + pdf_add_dict(p->trailer, + pdf_new_name("Encrypt"), pdf_ref_obj(encrypt)); + encrypt->flags |= OBJ_NO_ENCRYPT; + encrypt->flags |= OBJ_NO_OBJSTM; + pdf_release_obj(encrypt); + + extension = pdf_enc_get_extension_dict(p->sec_data); + if (extension) { + catalog = pdf_doc_catalog(); + pdf_add_dict(catalog, pdf_new_name("Extensions"), extension); + } } static void -dump_xref_table (void) +dump_xref_table (pdf_out *p) { - int length; - unsigned int i; + int i, length; + char buf[32]; - pdf_out(pdf_output_file, "xref\n", 5); + ASSERT(p); - length = sprintf(format_buffer, "%d %u\n", 0, next_label); - pdf_out(pdf_output_file, format_buffer, length); + pdf_out_str(p, "xref\n", 5); + + length = sprintf(buf, "%d %u\n", 0, p->obj.next_label); + pdf_out_str(p, buf, length); /* * Every space counts. The space after the 'f' and 'n' is * *essential*. * The PDF spec says the lines must be 20 characters long including the * end of line character. */ - for (i = 0; i < next_label; i++) { - unsigned char type = output_xref[i].type; + for (i = 0; i < p->obj.next_label; i++) { + uint8_t type = p->xref_table[i].type; if (type > 1) ERROR("object type %hu not allowed in xref table", type); - length = sprintf(format_buffer, "%010u %05hu %c \n", - output_xref[i].field2, output_xref[i].field3, - type ? 'n' : 'f'); - pdf_out(pdf_output_file, format_buffer, length); + length = sprintf(buf, "%010u %05hu %c \n", + p->xref_table[i].field2, p->xref_table[i].field3, + type ? 'n' : 'f'); + pdf_out_str(p, buf, length); } } static void -dump_trailer_dict (void) +dump_trailer (pdf_out *p) { - pdf_out(pdf_output_file, "trailer\n", 8); - enc_mode = 0; - write_dict(trailer_dict->data, pdf_output_file); - pdf_release_obj(trailer_dict); - pdf_out_char(pdf_output_file, '\n'); + ASSERT(p); + + pdf_out_str(p, "trailer\n", 8); + p->state.enc_mode = 0; + write_dict(p, p->trailer->data); + pdf_release_obj(p->trailer); + p->trailer = NULL; + pdf_out_char(p, '\n'); } /* @@ -434,16 +592,17 @@ dump_trailer_dict (void) * contributed by Matthias Franz (March 21, 2007) */ static void -dump_xref_stream (void) +dump_xref_stream (pdf_out *p) { - unsigned int pos, i; - unsigned poslen; + uint32_t pos, i; + uint32_t poslen; unsigned char buf[7] = {0, 0, 0, 0, 0}; + pdf_obj *w; - pdf_obj *w; + ASSERT(p); /* determine the necessary size of the offset field */ - pos = startxref; /* maximal offset value */ + pos = p->startxref; /* maximal offset value */ poslen = 1; while (pos >>= 8) poslen++; @@ -452,48 +611,52 @@ dump_xref_stream (void) pdf_add_array(w, pdf_new_number(1)); /* type */ pdf_add_array(w, pdf_new_number(poslen)); /* offset (big-endian) */ pdf_add_array(w, pdf_new_number(2)); /* generation */ - pdf_add_dict(trailer_dict, pdf_new_name("W"), w); + pdf_add_dict(p->trailer, pdf_new_name("W"), w); /* We need the xref entry for the xref stream right now */ - add_xref_entry(next_label-1, 1, startxref, 0); + add_xref_entry(p, p->obj.next_label - 1, 1, p->startxref, 0); - for (i = 0; i < next_label; i++) { - unsigned j; - unsigned short f3; - buf[0] = output_xref[i].type; - pos = output_xref[i].field2; + for (i = 0; i < p->obj.next_label; i++) { + size_t j; + uint16_t f3; + buf[0] = p->xref_table[i].type; + pos = p->xref_table[i].field2; for (j = poslen; j--; ) { buf[1+j] = (unsigned char) pos; pos >>= 8; } - f3 = output_xref[i].field3; + f3 = p->xref_table[i].field3; buf[poslen+1] = (unsigned char) (f3 >> 8); buf[poslen+2] = (unsigned char) (f3); - pdf_add_stream(xref_stream, &buf, poslen+3); + pdf_add_stream(p->xref_stream, &buf, poslen+3); } - pdf_release_obj(xref_stream); + pdf_release_obj(p->xref_stream); + p->xref_stream = NULL; } #if defined(LIBDPX) -static long pdf_output_file_stats = 0; long pdf_output_stats (void) { - return pdf_output_file_stats; + pdf_out *p = current_output(); + return p->output.file_stats; } #endif /* LIBDPX */ void pdf_out_flush (void) { - if (pdf_output_file) { - int length; + pdf_out *p = current_output(); + char buf[16]; + + if (p->output.file) { + int length; /* Flush current object stream */ - if (current_objstm) { - release_objstm(current_objstm); - current_objstm =NULL; + if (p->current_objstm) { + release_objstm(p->current_objstm); + p->current_objstm =NULL; } /* @@ -501,53 +664,56 @@ pdf_out_flush (void) * for the xref stream dictionary (= trailer). * Labelling it in pdf_out_init (with 1) does not work (why?). */ - if (xref_stream) - pdf_label_obj(xref_stream); + if (p->xref_stream) + pdf_label_obj(p, p->xref_stream); /* Record where this xref is for trailer */ - startxref = pdf_output_file_position; + p->startxref = p->output.file_position; - pdf_add_dict(trailer_dict, pdf_new_name("Size"), - pdf_new_number(next_label)); + pdf_add_dict(p->trailer, + pdf_new_name("Size"), pdf_new_number(p->obj.next_label)); - if (xref_stream) - dump_xref_stream(); + if (p->xref_stream) + dump_xref_stream(p); else { - dump_xref_table(); - dump_trailer_dict(); + dump_xref_table(p); + dump_trailer(p); } /* Done with xref table */ - RELEASE(output_xref); + RELEASE(p->xref_table); + p->xref_table = NULL; - pdf_out(pdf_output_file, "startxref\n", 10); - length = sprintf(format_buffer, "%u\n", startxref); - pdf_out(pdf_output_file, format_buffer, length); - pdf_out(pdf_output_file, "%%EOF\n", 6); + pdf_out_str(p, "startxref\n", 10); + length = sprintf(buf, "%u\n", p->startxref); + pdf_out_str(p, buf, length); + pdf_out_str(p, "%%EOF\n", 6); #if !defined(LIBDPX) MESG("\n"); #endif /* !LIBDPX */ if (dpx_conf.verbose_level > 0) { - if (compression_level > 0) { - MESG("Compression saved %ld bytes%s\n", compression_saved, - pdf_version < 15 ? ". Try \"-V 1.5\" for better compression" : ""); + if (p->options.compression.level > 0) { + MESG("Compression saved %ld bytes%s\n", p->output.compression_saved); } } #if !defined(LIBDPX) - MESG("%ld bytes written", pdf_output_file_position); + MESG("%ld bytes written", p->output.file_position); #else - pdf_output_file_stats = pdf_output_file_position; + p->output.file_stats = p->output.file_position; #endif /* !LIBDPX */ - MFCLOSE(pdf_output_file); - pdf_output_file_position = 0; - pdf_output_line_position = 0; - pdf_output_file = NULL; + MFCLOSE(p->output.file); + p->output.file = NULL; + p->output.file_position = 0; + p->output.line_position = 0; } + if (p->sec_data) + pdf_enc_close(&p->sec_data); #if defined(PDFOBJ_DEBUG) { int i; + error_out = 1; MESG("\ndebug>> %d PDF objects created.", cur_obj_id); for (i = 0; i < cur_obj_id; i++) { pdf_obj *obj = bucket[i]; @@ -555,110 +721,113 @@ pdf_out_flush (void) if (obj->label > 0) { WARN("Object obj_id=<%lu, %u> unreleased...", obj->label, obj->generation); WARN("Reference count=%d", obj->refcount); + pdf_write_obj(p, obj); + MESG("\n"); } else { - WARN("Unreleased object found: %d", i); - pdf_write_obj(obj, stderr); + WARN("Unreleased object found: (unlabeled) id=%d", i); + pdf_write_obj(p, obj); MESG("\n"); } } } } #endif + clean_pdf_out_struct(p); } void pdf_error_cleanup (void) { + pdf_out *p = current_output(); /* * This routine is the cleanup required for an abnormal exit. * For now, simply close the file. */ - if (pdf_output_file) - MFCLOSE(pdf_output_file); - pdf_output_file = NULL; + if (p->output.file) + MFCLOSE(p->output.file); + p->output.file = NULL; } void pdf_set_root (pdf_obj *object) { - if (pdf_add_dict(trailer_dict, pdf_new_name("Root"), pdf_ref_obj(object))) { + pdf_out *p = current_output(); + + if (pdf_lookup_dict(p->trailer, "Root")) ERROR("Root object already set!"); - } + pdf_add_dict(p->trailer, pdf_new_name("Root"), pdf_ref_obj(object)); /* Adobe Readers don't like a document catalog inside an encrypted * object stream, although the PDF v1.5 spec seems to allow this. * Note that we don't set OBJ_NO_ENCRYPT since the name dictionary in * a document catalog may contain strings, which should be encrypted. */ - if (doc_enc_mode) + if (p->options.enable_encrypt) object->flags |= OBJ_NO_OBJSTM; } void pdf_set_info (pdf_obj *object) { - if (pdf_add_dict(trailer_dict, pdf_new_name("Info"), pdf_ref_obj(object))) { + pdf_out *p = current_output(); + + if (pdf_lookup_dict(p->trailer, "Info")) ERROR ("Info object already set!"); - } + pdf_add_dict(p->trailer, pdf_new_name("Info"), pdf_ref_obj(object)); } -void -pdf_set_id (pdf_obj *id) -{ - if (pdf_add_dict(trailer_dict, pdf_new_name("ID"), id)) { - ERROR ("ID already set!"); - } -} -void -pdf_set_encrypt (pdf_obj *encrypt) -{ - if (pdf_add_dict(trailer_dict, pdf_new_name("Encrypt"), pdf_ref_obj(encrypt))) { - ERROR("Encrypt object already set!"); - } - encrypt->flags |= OBJ_NO_ENCRYPT; -} -static -void pdf_out_char (FILE *file, char c) +static void +pdf_out_char (pdf_out *p, char c) { - if (output_stream && file == pdf_output_file) - pdf_add_stream(output_stream, &c, 1); - else { - fputc(c, file); - /* Keep tallys for xref table *only* if writing a pdf file. */ - if (file == pdf_output_file) { - pdf_output_file_position += 1; + ASSERT(p); + + if (error_out) { + fputc(c, stderr); + } else { + if (p->output_stream) + pdf_add_stream(p->output_stream, &c, 1); + else { + fputc(c, p->output.file); + p->output.file_position += 1; if (c == '\n') - pdf_output_line_position = 0; + p->output.line_position = 0; else - pdf_output_line_position += 1; + p->output.line_position += 1; } } } static char xchar[] = "0123456789abcdef"; -#define pdf_out_xchar(f,c) do {\ - pdf_out_char((f), xchar[((c) >> 4) & 0x0f]);\ - pdf_out_char((f), xchar[(c) & 0x0f]);\ -} while (0) +static void +pdf_out_xchar (pdf_out *p, char c) +{ + ASSERT(p); -static -void pdf_out (FILE *file, const void *buffer, int length) + pdf_out_char(p, xchar[(c >> 4) & 0x0f]); + pdf_out_char(p, xchar[c & 0x0f]); +} + +static void +pdf_out_str (pdf_out *p, const void *buffer, size_t length) { - if (output_stream && file == pdf_output_file) - pdf_add_stream(output_stream, buffer, length); + ASSERT(p); + + if (error_out) + fwrite(buffer, 1, length, stderr); else { - fwrite(buffer, 1, length, file); - /* Keep tallys for xref table *only* if writing a pdf file */ - if (file == pdf_output_file) { - pdf_output_file_position += length; - pdf_output_line_position += length; + if (p->output_stream) + pdf_add_stream(p->output_stream, buffer, length); + else { + fwrite(buffer, 1, length, p->output.file); + p->output.file_position += length; + p->output.line_position += length; /* "foo\nbar\n "... */ if (length > 0 && - ((const char *)buffer)[length-1] == '\n') - pdf_output_line_position = 0; + ((const char *)buffer)[length-1] == '\n') + p->output.line_position = 0; } } } @@ -674,12 +843,14 @@ int pdf_need_white (int type1, int type2) } static -void pdf_out_white (FILE *file) +void pdf_out_white (pdf_out *p) { - if (file == pdf_output_file && pdf_output_line_position >= 80) { - pdf_out_char(file, '\n'); + ASSERT(p); + + if (p->output.line_position >= 80) { + pdf_out_char(p, '\n'); } else { - pdf_out_char(file, ' '); + pdf_out_char(p, ' '); } } @@ -724,8 +895,10 @@ pdf_obj_typeof (pdf_obj *object) } static void -pdf_label_obj (pdf_obj *object) +pdf_label_obj (pdf_out *p, pdf_obj *object) { + ASSERT(p); + if (INVALIDOBJ(object)) ERROR("pdf_label_obj(): passed invalid object."); @@ -733,7 +906,7 @@ pdf_label_obj (pdf_obj *object) * Don't change label on an already labeled object. Ignore such calls. */ if (object->label == 0) { - object->label = next_label++; + object->label = p->obj.next_label++; object->generation = 0; } } @@ -772,19 +945,23 @@ pdf_link_obj (pdf_obj *object) pdf_obj * pdf_ref_obj (pdf_obj *object) { + pdf_out *p = current_output(); + if (INVALIDOBJ(object)) ERROR("pdf_ref_obj(): passed invalid object."); if (object->refcount == 0) { MESG("\nTrying to refer already released object!!!\n"); - pdf_write_obj(object, stderr); + error_out = 1; + pdf_write_obj(p, object); ERROR("Cannot continue..."); + error_out = 0; } if (PDF_OBJ_INDIRECTTYPE(object)) { return pdf_link_obj(object); } else { - return pdf_new_ref(object); + return pdf_new_ref(p, object); } } @@ -795,14 +972,17 @@ release_indirect (pdf_indirect *data) } static void -write_indirect (pdf_indirect *indirect, FILE *file) +write_indirect (pdf_out *p, pdf_indirect *indirect) { - int length; + int length; + char buf[64]; + ASSERT(p); ASSERT(!indirect->pf); - length = sprintf(format_buffer, "%u %hu R", indirect->label, indirect->generation); - pdf_out(file, format_buffer, length); + length = sprintf(buf, "%u %hu R", + indirect->label, indirect->generation); + pdf_out_str(p, buf, length); } /* The undefined object is used as a placeholder in pdfnames.c @@ -831,9 +1011,9 @@ pdf_new_null (void) } static void -write_null (FILE *file) +write_null (pdf_out *p) { - pdf_out(file, "null", 4); + pdf_out_str(p, "null", 4); } pdf_obj * @@ -857,12 +1037,12 @@ release_boolean (pdf_obj *data) } static void -write_boolean (pdf_boolean *data, FILE *file) +write_boolean (pdf_out *p, pdf_boolean *data) { if (data->value) { - pdf_out(file, "true", 4); + pdf_out_str(p, "true", 4); } else { - pdf_out(file, "false", 5); + pdf_out_str(p, "false", 5); } } @@ -899,13 +1079,14 @@ release_number (pdf_number *data) } static void -write_number (pdf_number *number, FILE *file) +write_number (pdf_out *p, pdf_number *number) { - int count; + int count; + char buf[512]; - count = pdf_sprint_number(format_buffer, number->value); + count = pdf_sprint_number(buf, number->value); - pdf_out(file, format_buffer, count); + pdf_out_str(p, buf, count); } @@ -938,20 +1119,20 @@ pdf_new_string (const void *str, unsigned length) pdf_obj *result; pdf_string *data; + ASSERT(str); + result = pdf_new_obj(PDF_STRING); data = NEW(1, pdf_string); result->data = data; data->length = length; - if (str && length > 0) { + if (length) { data->string = NEW(length+1, unsigned char); memcpy(data->string, str, length); /* Shouldn't assume NULL terminated. */ data->string[length] = '\0'; - } else { + } else data->string = NULL; - data->length = 0; - } return result; } @@ -977,7 +1158,7 @@ pdf_string_length (pdf_obj *object) data = object->data; - return (unsigned) (data->length); + return (unsigned) data->length; } /* @@ -987,8 +1168,8 @@ pdf_string_length (pdf_obj *object) int pdfobj_escape_str (char *buffer, int bufsize, const unsigned char *s, int len) { - int result = 0; - int i; + size_t result = 0; + size_t i; for (i = 0; i < len; i++) { unsigned char ch; @@ -1031,21 +1212,22 @@ pdfobj_escape_str (char *buffer, int bufsize, const unsigned char *s, int len) } } - return result; + return (int) result; } static void -write_string (pdf_string *str, FILE *file) +write_string (pdf_out *p, pdf_string *str) { - unsigned char *s = NULL; - char wbuf[FORMAT_BUF_SIZE]; /* Shouldn't use format_buffer[]. */ - int nescc = 0, i, count; - size_t len = 0; + unsigned char *s = NULL; + size_t i, nescc = 0; + size_t len = 0; - if (enc_mode) { - pdf_encrypt_data(str->string, str->length, &s, &len); + ASSERT(p); + + if (p->state.enc_mode) { + pdf_encrypt_data(p->sec_data, str->string, str->length, &s, &len); } else { - s = str->string; + s = str->string; len = str->length; } @@ -1061,13 +1243,22 @@ write_string (pdf_string *str, FILE *file) * ASCII hex string. */ if (nescc > len / 3) { - pdf_out_char(file, '<'); + pdf_out_char(p, '<'); for (i = 0; i < len; i++) { - pdf_out_xchar(file, s[i]); + pdf_out_xchar(p, s[i]); } - pdf_out_char(file, '>'); + pdf_out_char(p, '>'); } else { - pdf_out_char(file, '('); + char *buf; + size_t size, count; + + /* At most len/3 is to be escaped here. (see above) + * Thus 4*len/3 + 2*len/3 + 2 is enough for buffer size. + */ + size = len * 2 + 3; + buf = NEW(size, char); + + pdf_out_char(p, '('); /* * This section of code probably isn't speed critical. Escaping the * characters in the string one at a time may seem slow, but it's @@ -1077,12 +1268,14 @@ write_string (pdf_string *str, FILE *file) * handled as quickly as possible since there are so many of them. */ for (i = 0; i < len; i++) { - count = pdfobj_escape_str(wbuf, FORMAT_BUF_SIZE, &(s[i]), 1); - pdf_out(file, wbuf, count); + count = pdfobj_escape_str(buf, size, &(s[i]), 1); + pdf_out_str(p, buf, count); } - pdf_out_char(file, ')'); + pdf_out_char(p, ')'); + RELEASE(buf); } - if (enc_mode && s) + + if (p->state.enc_mode && s) RELEASE(s); } @@ -1123,7 +1316,7 @@ pdf_obj * pdf_new_name (const char *name) { pdf_obj *result; - unsigned length; + size_t length; pdf_name *data; result = pdf_new_obj(PDF_NAME); @@ -1142,10 +1335,12 @@ pdf_new_name (const char *name) } static void -write_name (pdf_name *name, FILE *file) +write_name (pdf_out *p, pdf_name *name) { - char *s; - int i, length; + char *s; + size_t i, length; + + ASSERT(p); s = name->name; length = name->name ? strlen(name->name) : 0; @@ -1169,14 +1364,14 @@ write_name (pdf_name *name, FILE *file) (c) == '{' || (c) == '}' || \ (c) == '%') #endif - pdf_out_char(file, '/'); + pdf_out_char(p, '/'); for (i = 0; i < length; i++) { if (s[i] < '!' || s[i] > '~' || s[i] == '#' || is_delim(s[i])) { /* ^ "space" is here. */ - pdf_out_char (file, '#'); - pdf_out_xchar(file, s[i]); + pdf_out_char (p, '#'); + pdf_out_xchar(p, s[i]); } else { - pdf_out_char (file, s[i]); + pdf_out_char (p, s[i]); } } } @@ -1225,25 +1420,27 @@ pdf_new_array (void) } static void -write_array (pdf_array *array, FILE *file) +write_array (pdf_out *p, pdf_array *array) { - pdf_out_char(file, '['); + ASSERT(p); + + pdf_out_char(p, '['); if (array->size > 0) { - unsigned int i; - int type1 = PDF_UNDEFINED, type2; + size_t i; + int type1 = PDF_UNDEFINED, type2; for (i = 0; i < array->size; i++) { if (array->values[i]) { - type2 = array->values[i]->type; - if (type1 != PDF_UNDEFINED && pdf_need_white(type1, type2)) - pdf_out_white(file); - type1 = type2; - pdf_write_obj(array->values[i], file); + type2 = array->values[i]->type; + if (type1 != PDF_UNDEFINED && pdf_need_white(type1, type2)) + pdf_out_white(p); + type1 = type2; + pdf_write_obj(p, array->values[i]); } else - WARN("PDF array element #ld undefined.", i); + WARN("PDF array element #ld undefined.", i); } } - pdf_out_char(file, ']'); + pdf_out_char(p, ']'); } pdf_obj * @@ -1264,7 +1461,7 @@ pdf_get_array (pdf_obj *array, int idx) return result; } -unsigned int +unsigned pdf_array_length (pdf_obj *array) { pdf_array *data; @@ -1273,13 +1470,13 @@ pdf_array_length (pdf_obj *array) data = (pdf_array *) array->data; - return (unsigned int) data->size; + return (unsigned) data->size; } static void release_array (pdf_array *data) { - unsigned int i; + size_t i; if (data->values) { for (i = 0; i < data->size; i++) { @@ -1316,7 +1513,7 @@ pdf_add_array (pdf_obj *array, pdf_obj *object) #if 0 void -pdf_put_array (pdf_obj *array, unsigned idx, pdf_obj *object) +pdf_put_array (pdf_obj *array, int idx, pdf_obj *object) { pdf_array *data; int i; @@ -1357,7 +1554,7 @@ pdf_shift_array (pdf_obj *array) data = array->data; if (data->size > 0) { - int i; + size_t i; result = data->values[0]; for (i = 1; i < data->size; i++) @@ -1409,25 +1606,25 @@ pdf_pop_array (pdf_obj *array) #endif static void -write_dict (pdf_dict *dict, FILE *file) +write_dict (pdf_out *p, pdf_dict *dict) { #if 0 - pdf_out (file, "<<\n", 3); /* dropping \n saves few kb. */ + pdf_out_str (p, "<<\n", 3); /* dropping \n saves few kb. */ #else - pdf_out (file, "<<", 2); + pdf_out_str(p, "<<", 2); #endif while (dict->key != NULL) { - pdf_write_obj(dict->key, file); + pdf_write_obj(p, dict->key); if (pdf_need_white(PDF_NAME, (dict->value)->type)) { - pdf_out_white(file); + pdf_out_white(p); } - pdf_write_obj(dict->value, file); + pdf_write_obj(p, dict->value); #if 0 pdf_out_char (file, '\n'); /* removing this saves few kb. */ #endif dict = dict->next; } - pdf_out (file, ">>", 2); + pdf_out_str(p, ">>", 2); } pdf_obj * @@ -1826,7 +2023,9 @@ filter_PNG15_apply_filter (unsigned char *raster, return dst; } -/* This modifies "raster" itself! */ +/* TIFF predictor filter support + * This modifies "raster" itself! + */ static void apply_filter_TIFF2_1_2_4 (unsigned char *raster, int32_t width, int32_t height, @@ -1880,7 +2079,8 @@ apply_filter_TIFF2_1_2_4 (unsigned char *raster, } } if (outbits > 0) { - raster[k] = (outbuf << (8 - outbits)); k++; + raster[k] = (outbuf << (8 - outbits)); + k++; } } RELEASE(prev); @@ -1966,17 +2166,19 @@ filter_create_predictor_dict (int predictor, int32_t columns, } static void -write_stream (pdf_stream *stream, FILE *file) +write_stream (pdf_out *p, pdf_stream *stream) { unsigned char *filtered; - unsigned int filtered_length; + size_t filtered_length; #ifdef HAVE_ZLIB uLong buffer_length; #else - unsigned int buffer_length; + size_t buffer_length; #endif unsigned char *buffer; + ASSERT(p); + /* * Always work from a copy of the stream. All filters read from * "filtered" and leave their result in "filtered". @@ -2001,11 +2203,11 @@ write_stream (pdf_stream *stream, FILE *file) /* Apply compression filter if requested */ if (stream->stream_length > 0 && (stream->_flags & STREAM_COMPRESS) && - compression_level > 0) { + p->options.compression.level > 0) { pdf_obj *filters; /* First apply predictor filter if requested. */ - if ( compression_use_predictor && + if ( p->options.compression.use_predictor && (stream->_flags & STREAM_USE_PREDICTOR) && !pdf_lookup_dict(stream->dict, "DecodeParms")) { int bits_per_pixel = stream->decodeparms.colors * @@ -2071,18 +2273,19 @@ write_stream (pdf_stream *stream, FILE *file) } #ifdef HAVE_ZLIB_COMPRESS2 if (compress2(buffer, &buffer_length, filtered, - filtered_length, compression_level)) { + filtered_length, p->options.compression.level)) { ERROR("Zlib error"); } #else if (compress(buffer, &buffer_length, filtered, - filtered_length)) { + filtered_length)) { ERROR ("Zlib error"); } #endif /* HAVE_ZLIB_COMPRESS2 */ RELEASE(filtered); - compression_saved += filtered_length - buffer_length - - (filters ? strlen("/FlateDecode "): strlen("/Filter/FlateDecode\n")); + p->output.compression_saved += + filtered_length - buffer_length + - (filters ? strlen("/FlateDecode "): strlen("/Filter/FlateDecode\n")); filtered = buffer; filtered_length = buffer_length; @@ -2090,10 +2293,10 @@ write_stream (pdf_stream *stream, FILE *file) #endif /* HAVE_ZLIB */ /* AES will change the size of data! */ - if (enc_mode) { + if (p->state.enc_mode) { unsigned char *cipher = NULL; size_t cipher_len = 0; - pdf_encrypt_data(filtered, filtered_length, &cipher, &cipher_len); + pdf_encrypt_data(p->sec_data, filtered, filtered_length, &cipher, &cipher_len); RELEASE(filtered); filtered = cipher; filtered_length = cipher_len; @@ -2115,12 +2318,12 @@ write_stream (pdf_stream *stream, FILE *file) pdf_add_dict(stream->dict, pdf_new_name("Length"), pdf_new_number(filtered_length)); - pdf_write_obj(stream->dict, file); + pdf_write_obj(p, stream->dict); - pdf_out(file, "\nstream\n", 8); + pdf_out_str(p, "\nstream\n", 8); if (filtered_length > 0) - pdf_out(file, filtered, filtered_length); + pdf_out_str(p, filtered, filtered_length); RELEASE(filtered); /* @@ -2130,8 +2333,8 @@ write_stream (pdf_stream *stream, FILE *file) * filters, this could be a problem. */ - pdf_out(file, "\n", 1); - pdf_out(file, "endstream", 9); + pdf_out_str(p, "\n", 1); + pdf_out_str(p, "endstream", 9); } static void @@ -2497,7 +2700,7 @@ filter_stream_decode_FlateDecode (const void *data, size_t len, struct decode_pa WARN("Ignoring zlib error: status=%d, message=\"%s\"", status, z.msg); break; } else if (status != Z_OK) { - WARN("inflate() failed (status=%d, message=\"%s\").", status, z.msg); + WARN("inflate() failed. Broken PDF file?"); inflateEnd(&z); pdf_release_obj(tmp); return NULL; @@ -2861,76 +3064,83 @@ pdf_stream_get_flags (pdf_obj *stream) #endif static void -pdf_write_obj (pdf_obj *object, FILE *file) +pdf_write_obj (pdf_out *p, pdf_obj *object) { + ASSERT(p); + if (object == NULL) { - write_null(file); + write_null(p); return; } if (INVALIDOBJ(object) || PDF_OBJ_UNDEFINED(object)) ERROR("pdf_write_obj: Invalid object, type = %d\n", object->type); - if (file == stderr) + if (error_out) fprintf(stderr, "{%d}", object->refcount); switch (object->type) { case PDF_BOOLEAN: - write_boolean(object->data, file); + write_boolean(p, object->data); break; case PDF_NUMBER: - write_number (object->data, file); + write_number (p, object->data); break; case PDF_STRING: - write_string (object->data, file); + write_string (p, object->data); break; case PDF_NAME: - write_name(object->data, file); + write_name(p, object->data); break; case PDF_ARRAY: - write_array(object->data, file); + write_array(p, object->data); break; case PDF_DICT: - write_dict (object->data, file); + write_dict (p, object->data); break; case PDF_STREAM: - write_stream(object->data, file); + write_stream(p, object->data); break; case PDF_NULL: - write_null(file); + write_null(p); break; case PDF_INDIRECT: - write_indirect(object->data, file); + write_indirect(p, object->data); break; } } /* Write the object to the file */ static void -pdf_flush_obj (pdf_obj *object, FILE *file) +pdf_flush_obj (pdf_out *p, pdf_obj *object) { - int length; + size_t length; + char buf[64]; /* * Record file position */ - add_xref_entry(object->label, 1, - pdf_output_file_position, object->generation); - length = sprintf(format_buffer, "%u %hu obj\n", object->label, object->generation); - enc_mode = doc_enc_mode && !(object->flags & OBJ_NO_ENCRYPT); - pdf_enc_set_label(object->label); - pdf_enc_set_generation(object->generation); - pdf_out(file, format_buffer, length); - pdf_write_obj(object, file); - pdf_out(file, "\nendobj\n", 8); + add_xref_entry(p, object->label, 1, + p->output.file_position, object->generation); + length = sprintf(buf, "%u %hu obj\n", object->label, object->generation); + p->state.enc_mode = + (p->options.enable_encrypt && !(object->flags & OBJ_NO_ENCRYPT)) ? 1 : 0; + if (p->state.enc_mode) { + pdf_enc_set_label(p->sec_data, object->label); + pdf_enc_set_generation(p->sec_data, object->generation); + } + pdf_out_str(p, buf, length); + pdf_write_obj(p, object); + pdf_out_str(p, "\nendobj\n", 8); } static int -pdf_add_objstm (pdf_obj *objstm, pdf_obj *object) +pdf_add_objstm (pdf_out *p, pdf_obj *objstm, pdf_obj *object) { int *data, pos; TYPECHECK(objstm, PDF_STREAM); + ASSERT(p); data = get_objstm_data(objstm); pos = ++data[0]; @@ -2938,14 +3148,14 @@ pdf_add_objstm (pdf_obj *objstm, pdf_obj *object) data[2*pos] = object->label; data[2*pos+1] = pdf_stream_length(objstm); - add_xref_entry(object->label, 2, objstm->label, pos-1); + add_xref_entry(p, object->label, 2, objstm->label, pos-1); /* redirect output into objstm */ - output_stream = objstm; - enc_mode = 0; - pdf_write_obj(object, pdf_output_file); - pdf_out_char(pdf_output_file, '\n'); - output_stream = NULL; + p->output_stream = objstm; + p->state.enc_mode = 0; + pdf_write_obj(p, object); + pdf_out_char(p, '\n'); + p->output_stream = NULL; return pos; } @@ -2958,7 +3168,7 @@ release_objstm (pdf_obj *objstm) pdf_obj *dict; pdf_stream *stream; unsigned char *old_buf; - unsigned int old_length; + size_t old_length; stream = (pdf_stream *) objstm->data; /* Precede stream data by offset table */ @@ -2971,8 +3181,9 @@ release_objstm (pdf_obj *objstm) { int i = 2*pos, *val = data+2; while (i--) { - int length = sprintf(format_buffer, "%d ", *(val++)); - pdf_add_stream(objstm, format_buffer, length); + char buf[32]; + size_t length = sprintf(buf, "%d ", *(val++)); + pdf_add_stream(objstm, buf, length); } } @@ -2989,13 +3200,17 @@ release_objstm (pdf_obj *objstm) void pdf_release_obj (pdf_obj *object) { + pdf_out *p = current_output(); + if (object == NULL) return; if (INVALIDOBJ(object) || object->refcount <= 0) { MESG("\npdf_release_obj: object=%p, type=%d, refcount=%d\n", - object, object->type, object->refcount); - pdf_write_obj(object, stderr); + object, object->type, object->refcount); + error_out = 1; + pdf_write_obj(p, object); ERROR("pdf_release_obj: Called with invalid object."); + error_out = 0; } object->refcount -= 1; if (object->refcount == 0) { @@ -3006,23 +3221,23 @@ pdf_release_obj (pdf_obj *object) * Nothing is using this object so it's okay to remove it. * Nonzero "label" means object needs to be written before it's destroyed. */ - if (object->label && pdf_output_file != NULL) { - if (!do_objstm || object->flags & OBJ_NO_OBJSTM - || (doc_enc_mode && object->flags & OBJ_NO_ENCRYPT) - || object->generation) - pdf_flush_obj(object, pdf_output_file); + if (object->label && p->output.file != NULL) { + if (!p->options.use_objstm || object->flags & OBJ_NO_OBJSTM || + (p->options.enable_encrypt && (object->flags & OBJ_NO_ENCRYPT)) || + object->generation) + pdf_flush_obj(p, object); else { - if (!current_objstm) { - int *data = NEW(2*OBJSTM_MAX_OBJS+2, int); - data[0] = data[1] = 0; - current_objstm = pdf_new_stream(STREAM_COMPRESS); - set_objstm_data(current_objstm, data); - pdf_label_obj(current_objstm); - } - if (pdf_add_objstm(current_objstm, object) == OBJSTM_MAX_OBJS) { - release_objstm(current_objstm); - current_objstm = NULL; - } + if (!p->current_objstm) { + int *data = NEW(2*OBJSTM_MAX_OBJS+2, int); + data[0] = data[1] = 0; + p->current_objstm = pdf_new_stream(STREAM_COMPRESS); + set_objstm_data(p->current_objstm, data); + pdf_label_obj(p, p->current_objstm); + } + if (pdf_add_objstm(p, p->current_objstm, object) == OBJSTM_MAX_OBJS) { + release_objstm(p->current_objstm); + p->current_objstm = NULL; + } } } switch (object->type) { @@ -3060,6 +3275,9 @@ pdf_release_obj (pdf_obj *object) } } +/* Reading external PDF files + * + */ static int backup_line (FILE *pdf_input_file) { @@ -3086,11 +3304,11 @@ backup_line (FILE *pdf_input_file) static int find_xref (FILE *pdf_input_file) { - int xref_pos = 0; - int len, tries = 10; + size_t len, xref_pos = 0; + int tries = 10; do { - int currentpos; + size_t currentpos; if (!backup_line(pdf_input_file)) { tries = 0; @@ -3162,10 +3380,11 @@ parse_trailer (pdf_file *pf) * :-( */ static int -next_object_offset (pdf_file *pf, unsigned int obj_num) +next_object_offset (pdf_file *pf, uint32_t obj_num) { - int next = pf->file_size; /* Worst case */ - int i, curr; + uint32_t next = pf->file_size; /* Worst case */ + size_t i; + uint32_t curr; curr = pf->xref_table[obj_num].field2; /* Check all other type 1 objects to find next one */ @@ -3184,7 +3403,7 @@ next_object_offset (pdf_file *pf, unsigned int obj_num) ((pf)->xref_table[(n)].type == 2 && !(g)))) pdf_obj * -pdf_new_indirect (pdf_file *pf, unsigned obj_num, unsigned short obj_gen) +pdf_new_indirect (pdf_file *pf, uint32_t obj_num, uint16_t obj_gen) { pdf_obj *result; pdf_indirect *indirect; @@ -3202,13 +3421,12 @@ pdf_new_indirect (pdf_file *pf, unsigned obj_num, unsigned short obj_gen) } static pdf_obj * -pdf_read_object (unsigned int obj_num, unsigned short obj_gen, - pdf_file *pf, int offset, int limit) +pdf_read_object (uint32_t obj_num, uint16_t obj_gen, pdf_file *pf, size_t offset, size_t limit) { - int length; - char *buffer; + pdf_obj *result = NULL; + size_t length; + char *buffer; const char *p, *endptr; - pdf_obj *result; length = limit - offset; @@ -3227,7 +3445,7 @@ pdf_read_object (unsigned int obj_num, unsigned short obj_gen, { const char *q = p; /* <== p */ char *sp; - unsigned int n, g; + uint32_t n, g; skip_white(&q, endptr); sp = parse_unsigned(&q, endptr); @@ -3279,16 +3497,16 @@ pdf_read_object (unsigned int obj_num, unsigned short obj_gen, } static pdf_obj * -read_objstm (pdf_file *pf, unsigned int num) +read_objstm (pdf_file *pf, uint32_t num) { - unsigned int offset = pf->xref_table[num].field2; - unsigned short gen = pf->xref_table[num].field3; - int limit = next_object_offset(pf, num), n, first, *header = NULL; - char *data = NULL, *q; + size_t offset = pf->xref_table[num].field2; + uint16_t gen = pf->xref_table[num].field3; + size_t limit = next_object_offset(pf, num); + int n, first, *header = NULL; + char *data = NULL, *q; const char *p, *endptr; - int i; - - pdf_obj *objstm, *dict, *type, *n_obj, *first_obj; + int i; + pdf_obj *objstm, *dict, *type, *n_obj, *first_obj; objstm = pdf_read_object(num, gen, pf, offset, limit); @@ -3365,7 +3583,7 @@ read_objstm (pdf_file *pf, unsigned int num) * several cross-reference sections. */ static pdf_obj * -pdf_get_object (pdf_file *pf, unsigned int obj_num, unsigned short obj_gen) +pdf_get_object (pdf_file *pf, uint32_t obj_num, uint16_t obj_gen) { pdf_obj *result; @@ -3381,27 +3599,27 @@ pdf_get_object (pdf_file *pf, unsigned int obj_num, unsigned short obj_gen) if (pf->xref_table[obj_num].type == 1) { /* type == 1 */ - unsigned int offset; - int limit; + uint32_t offset; + size_t limit; offset = pf->xref_table[obj_num].field2; limit = next_object_offset(pf, obj_num); result = pdf_read_object(obj_num, obj_gen, pf, offset, limit); } else { /* type == 2 */ - unsigned int objstm_num = pf->xref_table[obj_num].field2; - unsigned short index = pf->xref_table[obj_num].field3; - pdf_obj *objstm; - int *data, n, first, length; + uint32_t objstm_num = pf->xref_table[obj_num].field2; + uint16_t index = pf->xref_table[obj_num].field3; + pdf_obj *objstm; + int *data, n, first, length; const char *p, *q; if (objstm_num >= pf->num_obj || - pf->xref_table[objstm_num].type != 1 || - !((objstm = pf->xref_table[objstm_num].direct) || - (objstm = read_objstm(pf, objstm_num)))) + pf->xref_table[objstm_num].type != 1 || + !((objstm = pf->xref_table[objstm_num].direct) || + (objstm = read_objstm(pf, objstm_num)))) goto error; - data = get_objstm_data(objstm); - n = *(data++); + data = get_objstm_data(objstm); + n = *(data++); first = *(data++); if (index >= n || data[2*index] != obj_num) @@ -3431,12 +3649,14 @@ pdf_get_object (pdf_file *pf, unsigned int obj_num, unsigned short obj_gen) #define OBJ_GEN(o) (((pdf_indirect *)((o)->data))->generation) static pdf_obj * -pdf_new_ref (pdf_obj *object) +pdf_new_ref (pdf_out *p, pdf_obj *object) { pdf_obj *result; + ASSERT(p); + if (object->label == 0) { - pdf_label_obj(object); + pdf_label_obj(p, object); } result = pdf_new_indirect(NULL, object->label, object->generation); OBJ_OBJ(result) = object; @@ -3456,8 +3676,8 @@ pdf_deref_obj (pdf_obj *obj) while (PDF_OBJ_INDIRECTTYPE(obj) && --count) { pdf_file *pf = OBJ_FILE(obj); if (pf) { - unsigned int obj_num = OBJ_NUM(obj); - unsigned short obj_gen = OBJ_GEN(obj); + uint32_t obj_num = OBJ_NUM(obj); + uint16_t obj_gen = OBJ_GEN(obj); pdf_release_obj(obj); obj = pdf_get_object(pf, obj_num, obj_gen); } else { @@ -3481,9 +3701,9 @@ pdf_deref_obj (pdf_obj *obj) } static void -extend_xref (pdf_file *pf, int new_size) +extend_xref (pdf_file *pf, size_t new_size) { - unsigned int i; + size_t i; pf->xref_table = RENEW(pf->xref_table, new_size, xref_entry); for (i = pf->num_obj; i < new_size; i++) { @@ -3498,12 +3718,12 @@ extend_xref (pdf_file *pf, int new_size) /* Returns < 0 for error, 1 for success, and 0 when xref stream found. */ static int -parse_xref_table (pdf_file *pf, int xref_pos) +parse_xref_table (pdf_file *pf, size_t xref_pos) { FILE *pdf_input_file = pf->file; const char *p, *endptr; char buf[256]; /* See, PDF ref. v.1.7, p.91 for "255+1" here. */ - int len; + size_t len; /* * This routine reads one xref segment. It may be called multiple times @@ -3535,10 +3755,10 @@ parse_xref_table (pdf_file *pf, int xref_pos) /* Next line in file has first item and size of table */ for (;;) { - char flag; - unsigned int current_pos; - int i; - uint32_t first, size, offset, obj_gen; + char flag; + size_t current_pos, size, offset; + int i; + uint32_t first, obj_gen; current_pos = tell_position(pdf_input_file); len = mfreadln(buf, 255, pdf_input_file); @@ -3702,10 +3922,10 @@ parse_xref_table (pdf_file *pf, int xref_pos) return 1; } -static unsigned int -parse_xrefstm_field (const char **p, int length, unsigned int def) +static uint32_t +parse_xrefstm_field (const char **p, size_t length, uint32_t def) { - unsigned int val = 0; + uint32_t val = 0; if (!length) return def; @@ -3720,9 +3940,9 @@ parse_xrefstm_field (const char **p, int length, unsigned int def) static int parse_xrefstm_subsec (pdf_file *pf, - const char **p, int *length, - int *W, int wsum, - int first, int size) { + const char **p, size_t *length, + int *W, int wsum, int first, int size) +{ xref_entry *e; if ((*length -= wsum*size) < 0) @@ -3733,9 +3953,9 @@ parse_xrefstm_subsec (pdf_file *pf, e = pf->xref_table + first; while (size--) { - unsigned char type; - unsigned int field2; - unsigned short field3; + uint8_t type; + uint32_t field2; + uint16_t field3; type = (unsigned char) parse_xrefstm_field(p, W[0], 1); if (type > 2) @@ -3746,8 +3966,8 @@ parse_xrefstm_subsec (pdf_file *pf, return -1; #endif - field2 = (unsigned int) parse_xrefstm_field(p, W[1], 0); - field3 = (unsigned short) parse_xrefstm_field(p, W[2], 0); + field2 = (uint32_t) parse_xrefstm_field(p, W[1], 0); + field3 = (uint16_t) parse_xrefstm_field(p, W[2], 0); if (!e->field2) { e->type = type; @@ -3761,12 +3981,12 @@ parse_xrefstm_subsec (pdf_file *pf, } static int -parse_xref_stream (pdf_file *pf, int xref_pos, pdf_obj **trailer) +parse_xref_stream (pdf_file *pf, size_t xref_pos, pdf_obj **trailer) { - pdf_obj *xrefstm, *size_obj, *W_obj, *index_obj; - unsigned int size; - int length; - int W[3], i, wsum = 0; + pdf_obj *xrefstm, *size_obj, *W_obj, *index_obj; + uint32_t size; + size_t length; + int W[3], i, wsum = 0; const char *p; xrefstm = pdf_read_object(0, 0, pf, xref_pos, pf->file_size); @@ -3786,7 +4006,7 @@ parse_xref_stream (pdf_file *pf, int xref_pos, pdf_obj **trailer) size_obj = pdf_lookup_dict(*trailer, "Size"); if (!PDF_OBJ_NUMBERTYPE(size_obj)) goto error; - size = (unsigned int) pdf_number_value(size_obj); + size = (uint32_t) pdf_number_value(size_obj); length = pdf_stream_length(xrefstm); @@ -3805,7 +4025,7 @@ parse_xref_stream (pdf_file *pf, int xref_pos, pdf_obj **trailer) index_obj = pdf_lookup_dict(*trailer, "Index"); if (index_obj) { - unsigned int index_len; + size_t index_len; if (!PDF_OBJ_ARRAYTYPE(index_obj) || ((index_len = pdf_array_length(index_obj)) % 2 )) goto error; @@ -3845,7 +4065,7 @@ static pdf_obj * read_xref (pdf_file *pf) { pdf_obj *trailer = NULL, *main_trailer = NULL; - int xref_pos; + size_t xref_pos; if (!(xref_pos = find_xref(pf->file))) goto error; @@ -3859,37 +4079,37 @@ read_xref (pdf_file *pf) pdf_obj *xrefstm; if (!(trailer = parse_trailer(pf))) - goto error; + goto error; if (!main_trailer) - main_trailer = pdf_link_obj(trailer); + main_trailer = pdf_link_obj(trailer); if ((xrefstm = pdf_lookup_dict(trailer, "XRefStm"))) { - pdf_obj *new_trailer = NULL; - if (PDF_OBJ_NUMBERTYPE(xrefstm) && - parse_xref_stream(pf, (int) pdf_number_value(xrefstm), + pdf_obj *new_trailer = NULL; + if (PDF_OBJ_NUMBERTYPE(xrefstm) && + parse_xref_stream(pf, (int) pdf_number_value(xrefstm), &new_trailer)) - pdf_release_obj(new_trailer); - else - WARN("Skipping hybrid reference section."); - /* Many PDF 1.5 xref streams use DecodeParms, which we cannot - parse. This way we can use at least xref tables in hybrid - documents. Or should we better stop parsing the file? - */ + pdf_release_obj(new_trailer); + else + WARN("Skipping hybrid reference section."); + /* Many PDF 1.5 xref streams use DecodeParms, which we cannot + * parse. This way we can use at least xref tables in hybrid + * documents. Or should we better stop parsing the file? + */ } } else if (!res && parse_xref_stream(pf, xref_pos, &trailer)) { /* cross-reference stream */ if (!main_trailer) - main_trailer = pdf_link_obj(trailer); + main_trailer = pdf_link_obj(trailer); } else goto error; if ((prev = pdf_lookup_dict(trailer, "Prev"))) { if (PDF_OBJ_NUMBERTYPE(prev)) - xref_pos = (int) pdf_number_value(prev); + xref_pos = (size_t) pdf_number_value(prev); else - goto error; + goto error; } else xref_pos = 0; @@ -3938,7 +4158,7 @@ pdf_file_new (FILE *file) static void pdf_file_free (pdf_file *pf) { - unsigned int i; + size_t i; if (!pf) { return; @@ -3995,6 +4215,7 @@ pdf_file_get_catalog (pdf_file *pf) pdf_file * pdf_open (const char *ident, FILE *file) { + pdf_out *p = current_output(); pdf_file *pf = NULL; ASSERT(pdf_files); @@ -4008,15 +4229,21 @@ pdf_open (const char *ident, FILE *file) pdf_obj *new_version; int version = check_for_pdf_version(file); - if (version < 10) - WARN("Unrecognized PDF version specified for input PDF file: %d.%d", - pdf_version/10, pdf_version%10); - else if (version > pdf_version) { - WARN("Trying to include PDF file with version (%d.%d), which is " \ - "newer than current output PDF setting (%d.%d).", - version/10, version%10, pdf_version/10, pdf_version%10); - } + if (!dpx_conf.is_xbb) { + int ver_major, ver_minor; + ver_major = version / 10; + ver_minor = version % 10; + + if (version < 10) + WARN("Unrecognized PDF version specified for input PDF file: %d.%d", + ver_major, ver_minor); + else if (pdf_check_version(ver_major, ver_minor) < 0) { + WARN("Trying to include PDF file with version (%d.%d), which is " \ + "newer than current output PDF setting (%d.%d).", + ver_major, ver_minor, p->version.major, p->version.minor); + } + } pf = pdf_file_new(file); pf->version = version; @@ -4096,7 +4323,7 @@ check_for_pdf (FILE *file) if (version < 0) /* not a PDF file */ return 0; - if (version <= pdf_version) + if (version <= pdf_get_version()) return 1; return 1; @@ -4122,10 +4349,11 @@ import_dict (pdf_obj *key, pdf_obj *value, void *pdata) static pdf_obj * pdf_import_indirect (pdf_obj *object) { + pdf_out *p = current_output(); pdf_file *pf = OBJ_FILE(object); - unsigned int obj_num = OBJ_NUM(object); - unsigned short obj_gen = OBJ_GEN(object); - pdf_obj *ref; + uint32_t obj_num = OBJ_NUM(object); + uint16_t obj_gen = OBJ_GEN(object); + pdf_obj *ref; ASSERT(pf); @@ -4154,7 +4382,7 @@ pdf_import_indirect (pdf_obj *object) * are completely read. */ reserved = pdf_new_null(); /* for reservation of label */ - pf->xref_table[obj_num].indirect = ref = pdf_new_ref(reserved); + pf->xref_table[obj_num].indirect = ref = pdf_new_ref(p, reserved); imported = pdf_import_object(obj); if (imported) { if (imported->label) { @@ -4187,7 +4415,7 @@ pdf_import_object (pdf_obj *object) { pdf_obj *imported; pdf_obj *tmp; - int i; + size_t i; switch (pdf_obj_typeof(object)) { @@ -4233,8 +4461,8 @@ pdf_import_object (pdf_obj *object) for (i = 0; i < pdf_array_length(object); i++) { tmp = pdf_import_object(pdf_get_array(object, i)); if (!tmp) { - pdf_release_obj(imported); - return NULL; + pdf_release_obj(imported); + return NULL; } pdf_add_array(imported, tmp); } diff --git a/Build/source/texk/dvipdfm-x/pdfobj.h b/Build/source/texk/dvipdfm-x/pdfobj.h index 04ba12e711c..7b41bb411b4 100644 --- a/Build/source/texk/dvipdfm-x/pdfobj.h +++ b/Build/source/texk/dvipdfm-x/pdfobj.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2020 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2020 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -25,6 +25,7 @@ #include +typedef struct pdf_out pdf_out; /* Here is the complete list of PDF object types */ @@ -54,13 +55,19 @@ typedef struct pdf_file pdf_file; extern void pdf_error_cleanup (void); extern FILE *pdf_get_output_file (void); - -extern void pdf_out_init (const char *filename, - int enable_encrypt, int enable_objstm, - int enable_predictor); +extern pdf_out *pdf_out_init (const char *filename, + const unsigned char *id1, const unsigned char *id2, + int ver_major, int ver_minor, + int compression_level, + int enable_encrypt, + int enable_objstm, + int enable_predictor); +extern void pdf_out_set_encrypt (int keybits, int32_t permission, + const char *opasswd, const char *upasswd, + int use_aes, int encrypt_metadata); extern void pdf_out_flush (void); -extern void pdf_set_version (int version); -extern int pdf_get_version (void); + +extern int pdf_get_version (void); extern int pdf_get_version_major (void); extern int pdf_get_version_minor (void); @@ -152,6 +159,7 @@ extern pdf_obj *pdf_new_stream (int flags); extern void pdf_add_stream (pdf_obj *stream, const void *stream_data_ptr, int stream_data_len); + extern int pdf_concat_stream (pdf_obj *dst, pdf_obj *src); extern pdf_obj *pdf_stream_dict (pdf_obj *stream); extern int pdf_stream_length (pdf_obj *stream); @@ -164,24 +172,21 @@ extern void pdf_stream_set_predictor (pdf_obj *stream, int predictor, int32_t columns, int bpc, int colors); -/* Compare labels of two indirect reference object. */ +/* Compare label of two indirect reference object. */ extern int pdf_compare_reference (pdf_obj *ref1, pdf_obj *ref2); /* Compare objects. */ extern int pdf_compare_object (pdf_obj *obj1, pdf_obj *obj2); + /* The following routines are not appropriate for pdfobj. */ -extern void pdf_set_compression (int level); - extern void pdf_set_info (pdf_obj *obj); extern void pdf_set_root (pdf_obj *obj); -extern void pdf_set_id (pdf_obj *id); -extern void pdf_set_encrypt (pdf_obj *encrypt); extern void pdf_files_init (void); extern void pdf_files_close (void); -extern int check_for_pdf (FILE *file); +extern int check_for_pdf (FILE *file); extern pdf_file *pdf_open (const char *ident, FILE *file); extern void pdf_close (pdf_file *pf); extern pdf_obj *pdf_file_get_trailer (pdf_file *pf); @@ -193,7 +198,7 @@ extern pdf_obj *pdf_import_object (pdf_obj *object); extern int pdfobj_escape_str (char *buffer, int size, const unsigned char *s, int len); -extern pdf_obj *pdf_new_indirect (pdf_file *pf, unsigned label, unsigned short generation); +extern pdf_obj *pdf_new_indirect (pdf_file *pf, uint32_t label, uint16_t generation); extern int pdf_check_version (int major, int minor); diff --git a/Build/source/texk/dvipdfm-x/pdfparse.c b/Build/source/texk/dvipdfm-x/pdfparse.c index 050eb988230..58ea9a0bc4e 100644 --- a/Build/source/texk/dvipdfm-x/pdfparse.c +++ b/Build/source/texk/dvipdfm-x/pdfparse.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2020 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -70,8 +70,6 @@ static struct { static int xtoi (char ch); -static const char *save = NULL; - void dump (const char *start, const char *end) { @@ -86,14 +84,6 @@ dump (const char *start, const char *end) MESG("<--\n"); } -#define SAVE(s,e) do {\ - save = (s);\ - } while (0) -#define DUMP_RESTORE(s,e) do {\ - dump(save, end);\ - (s) = save;\ - } while (0) - void pdfparse_skip_line (const char **start, const char *end) { @@ -646,28 +636,12 @@ parse_pdf_string (const char **pp, const char *endptr) return NULL; } -#ifndef PDF_PARSE_STRICT -pdf_obj * -parse_pdf_tainted_dict (const char **pp, const char *endptr) -{ - pdf_obj *result; - - parser_state.tainted = 1; - result = parse_pdf_dict(pp, endptr, NULL); - parser_state.tainted = 0; - - return result; -} -#else /* PDF_PARSE_STRICT */ -pdf_obj * -parse_pdf_tainted_dict (const char **pp, const char *endptr) -{ - return parse_pdf_dict(pp, endptr, NULL); -} -#endif /* !PDF_PARSE_STRICT */ - -pdf_obj * -parse_pdf_dict (const char **pp, const char *endptr, pdf_file *pf) +static pdf_obj * +parse_pdf_dict_extended (const char **pp, const char *endptr, pdf_file *pf, + pdf_obj* (*unknown_handler) (const char **pp, + const char *endptr, + void *user_data), + void *user_data) { pdf_obj *result = NULL; const char *p; @@ -699,7 +673,7 @@ parse_pdf_dict (const char **pp, const char *endptr, pdf_file *pf) skip_white(&p, endptr); - value = parse_pdf_object(&p, endptr, pf); + value = parse_pdf_object_extended(&p, endptr, pf, unknown_handler, user_data); if (!value) { pdf_release_obj(key); pdf_release_obj(value); @@ -723,8 +697,12 @@ parse_pdf_dict (const char **pp, const char *endptr, pdf_file *pf) return result; } -pdf_obj * -parse_pdf_array (const char **pp, const char *endptr, pdf_file *pf) +static pdf_obj * +parse_pdf_array_extended (const char **pp, const char *endptr, pdf_file *pf, + pdf_obj* (*unknown_handler) (const char **pp, + const char *endptr, + void *user_data), + void *user_data) { pdf_obj *result; const char *p; @@ -745,7 +723,7 @@ parse_pdf_array (const char **pp, const char *endptr, pdf_file *pf) while (p < endptr && p[0] != ']') { pdf_obj *elem; - elem = parse_pdf_object(&p, endptr, pf); + elem = parse_pdf_object_extended(&p, endptr, pf, unknown_handler, user_data); if (!elem) { pdf_release_obj(result); WARN("Could not find a valid object in array object."); @@ -865,39 +843,6 @@ parse_pdf_stream (const char **pp, const char *endptr, pdf_obj *dict) return result; } -#ifndef PDF_PARSE_STRICT - -/* PLEASE REMOVE THIS */ -#include "specials.h" - -/* This is not PDF indirect reference. */ -static pdf_obj * -parse_pdf_reference (const char **start, const char *end) -{ - pdf_obj *result = NULL; - char *name; - - SAVE(*start, end); - - skip_white(start, end); - name = parse_opt_ident(start, end); - if (name) { - result = spc_lookup_reference(name); - if (!result) { - WARN("Could not find the named reference (@%s).", name); - DUMP_RESTORE(*start, end); - } - RELEASE(name); - } else { - WARN("Could not find a reference name."); - DUMP_RESTORE(*start, end); - result = NULL; - } - - return result; -} -#endif /* !PDF_PARSE_STRICT */ - static pdf_obj * try_pdf_reference (const char *start, const char *end, const char **endptr, pdf_file *pf) { @@ -945,7 +890,11 @@ try_pdf_reference (const char *start, const char *end, const char **endptr, pdf_ } pdf_obj * -parse_pdf_object (const char **pp, const char *endptr, pdf_file *pf) +parse_pdf_object_extended (const char **pp, const char *endptr, pdf_file *pf, + pdf_obj* (*unknown_handler) (const char **pp, + const char *endptr, + void *user_data), + void *user_data) /* If pf is NULL, then indirect references are not allowed */ { pdf_obj *result = NULL; @@ -966,7 +915,7 @@ parse_pdf_object (const char **pp, const char *endptr, pdf_file *pf) } else { pdf_obj *dict; - result = parse_pdf_dict(pp, endptr, pf); + result = parse_pdf_dict_extended(pp, endptr, pf, unknown_handler, user_data); skip_white(pp, endptr); if ( result && *pp <= endptr - 15 && @@ -982,7 +931,7 @@ parse_pdf_object (const char **pp, const char *endptr, pdf_file *pf) result = parse_pdf_string(pp, endptr); break; case '[': - result = parse_pdf_array(pp, endptr, pf); + result = parse_pdf_array_extended(pp, endptr, pf, unknown_handler, user_data); break; case '/': result = parse_pdf_name(pp, endptr); @@ -1010,18 +959,51 @@ parse_pdf_object (const char **pp, const char *endptr, pdf_file *pf) } break; - case '@': - -#ifndef PDF_PARSE_STRICT - result = parse_pdf_reference(pp, endptr); -#endif /* !PDF_PARSE_STRICT */ - break; - default: - WARN("Unknown PDF object type."); - result = NULL; + if (unknown_handler) { + result = unknown_handler(pp, endptr, user_data); + } else { + WARN("Unknown PDF object type."); + result = NULL; + } + break; } return result; } +pdf_obj * +parse_pdf_dict (const char **pp, const char *endptr, pdf_file *pf) +{ + return parse_pdf_dict_extended(pp, endptr, pf, NULL, NULL); +} + +pdf_obj * +parse_pdf_array (const char **pp, const char *endptr, pdf_file *pf) +{ + return parse_pdf_array_extended(pp, endptr, pf, NULL, NULL); +} + +pdf_obj * +parse_pdf_object (const char **pp, const char *endptr, pdf_file *pf) +{ + return parse_pdf_object_extended(pp, endptr, pf, NULL, NULL); +} + + +pdf_obj * +parse_pdf_tainted_dict (const char **pp, const char *endptr, + pdf_obj* (*unknown_handler) (const char **pp, + const char *endptr, + void *user_data), + void *user_data) +{ + pdf_obj *result; + + parser_state.tainted = 1; + result = parse_pdf_dict_extended(pp, endptr, NULL, unknown_handler, user_data); + parser_state.tainted = 0; + + return result; +} + diff --git a/Build/source/texk/dvipdfm-x/pdfparse.h b/Build/source/texk/dvipdfm-x/pdfparse.h index f55469864c0..52ec95d99fc 100644 --- a/Build/source/texk/dvipdfm-x/pdfparse.h +++ b/Build/source/texk/dvipdfm-x/pdfparse.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2020 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -48,6 +48,15 @@ extern pdf_obj *parse_pdf_dict (const char **pp, const char *endptr, pdf_file extern pdf_obj *parse_pdf_array (const char **pp, const char *endptr, pdf_file *pf); extern pdf_obj *parse_pdf_object (const char **pp, const char *endptr, pdf_file *pf); -extern pdf_obj *parse_pdf_tainted_dict (const char **pp, const char *endptr); +extern pdf_obj *parse_pdf_object_extended (const char **pp, const char *endptr, pdf_file *pf, + pdf_obj* (*unknown_handler) (const char **pp, + const char *endptr, + void *user_data), + void *user_data); +extern pdf_obj *parse_pdf_tainted_dict (const char **pp, const char *endptr, + pdf_obj* (*unknown_handler) (const char **pp, + const char *endptr, + void *user_data), + void *user_data); #endif /* _PDFPARSE_H_ */ diff --git a/Build/source/texk/dvipdfm-x/pdfximage.c b/Build/source/texk/dvipdfm-x/pdfximage.c index e83d29f47fa..50190a2d439 100644 --- a/Build/source/texk/dvipdfm-x/pdfximage.c +++ b/Build/source/texk/dvipdfm-x/pdfximage.c @@ -38,7 +38,6 @@ #include "pdfdev.h" #include "pdfdraw.h" #include "pdfnames.h" -#include "specials.h" #include "epdf.h" #include "mpost.h" diff --git a/Build/source/texk/dvipdfm-x/spc_pdfm.c b/Build/source/texk/dvipdfm-x/spc_pdfm.c index 7d068ba4718..fdb2ac13d68 100644 --- a/Build/source/texk/dvipdfm-x/spc_pdfm.c +++ b/Build/source/texk/dvipdfm-x/spc_pdfm.c @@ -59,12 +59,6 @@ #define SPC_PDFM_SUPPORT_ANNOT_TRANS 1 -/* PLEASE REMOVE THIS */ -struct resource_map { - int type; - int res_id; -}; - struct tounicode { int cmap_id; int unescape_backslash; @@ -86,6 +80,27 @@ static struct spc_pdf_ _pdf_stat = { NULL }; +static pdf_obj * +parse_pdf_reference (const char **start, const char *end, void *user_data) +{ + pdf_obj *result = NULL; + char *name; + + skip_white(start, end); + name = parse_opt_ident(start, end); + if (name) { + result = spc_lookup_reference(name); + if (!result) { + WARN("Could not find the named reference (@%s).", name); + } + RELEASE(name); + } else { + WARN("Could not find a reference name."); + result = NULL; + } + + return result; +} static int spc_handler_pdfm__init (void *dp) @@ -340,7 +355,7 @@ spc_handler_pdfm_put (struct spc_env *spe, struct spc_arg *ap) } skip_white(&ap->curptr, ap->endptr); - obj2 = parse_pdf_object(&ap->curptr, ap->endptr, NULL); + obj2 = parse_pdf_object_extended(&ap->curptr, ap->endptr, NULL, parse_pdf_reference, spe); if (!obj2) { spc_warn(spe, "Missing (an) object(s) to put into \"%s\"!", ident); RELEASE(ident); @@ -386,7 +401,7 @@ spc_handler_pdfm_put (struct spc_env *spe, struct spc_arg *ap) /* dvipdfm */ pdf_add_array(obj1, pdf_link_obj(obj2)); while (ap->curptr < ap->endptr) { - pdf_obj *obj3 = parse_pdf_object(&ap->curptr, ap->endptr, NULL); + pdf_obj *obj3 = parse_pdf_object_extended(&ap->curptr, ap->endptr, NULL, parse_pdf_reference, spe); if (!obj3) break; pdf_add_array(obj1, obj3); @@ -577,17 +592,30 @@ parse_pdf_dict_with_tounicode (const char **pp, const char *endptr, struct touni pdf_obj *dict; /* disable this test for XDV files, as we do UTF8 reencoding with no cmap */ - if ((dpx_conf.compat_mode != dpx_mode_xdv_mode) && cd->cmap_id < 0) - return parse_pdf_dict(pp, endptr, NULL); - - /* :( */ - if (cd && cd->unescape_backslash) - dict = parse_pdf_tainted_dict(pp, endptr); - else { - dict = parse_pdf_dict(pp, endptr, NULL); + if ((dpx_conf.compat_mode != dpx_mode_xdv_mode) && cd->cmap_id < 0) { + dict = parse_pdf_object_extended(pp, endptr, NULL, parse_pdf_reference, NULL); + if (dict && !PDF_OBJ_DICTTYPE(dict)) { + WARN("Dictionary type object expected but non-dictionary type found."); + pdf_release_obj(dict); + dict = NULL; + } + } else { + /* :( */ + if (cd && cd->unescape_backslash) { + dict = parse_pdf_tainted_dict(pp, endptr, parse_pdf_reference, NULL); + } else { + dict = parse_pdf_object_extended(pp, endptr, NULL, parse_pdf_reference, NULL); + } + if (dict) { + if (!PDF_OBJ_DICTTYPE(dict)) { + WARN("Dictionary type object expected but non-dictionary type found."); + pdf_release_obj(dict); + dict = NULL; + } else { + pdf_foreach_dict(dict, modstrings, cd); + } + } } - if (dict) - pdf_foreach_dict(dict, modstrings, cd); return dict; } @@ -1246,7 +1274,7 @@ spc_handler_pdfm_image (struct spc_env *spe, struct spc_arg *args) skip_white(&args->curptr, args->endptr); if (args->curptr < args->endptr) { - options.dict = parse_pdf_object(&args->curptr, args->endptr, NULL); + options.dict = parse_pdf_object_extended(&args->curptr, args->endptr, NULL, parse_pdf_reference, spe); } xobj_id = pdf_ximage_load_image(ident, pdf_string_value(fspec), options); @@ -1297,7 +1325,7 @@ spc_handler_pdfm_dest (struct spc_env *spe, struct spc_arg *args) WARN("Failed to convert input string to UTF16..."); #endif - array = parse_pdf_object(&args->curptr, args->endptr, NULL); + array = parse_pdf_object_extended(&args->curptr, args->endptr, NULL, parse_pdf_reference, spe); if (!array) { spc_warn(spe, "No destination specified for pdf:dest."); pdf_release_obj(name); @@ -1334,7 +1362,7 @@ spc_handler_pdfm_names (struct spc_env *spe, struct spc_arg *args) return -1; } - tmp = parse_pdf_object(&args->curptr, args->endptr, NULL); + tmp = parse_pdf_object_extended(&args->curptr, args->endptr, NULL, parse_pdf_reference, spe); if (!tmp) { spc_warn(spe, "PDF object expected but not found."); pdf_release_obj(category); @@ -1369,7 +1397,7 @@ spc_handler_pdfm_names (struct spc_env *spe, struct spc_arg *args) pdf_release_obj(tmp); } else if (PDF_OBJ_STRINGTYPE(tmp)) { key = tmp; - value = parse_pdf_object(&args->curptr, args->endptr, NULL); + value = parse_pdf_object_extended(&args->curptr, args->endptr, NULL, parse_pdf_reference, spe); if (!value) { pdf_release_obj(category); pdf_release_obj(key); @@ -1474,7 +1502,7 @@ spc_handler_pdfm_object (struct spc_env *spe, struct spc_arg *args) return -1; } - object = parse_pdf_object(&args->curptr, args->endptr, NULL); + object = parse_pdf_object_extended(&args->curptr, args->endptr, NULL, parse_pdf_reference, spe); if (!object) { spc_warn(spe, "Could not find an object definition for \"%s\".", ident); RELEASE(ident); @@ -1692,12 +1720,18 @@ spc_handler_pdfm_stream_with_type (struct spc_env *spe, struct spc_arg *args, in stream_dict = pdf_stream_dict(fstream); - tmp = parse_pdf_dict(&args->curptr, args->endptr, NULL); + tmp = parse_pdf_object_extended(&args->curptr, args->endptr, NULL, parse_pdf_reference, spe); if (!tmp) { spc_warn(spe, "Parsing dictionary failed."); pdf_release_obj(fstream); RELEASE(ident); return -1; + } else if (!PDF_OBJ_DICTTYPE(tmp)) { + spc_warn(spe, "Expecting dictionary type object but non-dictionary type found."); + pdf_release_obj(fstream); + pdf_release_obj(tmp); + RELEASE(ident); + return -1; } if (pdf_lookup_dict(tmp, "Length")) { pdf_remove_dict(tmp, "Length"); @@ -1829,7 +1863,7 @@ spc_handler_pdfm_eform (struct spc_env *spe, struct spc_arg *args) skip_white(&args->curptr, args->endptr); if (args->curptr < args->endptr) { - attrib = parse_pdf_dict(&args->curptr, args->endptr, NULL); + attrib = parse_pdf_object_extended(&args->curptr, args->endptr, NULL, parse_pdf_reference, spe); if (attrib && !PDF_OBJ_DICTTYPE(attrib)) { pdf_release_obj(attrib); attrib = NULL; @@ -2131,7 +2165,7 @@ spc_handler_pdfm_pageresources (struct spc_env *spe, struct spc_arg *args) struct spc_pdf_ *sd = &_pdf_stat; pdf_obj *dict; - dict = parse_pdf_object(&args->curptr, args->endptr, NULL); + dict = parse_pdf_object_extended(&args->curptr, args->endptr, NULL, parse_pdf_reference, spe); if (!dict) { spc_warn(spe, "Dictionary object expected but not found."); return -1; @@ -2147,19 +2181,19 @@ spc_handler_pdfm_pageresources (struct spc_env *spe, struct spc_arg *args) static int spc_handler_pdfm_bxgstate (struct spc_env *spe, struct spc_arg *args) { - pdf_obj *object; + pdf_obj *obj; skip_white(&args->curptr, args->endptr); - object = parse_pdf_object(&args->curptr, args->endptr, NULL); - if (!object) { + obj = parse_pdf_object_extended(&args->curptr, args->endptr, NULL, parse_pdf_reference, spe); + if (!obj) { spc_warn(spe, "Could not find an object definition."); return -1; - } else if (!PDF_OBJ_DICTTYPE(object)) { + } else if (!PDF_OBJ_DICTTYPE(obj)) { spc_warn(spe, "Parsed object for ExtGState not a dictionary object!"); - pdf_release_obj(object); + pdf_release_obj(obj); return -1; } - pdf_dev_xgstate_push(object); + pdf_dev_xgstate_push(obj); skip_white(&args->curptr, args->endptr); diff --git a/Build/source/texk/dvipdfm-x/xbb.c b/Build/source/texk/dvipdfm-x/xbb.c index fbea47f173c..36e7e895349 100644 --- a/Build/source/texk/dvipdfm-x/xbb.c +++ b/Build/source/texk/dvipdfm-x/xbb.c @@ -304,7 +304,7 @@ int extractbb (int argc, char *argv[]) pdf_files_init(); - pdf_set_version(PDF_VERSION_MAX); + dpx_conf.is_xbb = 1; opterr = 0; -- cgit v1.2.3