From 4048ef67ad1aadfadb714751a1469867065ea587 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Sat, 24 Oct 2020 13:54:24 -0400 Subject: [PATCH 01/24] Update xdvipdfmx to the TeXLive 2020.0 reference There is a lot going on here so I hope that I got it all right. There is new code relating to CMaps that alters the PDF output, so unfortunately it does not seem practical to try to make it so that the new code can pass the existing PDF-output test suite. --- build.rs | 1 + tectonic/dpx-agl.c | 25 +- tectonic/dpx-agl.h | 3 +- tectonic/dpx-bmpimage.c | 7 +- tectonic/dpx-cid.c | 69 +- tectonic/dpx-cid.h | 3 +- tectonic/dpx-cid_p.h | 3 +- tectonic/dpx-cidtype0.c | 22 +- tectonic/dpx-cidtype0.h | 3 +- tectonic/dpx-cidtype2.c | 50 +- tectonic/dpx-cidtype2.h | 3 +- tectonic/dpx-cmap.c | 32 +- tectonic/dpx-cmap.h | 5 +- tectonic/dpx-cmap_p.h | 4 +- tectonic/dpx-cmap_read.c | 9 +- tectonic/dpx-cmap_write.c | 87 ++- tectonic/dpx-dpxconf.c | 4 +- tectonic/dpx-dpxconf.h | 19 +- tectonic/dpx-dpxfile.c | 39 +- tectonic/dpx-dpxfile.h | 8 +- tectonic/dpx-dpxutil.c | 66 +- tectonic/dpx-dpxutil.h | 8 +- tectonic/dpx-dvi.c | 262 +++++-- tectonic/dpx-dvi.h | 5 +- tectonic/dpx-dvipdfmx.c | 204 +++-- tectonic/dpx-dvipdfmx.h | 4 +- tectonic/dpx-epdf.c | 351 +-------- tectonic/dpx-fontmap.c | 42 +- tectonic/dpx-fontmap.h | 7 +- tectonic/dpx-jp2image.c | 9 +- tectonic/dpx-jpegimage.c | 27 +- tectonic/dpx-mem.h | 11 +- tectonic/dpx-mfileio.h | 2 +- tectonic/dpx-mpost.c | 75 +- tectonic/dpx-mpost.h | 4 +- tectonic/dpx-mt19937ar.c | 183 +++++ tectonic/dpx-numbers.c | 2 +- tectonic/dpx-numbers.h | 2 +- tectonic/dpx-pdfcolor.c | 37 +- tectonic/dpx-pdfcolor.h | 4 +- tectonic/dpx-pdfdev.c | 41 +- tectonic/dpx-pdfdev.h | 4 +- tectonic/dpx-pdfdoc.c | 522 +++++++------ tectonic/dpx-pdfdoc.h | 78 +- tectonic/dpx-pdfdraw.c | 3 +- tectonic/dpx-pdfencoding.c | 65 +- tectonic/dpx-pdfencoding.h | 4 +- tectonic/dpx-pdfencrypt.c | 146 ++-- tectonic/dpx-pdfencrypt.h | 9 +- tectonic/dpx-pdffont.c | 102 +-- tectonic/dpx-pdffont.h | 5 +- tectonic/dpx-pdflimits.h | 8 +- tectonic/dpx-pdfobj.c | 630 ++++++++++----- tectonic/dpx-pdfobj.h | 23 +- tectonic/dpx-pdfximage.c | 37 +- tectonic/dpx-pdfximage.h | 8 +- tectonic/dpx-pngimage.c | 24 +- tectonic/dpx-spc_dvips.c | 2 +- tectonic/dpx-spc_pdfm.c | 348 ++++++++- tectonic/dpx-spc_pdfm.h | 4 +- tectonic/dpx-spc_tpic.c | 9 +- tectonic/dpx-spc_util.c | 18 +- tectonic/dpx-spc_util.h | 5 +- tectonic/dpx-spc_xtx.c | 16 +- tectonic/dpx-specials.c | 27 +- tectonic/dpx-specials.h | 5 +- tectonic/dpx-subfont.c | 20 +- tectonic/dpx-subfont.h | 4 +- tectonic/dpx-system.h | 2 +- tectonic/dpx-t1_char.c | 4 +- tectonic/dpx-tfm.c | 16 +- tectonic/dpx-tfm.h | 3 +- tectonic/dpx-truetype.c | 40 +- tectonic/dpx-tt_aux.c | 18 +- tectonic/dpx-tt_aux.h | 4 +- tectonic/dpx-tt_cmap.c | 1509 ++++++++++++++++++++---------------- tectonic/dpx-tt_cmap.h | 10 +- tectonic/dpx-tt_gsub.c | 503 ++++++++++-- tectonic/dpx-tt_gsub.h | 9 +- tectonic/dpx-tt_post.c | 29 +- tectonic/dpx-tt_table.c | 19 +- tectonic/dpx-type0.c | 75 +- tectonic/dpx-type0.h | 4 +- tectonic/dpx-type1.c | 30 +- tectonic/dpx-type1c.c | 14 +- tectonic/dpx-unicode.c | 22 +- tectonic/dpx-vf.c | 16 +- tectonic/dpx-vf.h | 3 +- 88 files changed, 3657 insertions(+), 2541 deletions(-) create mode 100644 tectonic/dpx-mt19937ar.c diff --git a/build.rs b/build.rs index 3a084889fe..a2319d1b8a 100644 --- a/build.rs +++ b/build.rs @@ -318,6 +318,7 @@ fn main() { .file("tectonic/dpx-mem.c") .file("tectonic/dpx-mfileio.c") .file("tectonic/dpx-mpost.c") + .file("tectonic/dpx-mt19937ar.c") .file("tectonic/dpx-numbers.c") .file("tectonic/dpx-otl_conf.c") .file("tectonic/dpx-otl_opt.c") diff --git a/tectonic/dpx-agl.c b/tectonic/dpx-agl.c index 75041fb6ef..1da33280a5 100644 --- a/tectonic/dpx-agl.c +++ b/tectonic/dpx-agl.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -37,6 +37,7 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" /* Hash */ #include "dpx-dpxutil.h" @@ -48,14 +49,6 @@ static int agl_load_listfile (const char *filename, int format); -static int verbose = 0; - -void -agl_set_verbose (int level) -{ - verbose = level; -} - static agl_name * agl_new_name (void) { @@ -403,7 +396,7 @@ agl_load_listfile (const char *filename, int is_predef) return -1; } - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message("alternate = agln; } - if (verbose > 3) { + if (dpx_conf.verbose_level > 5) { if (agln->suffix) dpx_message("agl: %s [%s.%s] -->", name, agln->name, agln->suffix); else @@ -493,7 +486,7 @@ agl_load_listfile (const char *filename, int is_predef) ttstub_input_close(handle); - if (verbose) + if (dpx_conf.verbose_level) dpx_message(">"); return count; @@ -700,7 +693,7 @@ agl_sput_UTF16BE (const char *glyphstr, IS_PUA(agln1->unicodes[0]))) { agln0 = agl_normalized_name(name); if (agln0) { - if (verbose > 1 && agln0->suffix) { + if (dpx_conf.verbose_level > 1 && agln0->suffix) { dpx_warning("agl: fix %s --> %s.%s", name, agln0->name, agln0->suffix); } @@ -713,7 +706,7 @@ agl_sput_UTF16BE (const char *glyphstr, len += UC_UTF16BE_encode_char(agln1->unicodes[i], dstpp, limptr); } } else { - if (verbose) { + if (dpx_conf.verbose_level) { dpx_warning("No Unicode mapping for glyph name \"%s\" found.", name); } count++; @@ -790,7 +783,7 @@ agl_get_unicodes (const char *glyphstr, IS_PUA(agln1->unicodes[0]))) { agln0 = agl_normalized_name(name); if (agln0) { - if (verbose > 1 && agln0->suffix) { + if (dpx_conf.verbose_level > 1 && agln0->suffix) { dpx_warning("agl: fix %s --> %s.%s", name, agln0->name, agln0->suffix); } @@ -807,7 +800,7 @@ agl_get_unicodes (const char *glyphstr, unicodes[count++] = agln1->unicodes[i]; } } else { - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_warning("No Unicode mapping for glyph name \"%s\" found.", name); free(name); return -1; diff --git a/tectonic/dpx-agl.h b/tectonic/dpx-agl.h index bf587291a9..4c23e49397 100644 --- a/tectonic/dpx-agl.h +++ b/tectonic/dpx-agl.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -59,7 +59,6 @@ const char *agl_suffix_to_otltag (const char *suffix); agl_name *agl_lookup_list (const char *glyphname); -void agl_set_verbose (int level); void agl_init_map (void); void agl_close_map (void); diff --git a/tectonic/dpx-bmpimage.c b/tectonic/dpx-bmpimage.c index 3fd9388f0a..3bcb2950ab 100644 --- a/tectonic/dpx-bmpimage.c +++ b/tectonic/dpx-bmpimage.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -31,6 +31,7 @@ #include #include +#include "dpx-dpxconf.h" #include "dpx-error.h" #include "dpx-mem.h" #include "dpx-numbers.h" @@ -85,7 +86,9 @@ check_for_bmp (rust_input_handle_t handle) static void get_density (double *xdensity, double *ydensity, struct hdr_info *hdr) { - if (hdr->x_pix_per_meter > 0 && hdr->y_pix_per_meter > 0) { /* 0 for undefined. FIXME */ + if (dpx_conf.compat_mode == dpx_mode_compat_mode) + *xdensity = *ydensity = 72.0 / 100.0; + else if (hdr->x_pix_per_meter > 0 && hdr->y_pix_per_meter > 0) { /* 0 for undefined. FIXME */ *xdensity = 72.0 / (hdr->x_pix_per_meter * 0.0254); *ydensity = 72.0 / (hdr->y_pix_per_meter * 0.0254); } else { diff --git a/tectonic/dpx-cid.c b/tectonic/dpx-cid.c index 7d2ac6b9ca..12c04686ba 100644 --- a/tectonic/dpx-cid.c +++ b/tectonic/dpx-cid.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -38,6 +38,7 @@ #include "dpx-cid_p.h" #include "dpx-cidtype0.h" #include "dpx-cidtype2.h" +#include "dpx-dpxconf.h" #include "dpx-dpxutil.h" #include "dpx-error.h" #include "dpx-mem.h" @@ -61,15 +62,22 @@ static struct { /* Heighest Supplement values supported by PDF-1.0, 1.1, ...; see * also http://partners.adobe.com/public/developer/font/index.html#ckf */ - int supplement[16]; + int supplement[21]; } CIDFont_stdcc_def[] = { - {"Adobe", "UCS", {-1, -1, 0, 0, 0, 0, 0, 0}}, - {"Adobe", "GB1", {-1, -1, 0, 2, 4, 4, 4, 4}}, - {"Adobe", "CNS1", {-1, -1, 0, 0, 3, 4, 4, 4}}, - {"Adobe", "Japan1", {-1, -1, 2, 2, 4, 5, 6, 6}}, - {"Adobe", "Korea1", {-1, -1, 1, 1, 2, 2, 2, 2}}, - {"Adobe", "Identity", {-1, -1, 0, 0, 0, 0, 0, 0}}, - {NULL, NULL, { 0, 0, 0, 0, 0, 0, 0, 0}} + {"Adobe", "UCS", {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}}, + {"Adobe", "GB1", {-1, -1, 0, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4}}, + {"Adobe", "CNS1", {-1, -1, 0, 0, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4}}, + {"Adobe", "Japan1", {-1, -1, 2, 2, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6}}, + {"Adobe", "Korea1", {-1, -1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2}}, + {"Adobe", "Identity", {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}}, + {NULL, NULL, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}} }; #define UCS_CC 0 #define ACC_START 1 @@ -107,16 +115,7 @@ static struct { static void release_opt (cid_opt *opt); static CIDSysInfo *get_cidsysinfo (const char *map_name, fontmap_opt *fmap_opt); -static int __verbose = 0; -static int cidoptflags = 0; - -void -CIDFont_set_verbose (int level) -{ - CIDFont_type0_set_verbose(level); - CIDFont_type2_set_verbose(level); - __verbose = level; -} +static int cidoptflags = 0; static CIDFont * CIDFont_new (void) @@ -324,16 +323,16 @@ CIDFont_dofont (CIDFont *font) if (!font || !font->indirect) return; - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message(":%s", font->ident); - if (__verbose > 1) { + if (dpx_conf.verbose_level > 1) { if (font->fontname) dpx_message("[%s]", font->fontname); } switch (font->subtype) { case CIDFONT_TYPE0: - if(__verbose) + if(dpx_conf.verbose_level > 0) dpx_message("[CIDFontType0]"); if (CIDFont_get_flag(font, CIDFONT_FLAG_TYPE1)) CIDFont_type0_t1dofont(font); @@ -343,7 +342,7 @@ CIDFont_dofont (CIDFont *font) CIDFont_type0_dofont(font); break; case CIDFONT_TYPE2: - if(__verbose) + if(dpx_conf.verbose_level > 0) dpx_message("[CIDFontType2]"); CIDFont_type2_dofont(font); break; @@ -552,7 +551,6 @@ CIDFont_cache_find (const char *map_name, opt->name = NULL; opt->csi = get_cidsysinfo(map_name, fmap_opt); opt->stemv = fmap_opt->stemv; - opt->cff_charsets = NULL; if (!opt->csi && cmap_csi) { /* @@ -633,8 +631,6 @@ CIDFont_cache_find (const char *map_name, font->options = opt; __cache->fonts[font_id] = font; (__cache->num)++; - - fmap_opt->cff_charsets = opt->cff_charsets; } } else if (opt) { release_opt(opt); @@ -655,7 +651,7 @@ CIDFont_cache_close (void) font = __cache->fonts[font_id]; - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message("(CID"); CIDFont_dofont (font); @@ -664,7 +660,7 @@ CIDFont_cache_close (void) free(font); - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message(")"); } free(__cache->fonts); @@ -687,8 +683,6 @@ release_opt (cid_opt *opt) free(opt->csi->registry); free(opt->csi->ordering); free(opt->csi); - if (opt->cff_charsets) - cff_release_charsets((cff_charsets *) opt->cff_charsets); } free(opt); } @@ -697,11 +691,11 @@ static CIDSysInfo * get_cidsysinfo (const char *map_name, fontmap_opt *fmap_opt) { CIDSysInfo *csi = NULL; - int pdf_ver; + int sup_idx; int i, csi_idx = -1, m; size_t n; - pdf_ver = pdf_get_version(); + sup_idx = pdf_get_version() - 10; if (!fmap_opt || !fmap_opt->charcoll) return NULL; @@ -719,7 +713,7 @@ get_cidsysinfo (const char *map_name, fontmap_opt *fmap_opt) if (strlen(fmap_opt->charcoll) > n) { csi->supplement = (int) strtoul(&(fmap_opt->charcoll[n]), NULL, 10); } else { /* Use heighest supported value for current output PDF version. */ - csi->supplement = CIDFont_stdcc_def[csi_idx].supplement[pdf_ver]; + csi->supplement = CIDFont_stdcc_def[csi_idx].supplement[sup_idx]; } break; } @@ -771,11 +765,12 @@ get_cidsysinfo (const char *map_name, fontmap_opt *fmap_opt) } if (csi && csi_idx >= 0) { - if (csi->supplement > CIDFont_stdcc_def[csi_idx].supplement[pdf_ver] + if (csi->supplement > CIDFont_stdcc_def[csi_idx].supplement[sup_idx] && (fmap_opt->flags & FONTMAP_OPT_NOEMBED)) { - dpx_warning("%s: Heighest supplement number supported in PDF-1.%d for %s-%s is %d.", - CIDFONT_DEBUG_STR, pdf_ver, csi->registry, csi->ordering, - CIDFont_stdcc_def[csi_idx].supplement[pdf_ver]); + dpx_warning("%s: Heighest supplement number supported in PDF-%d.%d for %s-%s is %d.", + CIDFONT_DEBUG_STR, pdf_get_version_major(), pdf_get_version_minor(), + csi->registry, csi->ordering, + CIDFont_stdcc_def[csi_idx].supplement[sup_idx]); dpx_warning("%s: Some character may not shown without embedded font (--> %s).", CIDFONT_DEBUG_STR, map_name); } diff --git a/tectonic/dpx-cid.h b/tectonic/dpx-cid.h index 3df8e1e687..431ec2dbe4 100644 --- a/tectonic/dpx-cid.h +++ b/tectonic/dpx-cid.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -40,7 +40,6 @@ extern CIDSysInfo CSI_UNICODE; typedef struct CIDFont CIDFont; -void CIDFont_set_verbose (int level); void CIDFont_set_flags (int flags); #define CIDFONT_FORCE_FIXEDPITCH (1 << 1) diff --git a/tectonic/dpx-cid_p.h b/tectonic/dpx-cid_p.h index 61306d2c2a..da0bea3bf9 100644 --- a/tectonic/dpx-cid_p.h +++ b/tectonic/dpx-cid_p.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -44,7 +44,6 @@ typedef struct int style; int embed; int stemv; - void *cff_charsets; } cid_opt; struct CIDFont diff --git a/tectonic/dpx-cidtype0.c b/tectonic/dpx-cidtype0.c index 049788df51..960ebbec50 100644 --- a/tectonic/dpx-cidtype0.c +++ b/tectonic/dpx-cidtype0.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -45,6 +45,7 @@ #include "dpx-cmap.h" #include "dpx-cmap_write.h" #include "dpx-cs_type2.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" #include "dpx-error.h" #include "dpx-mem.h" @@ -62,15 +63,8 @@ #include "dpx-tt_table.h" #include "dpx-type0.h" -static int verbose = 0; static int opt_flags = 0; -void -CIDFont_type0_set_verbose (int level) -{ - verbose = level; -} - void CIDFont_type0_set_flags (int flags) { @@ -765,7 +759,7 @@ CIDFont_type0_dofont (CIDFont *font) CIDFontInfo_close(&info); - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("[%u/%u glyphs][%d bytes]", num_glyphs, cs_count, destlen); CIDFont_type0_add_CIDSet(font, used_chars, last_cid); @@ -838,12 +832,6 @@ CIDFont_type0_open (CIDFont *font, const char *name, ttstub_input_close(handle); return -1; } - - if (is_cid_font) { - cff_read_charsets(cffont); - opt->cff_charsets = cffont->charsets; - cffont->charsets = NULL; - } } else { if (!handle) return -1; @@ -880,7 +868,7 @@ CIDFont_type0_open (CIDFont *font, const char *name, _tt_abort("Inconsistent CMap specified for this font."); } if (csi->supplement < cmap_csi->supplement) { - dpx_warning("CMap have higher supplmement number."); + dpx_warning("CMap have higher supplement number."); dpx_warning("Some characters may not be displayed or printed."); } } @@ -1218,7 +1206,7 @@ CIDFont_type0_t1cdofont (CIDFont *font) CIDFontInfo_close(&info); - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("[%u glyphs][%d bytes]", num_glyphs, destlen); CIDFont_type0_add_CIDSet(font, used_chars, last_cid); diff --git a/tectonic/dpx-cidtype0.h b/tectonic/dpx-cidtype0.h index 61126fe555..9841759e84 100644 --- a/tectonic/dpx-cidtype0.h +++ b/tectonic/dpx-cidtype0.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -27,7 +27,6 @@ #include "dpx-cid_p.h" #include "dpx-fontmap.h" -void CIDFont_type0_set_verbose (int level); void CIDFont_type0_set_flags (int flags); int CIDFont_type0_open (CIDFont *font, const char *name, diff --git a/tectonic/dpx-cidtype2.c b/tectonic/dpx-cidtype2.c index 07c456f179..add239d548 100644 --- a/tectonic/dpx-cidtype2.c +++ b/tectonic/dpx-cidtype2.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-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -24,6 +24,7 @@ */ #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" #include "dpx-error.h" #include "dpx-mem.h" @@ -58,15 +59,8 @@ #include "dpx-tt_table.h" #include "dpx-type0.h" -static int verbose = 0; static int opt_flags = 0; -void -CIDFont_type2_set_verbose (int level) -{ - verbose = level; -} - void CIDFont_type2_set_flags (int32_t flags) { @@ -789,7 +783,7 @@ CIDFont_type2_dofont (CIDFont *font) if (CIDFont_get_embedding(font)) { if (tt_build_tables(sfont, glyphs) < 0) _tt_abort("Could not created FontFile stream."); - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("[%u glyphs (Max CID: %u)]", glyphs->num_glyphs, last_cid); } else { if (tt_get_metrics(sfont, glyphs) < 0) @@ -808,6 +802,26 @@ CIDFont_type2_dofont (CIDFont *font) add_TTCIDVMetrics(font->fontdict, glyphs, used_chars, last_cid); } + /* CIDSet + * NOTE: All glyphs including component glyph and dummy glyph must be + * listed in CIDSet. However, .notdef glyph should be ommitted. + */ + { + pdf_obj *cidset; + char *cidset_data; + + cidset_data = NEW(glyphs->last_gid/8 + 1, char); + memset(cidset_data, 0, glyphs->last_gid/8 + 1); + for (i = 1; i <= glyphs->last_gid; i++) + cidset_data[i/8] |= (1 << (7 - i % 8)); + cidset = pdf_new_stream(STREAM_COMPRESS); + pdf_add_stream(cidset, cidset_data, glyphs->last_gid/8 + 1); + free(cidset_data); + pdf_add_dict(font->descriptor, + pdf_new_name("CIDSet"), pdf_ref_obj(cidset)); + pdf_release_obj(cidset); + } + tt_build_finish(glyphs); /* Finish here if not embedded. */ @@ -841,7 +855,7 @@ CIDFont_type2_dofont (CIDFont *font) if (!fontfile) _tt_abort("Could not created FontFile stream for \"%s\".", font->ident); - if (verbose > 1) { + if (dpx_conf.verbose_level > 1) { dpx_message("[%d bytes]", pdf_stream_length(fontfile)); } @@ -850,20 +864,6 @@ CIDFont_type2_dofont (CIDFont *font) pdf_ref_obj (fontfile)); pdf_release_obj(fontfile); - /* - * CIDSet - */ - { - pdf_obj *cidset; - - cidset = pdf_new_stream(STREAM_COMPRESS); - pdf_add_stream(cidset, used_chars, last_cid/8 + 1); - pdf_add_dict(font->descriptor, - pdf_new_name("CIDSet"), - pdf_ref_obj(cidset)); - pdf_release_obj(cidset); - } - /* * CIDToGIDMap * Adobe's PDF Reference had been describing it as "optional" and @@ -1001,7 +1001,7 @@ CIDFont_type2_open (CIDFont *font, const char *name, _tt_abort("Incompatible CMap specified for this font."); } if (opt->csi->supplement < cmap_csi->supplement) { - dpx_warning("Supplmement value in CIDSystemInfo increased."); + dpx_warning("Supplement value in CIDSystemInfo increased."); dpx_warning("Some characters may not shown."); opt->csi->supplement = cmap_csi->supplement; } diff --git a/tectonic/dpx-cidtype2.h b/tectonic/dpx-cidtype2.h index 6e49372b8b..43220ba1f4 100644 --- a/tectonic/dpx-cidtype2.h +++ b/tectonic/dpx-cidtype2.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -26,7 +26,6 @@ #include "dpx-cid.h" #include "dpx-cid_p.h" -void CIDFont_type2_set_verbose (int level); void CIDFont_type2_set_flags (int flags); int CIDFont_type2_open (CIDFont *font, const char *name, diff --git a/tectonic/dpx-cmap.c b/tectonic/dpx-cmap.c index 651dce9ca7..61435d2bcb 100644 --- a/tectonic/dpx-cmap.c +++ b/tectonic/dpx-cmap.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -33,6 +33,7 @@ * * TODO: * Only cid(range|char) allowed for CODE_TO_CID and bf(range|char) for CID_TO_CODE ? + * */ #include "dpx-cmap.h" @@ -43,19 +44,13 @@ #include "core-bridge.h" #include "dpx-cmap_p.h" +#include "dpx-dpxconf.h" #include "dpx-dpxutil.h" #include "dpx-error.h" #include "dpx-mem.h" -static int __verbose = 0; static int __silent = 0; -void -CMap_set_verbose (int level) -{ - __verbose = level; -} - void CMap_set_silent (int value) { @@ -107,9 +102,6 @@ CMap_new (void) cmap->mapData->pos = 0; cmap->mapData->data = NEW(MEM_ALLOC_SIZE, unsigned char); - cmap->reverseMap = NEW(65536, int); - memset(cmap->reverseMap, 0, 65536 * sizeof(int)); - return cmap; } @@ -138,8 +130,6 @@ CMap_release (CMap *cmap) } } - free(cmap->reverseMap); - free(cmap); } @@ -349,14 +339,6 @@ CMap_decode (CMap *cmap, return count; } -int -CMap_reverse_decode(CMap *cmap, CID cid) { - int ch = cmap->reverseMap ? cmap->reverseMap[cid] : -1; - if (ch == 0 && cmap->useCMap) - return CMap_reverse_decode(cmap->useCMap, cid); - return ch; -} - char * CMap_get_name (CMap *cmap) { @@ -678,8 +660,6 @@ CMap_add_cidrange (CMap *cmap, for (v = 0, i = 0; i < srcdim - 1; i++) v = (v << 8) + srclo[i]; - cmap->reverseMap[base] = v; - for (c = srclo[srcdim-1]; c <= srchi[srcdim-1]; c++) { if (cur[c].flag != 0) { if (!__silent) @@ -690,8 +670,6 @@ CMap_add_cidrange (CMap *cmap, cur[c].code = get_mem(cmap, 2); cur[c].code[0] = base >> 8; cur[c].code[1] = base & 0xff; - - cmap->reverseMap[base] = (v << 8) + c; } if (base >= CID_MAX) dpx_warning("CID number too large."); @@ -930,7 +908,7 @@ CMap_cache_find (const char *cmap_name) return -1; } - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message("(CMap:%s", cmap_name); if (__cache->num >= __cache->max) { @@ -947,7 +925,7 @@ CMap_cache_find (const char *cmap_name) ttstub_input_close(handle); - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message(")"); return id; diff --git a/tectonic/dpx-cmap.h b/tectonic/dpx-cmap.h index 96bb0a2140..155dda9dcc 100644 --- a/tectonic/dpx-cmap.h +++ b/tectonic/dpx-cmap.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -61,7 +61,6 @@ typedef struct CMap CMap; /************************** CMAP_MAIN **************************/ -void CMap_set_verbose (int level); void CMap_set_silent (int value); CMap *CMap_new (void); @@ -111,8 +110,6 @@ size_t CMap_decode (CMap *cmap, const unsigned char **inbuf, size_t *inbytesleft, unsigned char **outbuf, size_t *outbytesleft); -int CMap_reverse_decode(CMap *cmap, CID cid); - void CMap_cache_init (void); CMap *CMap_cache_get (int id); int CMap_cache_find (const char *cmap_name); diff --git a/tectonic/dpx-cmap_p.h b/tectonic/dpx-cmap_p.h index f9f3ee5f02..4f49386412 100644 --- a/tectonic/dpx-cmap_p.h +++ b/tectonic/dpx-cmap_p.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -98,8 +98,6 @@ struct CMap { size_t minBytesOut; size_t maxBytesOut; } profile; - - int *reverseMap; }; #endif /* _CMAP_P_H_ */ diff --git a/tectonic/dpx-cmap_read.c b/tectonic/dpx-cmap_read.c index aaeff0633c..8e6d70b951 100644 --- a/tectonic/dpx-cmap_read.c +++ b/tectonic/dpx-cmap_read.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -30,13 +30,12 @@ #include "dpx-cid.h" #include "dpx-cmap.h" +#include "dpx-dpxconf.h" #include "dpx-dpxutil.h" #include "dpx-error.h" #include "dpx-mem.h" #include "dpx-pst.h" -static int __verbose = 0; - #define CMAP_PARSE_DEBUG_STR "CMap_parse:" #define CMAP_PARSE_DEBUG 3 @@ -88,8 +87,6 @@ ifreader_read (ifreader *reader, size_t size) assert(reader); bytesrem = (size_t) reader->endptr - (size_t) reader->cursor; if (size > reader->max) { - if (__verbose) - dpx_message("\nExtending buffer (%"PRIuZ" bytes)...\n", size); reader->buf = RENEW(reader->buf, size+1, unsigned char); reader->max = size; } @@ -102,8 +99,6 @@ ifreader_read (ifreader *reader, size_t size) _tt_abort("Reading file failed."); reader->endptr += bytesread; reader->unread -= bytesread; - if (__verbose) - dpx_message("Reading more %"PRIuZ" bytes (%"PRIuZ" bytes remains in buffer)...\n", bytesread, bytesrem); } *reader->endptr = 0; diff --git a/tectonic/dpx-cmap_write.c b/tectonic/dpx-cmap_write.c index ba9c47822e..ca405384de 100644 --- a/tectonic/dpx-cmap_write.c +++ b/tectonic/dpx-cmap_write.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-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -218,6 +218,74 @@ write_map (mapDef *mtab, size_t count, return count; } +/* duplicated from pdfobj.c */ +static void +write_string (char **outptr, char *endptr, const char *strptr) +{ + const char *s; + char *p; + int i, length; + + s = strptr; + length = strptr ? strlen(strptr) : 0; + p = *outptr; + + *p++ = '('; + for (i = 0; i < length; i++) { + unsigned char ch; + + ch = s[i]; + if (ch < 32 || ch > 126) { + p += sprintf(p, "\\%03o", ch); + } else { + switch (ch) { + case '(': case ')': case '\\': + *p++ = '\\'; + *p++ = ch; + break; + default: + *p++ = ch; + break; + } + } + } + *p++ = ')'; + + *outptr = p; +} + +static void +write_name (char **outptr, char *endptr, const char *name) +{ + const char *s; + char *p; + int i, length; + + s = name; + length = name ? strlen(name) : 0; + p = *outptr; +#ifndef is_delim + /* Avoid '{' and '}' for PostScript compatibility? */ +#define is_delim(c) ((c) == '(' || (c) == ')' || \ + (c) == '/' || \ + (c) == '<' || (c) == '>' || \ + (c) == '[' || (c) == ']' || \ + (c) == '{' || (c) == '}' || \ + (c) == '%') +#endif + *p++ = '/'; + for (i = 0; i < length; i++) { + if (s[i] < '!' || s[i] > '~' || s[i] == '#' || is_delim(s[i])) { + /* ^ "space" is here. */ + *p++ = '#'; + sputx(s[i], &p, endptr); + } else { + *p++ = s[i]; + } + } + *outptr = p; +} + #define CMAP_BEGIN "\ /CIDInit /ProcSet findresource begin\n\ 12 dict begin\n\ @@ -326,7 +394,7 @@ CMap_create_stream (CMap *cmap) } } -#define WBUF_SIZE 4096 +#define WBUF_SIZE 40960 wbuf.buf = NEW(WBUF_SIZE, char); codestr = NEW(cmap->profile.maxBytesIn, unsigned char); memset(codestr, 0, cmap->profile.maxBytesIn); @@ -338,7 +406,9 @@ CMap_create_stream (CMap *cmap) /* Start CMap */ pdf_add_stream(stream, (const void *) CMAP_BEGIN, strlen(CMAP_BEGIN)); - wbuf.curptr += sprintf(wbuf.curptr, "/CMapName /%s def\n", cmap->name); + wbuf.curptr += sprintf(wbuf.curptr, "/CMapName "); + write_name(&wbuf.curptr, wbuf.limptr, cmap->name); + wbuf.curptr += sprintf(wbuf.curptr, " def\n"); wbuf.curptr += sprintf(wbuf.curptr, "/CMapType %d def\n" , cmap->type); if (cmap->wmode != 0 && cmap->type != CMAP_TYPE_TO_UNICODE) @@ -349,8 +419,15 @@ CMap_create_stream (CMap *cmap) /Ordering (%s)\n\ /Supplement %d\n\ >> def\n" - wbuf.curptr += sprintf(wbuf.curptr, CMAP_CSI_FMT, - csi->registry, csi->ordering, csi->supplement); + wbuf.curptr += sprintf(wbuf.curptr, "/CIDSystemInfo <<\n"); + wbuf.curptr += sprintf(wbuf.curptr, " /Registry "); + write_string(&wbuf.curptr, wbuf.limptr, csi->registry); + wbuf.curptr += sprintf(wbuf.curptr, "\n"); + wbuf.curptr += sprintf(wbuf.curptr, " /Ordering "); + write_string(&wbuf.curptr, wbuf.limptr, csi->ordering); + wbuf.curptr += sprintf(wbuf.curptr, "\n"); + wbuf.curptr += sprintf(wbuf.curptr, " /Supplement %d\n>> def\n", + csi->supplement); pdf_add_stream(stream, wbuf.buf, (int)(wbuf.curptr - wbuf.buf)); wbuf.curptr = wbuf.buf; diff --git a/tectonic/dpx-dpxconf.c b/tectonic/dpx-dpxconf.c index 9c5f5495f2..de4b68def4 100644 --- a/tectonic/dpx-dpxconf.c +++ b/tectonic/dpx-dpxconf.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -25,6 +25,8 @@ #include +struct _dpx_conf dpx_conf = {0, dpx_mode_normal_mode, 0, {0}}; + #ifndef HAVE_LIBPAPER const struct paper paperspecs[] = { {"letter", 612.00, 792.00}, diff --git a/tectonic/dpx-dpxconf.h b/tectonic/dpx-dpxconf.h index 3edacd8f1c..8223a1911b 100644 --- a/tectonic/dpx-dpxconf.h +++ b/tectonic/dpx-dpxconf.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -26,6 +26,23 @@ #include "dpx-core.h" #include + +enum dpx_mode { + dpx_mode_normal_mode, + dpx_mode_compat_mode, + dpx_mode_xdv_mode, + dpx_mode_mpost_mode +}; + +extern struct _dpx_conf { + int verbose_level; + enum dpx_mode compat_mode; + int ignore_font_license; + struct { + int keep_cache; + } file; +} dpx_conf; + #ifdef HAVE_LIBPAPER #include #else diff --git a/tectonic/dpx-dpxfile.c b/tectonic/dpx-dpxfile.c index e4e875d431..f568490f37 100644 --- a/tectonic/dpx-dpxfile.c +++ b/tectonic/dpx-dpxfile.c @@ -1,5 +1,5 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -32,6 +32,7 @@ #include #endif +#include "dpx-dpxconf.h" #include "dpx-mem.h" #include "dpx-numbers.h" #include "dpx-system.h" @@ -41,17 +42,6 @@ #include #include -static int verbose = 0; -int keep_cache = 0; - -void -dpx_file_set_verbose (int level) -{ - verbose = level; -} - - - static char _sbuf[128]; /* * SFNT type sigs: @@ -353,7 +343,7 @@ dpx_delete_old_cache (int life) * it would have been annoying to port to Windows. */ if (life == -2) - keep_cache = -1; + dpx_conf.file.keep_cache = -1; } void @@ -361,7 +351,7 @@ dpx_delete_temp_file (char *tmp, int force) { if (!tmp) return; - if (force || keep_cache != 1) remove (tmp); + if (force || dpx_conf.file.keep_cache != 1) remove (tmp); free(tmp); return; @@ -376,9 +366,26 @@ dpx_delete_temp_file (char *tmp, int force) */ int dpx_file_apply_filter (const char *cmdtmpl, - const char *input, const char *output, - unsigned char version) + const char *input, const char *output, int version) { /* Tectonic: defused */ return -1; } + +#if defined(WIN32) +FILE *generic_fsyscp_fopen (const char *filename, const char *mode) +{ + FILE *f; + + f = fsyscp_fopen (filename, mode); + + if (f == NULL && file_system_codepage != win32_codepage) { + int tmpcp = file_system_codepage; + file_system_codepage = win32_codepage; + f = fsyscp_fopen (filename, mode); + file_system_codepage = tmpcp; + } + + return f; +} +#endif /* WIN32 */ diff --git a/tectonic/dpx-dpxfile.h b/tectonic/dpx-dpxfile.h index 3b71cc234e..e4f94df549 100644 --- a/tectonic/dpx-dpxfile.h +++ b/tectonic/dpx-dpxfile.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -47,17 +47,13 @@ rust_input_handle_t dpx_open_truetype_file (const char *filename); rust_input_handle_t dpx_open_opentype_file (const char *filename); rust_input_handle_t dpx_open_dfont_file (const char *filename); -void dpx_file_set_verbose (int level); - int dpx_file_apply_filter (const char *cmdtmpl, const char *input, const char *output, - unsigned char version); + int version); char *dpx_create_temp_file (void); void dpx_delete_old_cache (int life); void dpx_delete_temp_file (char *tmp, int force); /* tmp freed here */ -extern int keep_cache; - /* Tectonic-enabled I/O alternatives */ rust_input_handle_t dpx_tt_open (const char *filename, const char *suffix, diff --git a/tectonic/dpx-dpxutil.c b/tectonic/dpx-dpxutil.c index 0ed3c2e660..c3faa16b62 100644 --- a/tectonic/dpx-dpxutil.c +++ b/tectonic/dpx-dpxutil.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -28,6 +28,7 @@ #include #include +#include "dpx-dvipdfmx.h" #include "dpx-error.h" #include "dpx-mem.h" @@ -67,6 +68,69 @@ max4 (double x1, double x2, double x3, double x4) } + +#if defined(_MSC_VER) +#define strtoll _strtoi64 +#endif + +/* If an environment variable SOURCE_DATE_EPOCH is correctly defined like + * SOURCE_DATE_EPOCH=1456304492, then returns this value, to be used as the + * 'current time', otherwise returns INVALID_EPOCH_VALUE (= (time_t)-1). + * In the case of Microsoft Visual Studio 2010, the value should be less + * than 32535291600. + */ + +time_t +dpx_util_get_unique_time_if_given(void) +{ + const char *source_date_epoch; + int64_t epoch; + char *endptr; + time_t ret = INVALID_EPOCH_VALUE; + + source_date_epoch = getenv("SOURCE_DATE_EPOCH"); + if (source_date_epoch) { + errno = 0; + epoch = strtoll(source_date_epoch, &endptr, 10); + if (!(epoch < 0 || *endptr != '\0' || errno != 0)) { + ret = (time_t) epoch; +#if defined(_MSC_VER) + if (ret > 32535291599ULL) + ret = 32535291599ULL; +#endif + } + } + return ret; +} + + +/* + * Docinfo + */ +int +dpx_util_format_asn_date (char *date_string, int need_timezone) +{ + int32_t tz_offset = 0; + struct tm *bd_time = gmtime(&source_date_epoch); + + if (need_timezone) { + if (bd_time->tm_isdst > 0) { + tz_offset += 3600; + } + sprintf(date_string, "D:%04d%02d%02d%02d%02d%02d%c%02d'%02d'", + bd_time->tm_year + 1900, bd_time->tm_mon + 1, bd_time->tm_mday, + bd_time->tm_hour, bd_time->tm_min, bd_time->tm_sec, + (tz_offset > 0) ? '+' : '-', abs(tz_offset) / 3600, + (abs(tz_offset) / 60) % 60); + } else { + sprintf(date_string, "D:%04d%02d%02d%02d%02d%02d", + bd_time->tm_year + 1900, bd_time->tm_mon + 1, bd_time->tm_mday, + bd_time->tm_hour, bd_time->tm_min, bd_time->tm_sec); + } + + return strlen(date_string); +} + void skip_white_spaces (unsigned char **s, unsigned char *endptr) { diff --git a/tectonic/dpx-dpxutil.h b/tectonic/dpx-dpxutil.h index 483ee77130..b5b0ce6e68 100644 --- a/tectonic/dpx-dpxutil.h +++ b/tectonic/dpx-dpxutil.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -25,6 +25,8 @@ #include "dpx-core.h" +#include + #undef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #undef MAX @@ -35,6 +37,10 @@ extern double min4(double v1, double v2, double v3, double v4); extern double max4(double v1, double v2, double v3, double v4); +#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); + #ifndef is_space #define is_space(c) ((c) == ' ' || (c) == '\t' || (c) == '\f' || \ (c) == '\r' || (c) == '\n' || (c) == '\0') diff --git a/tectonic/dpx-dvi.c b/tectonic/dpx-dvi.c index 868f8e3c9b..41d85c2525 100644 --- a/tectonic/dpx-dvi.c +++ b/tectonic/dpx-dvi.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) 2012-2015 by Khaled Hosny @@ -37,7 +37,9 @@ #include "dpx-cff.h" #include "dpx-cff_dict.h" #include "dpx-cff_types.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" +#include "dpx-dpxutil.h" #include "dpx-dvicodes.h" #include "dpx-dvipdfmx.h" #include "dpx-error.h" @@ -47,9 +49,10 @@ #include "dpx-pdfcolor.h" #include "dpx-pdfdev.h" #include "dpx-pdfdoc.h" -#include "dpx-pdfencrypt.h" +#include "dpx-pdfdraw.h" #include "dpx-pdfobj.h" #include "dpx-pdfparse.h" +#include "dpx-pdfresource.h" #include "dpx-sfnt.h" #include "dpx-specials.h" #include "dpx-subfont.h" @@ -136,6 +139,7 @@ static struct loaded_font spt_t size; int source; /* Source is either DVI or VF */ uint32_t rgba_color; + int xgs_id; /* Transparency ExtGState */ struct tt_longMetrics *hvmt; int ascent; int descent; @@ -184,7 +188,6 @@ static struct font_def static unsigned int num_def_fonts = 0, max_def_fonts = 0; static int compute_boxes = 0, link_annot = 1; -static int verbose = 0; #define DVI_PAGE_BUF_CHUNK 0x10000U /* 64K should be plenty for most pages */ @@ -294,16 +297,6 @@ get_buffered_unsigned_num(unsigned char num) #define skip_bufferd_bytes(n) dvi_page_buf_index += n -void -dvi_set_verbose (int level) -{ - verbose = level; - subfont_set_verbose(level); - tfm_set_verbose(level); - vf_set_verbose(level); - spc_set_verbose(level); -} - unsigned int dvi_npages (void) { @@ -328,7 +321,7 @@ check_id_bytes (void) { static void need_XeTeX (int c) { - if (!is_xdv) + if (dpx_conf.compat_mode != dpx_mode_xdv_mode) _tt_abort("DVI opcode %i only valid for XeTeX", c); } @@ -368,7 +361,8 @@ find_post (void) } post_id_byte = ch; - is_xdv = (ch == XDV_ID || ch == XDV_ID_OLD); + if (ch == XDV_ID || ch == XDV_ID_OLD) + dpx_conf.compat_mode = dpx_mode_xdv_mode; is_ptex = ch == DVIV_ID; /* Make sure post_post is really there */ @@ -414,7 +408,7 @@ get_page_info (int32_t post_location) if (num_pages == 0) { _tt_abort("Page count is 0!"); } - if (verbose > 2) { + if (dpx_conf.verbose_level > 2) { dpx_message("Page count:\t %4d\n", num_pages); } @@ -467,7 +461,7 @@ get_dvi_info (int32_t post_location) _tt_abort("Capacity exceeded."); } - if (verbose > 2) { + if (dpx_conf.verbose_level > 2) { dpx_message("DVI File Info\n"); dpx_message("Unit: %" PRIu32 " / %" PRIu32 "\n", dvi_info.unit_num, dvi_info.unit_den); dpx_message("Magnification: %" PRIu32 "\n", dvi_info.mag); @@ -609,7 +603,7 @@ get_dvi_fonts (int32_t post_location) _tt_abort(invalid_signature); } } - if (verbose > 2) { + if (dpx_conf.verbose_level > 2) { unsigned int i; dpx_message("\n"); @@ -635,7 +629,7 @@ static void get_comment (void) _tt_abort(invalid_signature); } dvi_info.comment[length] = '\0'; - if (verbose) { + if (dpx_conf.verbose_level > 0) { dpx_message("DVI Comment: %s\n", dvi_info.comment); } } @@ -749,7 +743,7 @@ dvi_do_special (const void *buffer, int32_t size) mag = dvi_tell_mag(); if (spc_exec_special(p, size, x_user, y_user, mag) < 0) { - if (verbose) { + if (dpx_conf.verbose_level > 0) { dump(p, p + size); } } @@ -772,7 +766,7 @@ dvi_locate_font (const char *tfm_name, spt_t ptsize) int subfont_id = -1, font_id; /* VF or device font ID */ fontmap_rec *mrec; - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message("<%s@%.2fpt", tfm_name, ptsize * dvi2pts); need_more_fonts(1); @@ -818,7 +812,7 @@ dvi_locate_font (const char *tfm_name, spt_t ptsize) if (font_id >= 0) { loaded_fonts[cur_id].type = VIRTUAL; loaded_fonts[cur_id].font_id = font_id; - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message("(VF)>"); return cur_id; } @@ -848,7 +842,7 @@ dvi_locate_font (const char *tfm_name, spt_t ptsize) else { loaded_fonts[cur_id].type = VIRTUAL; loaded_fonts[cur_id].font_id = font_id; - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message("(OVF)>"); return cur_id; } @@ -886,8 +880,15 @@ dvi_locate_font (const char *tfm_name, spt_t ptsize) dpx_warning(">> Please check if kpathsea library can find this font: %s", mrec1->font_name); } } else if (mrec && !mrec->map_name) { - dpx_warning(">> This font is mapped to a physical font \"%s\".", mrec->font_name); - dpx_warning(">> Please check if kpathsea library can find this font: %s", mrec->font_name); + char *finaldot = strrchr(mrec->font_name, '.'); + if (finaldot && strcasecmp(finaldot, ".pfa") == 0) { + /* type1 fonts with pfa format are not supported */ + dpx_warning("This font is mapped to a physical font \"%s\".", mrec->font_name); + _tt_abort("Sorry, pfa format not supported; please convert the font to pfb, e.g., with t1binary."); + } else { + dpx_warning(">> This font is mapped to a physical font \"%s\".", mrec->font_name); + dpx_warning(">> Please check if kpathsea library can find this font: %s", mrec->font_name); + } } else { dpx_warning(">> There are no valid font mapping entry for this font."); dpx_warning(">> Font file name \"%s\" was assumed but failed to locate that font.", tfm_name); @@ -897,7 +898,7 @@ dvi_locate_font (const char *tfm_name, spt_t ptsize) loaded_fonts[cur_id].type = PHYSICAL; loaded_fonts[cur_id].font_id = font_id; - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message(">"); return cur_id; @@ -918,7 +919,7 @@ dvi_locate_native_font (const char *filename, uint32_t index, struct tt_hhea_table *hhea; int is_dfont = 0, is_type1 = 0; - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message("<%s@%.2fpt", filename, ptsize * dvi2pts); if ((handle = dpx_open_dfont_file(filename)) != NULL) @@ -1015,7 +1016,7 @@ dvi_locate_native_font (const char *filename, uint32_t index, loaded_fonts[cur_id].slant = mrec->opt.slant; loaded_fonts[cur_id].embolden = mrec->opt.bold; - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message(">"); return cur_id; @@ -1248,7 +1249,7 @@ dvi_rule (int32_t width, int32_t height) void dvi_dirchg (unsigned char dir) { - if (verbose) + if (dpx_conf.verbose_level > 0) fprintf(stderr, " > dvi_dirchg %d\n", dir); dvi_state.d = dir; pdf_dev_set_dirmode(dvi_state.d); /* 0: horizontal, 1,3: vertical */ @@ -1429,6 +1430,20 @@ do_fnt (uint32_t tex_id) def_fonts[i].point_size); } loaded_fonts[font_id].rgba_color = def_fonts[i].rgba_color; + /* Opacity: 0xff is fully opaque. */ + if ((loaded_fonts[font_id].rgba_color & 0xff) == 0xff) { + loaded_fonts[font_id].xgs_id = -1; + } else { + pdf_obj *xgs_dict; + int a = loaded_fonts[font_id].rgba_color & 0xff; + + /* Inefficient but don't care as transparency is not expected to be frequently used. */ + xgs_dict = pdf_new_dict(); + pdf_add_dict(xgs_dict, pdf_new_name("Type"), pdf_new_name("ExtGState")); + pdf_add_dict(xgs_dict, pdf_new_name("ca"), pdf_new_number(a/255.0)); + pdf_add_dict(xgs_dict, pdf_new_name("CA"), pdf_new_number(a/255.0)); + loaded_fonts[font_id].xgs_id = pdf_defineresource("ExtGState", NULL, xgs_dict, 0); + } loaded_fonts[font_id].source = DVI; def_fonts[i].used = 1; def_fonts[i].font_id = font_id; @@ -1646,6 +1661,23 @@ do_glyphs (int do_actual_text) (double)((unsigned char)(font->rgba_color >> 16) & 0xff) / 255, (double)((unsigned char)(font->rgba_color >> 8) & 0xff) / 255); pdf_color_push(&color, &color); + /* Opacity: + * Enter graphics_mode and then enclose with save/resotre + * since pdf_color_pop() may not restore graphics state. + */ + if (font->xgs_id >= 0) { + pdf_obj *ref; + char resname[16]; + char content[22]; + + sprintf(resname, "Xtx_Gs_%08x", current_font); + ref = pdf_get_resource_reference(font->xgs_id); + pdf_doc_add_page_resource("ExtGState", resname, ref); + graphics_mode(); + pdf_dev_gsave(); + sprintf(content, " /%s gs ", resname); + pdf_doc_add_page_content(content, strlen(content)); + } } for (i = 0; i < slen; i++) { @@ -1694,6 +1726,10 @@ do_glyphs (int do_actual_text) } if (font->rgba_color != 0xffffffff) { + if (font->xgs_id >= 0) { + graphics_mode(); + pdf_dev_grestore(); + } pdf_color_pop(); } free(xloc); @@ -2121,12 +2157,114 @@ read_length (double *vp, double mag, const char **pp, const char *endptr) return error; } +#include "dpx-pdfencrypt.h" + +static int +scan_special_encrypt (int *key_bits, int32_t *permission, char *opassword, char *upassword, + const char **curptr, const char *endptr) +{ + int error = 0; + const char *p = *curptr; + + skip_white(&p, endptr); + + opassword[0] = '\0'; + upassword[0] = '\0'; + while (!error && p < endptr) { + char *kp = parse_c_ident(&p, endptr); + if (!kp) + break; + else { + pdf_obj *obj; + skip_white(&p, endptr); + if (!strcmp(kp, "ownerpw")) { + if ((obj = parse_pdf_string(&p, endptr))) { + if (pdf_string_value(obj)) { + int str_length = (MAX_PWD_LEN - 1 > pdf_string_length(obj) + ? pdf_string_length(obj) : MAX_PWD_LEN - 1); + strncpy(opassword, pdf_string_value(obj), str_length); + opassword[str_length] = '\0'; + } + pdf_release_obj(obj); + } else + error = -1; + } else if (!strcmp(kp, "userpw")) { + if ((obj = parse_pdf_string(&p, endptr))) { + if (pdf_string_value(obj)) { + int str_length = (MAX_PWD_LEN - 1 > pdf_string_length(obj) + ? pdf_string_length(obj) : MAX_PWD_LEN - 1); + strncpy(upassword, pdf_string_value(obj), str_length); + upassword[str_length] = '\0'; + } + pdf_release_obj(obj); + } else + error = -1; + } else if (!strcmp(kp, "length")) { + if ((obj = parse_pdf_number(&p, endptr)) && PDF_OBJ_NUMBERTYPE(obj)) { + *key_bits = (unsigned) pdf_number_value(obj); + } else + error = -1; + if (obj) + pdf_release_obj(obj); + } else if (!strcmp(kp, "perm")) { + if ((obj = parse_pdf_number(&p, endptr)) && PDF_OBJ_NUMBERTYPE(obj)) { + *permission = (unsigned) pdf_number_value(obj); + } else + error = -1; + if (obj) + pdf_release_obj(obj); + } else + error = -1; + free(kp); + } + skip_white(&p, endptr); + } + *curptr = p; + + return error; +} + +static int +scan_special_trailerid (unsigned char *id1, unsigned char *id2, + const char **curptr, const char *endptr) +{ + int error = 0; + pdf_obj *id_array; + const char *p = *curptr; + + skip_white(&p, endptr); + id_array = parse_pdf_array(&p, endptr, NULL); + if (id_array) { + if (pdf_array_length(id_array) == 2) { + pdf_obj *tmp1, *tmp2; + tmp1 = pdf_get_array(id_array, 0); + tmp2 = pdf_get_array(id_array, 1); + if (PDF_OBJ_STRINGTYPE(tmp1) && pdf_string_length(tmp1) == 16 && + PDF_OBJ_STRINGTYPE(tmp2) && pdf_string_length(tmp2) == 16) { + memcpy(id1, pdf_string_value(tmp1), 16); + memcpy(id2, pdf_string_value(tmp2), 16); + } else { + error = -1; + } + } else { + error = -1; + } + pdf_release_obj(id_array); + } else { + error = -1; + } + skip_white(&p, endptr); + *curptr = p; + + return error; +} static int scan_special (double *wd, double *ht, double *xo, double *yo, int *lm, int *majorversion, int *minorversion, - int *do_enc, int *key_bits, int32_t *permission, - char *owner_pw, char *user_pw, + int *enable_encryption, int *key_bits, int32_t *permission, + char *opassword, char *upassword, + int *has_id, unsigned char *id1, unsigned char *id2, const char *buf, uint32_t size) { char *q; @@ -2253,50 +2391,19 @@ scan_special (double *wd, double *ht, double *xo, double *yo, int *lm, *majorversion = (int)strtol(kv, NULL, 10); free(kv); } - } else if (ns_pdf && streq_ptr(q, "encrypt") && do_enc) { - *do_enc = 1; - *owner_pw = *user_pw = 0; - while (!error && p < endptr) { - char *kp = parse_c_ident(&p, endptr); - if (!kp) - break; - else { - pdf_obj *obj; - skip_white(&p, endptr); - if (streq_ptr(kp, "ownerpw")) { - if ((obj = parse_pdf_string(&p, endptr))) { - if (pdf_string_value(obj)) - strncpy(owner_pw, pdf_string_value(obj), MAX_PWD_LEN); - pdf_release_obj(obj); - } else - error = -1; - } else if (streq_ptr(kp, "userpw")) { - if ((obj = parse_pdf_string(&p, endptr))) { - if (pdf_string_value(obj)) - strncpy(user_pw, pdf_string_value(obj), MAX_PWD_LEN); - pdf_release_obj(obj); - } else - error = -1; - } else if (streq_ptr(kp, "length")) { - if ((obj = parse_pdf_number(&p, endptr)) && PDF_OBJ_NUMBERTYPE(obj)) { - *key_bits = (unsigned) pdf_number_value(obj); - } else - error = -1; - pdf_release_obj(obj); - } else if (streq_ptr(kp, "perm")) { - if ((obj = parse_pdf_number(&p, endptr)) && PDF_OBJ_NUMBERTYPE(obj)) { - *permission = (unsigned) pdf_number_value(obj); - } else - error = -1; - pdf_release_obj(obj); - } else - error = -1; - free(kp); - } - skip_white(&p, endptr); - } + } else if (enable_encryption && ns_pdf && streq_ptr(q, "encrypt")) { + *enable_encryption = 1; + error = scan_special_encrypt(key_bits, permission, opassword, upassword, &p, endptr); } else if (ns_dvipdfmx && streq_ptr(q, "config")) { dpx_warning("Tectonic does not support `config' special. Ignored."); + } else if (has_id && id1 && id2 && ns_pdf && !strcmp(q, "trailerid")) { + error = scan_special_trailerid(id1, id2, &p, endptr); + if (error) { + dpx_warning("Invalid argument for pdf:trailerid special."); + *has_id = 0; + } else { + *has_id = 1; + } } free(q); } @@ -2311,7 +2418,8 @@ dvi_scan_specials (int page_no, double *x_offset, double *y_offset, int *landscape, int *majorversion, int *minorversion, int *do_enc, int *key_bits, int32_t *permission, - char *owner_pw, char *user_pw) + char *owner_pw, char *user_pw, + int *has_id, unsigned char *id1, unsigned char *id2) { uint32_t offset; unsigned char opcode; @@ -2356,6 +2464,7 @@ dvi_scan_specials (int page_no, if (scan_special(page_width, page_height, x_offset, y_offset, landscape, majorversion, minorversion, do_enc, key_bits, permission, owner_pw, user_pw, + has_id, id1, id2, buf, size)) dpx_warning("Reading special command failed: \"%.*s\"", size, buf); #undef buf @@ -2449,7 +2558,6 @@ dvi_reset_global_state(void) max_def_fonts = 0; compute_boxes = 0; link_annot = 1; - verbose = 0; - - num_loaded_fonts = 0; max_loaded_fonts = 0; + num_loaded_fonts = 0; + max_loaded_fonts = 0; } diff --git a/tectonic/dpx-dvi.h b/tectonic/dpx-dvi.h index 3f34bc51fa..e62c2fdb8e 100644 --- a/tectonic/dpx-dvi.h +++ b/tectonic/dpx-dvi.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -40,7 +40,6 @@ extern int landscape_mode; double get_origin (int x); void dvi_reset_global_state (void); -void dvi_set_verbose (int level); /* returns scale (dvi2pts) */ double dvi_init (const char *dvi_filename, double mag); /* may append .dvi or .xdv to filename */ @@ -81,7 +80,7 @@ void dvi_scan_specials (int page_no, double *x_offset, double *y_offset, int *landscape, int *majorversion, int *minorversion, int *do_enc, int *keybits, int32_t *perm, - char *opasswd, char *upasswd); + char *opasswd, char *upasswd, int *has_id, unsigned char *id1, unsigned char *id2); unsigned int dvi_locate_font (const char *name, spt_t ptsize); /* link or nolink: diff --git a/tectonic/dpx-dvipdfmx.c b/tectonic/dpx-dvipdfmx.c index e3398903c5..786c0f40da 100644 --- a/tectonic/dpx-dvipdfmx.c +++ b/tectonic/dpx-dvipdfmx.c @@ -2,7 +2,7 @@ DVIPDFMx, an eXtended version of DVIPDFM by Mark A. Wicks. - Copyright (C) 2002-2017 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, + Copyright (C) 2002-2020 by Jin-Hwan Cho, Matthias Franz, Shunsaku Hirata, the DVIPDFMx project team. Copyright (c) 2006 SIL. (xdvipdfmx extensions for XeTeX support) @@ -36,12 +36,14 @@ #include "core-bridge.h" #include "dpx-cid.h" #include "dpx-dpxconf.h" +#include "dpx-dpxcrypt.h" #include "dpx-dpxfile.h" #include "dpx-dpxutil.h" #include "dpx-dvi.h" #include "dpx-error.h" #include "dpx-fontmap.h" #include "dpx-mem.h" +#include "dpx-mpost.h" #include "dpx-pdfdev.h" #include "dpx-pdfdoc.h" #include "dpx-pdfencrypt.h" @@ -49,6 +51,7 @@ #include "dpx-pdflimits.h" #include "dpx-pdfobj.h" #include "dpx-pdfparse.h" +#include "dpx-pdfximage.h" #include "dpx-spc_tpic.h" #include "dpx-specials.h" #include "dpx-tfm.h" @@ -61,8 +64,6 @@ typedef struct page_range int last; } PageRange; -int is_xdv = 0; -int translate_origin = 0; const XdvipdfmxConfig* dpx_config; #define OPT_TPIC_TRANSPARENT_FILL (1 << 1) @@ -72,11 +73,16 @@ const XdvipdfmxConfig* dpx_config; #define OPT_PDFOBJ_NO_PREDICTOR (1 << 5) #define OPT_PDFOBJ_NO_OBJSTM (1 << 6) +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; /* * Precision is essentially limited to 0.01pt. @@ -89,6 +95,9 @@ static int pdfdecimaldigits = 3; /* -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; @@ -103,8 +112,8 @@ 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; -int always_embed = 0; /* always embed fonts, regardless of licensing flags */ /* XXX: there are four quasi-redundant versions of this; grp for K_UNIT__PT */ static int @@ -203,15 +212,13 @@ select_paper (const char *paperspec) _tt_abort("Invalid paper size: %s (%.2fx%.2f)", paperspec, paper_width, paper_height); } +PageRange *page_ranges = NULL; +int num_page_ranges = 0; +int max_page_ranges = 0; + static void -select_pages ( - const char *pagespec, - PageRange **ret_page_ranges, - unsigned int *ret_num_page_ranges) +select_pages (const char *pagespec) { - PageRange *page_ranges = NULL; - unsigned int num_page_ranges = 0; - unsigned int max_page_ranges = 0; char *q; const char *p = pagespec; @@ -259,9 +266,6 @@ select_pages ( _tt_abort("Bad page range specification: %s", p); } } - - *ret_page_ranges = page_ranges; - *ret_num_page_ranges = num_page_ranges; } #define SWAP(v1,v2) do {\ @@ -271,7 +275,7 @@ select_pages ( } while (0) static void -do_dvi_pages (PageRange *page_ranges, unsigned int num_page_ranges) +do_dvi_pages (void) { int page_no, step; unsigned int page_count, i; @@ -281,6 +285,16 @@ do_dvi_pages (PageRange *page_ranges, unsigned int num_page_ranges) spc_exec_at_begin_document(); + if (num_page_ranges == 0) { + if (!page_ranges) { + page_ranges = NEW(1, struct page_range); + max_page_ranges = 1; + } + page_ranges[0].first = 0; + page_ranges[0].last = -1; /* last page */ + num_page_ranges = 1; + } + init_paper_width = page_width = paper_width; init_paper_height = page_height = paper_height; page_count = 0; @@ -308,8 +322,10 @@ do_dvi_pages (PageRange *page_ranges, unsigned int num_page_ranges) 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); - if (lm != landscape_mode) { + 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 */ SWAP(w, h); landscape_mode = lm; } @@ -353,6 +369,25 @@ do_dvi_pages (PageRange *page_ranges, unsigned int num_page_ranges) spc_exec_at_end_document(); } +static void +compute_id_string (unsigned char *id, const char *producer, + const char *dviname, const char *pdfname) +{ + char datestr[32]; + MD5_CONTEXT md5; + + MD5_init(&md5); + /* Don't use timezone for compatibility */ + dpx_util_format_asn_date(datestr, 0); + MD5_write(&md5, (const unsigned char *)datestr, strlen(datestr)); + if (producer) + MD5_write(&md5, (const unsigned char *)producer, strlen(producer)); + if (dviname) + MD5_write(&md5, (const unsigned char *)dviname, strlen(dviname)); + if (pdfname) + MD5_write(&md5, (const unsigned char *)pdfname, strlen(pdfname)); + MD5_final(id, &md5); +} int dvipdfmx_main ( @@ -367,16 +402,21 @@ dvipdfmx_main ( unsigned int verbose, time_t build_date) { - bool enable_object_stream = true; double dvi2pts; - unsigned int num_page_ranges = 0; - PageRange *page_ranges = NULL; + const char *creator = NULL; + char oplain[128] = "", uplain[128] = ""; + int has_id = 0; + unsigned char id1[16], id2[16]; + struct pdf_setting settings; assert(pdf_filename); assert(dvi_filename); translate_origin = translate; + page_ranges = NULL; + num_page_ranges = 0; + max_page_ranges = 0; dvi_reset_global_state(); tfm_reset_global_state(); @@ -388,18 +428,9 @@ dvipdfmx_main ( if (quiet) { shut_up(2); } else { - - dvi_set_verbose(verbose); - pdf_dev_set_verbose(verbose); - pdf_doc_set_verbose(verbose); - pdf_enc_set_verbose(verbose); - pdf_obj_set_verbose(verbose); - pdf_fontmap_set_verbose(verbose); - dpx_file_set_verbose(verbose); - tt_aux_set_verbose(verbose); + dpx_conf.verbose_level = verbose; } - pdf_set_compression(compress ? 9 : 0); pdf_font_set_deterministic_unique_tags(deterministic_tags ? 1 : 0); pdf_init_fontmaps(); /* This must come before parsing options... */ @@ -423,15 +454,7 @@ dvipdfmx_main ( pdf_load_fontmap_file("ckx.map", FONTMAP_RMODE_APPEND); if (pagespec) { - select_pages(pagespec, &page_ranges, &num_page_ranges); - } - if (!page_ranges) { - page_ranges = NEW(1, PageRange); - } - if (num_page_ranges == 0) { - page_ranges[0].first = 0; - page_ranges[0].last = -1; /* last page */ - num_page_ranges = 1; + select_pages(pagespec); } /*kpse_init_prog("", font_dpi, NULL, NULL); @@ -439,76 +462,93 @@ dvipdfmx_main ( pdf_font_set_dpi(font_dpi); dpx_delete_old_cache(image_cache_life); - pdf_enc_compute_id_string(dvi_filename, pdf_filename); - { - int ver_major = 0, ver_minor = 0; - char owner_pw[MAX_PWD_LEN], user_pw[MAX_PWD_LEN]; /* Dependency between DVI and PDF side is rather complicated... */ dvi2pts = dvi_init(dvi_filename, mag); if (dvi2pts == 0.0) _tt_abort("dvi_init() failed!"); - pdf_doc_set_creator(dvi_comment()); - + creator = dvi_comment(); /* Set PDF Creator entry */ dvi_scan_specials(0, &paper_width, &paper_height, &x_offset, &y_offset, &landscape_mode, - &ver_major, &ver_minor, - &do_encryption, &key_bits, &permission, owner_pw, user_pw); - if (ver_minor >= PDF_VERSION_MIN && ver_minor <= PDF_VERSION_MAX) { - pdf_set_version(ver_minor); - } - if (do_encryption) { - if (!(key_bits >= 40 && key_bits <= 128 && (key_bits % 8 == 0)) && - key_bits != 256) - _tt_abort("Invalid encryption key length specified: %u", key_bits); - else if (key_bits > 40 && pdf_get_version() < 4) - _tt_abort("Chosen key length requires at least PDF 1.4. " \ - "Use \"-V 4\" to change."); - do_encryption = 1; - pdf_enc_set_passwd(key_bits, permission, owner_pw, user_pw); - } - if (landscape_mode) { - SWAP(paper_width, paper_height); - } + &pdf_version_major, &pdf_version_minor, + &do_encryption, &key_bits, &permission, oplain, uplain, + &has_id, id1, id2); } - pdf_files_init(); + /* Encryption and Other Settings */ + { + memset(&settings.encrypt, 0, sizeof(struct pdf_enc_setting)); + settings.enable_encrypt = do_encryption; + settings.encrypt.use_aes = 1; + settings.encrypt.encrypt_metadata = 1; + settings.encrypt.key_size = key_bits; + settings.encrypt.permission = permission; + settings.encrypt.uplain = uplain; + settings.encrypt.oplain = oplain; + } - if (opt_flags & OPT_PDFOBJ_NO_OBJSTM) - enable_object_stream = false; + if (opt_flags & OPT_PDFOBJ_NO_OBJSTM) { + settings.object.enable_objstm = 0; + } else { + settings.object.enable_objstm = 1; + } + if (opt_flags & OPT_PDFOBJ_NO_PREDICTOR) { + settings.object.enable_predictor = 0; + } else { + settings.object.enable_predictor = 1; + } /* 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. */ - pdf_open_document(pdf_filename, do_encryption, enable_object_stream, - paper_width, paper_height, annot_grow, bookmark_open, - !(opt_flags & OPT_PDFDOC_NO_DEST_REMOVE)); - - /* Ignore_colors placed here since - * they are considered as device's capacity. + if (landscape_mode) { + SWAP(paper_width, paper_height); + } + settings.media_width = paper_width; + settings.media_height = paper_height; + settings.annot_grow_amount = annot_grow; + settings.outline_open_depth = bookmark_open; + settings.check_gotos = !(opt_flags & OPT_PDFDOC_NO_DEST_REMOVE); + + 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. */ pdf_init_device(dvi2pts, pdfdecimaldigits, ignore_colors); + { + int version = pdf_version_major * 10 + pdf_version_minor; + pdf_set_version(version); + } + pdf_set_compression(compress ? compression_level : 0); + if (enable_thumbnail) + pdf_doc_enable_manual_thumbnails(); + + if (!has_id) { + const char *producer = "xdvipdfmx-0.1, Copyright 2002-2015 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata"; + 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); if (opt_flags & OPT_CIDFONT_FIXEDPITCH) CIDFont_set_flags(CIDFONT_FORCE_FIXEDPITCH); - /* Please move this to spc_init_specials(). */ if (opt_flags & OPT_TPIC_TRANSPARENT_FILL) tpic_set_fill_mode(1); + if (translate_origin) + mps_set_translate_origin(1); - if (opt_flags & OPT_PDFOBJ_NO_PREDICTOR) - pdf_set_use_predictor(0); /* No prediction */ - - do_dvi_pages(page_ranges, num_page_ranges); - - pdf_files_close(); + do_dvi_pages(); - /* Order of close... */ - pdf_close_device (); - /* pdf_close_document flushes XObject (image) and other resources. */ pdf_close_document(); pdf_close_fontmaps(); /* pdf_font may depend on fontmap. */ diff --git a/tectonic/dpx-dvipdfmx.h b/tectonic/dpx-dvipdfmx.h index 7849600699..2605972c23 100644 --- a/tectonic/dpx-dvipdfmx.h +++ b/tectonic/dpx-dvipdfmx.h @@ -1,6 +1,6 @@ /* DVIPDFMx, an eXtended version of DVIPDFM by Mark A. Wicks. - Copyright (C) 2002-2016 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, the DVIPDFMx project team. Copyright (c) 2006 SIL. (xdvipdfmx extensions for XeTeX support) @@ -31,8 +31,6 @@ #define DVIPDFMX_PROG_NAME "xdvipdfmx" -extern int is_xdv; -extern int translate_origin; extern time_t source_date_epoch; extern const XdvipdfmxConfig* dpx_config; diff --git a/tectonic/dpx-epdf.c b/tectonic/dpx-epdf.c index ec102779e6..d52a237991 100644 --- a/tectonic/dpx-epdf.c +++ b/tectonic/dpx-epdf.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -43,262 +43,8 @@ #include "dpx-pdfparse.h" #include "dpx-pdfximage.h" -static int rect_equal (pdf_obj *rect1, pdf_obj *rect2); -/* - * From PDFReference15_v6.pdf (p.119 and p.834) - * - * MediaBox rectangle (Required; inheritable) - * - * The media box defines the boundaries of the physical medium on which the - * page is to be printed. It may include any extended area surrounding the - * finished page for bleed, printing marks, or other such purposes. It may - * also include areas close to the edges of the medium that cannot be marked - * because of physical limitations of the output device. Content falling - * outside this boundary can safely be discarded without affecting the - * meaning of the PDF file. - * - * CropBox rectangle (Optional; inheritable) - * - * The crop box defines the region to which the contents of the page are to be - * clipped (cropped) when displayed or printed. Unlike the other boxes, the - * crop box has no defined meaning in terms of physical page geometry or - * intended use; it merely imposes clipping on the page contents. However, - * in the absence of additional information (such as imposition instructions - * specified in a JDF or PJTF job ticket), the crop box will determine how - * the page's contents are to be positioned on the output medium. The default - * value is the page's media box. - * - * BleedBox rectangle (Optional; PDF 1.3) - * - * The bleed box (PDF 1.3) defines the region to which the contents of the - * page should be clipped when output in a production environment. This may - * include any extra bleed area needed to accommodate the physical - * limitations of cutting, folding, and trimming equipment. The actual printed - * page may include printing marks that fall outside the bleed box. - * The default value is the page's crop box. - * - * TrimBox rectangle (Optional; PDF 1.3) - * - * The trim box (PDF 1.3) defines the intended dimensions of the finished page - * after trimming. It may be smaller than the media box, to allow for - * production-related content such as printing instructions, cut marks, or - * color bars. The default value is the page’s crop box. - * - * ArtBox rectangle (Optional; PDF 1.3) - * - * The art box (PDF 1.3) defines the extent of the page's meaningful content - * (including potential white space) as intended by the page's creator. - * The default value is the page's crop box. - * - * Rotate integer (Optional; inheritable) - * - * The number of degrees by which the page should be rotated clockwise when - * displayed or printed. The value must be a multiple of 90. Default value: 0. - */ - -static int -rect_equal (pdf_obj *rect1, pdf_obj *rect2) -{ - int i; - - if (!rect1 || !rect2) - return 0; - for (i = 0; i < 4; i++) { - if (pdf_number_value(pdf_get_array(rect1, i)) != - pdf_number_value(pdf_get_array(rect2, i))) - return 0; - } - - return 1; -} - static pdf_obj* -pdf_get_page_obj (pdf_file *pf, int page_no, - pdf_obj **ret_bbox, pdf_obj **ret_resources) -{ - pdf_obj *page_tree; - pdf_obj *bbox = NULL, *resources = NULL, *rotate = NULL; - int page_idx; - - /* - * Get Page Tree. - */ - page_tree = NULL; - { - pdf_obj *trailer, *catalog; - pdf_obj *markinfo, *tmp; - - trailer = pdf_file_get_trailer(pf); - - if (pdf_lookup_dict(trailer, "Encrypt")) { - dpx_warning("This PDF document is encrypted."); - pdf_release_obj(trailer); - return NULL; - } - - catalog = pdf_deref_obj(pdf_lookup_dict(trailer, "Root")); - if (!PDF_OBJ_DICTTYPE(catalog)) { - dpx_warning("Can't read document catalog."); - pdf_release_obj(trailer); - pdf_release_obj(catalog); - return NULL; - } - pdf_release_obj(trailer); - - markinfo = pdf_deref_obj(pdf_lookup_dict(catalog, "MarkInfo")); - if (markinfo) { - tmp = pdf_lookup_dict(markinfo, "Marked"); - if (PDF_OBJ_BOOLEANTYPE(tmp) && pdf_boolean_value(tmp)) - dpx_warning("PDF file is tagged... Ignoring tags."); - pdf_release_obj(markinfo); - } - - page_tree = pdf_deref_obj(pdf_lookup_dict(catalog, "Pages")); - pdf_release_obj(catalog); - } - if (!page_tree) { - dpx_warning("Page tree not found."); - return NULL; - } - - /* - * Negative page numbers are counted from the back. - */ - { - int count = pdf_number_value(pdf_lookup_dict(page_tree, "Count")); - page_idx = page_no + (page_no >= 0 ? -1 : count); - if (page_idx < 0 || page_idx >= count) { - dpx_warning("Page %d does not exist.", page_no); - pdf_release_obj(page_tree); - return NULL; - } - page_no = page_idx+1; - } - - /* - * Seek correct page. Get Media/Crop Box. - * Media box and resources can be inherited. - */ - { - pdf_obj *kids_ref, *kids; - pdf_obj *crop_box = NULL; - pdf_obj *tmp; - - tmp = pdf_lookup_dict(page_tree, "Resources"); - resources = tmp ? pdf_deref_obj(tmp) : pdf_new_dict(); - - while (1) { - int kids_length, i; - - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "MediaBox")))) { - pdf_release_obj(bbox); - bbox = tmp; - } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "BleedBox")))) { - if (!rect_equal(tmp, bbox)) { - pdf_release_obj(bbox); - bbox = tmp; - } else { - pdf_release_obj(tmp); - } - } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "TrimBox")))) { - if (!rect_equal(tmp, bbox)) { - pdf_release_obj(bbox); - bbox = tmp; - } else { - pdf_release_obj(tmp); - } - } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "ArtBox")))) { - if (!rect_equal(tmp, bbox)) { - pdf_release_obj(bbox); - bbox = tmp; - } else { - pdf_release_obj(tmp); - } - } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "CropBox")))) { - pdf_release_obj(crop_box); - crop_box = tmp; - } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Rotate")))) { - pdf_release_obj(rotate); - rotate = tmp; - } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Resources")))) { - pdf_release_obj(resources); - resources = tmp; - } - - kids_ref = pdf_lookup_dict(page_tree, "Kids"); - if (!kids_ref) - break; - kids = pdf_deref_obj(kids_ref); - kids_length = pdf_array_length(kids); - - for (i = 0; i < kids_length; i++) { - int count; - - pdf_release_obj(page_tree); - page_tree = pdf_deref_obj(pdf_get_array(kids, i)); - - tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Count")); - if (tmp) { - /* Pages object */ - count = pdf_number_value(tmp); - pdf_release_obj(tmp); - } else { - /* Page object */ - count = 1; - } - if (page_idx < count) - break; - - page_idx -= count; - } - - pdf_release_obj(kids); - - if (i == kids_length) { - dpx_warning("Page %d not found! Broken PDF file?", page_no); - pdf_release_obj(bbox); - pdf_release_obj(crop_box); - pdf_release_obj(rotate); - pdf_release_obj(resources); - pdf_release_obj(page_tree); - return NULL; - } - } - if (crop_box) { - pdf_release_obj(bbox); - bbox = crop_box; - } - } - - if (!bbox) { - dpx_warning("No BoundingBox information available."); - pdf_release_obj(page_tree); - pdf_release_obj(resources); - pdf_release_obj(rotate); - return NULL; - } - - if (rotate) { - pdf_release_obj(rotate); - rotate = NULL; - } - - if (ret_bbox != NULL) - *ret_bbox = bbox; - if (ret_resources != NULL) - *ret_resources = resources; - - return page_tree; -} - -static pdf_obj* -pdf_get_page_content (pdf_obj* page) +get_page_content (pdf_file *pf, pdf_obj* page) { pdf_obj *contents, *content_new; @@ -306,7 +52,7 @@ pdf_get_page_content (pdf_obj* page) if (!contents) return NULL; - if (pdf_obj_typeof(contents) == PDF_NULL) { + if (PDF_OBJ_NULLTYPE(contents)) { /* empty page */ pdf_release_obj(contents); /* TODO: better don't include anything if the page is empty */ @@ -316,29 +62,25 @@ pdf_get_page_content (pdf_obj* page) * Concatenate all content streams. */ pdf_obj *content_seg; - int idx = 0; + int i; content_new = pdf_new_stream(STREAM_COMPRESS); - for (;;) { - content_seg = pdf_deref_obj(pdf_get_array(contents, idx)); - if (!content_seg) - break; - else if (PDF_OBJ_NULLTYPE(content_seg)) { - /* Silently ignore. */ - } else if (!PDF_OBJ_STREAMTYPE(content_seg)) { - dpx_warning("Page content not a stream object. Broken PDF file?"); - pdf_release_obj(content_seg); - pdf_release_obj(content_new); - pdf_release_obj(contents); + for (i = 0; i < pdf_array_length(contents); i++) { + content_seg = pdf_deref_obj(pdf_get_array(contents, i)); + if (!content_seg) { + dpx_warning("Could not read page content stream."); + pdf_release_obj(content_new); return NULL; - } else if (pdf_concat_stream(content_new, content_seg) < 0) { - dpx_warning("Could not handle content stream with multiple segments."); + } + if (PDF_OBJ_STREAMTYPE(content_seg)) { + pdf_concat_stream(content_new, content_seg); + } else if (!PDF_OBJ_NULLTYPE(content_seg)) { + dpx_warning("Page content not a stream object. Broken PDF file?"); pdf_release_obj(content_seg); pdf_release_obj(content_new); pdf_release_obj(contents); return NULL; } pdf_release_obj(content_seg); - idx++; } pdf_release_obj(contents); contents = content_new; @@ -350,12 +92,7 @@ pdf_get_page_content (pdf_obj* page) } /* Flate the contents if necessary. */ content_new = pdf_new_stream(STREAM_COMPRESS); - if (pdf_concat_stream(content_new, contents) < 0) { - dpx_warning("Could not handle a content stream."); - pdf_release_obj(contents); - pdf_release_obj(content_new); - return NULL; - } + pdf_concat_stream(content_new, contents); pdf_release_obj(contents); contents = content_new; } @@ -379,11 +116,6 @@ pdf_include_page (pdf_ximage *ximage, if (!pf) return -1; - if (pdf_file_get_version(pf) > pdf_get_version()) { - dpx_warning("Trying to include PDF file which has newer version number " \ - "than output PDF: 1.%d.", pdf_get_version()); - } - pdf_ximage_init_form_info(&info); if (options.page_no == 0) @@ -409,51 +141,12 @@ pdf_include_page (pdf_ximage *ximage, pdf_release_obj(tmp); } - contents = pdf_deref_obj(pdf_lookup_dict(page, "Contents")); - pdf_release_obj(page); - page = NULL; - /* * Handle page content stream. */ - { - pdf_obj *content_new; - - if (!contents) { - /* - * Empty page - */ - content_new = pdf_new_stream(0); - /* TODO: better don't include anything if the page is empty */ - } else if (PDF_OBJ_STREAMTYPE(contents)) { - /* - * We must import the stream because its dictionary - * may contain indirect references. - */ - content_new = pdf_import_object(contents); - } else if (PDF_OBJ_ARRAYTYPE(contents)) { - /* - * Concatenate all content streams. - */ - int idx, len = pdf_array_length(contents); - content_new = pdf_new_stream(STREAM_COMPRESS); - for (idx = 0; idx < len; idx++) { - pdf_obj *content_seg = pdf_deref_obj(pdf_get_array(contents, idx)); - if (!PDF_OBJ_STREAMTYPE(content_seg) || - pdf_concat_stream(content_new, content_seg) < 0) { - pdf_release_obj(content_seg); - pdf_release_obj(content_new); - goto error; - } - pdf_release_obj(content_seg); - } - } else { - goto error; - } - - pdf_release_obj(contents); - contents = content_new; - } + contents = get_page_content(pf, page); + pdf_release_obj(page); + page = NULL; /* * Add entries to contents stream dictionary. @@ -586,6 +279,8 @@ pdf_copy_clip (rust_input_handle_t image_file, int pageNo, double x_user, double char *save_path, *temp; pdf_tmatrix M; double stack[6]; + pdf_rect bbox; + pdf_tmatrix mtrx; pdf_file *pf; pf = pdf_open(NULL, image_file); @@ -595,13 +290,13 @@ pdf_copy_clip (rust_input_handle_t image_file, int pageNo, double x_user, double pdf_dev_currentmatrix(&M); pdf_invertmatrix(&M); M.e += x_user; M.f += y_user; - page_tree = pdf_get_page_obj (pf, pageNo, NULL, NULL); + + page_tree = pdf_doc_get_page(pf, pageNo, 0, &bbox, &mtrx, NULL); if (!page_tree) { pdf_close(pf); return -1; } - - contents = pdf_get_page_content(page_tree); + contents = get_page_content(pf, page_tree); pdf_release_obj(page_tree); if (!contents) { pdf_close(pf); diff --git a/tectonic/dpx-fontmap.c b/tectonic/dpx-fontmap.c index abdbba8e10..ea05227020 100644 --- a/tectonic/dpx-fontmap.c +++ b/tectonic/dpx-fontmap.c @@ -23,6 +23,7 @@ #include "dpx-fontmap.h" #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" #include "dpx-dpxutil.h" #include "dpx-error.h" @@ -33,14 +34,6 @@ /* CIDFont */ static char *strip_options (const char *map_name, fontmap_opt *opt); -static int verbose = 0; -void -pdf_fontmap_set_verbose (int level) -{ - verbose = level; -} - - void pdf_init_fontmap_record (fontmap_rec *mrec) { @@ -72,7 +65,7 @@ pdf_init_fontmap_record (fontmap_rec *mrec) mrec->opt.style = FONTMAP_STYLE_NONE; mrec->opt.stemv = -1; /* not given explicitly by an option */ - mrec->opt.cff_charsets = NULL; + mrec->opt.use_glyph_encoding = 0; } void @@ -131,7 +124,7 @@ pdf_copy_fontmap_record (fontmap_rec *dst, const fontmap_rec *src) dst->opt.style = src->opt.style; dst->opt.stemv = src->opt.stemv; - dst->opt.cff_charsets = src->opt.cff_charsets; + dst->opt.use_glyph_encoding = src->opt.use_glyph_encoding; } @@ -728,7 +721,7 @@ pdf_append_fontmap_record (const char *kp, const fontmap_rec *vp) return -1; } - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message("fontmap>> append key=\"%s\"...", kp); fnt_name = chop_sfd_name(kp, &sfd_name); @@ -767,7 +760,7 @@ pdf_append_fontmap_record (const char *kp, const fontmap_rec *vp) } ht_insert_table(fontmap, kp, strlen(kp), mrec); } - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message("\n"); return 0; @@ -781,7 +774,7 @@ pdf_remove_fontmap_record (const char *kp) if (!kp) return -1; - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message("fontmap>> remove key=\"%s\"...", kp); fnt_name = chop_sfd_name(kp, &sfd_name); @@ -792,13 +785,13 @@ pdf_remove_fontmap_record (const char *kp) subfont_ids = sfd_get_subfont_ids(sfd_name, &n); if (!subfont_ids) return -1; - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message("\nfontmap>> Expand @%s@:", sfd_name); while (n-- > 0) { tfm_name = make_subfont_name(kp, sfd_name, subfont_ids[n]); if (!tfm_name) continue; - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message(" %s", tfm_name); ht_remove_table(fontmap, tfm_name, strlen(tfm_name)); free(tfm_name); @@ -809,7 +802,7 @@ pdf_remove_fontmap_record (const char *kp) ht_remove_table(fontmap, kp, strlen(kp)); - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message("\n"); return 0; @@ -826,7 +819,7 @@ pdf_insert_fontmap_record (const char *kp, const fontmap_rec *vp) return NULL; } - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message("fontmap>> insert key=\"%s\"...", kp); fnt_name = chop_sfd_name(kp, &sfd_name); @@ -841,13 +834,13 @@ pdf_insert_fontmap_record (const char *kp, const fontmap_rec *vp) free(sfd_name); return NULL; } - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message("\nfontmap>> Expand @%s@:", sfd_name); while (n-- > 0) { tfm_name = make_subfont_name(kp, sfd_name, subfont_ids[n]); if (!tfm_name) continue; - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message(" %s", tfm_name); mrec = NEW(1, fontmap_rec); pdf_init_fontmap_record(mrec); @@ -868,7 +861,7 @@ pdf_insert_fontmap_record (const char *kp, const fontmap_rec *vp) } ht_insert_table(fontmap, kp, strlen(kp), mrec); - if (verbose > 3) + if (dpx_conf.verbose_level > 3) dpx_message("\n"); return mrec; @@ -969,7 +962,7 @@ pdf_load_fontmap_file (const char *filename, int mode) assert(filename); assert(fontmap); - if (verbose) + if (dpx_conf.verbose_level) dpx_message(""); return error; @@ -1048,7 +1041,7 @@ pdf_insert_native_fontmap_record (const char *path, uint32_t index, fontmap_key = xmalloc(strlen(path) + 40); // CHECK sprintf(fontmap_key, "%s/%d/%c/%d/%d/%d", path, index, layout_dir == 0 ? 'H' : 'V', extend, slant, embolden); - if (verbose) + if (dpx_conf.verbose_level) dpx_message("opt.extend = extend / 65536.0; mrec->opt.slant = slant / 65536.0; mrec->opt.bold = embolden / 65536.0; + mrec->opt.use_glyph_encoding = 1; ret = pdf_insert_fontmap_record(mrec->map_name, mrec); pdf_clear_fontmap_record(mrec); free(mrec); - if (verbose) + if (dpx_conf.verbose_level) dpx_message(">"); return ret; diff --git a/tectonic/dpx-fontmap.h b/tectonic/dpx-fontmap.h index 1409e34167..6fd2e60f9e 100644 --- a/tectonic/dpx-fontmap.h +++ b/tectonic/dpx-fontmap.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -49,14 +49,13 @@ typedef struct fontmap_opt { char *otl_tags; /* currently unused */ char *tounicode; /* not implemented yet */ - void *cff_charsets; - double design_size; /* unused */ char *charcoll; /* Adobe-Japan1-4, etc. */ int index; /* TTC index */ int style; /* ,Bold, etc. */ int stemv; /* StemV value especially for CJK fonts */ + int use_glyph_encoding; /* XeTeX support */ } fontmap_opt; typedef struct fontmap_rec { @@ -76,8 +75,6 @@ typedef struct fontmap_rec { fontmap_opt opt; } fontmap_rec; -void pdf_fontmap_set_verbose (int level); - void pdf_init_fontmaps (void); void pdf_close_fontmaps (void); diff --git a/tectonic/dpx-jp2image.c b/tectonic/dpx-jp2image.c index b481e632b5..dcdbcfdc8e 100644 --- a/tectonic/dpx-jp2image.c +++ b/tectonic/dpx-jp2image.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 Matthias Franz, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Matthias Franz, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -32,6 +32,7 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-error.h" #include "dpx-mfileio.h" #include "dpx-numbers.h" @@ -353,14 +354,12 @@ check_for_jp2 (FILE *fp) int jp2_include_image (pdf_ximage *ximage, FILE *fp) { - unsigned int pdf_version; int smask = 0; pdf_obj *stream, *stream_dict; ximage_info info; - pdf_version = pdf_get_version(); - if (pdf_version < 5) { - dpx_warning("JPEG 2000 support requires PDF version >= 1.5 (Current setting 1.%d)\n", pdf_version); + if (pdf_check_version(1, 5) < 0) { + dpx_warning("JPEG 2000 support requires PDF version >= 1.5 (Current setting %d.%d)\n", pdf_get_version_major(), pdf_get_version_minor()); return -1; } diff --git a/tectonic/dpx-jpegimage.c b/tectonic/dpx-jpegimage.c index 1fd13e5111..1b0a096632 100644 --- a/tectonic/dpx-jpegimage.c +++ b/tectonic/dpx-jpegimage.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -56,6 +56,7 @@ #include #include +#include "dpx-dpxconf.h" #include "dpx-error.h" #include "dpx-mem.h" #include "dpx-mfileio.h" @@ -269,7 +270,7 @@ jpeg_include_image (pdf_ximage *ximage, rust_input_handle_t handle) pdf_add_dict(stream_dict, pdf_new_name("Filter"), pdf_new_name("DCTDecode")); /* XMP Metadata */ - if (pdf_get_version() >= 4) { + if (pdf_check_version(1, 4) >= 0) { if (j_info.flags & HAVE_APPn_XMP) { pdf_obj *XMP_stream; @@ -943,6 +944,12 @@ JPEG_copy_stream (struct JPEG_info *j_info, pdf_obj *stream, rust_input_handle_t return (found_SOFn ? 0 : -1); } +/* Adobe Technical Note #5116 "Supporting the DCT Filters in PostScript Level 2" + * 6. "DCTDecode Filter Summary" + * ... APPn (application-specific) markers are skipped over harmlessly except + * for the Adobe reserved marker described later. + * + */ #define SET_SKIP(j,c) if ((c) < MAX_COUNT) { \ (j)->skipbits[(c) / 8] |= (1 << (7 - ((c) % 8))); \ } @@ -978,11 +985,17 @@ JPEG_scan_file (struct JPEG_info *j_info, rust_input_handle_t handle) return -1; length -= 5; if (!memcmp(app_sig, "JFIF\000", 5)) { + /* APP0 JFIF marker preserved */ j_info->flags |= HAVE_APPn_JFIF; length -= read_APP0_JFIF(j_info, handle); } else if (!memcmp(app_sig, "JFXX", 5)) { length -= read_APP0_JFXX(handle, length); + SET_SKIP(j_info, count); + } else { + SET_SKIP(j_info, count); } + } else { + SET_SKIP(j_info, count); } ttstub_input_seek(handle, length, SEEK_CUR); break; @@ -992,6 +1005,7 @@ JPEG_scan_file (struct JPEG_info *j_info, rust_input_handle_t handle) return -1; length -= 5; if (!memcmp(app_sig, "Exif\000", 5)) { + /* APP1 Exif marker preserved */ j_info->flags |= HAVE_APPn_Exif; length -= read_APP1_Exif(j_info, handle, length); } else if (!memcmp(app_sig, "http:", 5) && length > 24) { @@ -1001,9 +1015,11 @@ JPEG_scan_file (struct JPEG_info *j_info, rust_input_handle_t handle) if (!memcmp(app_sig, "//ns.adobe.com/xap/1.0/\000", 24)) { j_info->flags |= HAVE_APPn_XMP; length -= read_APP1_XMP(j_info, handle, length); - SET_SKIP(j_info, count); } + SET_SKIP(j_info, count); } + } else { + SET_SKIP(j_info, count); } ttstub_input_seek(handle, length, SEEK_CUR); break; @@ -1015,10 +1031,10 @@ JPEG_scan_file (struct JPEG_info *j_info, rust_input_handle_t handle) if (!memcmp(app_sig, "ICC_PROFILE\000", 12)) { j_info->flags |= HAVE_APPn_ICC; length -= read_APP2_ICC(j_info, handle, length); - SET_SKIP(j_info, count); } } ttstub_input_seek(handle, length, SEEK_CUR); + SET_SKIP(j_info, count); break; case JM_APP14: if (length > 5) { @@ -1026,11 +1042,14 @@ JPEG_scan_file (struct JPEG_info *j_info, rust_input_handle_t handle) return -1; length -= 5; if (!memcmp(app_sig, "Adobe", 5)) { + /* APP14 Adobe marker preserved */ j_info->flags |= HAVE_APPn_ADOBE; length -= read_APP14_Adobe(j_info, handle); } else { SET_SKIP(j_info, count); } + } else { + SET_SKIP(j_info, count); } ttstub_input_seek(handle, length, SEEK_CUR); break; diff --git a/tectonic/dpx-mem.h b/tectonic/dpx-mem.h index d99ab4c1dd..8a5ed5100c 100644 --- a/tectonic/dpx-mem.h +++ b/tectonic/dpx-mem.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-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -34,4 +34,13 @@ void *renew (void *p, uint32_t size); #define NEW(n,type) (type *) new(((uint32_t)(n))*sizeof(type)) #define RENEW(p,n,type) (type *) renew(p,((uint32_t)(n))*sizeof(type)) +/* + * mem.h is not suitable for the following, but it is the only common + * header file for dpxcrypt.c, pdfencrypt.c, and pdffont.c, which use + * the function rand(). + */ +void init_genrand(unsigned long long s); +long genrand_int31(void); +#define srand(x) init_genrand((x)) +#define rand() genrand_int31() #endif /* _MEM_H_ */ diff --git a/tectonic/dpx-mfileio.h b/tectonic/dpx-mfileio.h index a4f2d10726..b6d33472f7 100644 --- a/tectonic/dpx-mfileio.h +++ b/tectonic/dpx-mfileio.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-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks diff --git a/tectonic/dpx-mpost.c b/tectonic/dpx-mpost.c index 6ba14194f9..024a0ecffb 100644 --- a/tectonic/dpx-mpost.c +++ b/tectonic/dpx-mpost.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -49,6 +49,12 @@ */ static double Xorigin, Yorigin; +static int translate_origin = 0; + +void +mps_set_translate_origin (int v) { + translate_origin = v; +} /* * In PDF, current path is not a part of graphics state parameter. @@ -79,9 +85,24 @@ static struct mp_font } font_stack[PDF_GSAVE_MAX] = { {NULL, -1, -1, -1, 0} }; -static int currentfont = -1; +static int currentfont = 0; #define CURRENT_FONT() ((currentfont < 0) ? NULL : &font_stack[currentfont]) +#define FONT_DEFINED(f) ((f) && (f)->font_name && ((f)->font_id >= 0)) + +static void +clear_mp_font_struct (struct mp_font *font) +{ + assert(font); + + if (font->font_name) + free(font->font_name); + font->font_name = NULL; + font->font_id = -1; + font->tfm_id = -1; + font->subfont_id = -1; + font->pt_size = 0.0; +} /* Compatibility */ #define MP_CMODE_MPOST 0 @@ -99,17 +120,6 @@ mp_setfont (const char *font_name, double pt_size) font = CURRENT_FONT(); - if (font) { - if (streq_ptr(font->font_name, font_name) && - font->pt_size == pt_size) - return 0; - } else { /* No currentfont */ -/* ***TODO*** Here some problem exists! */ - font = &font_stack[0]; - font->font_name = NULL; - currentfont = 0; - } - mrec = pdf_lookup_fontmap_record(font_name); if (mrec && mrec->charmap.sfd_name && mrec->charmap.subfont_id) { subfont_id = sfd_load_record(mrec->charmap.sfd_name, mrec->charmap.subfont_id); @@ -143,23 +153,22 @@ save_font (void) { struct mp_font *current, *next; - if (currentfont < 0) { - font_stack[0].font_name = NEW(strlen("Courier") + 1, char); - strcpy(font_stack[0].font_name, "Courier"); - font_stack[0].pt_size = 1; - font_stack[0].tfm_id = 0; - font_stack[0].subfont_id = 0; - currentfont = 0; - } - current = &font_stack[currentfont++]; next = &font_stack[currentfont ]; - next->font_name = NEW(strlen(current->font_name)+1, char); - strcpy(next->font_name, current->font_name); - next->pt_size = current->pt_size; - - next->subfont_id = current->subfont_id; - next->tfm_id = current->tfm_id; + if (FONT_DEFINED(current)) { + next->font_name = NEW(strlen(current->font_name)+1, char); + strcpy(next->font_name, current->font_name); + next->font_id = current->font_id; + next->pt_size = current->pt_size; + next->subfont_id = current->subfont_id; + next->tfm_id = current->tfm_id; + } else { + next->font_name = NULL; + next->font_id = -1; + next->pt_size = 0.0; + next->subfont_id = -1; + next->tfm_id = -1; + } } static void @@ -169,9 +178,7 @@ restore_font (void) current = CURRENT_FONT(); if (current) { - current->font_name = mfree(current->font_name); - } else { - _tt_abort("No currentfont..."); + clear_mp_font_struct(current); } currentfont--; @@ -181,7 +188,7 @@ static void clear_fonts (void) { while (currentfont >= 0) { - free(font_stack[currentfont].font_name); + clear_mp_font_struct(&font_stack[currentfont]); currentfont--; } } @@ -713,7 +720,7 @@ do_currentfont (void) pdf_obj *font_dict; font = CURRENT_FONT(); - if (!font) { + if (!FONT_DEFINED(font)) { dpx_warning("Currentfont undefined..."); return 1; } else { @@ -750,7 +757,7 @@ do_show (void) double text_width; font = CURRENT_FONT(); - if (!font) { + if (!FONT_DEFINED(font)) { dpx_warning("Currentfont not set."); /* Should not be error... */ return 1; } diff --git a/tectonic/dpx-mpost.h b/tectonic/dpx-mpost.h index 96d8859278..605af62bd4 100644 --- a/tectonic/dpx-mpost.h +++ b/tectonic/dpx-mpost.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -31,6 +31,8 @@ #include "dpx-pdfdev.h" #include "dpx-pdfximage.h" +void mps_set_translate_origin (int boolean_value); + int mps_scan_bbox (const char **pp, const char *endptr, pdf_rect *bbox); int mps_exec_inline (const char **buffer, const char *endptr, diff --git a/tectonic/dpx-mt19937ar.c b/tectonic/dpx-mt19937ar.c new file mode 100644 index 0000000000..ff008b0f09 --- /dev/null +++ b/tectonic/dpx-mt19937ar.c @@ -0,0 +1,183 @@ +/* + A C-program for MT19937, with initialization improved 2002/1/26. + Coded by Takuji Nishimura and Makoto Matsumoto. + + Before using, initialize the state by using init_genrand(seed) + or init_by_array(init_key, key_length). + + Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + Any feedback is very welcome. + http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html + email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) +*/ + +/* Tectonic notes: + - These functions are exposed as aliases in dpx-mem.h +*/ + +#include + +/* Period parameters */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0dfUL /* constant vector a */ +#define UPPER_MASK 0x80000000UL /* most significant w-r bits */ +#define LOWER_MASK 0x7fffffffUL /* least significant r bits */ + +static unsigned long mt[N]; /* the array for the state vector */ +static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */ + +void init_genrand(unsigned long long s); +long genrand_int31(void); + +/* initializes mt[N] with a seed */ +/* void init_genrand(unsigned long s) */ +void init_genrand(unsigned long long s) +{ + mt[0]= s & 0xffffffffUL; + for (mti=1; mti> 30)) + mti); + /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ + /* In the previous versions, MSBs of the seed affect */ + /* only MSBs of the array mt[]. */ + /* 2002/01/09 modified by Makoto Matsumoto */ + mt[mti] &= 0xffffffffUL; + /* for >32 bit machines */ + } +} + +#if 0 /* unused in Tectonic: */ +/* initialize by an array with array-length */ +/* init_key is the array for initializing keys */ +/* key_length is its length */ +/* slight change for C++, 2004/2/26 */ +void init_by_array(unsigned long init_key[], int key_length) +{ + int i, j, k; + init_genrand(19650218UL); + i=1; j=0; + k = (N>key_length ? N : key_length); + for (; k; k--) { + mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) + + init_key[j] + j; /* non linear */ + mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ + i++; j++; + if (i>=N) { mt[0] = mt[N-1]; i=1; } + if (j>=key_length) j=0; + } + for (k=N-1; k; k--) { + mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) + - i; /* non linear */ + mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ + i++; + if (i>=N) { mt[0] = mt[N-1]; i=1; } + } + + mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ +} +#endif + +/* generates a random number on [0,0xffffffff]-interval */ +static unsigned long genrand_int32(void) +{ + unsigned long y; + static unsigned long mag01[2]={0x0UL, MATRIX_A}; + /* mag01[x] = x * MATRIX_A for x=0,1 */ + + if (mti >= N) { /* generate N words at one time */ + int kk; + + if (mti == N+1) /* if init_genrand() has not been called, */ + init_genrand(5489UL); /* a default initial seed is used */ + + for (kk=0;kk> 1) ^ mag01[y & 0x1UL]; + } + for (;kk> 1) ^ mag01[y & 0x1UL]; + } + y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); + mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; + + mti = 0; + } + + y = mt[mti++]; + + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + + return y; +} + +/* generates a random number on [0,0x7fffffff]-interval */ +long genrand_int31(void) +{ + return (long)(genrand_int32()>>1); +} + +#if 0 /* unused in Tectonic */ +/* generates a random number on [0,1]-real-interval */ +double genrand_real1(void) +{ + return genrand_int32()*(1.0/4294967295.0); + /* divided by 2^32-1 */ +} + +/* generates a random number on [0,1)-real-interval */ +double genrand_real2(void) +{ + return genrand_int32()*(1.0/4294967296.0); + /* divided by 2^32 */ +} + +/* generates a random number on (0,1)-real-interval */ +double genrand_real3(void) +{ + return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0); + /* divided by 2^32 */ +} + +/* generates a random number on [0,1) with 53-bit resolution*/ +double genrand_res53(void) +{ + unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6; + return(a*67108864.0+b)*(1.0/9007199254740992.0); +} +#endif diff --git a/tectonic/dpx-numbers.c b/tectonic/dpx-numbers.c index 99e17e521f..8ecb7ffe74 100644 --- a/tectonic/dpx-numbers.c +++ b/tectonic/dpx-numbers.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks diff --git a/tectonic/dpx-numbers.h b/tectonic/dpx-numbers.h index 2dcb309b34..e1bc755097 100644 --- a/tectonic/dpx-numbers.h +++ b/tectonic/dpx-numbers.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks diff --git a/tectonic/dpx-pdfcolor.c b/tectonic/dpx-pdfcolor.c index 673be503d0..e1c96a923f 100644 --- a/tectonic/dpx-pdfcolor.c +++ b/tectonic/dpx-pdfcolor.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-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -32,18 +32,12 @@ #include #include +#include "dpx-dpxconf.h" #include "dpx-error.h" #include "dpx-mem.h" #include "dpx-numbers.h" #include "dpx-pdfdev.h" -static int verbose = 0; -void -pdf_color_set_verbose (int level) -{ - verbose = level; -} - /* This function returns PDF_COLORSPACE_TYPE_GRAY, * PDF_COLORSPACE_TYPE_RGB, PDF_COLORSPACE_TYPE_CMYK or * PDF_COLORSPACE_TYPE_SPOT. @@ -329,7 +323,7 @@ pdf_color_set (pdf_color *sc, pdf_color *fc) { pdf_color_copycolor(&color_stack.stroke[color_stack.current], sc); pdf_color_copycolor(&color_stack.fill[color_stack.current], fc); - pdf_dev_reset_color(0); + pdf_dev_reset_color(1); } void @@ -351,7 +345,7 @@ pdf_color_pop (void) dpx_warning("Color stack underflow. Just ignore."); } else { color_stack.current--; - pdf_dev_reset_color(0); + pdf_dev_reset_color(1); } return; } @@ -390,19 +384,22 @@ static struct {0x04, 0x00}, /* PDF-1.5 */ {0x04, 0x00}, /* PDF-1.6 */ {0x04, 0x20}, /* PDF-1.7 */ + {0x04, 0x20}, /* Dummy(1.8)*/ + {0x04, 0x20}, /* Dummy(1.9) */ + {0x04, 0x20} /* PDF-2.0 */ }; static int iccp_version_supported (int major, int minor) { - int pdf_ver; + int idx; - pdf_ver = pdf_get_version(); - if (pdf_ver < 8) { - if (icc_versions[pdf_ver].major < major) + idx = pdf_get_version() - 10; + if (idx < 11) { + if (icc_versions[idx].major < major) return 0; - else if (icc_versions[pdf_ver].major == major && - icc_versions[pdf_ver].minor < minor) + else if (icc_versions[idx].major == major && + icc_versions[idx].minor < minor) return 0; else { return 1; @@ -965,12 +962,12 @@ iccp_load_profile (const char *ident, cspc_id = pdf_colorspace_findresource(ident, PDF_COLORSPACE_TYPE_ICCBASED, cdata); if (cspc_id >= 0) { - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message("(ICCP:[id=%d])", cspc_id); release_iccbased_cdata(cdata); return cspc_id; } - if (verbose > 1) { + if (dpx_conf.verbose_level > 1) { print_iccp_header(&icch, checksum); } @@ -1113,9 +1110,9 @@ pdf_colorspace_defineresource (const char *ident, colorspace->cdata = cdata; colorspace->resource = resource; - if (verbose) { + if (dpx_conf.verbose_level > 0) { dpx_message("(ColorSpace:%s", ident); - if (verbose > 1) { + if (dpx_conf.verbose_level > 1) { switch (subtype) { case PDF_COLORSPACE_TYPE_ICCBASED: dpx_message("[ICCBased]"); diff --git a/tectonic/dpx-pdfcolor.h b/tectonic/dpx-pdfcolor.h index ebd15d296b..e5b3074f50 100644 --- a/tectonic/dpx-pdfcolor.h +++ b/tectonic/dpx-pdfcolor.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -53,8 +53,6 @@ typedef struct double values[PDF_COLOR_COMPONENT_MAX]; } pdf_color; -void pdf_color_set_verbose (int level); - int pdf_color_rgbcolor (pdf_color *color, double r, double g, double b); int pdf_color_cmykcolor (pdf_color *color, diff --git a/tectonic/dpx-pdfdev.c b/tectonic/dpx-pdfdev.c index d3ae62313c..18c07ad1ed 100644 --- a/tectonic/dpx-pdfdev.c +++ b/tectonic/dpx-pdfdev.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-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -32,6 +32,7 @@ #include "dpx-cff.h" #include "dpx-cff_types.h" #include "dpx-cmap.h" +#include "dpx-dpxconf.h" #include "dpx-dvi.h" #include "dpx-error.h" #include "dpx-fontmap.h" @@ -46,14 +47,6 @@ #include "dpx-pdfximage.h" #include "dpx-type0.h" -static int verbose = 0; - -void -pdf_dev_set_verbose (int level) -{ - verbose = level; -} - /* Not working yet... */ double pdf_dev_scale (void) @@ -492,8 +485,6 @@ struct dev_font { int ucs_plane; int is_unicode; - - cff_charsets *cff_charsets; }; static struct dev_font *dev_fonts = NULL; @@ -934,26 +925,8 @@ handle_multibyte_string (struct dev_font *font, p = *str_ptr; length = *str_len; - if (ctype == -1 && font->cff_charsets) { /* freetype glyph indexes */ - /* Convert freetype glyph indexes to CID. */ - const unsigned char *inbuf = p; - unsigned char *outbuf = sbuf0; - for (i = 0; i < length; i += 2) { - unsigned int gid; - gid = *inbuf++ << 8; - gid += *inbuf++; - - gid = cff_charsets_lookup_cid(font->cff_charsets, gid); - - *outbuf++ = gid >> 8; - *outbuf++ = gid & 0xff; - } - - p = sbuf0; - length = outbuf - sbuf0; - } /* _FIXME_ */ - else if (font->is_unicode) { /* UCS-4 */ + if (font->is_unicode) { /* UCS-4 */ if (ctype == 1) { if (length * 4 >= FORMAT_BUF_SIZE) { dpx_warning("Too long string..."); @@ -1016,7 +989,7 @@ handle_multibyte_string (struct dev_font *font, * encoding. * TODO: A character decomposed to multiple characters. */ - if (ctype != -1 && font->enc_id >= 0) { + if (font->enc_id >= 0) { const unsigned char *inbuf; unsigned char *outbuf; size_t inbytesleft, outbytesleft; @@ -1282,7 +1255,6 @@ pdf_close_device (void) pdf_release_obj(dev_fonts[i].resource); dev_fonts[i].tex_name = NULL; dev_fonts[i].resource = NULL; - dev_fonts[i].cff_charsets = NULL; } free(dev_fonts); } @@ -1440,16 +1412,13 @@ pdf_dev_locate_font (const char *font_name, spt_t ptsize) /* New font */ mrec = pdf_lookup_fontmap_record(font_name); - if (verbose > 1) + if (dpx_conf.verbose_level > 1) print_fontmap(font_name, mrec); font->font_id = pdf_font_findresource(font_name, ptsize * dev_unit.dvi2pts, mrec); if (font->font_id < 0) return -1; - if (mrec) - font->cff_charsets = mrec->opt.cff_charsets; - /* We found device font here. */ if (i < num_dev_fonts) { font->real_font_index = i; diff --git a/tectonic/dpx-pdfdev.h b/tectonic/dpx-pdfdev.h index 9e26353e41..3fc3785514 100644 --- a/tectonic/dpx-pdfdev.h +++ b/tectonic/dpx-pdfdev.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-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -76,8 +76,6 @@ typedef struct #define INFO_DO_HIDE (1 << 4) void transform_info_clear (transform_info *info); - -void pdf_dev_set_verbose (int level); void pdf_dev_reset_global_state (void); /* Not in spt_t. */ diff --git a/tectonic/dpx-pdfdoc.c b/tectonic/dpx-pdfdoc.c index 0ce6832f10..1356c5d380 100644 --- a/tectonic/dpx-pdfdoc.c +++ b/tectonic/dpx-pdfdoc.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2008-2017 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, + Copyright (C) 2008-2019 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -36,6 +36,7 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dpxutil.h" #include "dpx-dvipdfmx.h" #include "dpx-error.h" @@ -58,8 +59,6 @@ #define PDFDOC_ARTICLE_ALLOC_SIZE 16 #define PDFDOC_BEAD_ALLOC_SIZE 16 -static int verbose = 0; - static char manual_thumb_enabled = 0; static char *thumb_basename = NULL; @@ -103,15 +102,6 @@ read_thumbnail (const char *thumb_filename) return image_ref; } -void -pdf_doc_set_verbose (int level) -{ - verbose = level; - pdf_font_set_verbose(level); - pdf_color_set_verbose(level); - pdf_ximage_set_verbose(level); -} - typedef struct pdf_form { char *ident; @@ -418,23 +408,6 @@ pdf_doc_set_eop_content (const char *content, unsigned int length) return; } -/* - * Docinfo - */ -static int -asn_date (char *date_string, time_t date) -{ - int32_t tz_offset = 0; - struct tm *bd_time = gmtime(&date); - sprintf(date_string, "D:%04d%02d%02d%02d%02d%02d%c%02d'%02d'", - bd_time->tm_year + 1900, bd_time->tm_mon + 1, bd_time->tm_mday, - bd_time->tm_hour, bd_time->tm_min, bd_time->tm_sec, - (tz_offset > 0) ? '+' : '-', abs(tz_offset) / 3600, - (abs(tz_offset) / 60) % 60); - - return strlen(date_string); -} - static void pdf_doc_init_docinfo (pdf_doc *p) { @@ -495,7 +468,7 @@ pdf_doc_close_docinfo (pdf_doc *p) if (!pdf_lookup_dict(docinfo, "CreationDate") && source_date_epoch) { char now[80]; - asn_date(now, source_date_epoch); + dpx_util_format_asn_date(now, 1); pdf_add_dict(docinfo, pdf_new_name ("CreationDate"), pdf_new_string(now, strlen(now))); @@ -536,6 +509,9 @@ pdf_doc_get_page_resources (pdf_doc *p, const char *category) if (!resources) { resources = pdf_new_dict(); pdf_add_dict(res_dict, pdf_new_name(category), resources); + } else if (pdf_obj_typeof(resources) == PDF_INDIRECT) { + resources = pdf_deref_obj(resources); /* FIXME: deref_obj increment link count */ + pdf_release_obj(resources); /* FIXME: just to decrement link count */ } return resources; @@ -549,10 +525,6 @@ pdf_doc_add_page_resource (const char *category, pdf_obj *resources; pdf_obj *duplicate; - if (!PDF_OBJ_INDIRECTTYPE(resource_ref)) { - dpx_warning("Passed non indirect reference..."); - resource_ref = pdf_ref_obj(resource_ref); /* leak */ - } resources = pdf_doc_get_page_resources(p, category); duplicate = pdf_lookup_dict(resources, resource_name); if (duplicate && pdf_compare_reference(duplicate, resource_ref)) { @@ -858,6 +830,184 @@ pdf_doc_get_page_count (pdf_file *pf) return count; } +static int +set_bounding_box (pdf_rect *bbox, enum pdf_page_boundary opt_bbox, + pdf_obj *media_box, pdf_obj *crop_box, + pdf_obj *art_box, pdf_obj *trim_box, pdf_obj *bleed_box) +{ + pdf_obj *box = NULL; + + if (!media_box) { + dpx_warning("MediaBox not found in included PDF..."); + return -1; + } +#define VALIDATE_BOX(o) if ((o)) {\ + if (!PDF_OBJ_ARRAYTYPE((o)) || pdf_array_length((o)) != 4) \ + return -1;\ +} + VALIDATE_BOX(media_box); + VALIDATE_BOX(crop_box); + VALIDATE_BOX(art_box); + VALIDATE_BOX(trim_box); + VALIDATE_BOX(bleed_box); + + if (opt_bbox == pdf_page_boundary__auto) { + if (crop_box) + box = pdf_link_obj(crop_box); + else if (art_box) + box = pdf_link_obj(art_box); + else if (trim_box) + box = pdf_link_obj(trim_box); + else if (bleed_box) + box = pdf_link_obj(bleed_box); + else { + box = pdf_link_obj(media_box); + } + } else { + if (!crop_box) { + crop_box = pdf_link_obj(media_box); + } + if (!art_box) { + art_box = pdf_link_obj(crop_box); + } + if (!trim_box) { + trim_box = pdf_link_obj(crop_box); + } + if (!bleed_box) { + bleed_box = pdf_link_obj(crop_box); + } + /* At this point all boxes must be defined. */ + switch (opt_bbox) { + case pdf_page_boundary_cropbox: + box = pdf_link_obj(crop_box); + break; + case pdf_page_boundary_mediabox: + box = pdf_link_obj(media_box); + break; + case pdf_page_boundary_artbox: + box = pdf_link_obj(art_box); + break; + case pdf_page_boundary_trimbox: + box = pdf_link_obj(trim_box); + break; + case pdf_page_boundary_bleedbox: + box = pdf_link_obj(bleed_box); + break; + default: + box = pdf_link_obj(crop_box); + break; + } + } + + if (!box) { + /* Impossible */ + dpx_warning("No appropriate page boudary box found???"); + return -1; + } else { + int i; + + for (i = 4; i--; ) { + double x; + pdf_obj *tmp = pdf_deref_obj(pdf_get_array(box, i)); + if (!PDF_OBJ_NUMBERTYPE(tmp)) { + pdf_release_obj(tmp); + pdf_release_obj(box); + return -1; + } + x = pdf_number_value(tmp); + switch (i) { + case 0: bbox->llx = x; break; + case 1: bbox->lly = x; break; + case 2: bbox->urx = x; break; + case 3: bbox->ury = x; break; + } + pdf_release_obj(tmp); + } + + /* New scheme only for XDV files */ + if (dpx_conf.compat_mode == dpx_mode_xdv_mode || + opt_bbox != pdf_page_boundary__auto) { + for (i = 4; i--; ) { + double x; + pdf_obj *tmp = pdf_deref_obj(pdf_get_array(media_box, i)); + if (!PDF_OBJ_NUMBERTYPE(tmp)) { + pdf_release_obj(tmp); + pdf_release_obj(box); + return -1; + } + x = pdf_number_value(tmp); + switch (i) { + case 0: if (bbox->llx < x) bbox->llx = x; break; + case 1: if (bbox->lly < x) bbox->lly = x; break; + case 2: if (bbox->urx > x) bbox->urx = x; break; + case 3: if (bbox->ury > x) bbox->ury = x; break; + } + pdf_release_obj(tmp); + } + } + } + pdf_release_obj(box); + + return 0; +} + +static int +set_transform_matrix (pdf_tmatrix *matrix, pdf_rect *bbox, pdf_obj *rotate) +{ + double deg; + int rot; + + matrix->a = matrix->d = 1.0; + matrix->b = matrix->c = 0.0; + matrix->e = matrix->f = 0.0; + /* Handle Rotate */ + if (rotate) { + if (!PDF_OBJ_NUMBERTYPE(rotate)) { + return -1; + } else { + deg = pdf_number_value(rotate); + if (deg - (int)deg != 0.0) { + dpx_warning("Invalid value specified for /Rotate: %f", deg); + return -1; + } else if (deg != 0.0) { + rot = (int) deg; + if (rot % 90 != 0.0) { + dpx_warning("Invalid value specified for /Rotate: %f", deg); + } else { + rot = rot % 360; + if (rot < 0) rot += 360; + switch (rot) { + case 90: + matrix->a = matrix->d = 0; + matrix->b = -1; + matrix->c = 1; + matrix->e = bbox->llx - bbox->lly; + matrix->f = bbox->lly + bbox->urx; + break; + case 180: + matrix->a = matrix->d = -1; + matrix->b = matrix->c = 0; + matrix->e = bbox->llx + bbox->urx; + matrix->f = bbox->lly + bbox->ury; + break; + case 270: + matrix->a = matrix->d = 0; + matrix->b = 1; + matrix->c = -1; + matrix->e = bbox->llx + bbox->ury; + matrix->f = bbox->lly - bbox->llx; + break; + default: + dpx_warning("Invalid value specified for /Rotate: %f", deg); + break; + } + } + } + } + } + return 0; +} + /* * From PDFReference15_v6.pdf (p.119 and p.834) * @@ -915,27 +1065,29 @@ pdf_doc_get_page_count (pdf_file *pf) */ pdf_obj * pdf_doc_get_page (pdf_file *pf, - int page_no, int options, /* load options */ + int page_no, enum pdf_page_boundary opt_bbox, /* load options */ pdf_rect *bbox, pdf_tmatrix *matrix, /* returned value */ pdf_obj **resources_p /* returned values */ ) { - pdf_obj *page_tree = NULL; - pdf_obj *resources = NULL, *box = NULL, *rotate = NULL, *medbox = NULL; - pdf_obj *catalog; + pdf_obj *catalog = NULL, *page_tree = NULL; + pdf_obj *resources = NULL, *rotate = NULL; + pdf_obj *art_box = NULL, *trim_box = NULL, *bleed_box = NULL; + pdf_obj *media_box = NULL, *crop_box = NULL; + int error = 0; catalog = pdf_file_get_catalog(pf); page_tree = pdf_deref_obj(pdf_lookup_dict(catalog, "Pages")); if (!PDF_OBJ_DICTTYPE(page_tree)) - goto error; + goto error_exit; { int count; pdf_obj *tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Count")); if (!PDF_OBJ_NUMBERTYPE(tmp)) { pdf_release_obj(tmp); - goto error; + goto error_exit; } count = pdf_number_value(tmp); pdf_release_obj(tmp); @@ -950,42 +1102,35 @@ pdf_doc_get_page (pdf_file *pf, * (Note that these entries can be inherited.) */ { - pdf_obj *art_box = NULL, *trim_box = NULL, *bleed_box = NULL; - pdf_obj *media_box = NULL, *crop_box = NULL, *kids, *tmp; - int depth = PDF_OBJ_MAX_DEPTH; - int page_idx = page_no-1, kids_length = 1, i = 0; + pdf_obj *kids, *tmp; + int depth = PDF_OBJ_MAX_DEPTH; + int page_idx = page_no - 1, kids_length = 1, i = 0; while (--depth && i != kids_length) { if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "MediaBox")))) { pdf_release_obj(media_box); media_box = tmp; } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "CropBox")))) { pdf_release_obj(crop_box); crop_box = tmp; } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "ArtBox")))) { pdf_release_obj(art_box); art_box = tmp; } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "TrimBox")))) { pdf_release_obj(trim_box); trim_box = tmp; } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "BleedBox")))) { pdf_release_obj(bleed_box); bleed_box = tmp; } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Rotate")))) { pdf_release_obj(rotate); rotate = tmp; } - if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Resources")))) { pdf_release_obj(resources); resources = tmp; @@ -996,7 +1141,7 @@ pdf_doc_get_page (pdf_file *pf, break; else if (!PDF_OBJ_ARRAYTYPE(kids)) { pdf_release_obj(kids); - goto error; + goto error_exit; } kids_length = pdf_array_length(kids); @@ -1006,7 +1151,7 @@ pdf_doc_get_page (pdf_file *pf, pdf_release_obj(page_tree); page_tree = pdf_deref_obj(pdf_get_array(kids, i)); if (!PDF_OBJ_DICTTYPE(page_tree)) - goto error; + goto error_exit; tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Count")); if (PDF_OBJ_NUMBERTYPE(tmp)) { @@ -1018,187 +1163,50 @@ pdf_doc_get_page (pdf_file *pf, count = 1; else { pdf_release_obj(tmp); - goto error; + goto error_exit; } - if (page_idx < count) break; - page_idx -= count; } - pdf_release_obj(kids); } - - if (!depth || kids_length == i) { - pdf_release_obj(media_box); - pdf_release_obj(crop_box); - goto error; - } - - /* Nasty BBox selection... */ - if (options == 0 || options == 1) { - if (crop_box) - box = crop_box; - else - if (!(box = media_box) && - !(box = bleed_box) && - !(box = trim_box) && - art_box) { - box = art_box; - } - } else if (options == 2) { - if (media_box) - box = media_box; - else - if (!(box = crop_box) && - !(box = bleed_box) && - !(box = trim_box) && - art_box) { - box = art_box; - } - } else if (options == 3) { - if (art_box) - box = art_box; - else - if (!(box = crop_box) && - !(box = media_box) && - !(box = bleed_box) && - trim_box) { - box = trim_box; - } - } else if (options == 4) { - if (trim_box) - box = trim_box; - else - if (!(box = crop_box) && - !(box = media_box) && - !(box = bleed_box) && - art_box) { - box = art_box; - } - } else if (options == 5) { - if (bleed_box) - box = bleed_box; - else - if (!(box = crop_box) && - !(box = media_box) && - !(box = trim_box) && - art_box) { - box = art_box; - } - } - medbox = media_box; - } - - if (!PDF_OBJ_ARRAYTYPE(box) || pdf_array_length(box) != 4 || - !PDF_OBJ_DICTTYPE(resources)) - goto error; - - { - int i; - - for (i = 4; i--; ) { - double x; - pdf_obj *tmp = pdf_deref_obj(pdf_get_array(box, i)); - if (!PDF_OBJ_NUMBERTYPE(tmp)) { - pdf_release_obj(tmp); - goto error; - } - x = pdf_number_value(tmp); - switch (i) { - case 0: bbox->llx = x; break; - case 1: bbox->lly = x; break; - case 2: bbox->urx = x; break; - case 3: bbox->ury = x; break; - } - pdf_release_obj(tmp); - } - - /* New scheme only for XDV files */ - if (medbox && (is_xdv || options)) { - for (i = 4; i--; ) { - double x; - pdf_obj *tmp = pdf_deref_obj(pdf_get_array(medbox, i)); - if (!PDF_OBJ_NUMBERTYPE(tmp)) { - pdf_release_obj(tmp); - goto error; - } - x = pdf_number_value(tmp); - switch (i) { - case 0: if (bbox->llx < x) bbox->llx = x; break; - case 1: if (bbox->lly < x) bbox->lly = x; break; - case 2: if (bbox->urx > x) bbox->urx = x; break; - case 3: if (bbox->ury > x) bbox->ury = x; break; - } - pdf_release_obj(tmp); - } - } - } - - pdf_release_obj(box); - - matrix->a = matrix->d = 1.0; - matrix->b = matrix->c = 0.0; - matrix->e = matrix->f = 0.0; - if (PDF_OBJ_NUMBERTYPE(rotate)) { - double deg = pdf_number_value(rotate); - if (deg - (int)deg != 0.0) - dpx_warning("Invalid value specified for /Rotate: %f", deg); - else if (deg != 0.0) { - int rot = (int) deg; - if (rot % 90 != 0.0) { - dpx_warning("Invalid value specified for /Rotate: %f", deg); - } else { - rot = rot % 360; - if (rot < 0) rot += 360; - switch (rot) { - case 90: - matrix->a = matrix->d = 0; - matrix->b = -1; - matrix->c = 1; - matrix->e = bbox->llx - bbox->lly; - matrix->f = bbox->lly + bbox->urx; - break; - case 180: - matrix->a = matrix->d = -1; - matrix->b = matrix->c = 0; - matrix->e = bbox->llx + bbox->urx; - matrix->f = bbox->lly + bbox->ury; - break; - case 270: - matrix->a = matrix->d = 0; - matrix->b = 1; - matrix->c = -1; - matrix->e = bbox->llx + bbox->ury; - matrix->f = bbox->lly - bbox->llx; - break; - } - } - } - pdf_release_obj(rotate); - rotate = NULL; - } else if (rotate) { - goto error; + if (!depth || kids_length == i) + goto error_exit; } + if (!PDF_OBJ_DICTTYPE(resources)) + goto error_exit; if (resources_p) - *resources_p = resources; - else { - pdf_release_obj(resources); - } + *resources_p = pdf_link_obj(resources); - return page_tree; + /* Select page boundary box */ + error = set_bounding_box(bbox, opt_bbox, media_box, crop_box, art_box, trim_box, bleed_box); + if (error) + goto error_exit; + /* Set transformation matrix */ + error = set_transform_matrix(matrix, bbox, rotate); + if (error) + goto error_exit; - error: - dpx_warning("Cannot parse document. Broken PDF file?"); + goto clean_exit; /* Success */ + + error_exit: + dpx_warning("Error found in including PDF image."); error_silent: - pdf_release_obj(box); + pdf_release_obj(page_tree); + page_tree = NULL; + +clean_exit: + pdf_release_obj(crop_box); + pdf_release_obj(bleed_box); + pdf_release_obj(trim_box); + pdf_release_obj(art_box); + pdf_release_obj(media_box); pdf_release_obj(rotate); pdf_release_obj(resources); - pdf_release_obj(page_tree); - return NULL; + return page_tree; } #ifndef BOOKMARKS_OPEN_DEFAULT @@ -1674,7 +1682,7 @@ pdf_doc_close_names (pdf_doc *p) else { name_tree = pdf_names_create_tree(data, &count, &pdoc.gotos); - if (verbose && count < data->count) + if (dpx_conf.verbose_level > 0 && count < data->count) dpx_message("\nRemoved %d unused PDF destinations\n", data->count-count); if (count < pdoc.gotos.count) @@ -1728,7 +1736,6 @@ pdf_doc_add_annot (unsigned page_no, const pdf_rect *rect, pdf_doc *p = &pdoc; pdf_page *page; pdf_obj *rect_array; - double annot_grow = p->opt.annot_grow; double xpos, ypos; pdf_rect annbox; @@ -1760,10 +1767,10 @@ pdf_doc_add_annot (unsigned page_no, const pdf_rect *rect, } rect_array = pdf_new_array(); - pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.llx - annot_grow, 0.001))); - pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.lly - annot_grow, 0.001))); - pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.urx + annot_grow, 0.001))); - pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.ury + annot_grow, 0.001))); + pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.llx, 0.001))); + pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.lly, 0.001))); + pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.urx, 0.001))); + pdf_add_array(rect_array, pdf_new_number(ROUND(annbox.ury, 0.001))); pdf_add_dict (annot_dict, pdf_new_name("Rect"), rect_array); pdf_add_array(page->annots, pdf_ref_obj(annot_dict)); @@ -2432,23 +2439,24 @@ pdf_doc_add_page_content (const char *buffer, unsigned int length) return; } -static char *doccreator = NULL; /* Ugh */ - void pdf_open_document (const char *filename, - bool enable_encrypt, bool enable_object_stream, - double media_width, double media_height, - double annot_grow_amount, int bookmark_open_depth, - int check_gotos) + const char *creator, const unsigned char *id1, const unsigned char *id2, + struct pdf_setting settings) { pdf_doc *p = &pdoc; - pdf_out_init(filename, enable_encrypt, enable_object_stream); + if (settings.enable_encrypt) + pdf_init_encryption(settings.encrypt, id1); + + pdf_out_init(filename, settings.enable_encrypt, + settings.object.enable_objstm, settings.object.enable_predictor); + pdf_files_init(); pdf_doc_init_catalog(p); - p->opt.annot_grow = annot_grow_amount; - p->opt.outline_open_depth = bookmark_open_depth; + p->opt.annot_grow = settings.annot_grow_amount; + p->opt.outline_open_depth = settings.outline_open_depth; pdf_init_resources(); pdf_init_colors(); @@ -2457,26 +2465,31 @@ pdf_open_document (const char *filename, pdf_init_images(); pdf_doc_init_docinfo(p); - if (doccreator) { + if (creator) { pdf_add_dict(p->info, pdf_new_name("Creator"), - pdf_new_string(doccreator, strlen(doccreator))); - doccreator = mfree(doccreator); + pdf_new_string(creator, strlen(creator))); } - pdf_doc_init_bookmarks(p, bookmark_open_depth); + pdf_doc_init_bookmarks(p, settings.outline_open_depth); pdf_doc_init_articles (p); - pdf_doc_init_names (p, check_gotos); - pdf_doc_init_page_tree(p, media_width, media_height); + pdf_doc_init_names (p, settings.check_gotos); + pdf_doc_init_page_tree(p, settings.media_width, settings.media_height); pdf_doc_set_bgcolor(NULL); - if (enable_encrypt) { + if (settings.enable_encrypt) { pdf_obj *encrypt = pdf_encrypt_obj(); pdf_set_encrypt(encrypt); pdf_release_obj(encrypt); } - pdf_set_id(pdf_enc_id_array()); + 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); + } /* Create a default name for thumbnail image files */ if (manual_thumb_enabled) { @@ -2494,26 +2507,19 @@ pdf_open_document (const char *filename, p->pending_forms = NULL; - return; -} - -void -pdf_doc_set_creator (const char *creator) -{ - if (!creator || - creator[0] == '\0') - return; + pdf_init_device(settings.device.dvi2pts, settings.device.precision, + settings.device.ignore_colors); - doccreator = NEW(strlen(creator)+1, char); - strcpy(doccreator, creator); /* Ugh */ + return; } - void pdf_close_document (void) { pdf_doc *p = &pdoc; + pdf_close_device(); + /* * Following things were kept around so user can add dictionary items. */ @@ -2531,6 +2537,7 @@ pdf_close_document (void) pdf_close_resources(); /* Should be at last. */ + pdf_files_close(); pdf_out_flush(); free(thumb_basename); @@ -2744,13 +2751,22 @@ pdf_doc_end_annot (void) void pdf_doc_break_annot (void) { + pdf_doc *p = &pdoc; + double g = p->opt.annot_grow; + if (breaking_state.dirty) { pdf_obj *annot_dict; + pdf_rect rect; /* Copy dict */ annot_dict = pdf_new_dict(); pdf_merge_dict(annot_dict, breaking_state.annot_dict); - pdf_doc_add_annot(pdf_doc_current_page_number(), &(breaking_state.rect), + rect = breaking_state.rect; + rect.llx -= g; + rect.lly -= g; + rect.urx += g; + rect.ury += g; + pdf_doc_add_annot(pdf_doc_current_page_number(), &rect, annot_dict, !breaking_state.broken); pdf_release_obj(annot_dict); diff --git a/tectonic/dpx-pdfdoc.h b/tectonic/dpx-pdfdoc.h index 61ee5253fa..cd7c9888c6 100644 --- a/tectonic/dpx-pdfdoc.h +++ b/tectonic/dpx-pdfdoc.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -30,18 +30,54 @@ #include "dpx-pdfobj.h" #include "dpx-pdfdev.h" -#define PDF_DOC_GRABBING_NEST_MAX 4 +enum pdf_page_boundary +{ + pdf_page_boundary__auto = 0, + pdf_page_boundary_mediabox, + pdf_page_boundary_cropbox, + pdf_page_boundary_artbox, + pdf_page_boundary_trimbox, + pdf_page_boundary_bleedbox +}; -void pdf_doc_set_verbose (int level); +#define PDF_DOC_GRABBING_NEST_MAX 4 -void pdf_open_document (const char *filename, - bool enable_encrypt, - bool enable_object_stream, - double media_width, double media_height, - double annot_grow_amount, - int bookmark_open_depth, - int check_gotos); -void pdf_close_document (void); +struct pdf_dev_setting { + double dvi2pts; /* conversion unit */ + int precision; /* number of decimal digits kept */ + int ignore_colors; /* 1 for black or white */ +}; + +struct pdf_enc_setting { + int key_size; + uint32_t permission; + const char *uplain, *oplain; /* password */ + int use_aes; + int encrypt_metadata; +}; + +struct pdf_obj_setting { + int enable_objstm; + int enable_predictor; +}; + +struct pdf_setting +{ + double media_width, media_height; + double annot_grow_amount; + int outline_open_depth; + int check_gotos; + int enable_encrypt; + struct pdf_enc_setting encrypt; + struct pdf_dev_setting device; + struct pdf_obj_setting object; +}; + +void pdf_open_document (const char *filename, + const char *creator, + const unsigned char *id1, const unsigned char *id2, + struct pdf_setting settings); +void pdf_close_document (void); /* PDF document metadata */ @@ -51,23 +87,23 @@ void pdf_doc_set_creator (const char *creator); /* They just return PDF dictionary object. * Callers are completely responsible for doing right thing... */ -pdf_obj *pdf_doc_get_dictionary (const char *category); -pdf_obj *pdf_doc_get_reference (const char *category); +pdf_obj *pdf_doc_get_dictionary(const char *category); +pdf_obj *pdf_doc_get_reference(const char *category); #define pdf_doc_page_tree() pdf_doc_get_dictionary("Pages") -#define pdf_doc_catalog() pdf_doc_get_dictionary("Catalog") -#define pdf_doc_docinfo() pdf_doc_get_dictionary("Info") -#define pdf_doc_names() pdf_doc_get_dictionary("Names") +#define pdf_doc_catalog() pdf_doc_get_dictionary("Catalog") +#define pdf_doc_docinfo() pdf_doc_get_dictionary("Info") +#define pdf_doc_names() pdf_doc_get_dictionary("Names") #define pdf_doc_this_page() pdf_doc_get_dictionary("@THISPAGE") -int pdf_doc_get_page_count (pdf_file *pf); -pdf_obj *pdf_doc_get_page (pdf_file *pf, int page_no, int options, +int pdf_doc_get_page_count (pdf_file *pf); +pdf_obj *pdf_doc_get_page (pdf_file *pf, int page_no, enum pdf_page_boundary opt_bbox, pdf_rect *bbox, pdf_tmatrix *matrix, pdf_obj **resources_p); -int pdf_doc_current_page_number (void); -pdf_obj *pdf_doc_current_page_resources (void); +int pdf_doc_current_page_number(void); +pdf_obj *pdf_doc_current_page_resources(void); -pdf_obj *pdf_doc_ref_page (unsigned page_no); +pdf_obj *pdf_doc_ref_page(unsigned page_no); #define pdf_doc_this_page_ref() pdf_doc_get_reference("@THISPAGE") #define pdf_doc_next_page_ref() pdf_doc_get_reference("@NEXTPAGE") #define pdf_doc_prev_page_ref() pdf_doc_get_reference("@PREVPAGE") diff --git a/tectonic/dpx-pdfdraw.c b/tectonic/dpx-pdfdraw.c index 87d025d335..839272ea3f 100644 --- a/tectonic/dpx-pdfdraw.c +++ b/tectonic/dpx-pdfdraw.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -28,6 +28,7 @@ #include #include +#include "dpx-dpxconf.h" #include "dpx-dpxutil.h" #include "dpx-error.h" #include "dpx-mem.h" diff --git a/tectonic/dpx-pdfencoding.c b/tectonic/dpx-pdfencoding.c index b0ee6c2473..3785716cff 100644 --- a/tectonic/dpx-pdfencoding.c +++ b/tectonic/dpx-pdfencoding.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2008-2016 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, + Copyright (C) 2008-2019 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -30,6 +30,7 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" #include "dpx-error.h" #include "dpx-mem.h" @@ -40,18 +41,10 @@ static bool is_similar_charset (char **encoding, const char **encoding2); static pdf_obj *make_encoding_differences (char **encoding, char **baseenc, const char *is_used); -static unsigned char verbose = 0; - static const char *MacRomanEncoding[256]; static const char *MacExpertEncoding[256]; static const char *WinAnsiEncoding[256]; -void -pdf_encoding_set_verbose (int level) -{ - verbose = level; -} - /* * ident: File name, e.g., 8a.enc. * name: Name of encoding, StandardEncoding, TeXBase1Encoding, ... @@ -268,7 +261,7 @@ load_encoding_file (const char *filename) if (!filename) return -1; - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message("(Encoding:%s", filename); handle = dpx_tt_open(filename, ".enc", TTIF_ENC); @@ -314,14 +307,14 @@ load_encoding_file (const char *filename) filename, enc_vec, NULL, 0); if (enc_name) { - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("[%s]", pdf_name_value(enc_name)); pdf_release_obj(enc_name); } pdf_release_obj(encoding_array); - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message(")"); return enc_id; @@ -447,7 +440,7 @@ void pdf_encoding_complete (void) * we do use a base encodings for PDF versions >= 1.3. */ int with_base = !(encoding->flags & FLAG_USED_BY_TYPE3) - || pdf_get_version() >= 4; + || pdf_check_version(1, 4) >= 0; assert(!encoding->resource); encoding->resource = create_encoding_resource(encoding, with_base ? encoding->baseenc : NULL); @@ -615,6 +608,10 @@ pdf_encoding_get_tounicode (int encoding_id) * Note: The PDF 1.4 reference is not consistent: Section 5.9 describes * the Unicode mapping of PDF 1.3 and Section 9.7.2 (in the context of * Tagged PDF) the one of PDF 1.5. + * + * CHANGED: 20180906 + * Always create ToUnicode CMap unless there is missing mapping. + * Change made on rev.7557 broke ToUnicode CMap support. Now reverted. */ pdf_obj * pdf_create_ToUnicode_CMap (const char *enc_name, @@ -622,12 +619,15 @@ pdf_create_ToUnicode_CMap (const char *enc_name, { pdf_obj *stream; CMap *cmap; - int code, all_predef; + int code, count, total_fail; char *cmap_name; unsigned char *p, *endptr; assert(enc_name && enc_vec); + if (!is_used) + return NULL; + cmap_name = NEW(strlen(enc_name)+strlen("-UTF16")+1, char); sprintf(cmap_name, "%s-UTF16", enc_name); @@ -640,32 +640,33 @@ pdf_create_ToUnicode_CMap (const char *enc_name, CMap_add_codespacerange(cmap, range_min, range_max, 1); - all_predef = 1; + count = 0; + total_fail = 0; for (code = 0; code <= 0xff; code++) { if (is_used && !is_used[code]) continue; if (enc_vec[code]) { - int32_t len; + size_t len; int fail_count = 0; - agl_name *agln = agl_lookup_list(enc_vec[code]); - /* Adobe glyph naming conventions are not used by viewers, - * hence even ligatures (e.g, "f_i") must be explicitly defined - */ - if (pdf_get_version() < 5 || !agln || !agln->is_predef) { - wbuf[0] = (code & 0xff); - p = wbuf + 1; - endptr = wbuf + WBUF_SIZE; - len = agl_sput_UTF16BE(enc_vec[code], &p, endptr, &fail_count); - if (len >= 1 && !fail_count) { - CMap_add_bfchar(cmap, wbuf, 1, wbuf + 1, len); - all_predef &= agln && agln->is_predef; - } - } + wbuf[0] = (code & 0xff); + p = wbuf + 1; + endptr = wbuf + WBUF_SIZE; + len = agl_sput_UTF16BE(enc_vec[code], &p, endptr, &fail_count); + if (len < 1 && fail_count > 0) { + total_fail++; + } else { + CMap_add_bfchar(cmap, wbuf, 1, wbuf + 1, len); + count++; + } } } - stream = all_predef ? NULL : CMap_create_stream(cmap); + if (total_fail > 0) { + if (dpx_conf.verbose_level > 0) + dpx_warning("Glyphs with no Unicode mapping found. Removing ToUnicode CMap."); + } + stream = (count == 0 || total_fail > 0) ? NULL : CMap_create_stream(cmap); CMap_release(cmap); free(cmap_name); @@ -697,7 +698,7 @@ pdf_load_ToUnicode_stream (const char *ident) if (CMap_parse(cmap, handle) < 0) { dpx_warning("Reading CMap file \"%s\" failed.", ident); } else { - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message("(CMap:%s)", ident); stream = CMap_create_stream(cmap); diff --git a/tectonic/dpx-pdfencoding.h b/tectonic/dpx-pdfencoding.h index b987e98b32..204e6002b4 100644 --- a/tectonic/dpx-pdfencoding.h +++ b/tectonic/dpx-pdfencoding.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -27,8 +27,6 @@ #include "dpx-pdfobj.h" -void pdf_encoding_set_verbose (int level); - void pdf_init_encodings (void); void pdf_close_encodings (void); diff --git a/tectonic/dpx-pdfencrypt.c b/tectonic/dpx-pdfencrypt.c index c36c71cecf..e108fe2e5c 100644 --- a/tectonic/dpx-pdfencrypt.c +++ b/tectonic/dpx-pdfencrypt.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -26,7 +26,9 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dpxcrypt.h" +#include "dpx-dpxutil.h" #include "dpx-dvipdfmx.h" #include "dpx-error.h" #include "dpx-mem.h" @@ -42,6 +44,9 @@ * 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 @@ -64,6 +69,7 @@ static struct pdf_sec { struct { int use_aes; int encrypt_metadata; + int need_adobe_extension; } setting; struct { @@ -79,57 +85,28 @@ static const unsigned char padding_bytes[32] = { 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a }; -static unsigned char verbose = 0; - -void pdf_enc_set_verbose (int level) -{ - verbose = level; -} - -static void -pdf_enc_init (int use_aes, int encrypt_metadata) +int +pdf_init_encryption (struct pdf_enc_setting settings, const unsigned char *trailer_id) { + time_t current_time; struct pdf_sec *p = &sec_data; - srand(source_date_epoch); /* For AES IV */ - p->setting.use_aes = use_aes; - p->setting.encrypt_metadata = encrypt_metadata; -} - -#define PRODUCER \ -"%s-%s, Copyright 2002-2015 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata" - -void -pdf_enc_compute_id_string (const char *dviname, const char *pdfname) -{ - struct pdf_sec *p = &sec_data; - char *date_string, *producer; - struct tm *bd_time; - MD5_CONTEXT md5; - - /* FIXME: This should be placed in main() or somewhere. */ - pdf_enc_init(1, 1); - - MD5_init(&md5); - - date_string = NEW(15, char); - bd_time = gmtime(&source_date_epoch); - sprintf(date_string, "%04d%02d%02d%02d%02d%02d", - bd_time->tm_year + 1900, bd_time->tm_mon + 1, bd_time->tm_mday, - bd_time->tm_hour, bd_time->tm_min, bd_time->tm_sec); - MD5_write(&md5, (unsigned char *)date_string, strlen(date_string)); - free(date_string); - - producer = NEW(strlen(PRODUCER)+strlen(DVIPDFMX_PROG_NAME)+strlen(DPX_VERSION), char); - sprintf(producer, PRODUCER, DVIPDFMX_PROG_NAME, DPX_VERSION); - MD5_write(&md5, (unsigned char *)producer, strlen(producer)); - free(producer); - - if (dviname) - MD5_write(&md5, (const unsigned char *) dviname, strlen(dviname)); - if (pdfname) - MD5_write(&md5, (const unsigned char *) pdfname, strlen(pdfname)); - MD5_final(p->ID, &md5); + if (trailer_id) { + memcpy(p->ID, trailer_id, 16); + } else { + memset(p->ID, 0, 16); + } + 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; + + pdf_enc_set_passwd(settings.key_size, settings.permission, + settings.oplain, settings.uplain); + return 0; } static void @@ -177,16 +154,16 @@ compute_owner_password (struct pdf_sec *p, ARC4(&arc4, 32, padded, tmp1); if (p->R >= 3) { - for (i = 1; i <= 19; i++) { + for (i = 1; i <= 19; i++) { memcpy(tmp2, tmp1, 32); for (j = 0; j < p->key_size; j++) key[j] = hash[j] ^ i; ARC4_set_key(&arc4, p->key_size, key); ARC4(&arc4, 32, tmp2, tmp1); + } } - } + memcpy(p->O, tmp1, 32); } - memcpy(p->O, hash, 32); } static void @@ -281,17 +258,20 @@ compute_hash_V5 (unsigned char *hash, const unsigned char *salt, const unsigned char *user_key, int R /* revision */) { - SHA256_CONTEXT sha; unsigned char K[64]; size_t K_len; int nround; - SHA256_init (&sha); - SHA256_write(&sha, (const unsigned char *)passwd, strlen(passwd)); - SHA256_write(&sha, salt, 8); - if (user_key) - SHA256_write(&sha, user_key, 48); - SHA256_final(hash, &sha); + { + SHA256_CONTEXT sha; + + SHA256_init (&sha); + SHA256_write(&sha, (const unsigned char *)passwd, strlen(passwd)); + SHA256_write(&sha, salt, 8); + if (user_key) + SHA256_write(&sha, user_key, 48); + SHA256_final(hash, &sha); + } assert( R ==5 || R == 6 ); @@ -415,17 +395,21 @@ compute_user_password_V5 (struct pdf_sec *p, const char *uplain) static void check_version (struct pdf_sec *p, int version) { - if (p->V > 2 && version < 4) { + if (p->V > 2 && version < 14) { dpx_warning("Current encryption setting requires PDF version >= 1.4."); p->V = 1; p->key_size = 5; - } else if (p->V == 4 && version < 5) { + } else if (p->V == 4 && version < 15) { dpx_warning("Current encryption setting requires PDF version >= 1.5."); p->V = 2; - } else if (p->V ==5 && version < 7) { + } else if (p->V ==5 && version < 17) { dpx_warning("Current encryption setting requires PDF version >= 1.7" \ " (plus Adobe Extension Level 3)."); p->V = 4; + p->key_size = 16; + } + if (p->V == 5 && version < 20) { + p->setting.need_adobe_extension = 1; } } @@ -499,16 +483,14 @@ preproc_password (const char *passwd, char *outbuf, int V) return error; } -void +static void pdf_enc_set_passwd (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; - - assert(oplain); - assert(uplain); + char empty_passwd[1] = "\0"; version = pdf_get_version(); @@ -527,6 +509,9 @@ pdf_enc_set_passwd (unsigned int bits, unsigned int perm, check_version(p, version); p->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) { case 1: p->R = (p->P < 0x100L) ? 2 : 3; @@ -553,11 +538,19 @@ pdf_enc_set_passwd (unsigned int bits, unsigned int perm, memset(opasswd, 0, 128); memset(upasswd, 0, 128); /* Password must be preprocessed. */ - if (preproc_password(oplain, opasswd, p->V) < 0) - dpx_warning("Invaid UTF-8 string for password."); + if (oplain) { + if (preproc_password(oplain, opasswd, p->V) < 0) + dpx_warning("Invaid UTF-8 string for password."); + } else { + preproc_password(empty_passwd, opasswd, p->V); + } - if (preproc_password(uplain, upasswd, p->V) < 0) - dpx_warning("Invalid UTF-8 string for passowrd."); + if (uplain) { + if (preproc_password(uplain, upasswd, p->V) < 0) + dpx_warning("Invalid UTF-8 string for passowrd."); + } else { + preproc_password(empty_passwd, upasswd, p->V); + } if (p->R >= 3) p->P |= 0xFFFFF000U; @@ -715,7 +708,7 @@ pdf_encrypt_obj (void) } #ifdef USE_ADOBE_EXTENSION - if (p->R > 5) { + 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(); @@ -731,17 +724,6 @@ pdf_encrypt_obj (void) return doc_encrypt; } -pdf_obj *pdf_enc_id_array (void) -{ - struct pdf_sec *p = &sec_data; - pdf_obj *id = pdf_new_array(); - - pdf_add_array(id, pdf_new_string(p->ID, 16)); - pdf_add_array(id, pdf_new_string(p->ID, 16)); - - return id; -} - void pdf_enc_set_label (unsigned label) { struct pdf_sec *p = &sec_data; diff --git a/tectonic/dpx-pdfencrypt.h b/tectonic/dpx-pdfencrypt.h index d07cf7da25..65c1f76a69 100644 --- a/tectonic/dpx-pdfencrypt.h +++ b/tectonic/dpx-pdfencrypt.h @@ -2,7 +2,7 @@ This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -27,17 +27,14 @@ #include +#include "dpx-pdfdoc.h" #include "dpx-pdfobj.h" #define MAX_PWD_LEN 127 -void pdf_enc_set_verbose (int level); -pdf_obj *pdf_enc_id_array (void); -void pdf_enc_compute_id_string (const char *dviname, const char *pdfname); +int pdf_init_encryption(struct pdf_enc_setting, const unsigned char *trailer_id); void pdf_enc_set_label (unsigned label); void pdf_enc_set_generation (unsigned generation); -void pdf_enc_set_passwd (unsigned int size, unsigned int perm, - const char *owner, const char *user); void pdf_encrypt_data (const unsigned char *plain, size_t plain_len, unsigned char **cipher, size_t *cipher_len); pdf_obj *pdf_encrypt_obj (void); diff --git a/tectonic/dpx-pdffont.c b/tectonic/dpx-pdffont.c index 02c00429ac..19e003c84b 100644 --- a/tectonic/dpx-pdffont.c +++ b/tectonic/dpx-pdffont.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2008-2017 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, + Copyright (C) 2008-2018 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -33,13 +33,13 @@ #include #include #include -#include #include "core-bridge.h" #include "dpx-agl.h" #include "dpx-cid.h" #include "dpx-cidtype0.h" #include "dpx-cmap.h" +#include "dpx-dpxconf.h" #include "dpx-error.h" #include "dpx-mem.h" #include "dpx-pdfencoding.h" @@ -52,28 +52,8 @@ #include "dpx-type1.h" #include "dpx-type1c.h" -static int __verbose = 0; - #define MREC_HAS_TOUNICODE(m) ((m) && (m)->opt.tounicode) -void -pdf_font_set_verbose (int level) -{ - __verbose = level; - CMap_set_verbose(level); - Type0Font_set_verbose(level); - CIDFont_set_verbose(level); - pdf_encoding_set_verbose(level); - agl_set_verbose(level); - otf_cmap_set_verbose(level); -} - -int -pdf_font_get_verbose (void) -{ - return __verbose; -} - void pdf_font_set_dpi (int font_dpi) { @@ -436,7 +416,7 @@ try_load_ToUnicode_CMap (pdf_font *font) pdf_add_dict(fontdict, pdf_new_name("ToUnicode"), pdf_ref_obj (tounicode)); /* _FIXME_ */ - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message("pdf_font>> ToUnicode CMap \"%s\" attached to font id=\"%s\".\n", cmap_name, font->map_name); } @@ -457,19 +437,19 @@ pdf_close_fonts (void) font = GET_FONT(font_id); - if (__verbose) { + if (dpx_conf.verbose_level > 0) { if (font->subtype != PDF_FONT_FONTTYPE_TYPE0) { dpx_message("(%s", pdf_font_get_ident(font)); - if (__verbose > 2 && + if (dpx_conf.verbose_level > 2 && !pdf_font_get_flag(font, PDF_FONT_FLAG_NOEMBED)) { dpx_message("[%s+%s]", pdf_font_get_uniqueTag(font), pdf_font_get_fontname(font)); - } else if (__verbose > 1) { + } else if (dpx_conf.verbose_level > 1) { dpx_message("[%s]", pdf_font_get_fontname(font)); } - if (__verbose > 1) { + if (dpx_conf.verbose_level > 1) { if (pdf_font_get_encoding(font) >= 0) { dpx_message("[%s]", pdf_encoding_get_name(pdf_font_get_encoding(font))); @@ -487,23 +467,23 @@ pdf_close_fonts (void) /* Type 0 is handled separately... */ switch (font->subtype) { case PDF_FONT_FONTTYPE_TYPE1: - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[Type1]"); if (!pdf_font_get_flag(font, PDF_FONT_FLAG_BASEFONT)) pdf_font_load_type1(font); break; case PDF_FONT_FONTTYPE_TYPE1C: - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[Type1C]"); pdf_font_load_type1c(font); break; case PDF_FONT_FONTTYPE_TRUETYPE: - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[TrueType]"); pdf_font_load_truetype(font); break; case PDF_FONT_FONTTYPE_TYPE3: - if (__verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[Type3/PK]"); pdf_font_load_pkfont (font); break; @@ -517,7 +497,7 @@ pdf_close_fonts (void) if (font->encoding_id >= 0 && font->subtype != PDF_FONT_FONTTYPE_TYPE0) pdf_encoding_add_usedchars(font->encoding_id, font->usedchars); - if (__verbose) { + if (dpx_conf.verbose_level > 0) { if (font->subtype != PDF_FONT_FONTTYPE_TYPE0) dpx_message(")"); } @@ -533,16 +513,20 @@ pdf_close_fonts (void) pdf_obj *tounicode; /* Predefined encodings (and those simplified to them) are embedded - as direct objects, but this is purely a matter of taste. */ + * as direct objects, but this is purely a matter of taste. + */ if (enc_obj) pdf_add_dict(font->resource, pdf_new_name("Encoding"), PDF_OBJ_NAMETYPE(enc_obj) ? pdf_link_obj(enc_obj) : pdf_ref_obj(enc_obj)); - + /* For built-in encoding, each font loader create ToUnicode CMap. */ if (!pdf_lookup_dict(font->resource, "ToUnicode") - && (tounicode = pdf_encoding_get_tounicode(font->encoding_id))) - pdf_add_dict(font->resource, - pdf_new_name("ToUnicode"), pdf_ref_obj(tounicode)); + && (tounicode = pdf_encoding_get_tounicode(font->encoding_id))) { + if (tounicode) { + pdf_add_dict(font->resource, + pdf_new_name("ToUnicode"), pdf_ref_obj(tounicode)); + } + } } else if (font->subtype == PDF_FONT_FONTTYPE_TRUETYPE) { /* encoding_id < 0 means MacRoman here (but not really) * We use MacRoman as "default" encoding. */ @@ -582,7 +566,35 @@ pdf_font_findresource (const char *tex_name, * point sizes would be looked up twice unecessarily.) */ fontname = mrec ? mrec->font_name : tex_name; - if (mrec && mrec->enc_name) { + /* XeTeX specific... + * First try loading GID-to-CID mapping from CFF CID-keyed OpenType font. + * There was a serious bug in xdv support... It was implemented with the wrong + * assumption that CID always equals to GID. + * TODO: There is a possibility that GID-to-CID mapping is not one-to-one. + * Use internal glyph ordering rather than map GID to CIDs. + */ + if (mrec && mrec->opt.use_glyph_encoding) { + int wmode = 0; + /* Should be always Identity-H or Identity-V for XeTeX output. */ + if (mrec->enc_name) { + if (!strcmp(mrec->enc_name, "Identity-V")) + wmode = 1; + else if (!strcmp(mrec->enc_name, "Identity-H")) + wmode = 0; + else { + dpx_warning("Unexpected encoding specified for xdv: %s", mrec->enc_name); + } + /* cmap_id < 0 is returned if ... + * Font is not a CFF font + * GID to CID mapping is identity mapping + * + * TODO: fontmap record still has Identity CMap assigned but actually different CMap + * can be attached to the font here. Should we fix mrec->enc_name here? + */ + cmap_id = otf_try_load_GID_to_CID_map(mrec->font_name, mrec->opt.index, wmode); + } + } + if (cmap_id < 0 && mrec && mrec->enc_name) { #define MAYBE_CMAP(s) (!strstr((s), ".enc") || strstr((s), ".cmap")) if (MAYBE_CMAP(mrec->enc_name)) { cmap_id = CMap_cache_find(mrec->enc_name); @@ -605,13 +617,14 @@ pdf_font_findresource (const char *tex_name, * Turn on map option. */ if (minbytes == 2 && mrec->opt.mapc < 0) { - if (__verbose) { + if (dpx_conf.verbose_level > 0) { dpx_message("\n"); dpx_message("pdf_font>> Input encoding \"%s\" requires at least 2 bytes.\n", CMap_get_name(cmap)); dpx_message("pdf_font>> The -m <00> option will be assumed for \"%s\".\n", mrec->font_name); } - mrec->opt.mapc = 0; /* _FIXME_ */ + /* FIXME: The following code modifies mrec. */ + mrec->opt.mapc = 0; } } else if (streq_ptr(mrec->enc_name, "unicode")) { cmap_id = otf_load_Unicode_CMap(mrec->font_name, @@ -631,7 +644,6 @@ pdf_font_findresource (const char *tex_name, _tt_abort("Could not find encoding file \"%s\".", mrec->enc_name); } } - if (mrec && cmap_id >= 0) { /* * Composite Font @@ -650,7 +662,7 @@ pdf_font_findresource (const char *tex_name, font->font_id == type0_id && font->encoding_id == cmap_id) { found = 1; - if (__verbose) { + if (dpx_conf.verbose_level > 0) { dpx_message("\npdf_font>> Type0 font \"%s\" (cmap_id=%d) found at font_id=%d.\n", mrec->font_name, cmap_id, font_id); } @@ -673,7 +685,7 @@ pdf_font_findresource (const char *tex_name, font_cache.count++; - if (__verbose) { + if (dpx_conf.verbose_level > 0) { dpx_message("\npdf_font>> Type0 font \"%s\"", fontname); dpx_message(" cmap_id=<%s,%d>", mrec->enc_name, font->encoding_id); dpx_message(" opened at font_id=<%s,%d>.\n", tex_name, font_id); @@ -724,7 +736,7 @@ pdf_font_findresource (const char *tex_name, } if (found) { - if (__verbose) { + if (dpx_conf.verbose_level > 0) { dpx_message("\npdf_font>> Simple font \"%s\" (enc_id=%d) found at id=%d.\n", fontname, encoding_id, font_id); } @@ -767,7 +779,7 @@ pdf_font_findresource (const char *tex_name, font_cache.count++; - if (__verbose) { + if (dpx_conf.verbose_level > 0) { dpx_message("\npdf_font>> Simple font \"%s\"", fontname); dpx_message(" enc_id=<%s,%d>", (mrec && mrec->enc_name) ? mrec->enc_name : "builtin", font->encoding_id); diff --git a/tectonic/dpx-pdffont.h b/tectonic/dpx-pdffont.h index 3519fd2a62..47b5c36d34 100644 --- a/tectonic/dpx-pdffont.h +++ b/tectonic/dpx-pdffont.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -38,9 +38,6 @@ #define PDF_FONT_FONTTYPE_TYPE0 4 -void pdf_font_set_verbose (int level); -int pdf_font_get_verbose (void); - void pdf_font_set_dpi (int font_dpi); #define PDF_FONT_FLAG_NOEMBED (1 << 0) diff --git a/tectonic/dpx-pdflimits.h b/tectonic/dpx-pdflimits.h index aac8160a35..89e49a5ce0 100644 --- a/tectonic/dpx-pdflimits.h +++ b/tectonic/dpx-pdflimits.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -30,9 +30,9 @@ * NOTE: Don't forget to update CIDFont_stdcc_def[] in cid.c * if you increase PDF_VERSION_MAX! */ -#define PDF_VERSION_MIN 3 -#define PDF_VERSION_MAX 7 -#define PDF_VERSION_DEFAULT 5 +#define PDF_VERSION_MIN 13 +#define PDF_VERSION_MAX 20 +#define PDF_VERSION_DEFAULT 15 /* * PDF_NAME_LEN_MAX: see, Appendix C of PDF Ref. v1.3, 2nd. ed. diff --git a/tectonic/dpx-pdfobj.c b/tectonic/dpx-pdfobj.c index f39d521626..936842ca81 100644 --- a/tectonic/dpx-pdfobj.c +++ b/tectonic/dpx-pdfobj.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2020 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -28,6 +28,7 @@ #include #include +#include "dpx-dpxconf.h" #include "dpx-dpxutil.h" #include "dpx-error.h" #include "dpx-mem.h" @@ -66,6 +67,7 @@ struct pdf_obj unsigned int refcount; /* Number of links to this object */ int flags; void *data; + /* Tectonic: not including PDFOBJ_DEBUG #ifdefs */ }; struct pdf_boolean @@ -200,7 +202,7 @@ static pdf_obj *xref_stream; /* Internal static routines */ -static int parse_pdf_version (rust_input_handle_t handle, unsigned int *ret_version); +static int check_for_pdf_version (rust_input_handle_t handle); static void pdf_flush_obj (pdf_obj *object, rust_output_handle_t handle); static void pdf_label_obj (pdf_obj *object); @@ -240,7 +242,6 @@ static void release_dict (pdf_dict *dict); static void write_stream (pdf_stream *stream, rust_output_handle_t handle); static void release_stream (pdf_stream *stream); -static int verbose = 0; static char compression_level = 9; static char compression_use_predictor = 1; @@ -264,16 +265,10 @@ pdf_set_compression (int level) return; } -void -pdf_set_use_predictor (int bval) -{ - compression_use_predictor = bval ? 1 : 0; -} - -static unsigned int pdf_version = PDF_VERSION_DEFAULT; +static int pdf_version = PDF_VERSION_DEFAULT; void -pdf_set_version (unsigned version) +pdf_set_version (int version) { /* Don't forget to update CIDFont_stdcc_def[] in cid.c too! */ if (version >= PDF_VERSION_MIN && version <= PDF_VERSION_MAX) { @@ -281,22 +276,28 @@ pdf_set_version (unsigned version) } } -unsigned int +int pdf_get_version (void) { return pdf_version; } int -pdf_obj_get_verbose(void) +pdf_get_version_major (void) { - return verbose; + return pdf_version/10; } -void -pdf_obj_set_verbose(int level) +int +pdf_get_version_minor (void) +{ + return pdf_version%10; +} + +int +pdf_check_version (int major, int minor) { - verbose = level; + return (pdf_version >= major*10+minor) ? 0 : -1; } static pdf_obj *current_objstm = NULL; @@ -319,7 +320,8 @@ add_xref_entry (unsigned label, unsigned char type, unsigned int field2, unsigne #define BINARY_MARKER "%\344\360\355\370\n" void -pdf_out_init (const char *filename, bool do_encryption, bool enable_object_stream) +pdf_out_init (const char *filename, + bool do_encryption, bool enable_objstm, bool enable_predictor) { char v; @@ -328,8 +330,8 @@ pdf_out_init (const char *filename, bool do_encryption, bool enable_object_strea add_xref_entry(0, 0, 0, 0xffff); next_label = 1; - if (pdf_version >= 5) { - if (enable_object_stream) { + if (pdf_version >= 15) { + if (enable_objstm) { xref_stream = pdf_new_stream(STREAM_COMPRESS); xref_stream->flags |= OBJ_NO_ENCRYPT; trailer_dict = pdf_stream_dict(xref_stream); @@ -358,14 +360,18 @@ pdf_out_init (const char *filename, bool do_encryption, bool enable_object_strea _tt_abort("Unable to open file."); } - pdf_out(pdf_output_handle, "%PDF-1.", strlen("%PDF-1.")); - v = '0' + pdf_version; + pdf_out(pdf_output_handle, "%PDF-", strlen("%PDF-")); + v = '0' + (pdf_version / 10); + pdf_out(pdf_output_handle, &v, 1); + pdf_out(pdf_output_handle, ".", 1); + v = '0' + (pdf_version % 10); pdf_out(pdf_output_handle, &v, 1); pdf_out(pdf_output_handle, "\n", 1); pdf_out(pdf_output_handle, BINARY_MARKER, strlen(BINARY_MARKER)); enc_mode = false; doc_enc_mode = do_encryption; + compression_use_predictor = enable_predictor; } static void @@ -493,14 +499,16 @@ pdf_out_flush (void) pdf_out(pdf_output_handle, format_buffer, length); pdf_out(pdf_output_handle, "%%EOF\n", 6); - if (verbose) { + if (dpx_conf.verbose_level > 0) { if (compression_level > 0) { dpx_message("Compression saved %d bytes%s\n", compression_saved, - pdf_version < 5 ? ". Try \"-V 5\" for better compression" : ""); + pdf_version < 15 ? ". Try \"-V 1.5\" for better compression" : ""); } } ttstub_output_close(pdf_output_handle); + pdf_output_file_position = 0; + pdf_output_line_position = 0; pdf_output_handle = NULL; } } @@ -872,20 +880,20 @@ pdf_new_string (const void *str, size_t 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 (length) { + if (str && 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; } @@ -1622,20 +1630,6 @@ filter_PNG15_apply_filter (unsigned char *raster, return dst; } -/* TIFF predictor filter support - * - * Many PDF viewers seems to have broken TIFF 2 predictor support? - * Ony GhostScript and MuPDF render 4bpc grayscale image with TIFF 2 predictor - * filter applied correctly. - * - * Acrobat Reader DC 2015.007.20033 NG - * Adobe Acrobat X 10.1.13 NG - * Foxit Reader 4.1.5.425 NG - * GhostScript 9.16 OK - * SumatraPDF(MuPDF) v3.0 OK - * Evince(poppler) 2.32.0.145 NG (1bit and 4bit broken) - */ - /* This modifies "raster" itself! */ static void apply_filter_TIFF2_1_2_4 (unsigned char *raster, @@ -1699,8 +1693,9 @@ apply_filter_TIFF2_1_2_4 (unsigned char *raster, } } - if (outbits > 0) + if (outbits > 0) { raster[k] = outbuf << (8 - outbits); + } } free(prev); @@ -2023,48 +2018,9 @@ pdf_add_stream (pdf_obj *stream, const void *stream_data, int length) #if HAVE_ZLIB #define WBUF_SIZE 4096 -int -pdf_add_stream_flate (pdf_obj *dst, const void *data, int len) -{ - z_stream z; - Bytef wbuf[WBUF_SIZE]; - - z.zalloc = Z_NULL; z.zfree = Z_NULL; z.opaque = Z_NULL; - - z.next_in = data; z.avail_in = len; - z.next_out = (Bytef *) wbuf; z.avail_out = WBUF_SIZE; - - if (inflateInit(&z) != Z_OK) { - dpx_warning("inflateInit() failed."); - return -1; - } - - for (;;) { - int status; - status = inflate(&z, Z_NO_FLUSH); - if (status == Z_STREAM_END) - break; - else if (status != Z_OK) { - dpx_warning("inflate() failed. Broken PDF file?"); - inflateEnd(&z); - return -1; - } - - if (z.avail_out == 0) { - pdf_add_stream(dst, wbuf, WBUF_SIZE); - z.next_out = wbuf; - z.avail_out = WBUF_SIZE; - } - } - - if (WBUF_SIZE - z.avail_out > 0) - pdf_add_stream(dst, wbuf, WBUF_SIZE - z.avail_out); - - return (inflateEnd(&z) == Z_OK ? 0 : -1); -} static int -get_decode_parms (struct decode_parms *parms, pdf_obj *dict) +filter_get_DecodeParms_FlateDecode (struct decode_parms *parms, pdf_obj *dict) { pdf_obj *tmp; @@ -2078,18 +2034,25 @@ get_decode_parms (struct decode_parms *parms, pdf_obj *dict) parms->columns = 1; tmp = pdf_deref_obj(pdf_lookup_dict(dict, "Predictor")); - if (tmp) + if (tmp) { parms->predictor = pdf_number_value(tmp); + pdf_release_obj(tmp); + } tmp = pdf_deref_obj(pdf_lookup_dict(dict, "Colors")); - if (tmp) + if (tmp) { parms->colors = pdf_number_value(tmp); + pdf_release_obj(tmp); + } tmp = pdf_deref_obj(pdf_lookup_dict(dict, "BitsPerComponent")); - if (tmp) + if (tmp) { parms->bits_per_component = pdf_number_value(tmp); + pdf_release_obj(tmp); + } tmp = pdf_deref_obj(pdf_lookup_dict(dict, "Columns")); - if (tmp) + if (tmp) { parms->columns = pdf_number_value(tmp); - + pdf_release_obj(tmp); + } if (parms->bits_per_component != 1 && parms->bits_per_component != 2 && parms->bits_per_component != 4 && @@ -2154,10 +2117,10 @@ filter_row_TIFF2 (unsigned char *dst, const unsigned char *src, * Especially, calling pdf_add_stream() for each 4 bytes append is highly * inefficient. */ -static int -filter_decoded (pdf_obj *dst, const void *src, int srclen, - struct decode_parms *parms) +static pdf_obj * +filter_stream_decode_Predictor (const void *src, size_t srclen, struct decode_parms *parms) { + pdf_obj *dst; const unsigned char *p = (const unsigned char *) src; const unsigned char *endptr = p + srclen; unsigned char *prev, *buf; @@ -2166,6 +2129,8 @@ filter_decoded (pdf_obj *dst, const void *src, int srclen, int length = (parms->columns * bits_per_pixel + 7) / 8; int i, error = 0; + dst = pdf_new_stream(0); + prev = NEW(length, unsigned char); buf = NEW(length, unsigned char); @@ -2291,16 +2256,21 @@ filter_decoded (pdf_obj *dst, const void *src, int srclen, free(prev); free(buf); - return error; + if (error) { + pdf_release_obj(dst); + dst = NULL; + } + + return dst; } -static int -pdf_add_stream_flate_filtered (pdf_obj *dst, const void *data, int len, struct decode_parms *parms) +static pdf_obj * +filter_stream_decode_FlateDecode (const void *data, size_t len, struct decode_parms *parms) { + pdf_obj *dst; pdf_obj *tmp; z_stream z; Bytef wbuf[WBUF_SIZE]; - int error; z.zalloc = Z_NULL; z.zfree = Z_NULL; z.opaque = Z_NULL; @@ -2309,19 +2279,22 @@ pdf_add_stream_flate_filtered (pdf_obj *dst, const void *data, int len, struct d if (inflateInit(&z) != Z_OK) { dpx_warning("inflateInit() failed."); - return -1; + return NULL; } tmp = pdf_new_stream(0); for (;;) { int status; status = inflate(&z, Z_NO_FLUSH); - if (status == Z_STREAM_END) + if (status == Z_STREAM_END) { break; - else if (status != Z_OK) { - dpx_warning("inflate() failed. Broken PDF file?"); + } else if (status == Z_DATA_ERROR && z.avail_in == 0) { + dpx_warning("Ignoring zlib error: status=%d, message=\"%s\"", status, z.msg); + } else if (status != Z_OK) { + dpx_warning("inflate() failed (status=%d, message=\"%s\"", status, z.msg); inflateEnd(&z); - return -1; + pdf_release_obj(tmp); + return NULL; } if (z.avail_out == 0) { @@ -2334,83 +2307,312 @@ pdf_add_stream_flate_filtered (pdf_obj *dst, const void *data, int len, struct d if (WBUF_SIZE - z.avail_out > 0) pdf_add_stream(tmp, wbuf, WBUF_SIZE - z.avail_out); - error = filter_decoded(dst, pdf_stream_dataptr(tmp), pdf_stream_length(tmp), parms); + if (inflateEnd(&z) == Z_OK) { + if (parms) { + dst = filter_stream_decode_Predictor(pdf_stream_dataptr(tmp), pdf_stream_length(tmp), parms); + } else { + dst = pdf_link_obj(tmp); + } + } else { + dst = NULL; + } pdf_release_obj(tmp); - return ((!error && inflateEnd(&z) == Z_OK) ? 0 : -1); + return dst; } #endif -int -pdf_concat_stream (pdf_obj *dst, pdf_obj *src) +static pdf_obj * +filter_stream_decode_ASCIIHexDecode (const void *data, size_t len) +{ + pdf_obj *dst; + int eod, error; + const char *p = (const char *) data; + const char *endptr = p + len; + unsigned char *buf, ch; + size_t pos, n; + + buf = NEW((len+1)/2, unsigned char); + skip_white(&p, endptr); + ch = 0; n = 0; pos = 0; eod = 0; error = 0; + while (p < endptr && !error && !eod) { + char c1, val; + c1 = p[0]; + if (c1 >= 'A' && c1 <= 'F') { + val = c1 - 'A' + 10; + } else if (c1 >= 'a' && c1 <= 'f') { + val = c1 - 'a' + 10; + } else if (c1 >= '0' && c1 <= '9') { + val = c1 - '0'; + } else if (c1 == '>') { + val = 0; + eod = 1; + if ((pos % 2) == 0) + break; + } else { + error = -1; + break; + } + if (pos % 2) { + buf[n] = ch + val; + n++; + ch = 0; + } else { + ch = val << 4; + } + pos++; p++; + skip_white(&p, endptr); + } + if (error || !eod) { + dpx_warning("Invalid ASCIIHex data seen: %s", error ? "Invalid character" : "No EOD marker"); + dst = NULL; + } else { + dst = pdf_new_stream(0); + pdf_add_stream(dst, buf, n); + } + free(buf); + + return dst; +} + +/* Percent sign is not start of comment here. + * We need this for reading Ascii85 encoded data. + */ +#define is_space(c) ((c) == ' ' || (c) == '\t' || (c) == '\f' || \ + (c) == '\r' || (c) == '\n' || (c) == '\0') +static void +skip_white_a85 (const char **p, const char *endptr) { + while (*p < endptr && (is_space(**p))) { + (*p)++; + } +} + +static pdf_obj * +filter_stream_decode_ASCII85Decode (const void *data, size_t len) +{ + pdf_obj *dst; + int eod, error; + const char *p = (const char *) data; + const char *endptr = p + len; + unsigned char *buf; + size_t n; + + buf = NEW(((len+4)/5)*4, unsigned char); + skip_white_a85(&p, endptr); + n = 0; eod = 0; error = 0; + while (p < endptr && !error && !eod) { + char q[5] = {'u', 'u', 'u', 'u', 'u'}; + int m; + char ch; + + ch = p[0]; + p++; + skip_white_a85(&p, endptr); + if (ch == 'z') { + memset(buf+n, 0, 4); + n += 4; + continue; + } else if (ch == '~') { + if (p < endptr && p[0] == '>') { + eod = 1; + p++; + } else { + error = -1; + } + break; + } + q[0] = ch; + for (m = 1; m < 5 && p < endptr; m++) { + ch = p[0]; + p++; + skip_white_a85(&p, endptr); + if (ch == '~') { + if (p < endptr && p[0] == '>') { + eod = 1; + p++; + } else { + error = -1; + } + break; + } else if (ch < '!' || ch > 'u') { + error = -1; + break; + } else { + q[m] = ch; + } + } + if (!error) { + uint32_t val = 0; + int i; + if (m <= 1) { + error = -1; + break; + } + val = 85*85*85*(q[0] - '!') + 85*85*(q[1] - '!') + + 85*(q[2] - '!') + (q[3] - '!'); + /* Check overflow */ + if (val > UINT32_MAX / 85) { + error = -1; + break; + } else { + val = 85 * val; + if (val > UINT32_MAX - (q[4] - '!')) { + error = -1; + break; + } + val += (q[4] - '!'); + } + if (!error) { + for (i = 3; i >= 0; i--) { + buf[n + i] = val & 0xff; + val /= 256; + } + n += m - 1; + } + } + } + + if (error) { + dpx_warning("Error in reading ASCII85 data."); + } else if (!eod) { + dpx_warning("Error in reading ASCII85 data: No EOD"); + dst = NULL; + } else { + dst = pdf_new_stream(0); + pdf_add_stream(dst, buf, n); + } + free(buf); + + return dst; +} + +static pdf_obj * +filter_stream_decode (const char *filter_name, pdf_obj *src, pdf_obj *parm) +{ + pdf_obj *dec; const char *stream_data; - int stream_length; - pdf_obj *stream_dict; - pdf_obj *filter; - int error = 0; + size_t stream_length; - if (!PDF_OBJ_STREAMTYPE(dst) || !PDF_OBJ_STREAMTYPE(src)) - _tt_abort("Invalid type."); + if (!filter_name) + return pdf_link_obj(src); stream_data = pdf_stream_dataptr(src); - stream_length = pdf_stream_length (src); - stream_dict = pdf_stream_dict (src); + stream_length = pdf_stream_length(src); - filter = pdf_lookup_dict(stream_dict, "Filter"); - if (!filter) { - pdf_add_stream(dst, stream_data, stream_length); - } + if (!strcmp(filter_name, "ASCIIHexDecode")) { + dec = filter_stream_decode_ASCIIHexDecode(stream_data, stream_length); + } else if (!strcmp(filter_name, "ASCII85Decode")) { + dec = filter_stream_decode_ASCII85Decode(stream_data, stream_length); #if HAVE_ZLIB - else { - struct decode_parms parms; - int have_parms = 0; + } else if (!strcmp(filter_name, "FlateDecode")) { + struct decode_parms decode_parm; + if (parm) + filter_get_DecodeParms_FlateDecode(&decode_parm, parm); + dec = filter_stream_decode_FlateDecode(stream_data, stream_length, parm ? &decode_parm : NULL); +#endif /* HAVE_ZLIB */ + } else { + dpx_warning("DecodeFilter \"%s\" not supported.", filter_name); + dec = NULL; + } - if (pdf_lookup_dict(stream_dict, "DecodeParms")) { - pdf_obj *tmp; + return dec; +} - /* Dictionary or array */ - tmp = pdf_deref_obj(pdf_lookup_dict(stream_dict, "DecodeParms")); - if (PDF_OBJ_ARRAYTYPE(tmp)) { - if (pdf_array_length(tmp) > 1) { - dpx_warning("Unexpected size for DecodeParms array."); - return -1; - } - tmp = pdf_deref_obj(pdf_get_array(tmp, 0)); - } - if (!PDF_OBJ_DICTTYPE(tmp)) { - dpx_warning("PDF dict expected for DecodeParms..."); - return -1; - } - error = get_decode_parms(&parms, tmp); - if (error) - _tt_abort("Invalid value(s) in DecodeParms dictionary."); - have_parms = 1; - } - if (PDF_OBJ_ARRAYTYPE(filter)) { - if (pdf_array_length(filter) > 1) { - dpx_warning("Multiple DecodeFilter not supported."); - return -1; - } - filter = pdf_get_array(filter, 0); - } - if (PDF_OBJ_NAMETYPE(filter)) { - char *filter_name = pdf_name_value(filter); - if (streq_ptr(filter_name, "FlateDecode")) { - if (have_parms) - error = pdf_add_stream_flate_filtered(dst, stream_data, stream_length, &parms); - else - error = pdf_add_stream_flate(dst, stream_data, stream_length); - } else { - dpx_warning("DecodeFilter \"%s\" not supported.", filter_name); - error = -1; - } - } else - _tt_abort("Broken PDF file?"); - } -#endif /* HAVE_ZLIB */ +int +pdf_concat_stream (pdf_obj *dst, pdf_obj *src) +{ + pdf_obj *filtered; + pdf_obj *stream_dict; + pdf_obj *filter, *parms; + int error = 0; - return error; + if (!PDF_OBJ_STREAMTYPE(dst) || !PDF_OBJ_STREAMTYPE(src)) { + dpx_warning("Passed invalid type in pdf_concat_stream()."); + return -1; + } + + stream_dict = pdf_stream_dict(src); + + filter = pdf_lookup_dict(stream_dict, "Filter"); + if (!filter) { + pdf_add_stream(dst, pdf_stream_dataptr(src), pdf_stream_length(src)); + return 0; + } + if (pdf_lookup_dict(stream_dict, "DecodeParms")) { + /* Dictionary or array */ + parms = pdf_deref_obj(pdf_lookup_dict(stream_dict, "DecodeParms")); + if (!parms) { + dpx_warning("Failed to deref DeocdeParms..."); + return -1; + } else if (!PDF_OBJ_ARRAYTYPE(parms) && !PDF_OBJ_DICTTYPE(parms)) { + dpx_warning("PDF dict or array expected for DecodeParms..."); + pdf_release_obj(parms); + return -1; + } + } else { + parms = NULL; + } + if (PDF_OBJ_ARRAYTYPE(filter)) { + int i, num; + pdf_obj *prev = NULL; + + num = pdf_array_length(filter); + if (parms) { + if (!PDF_OBJ_ARRAYTYPE(parms) || pdf_array_length(parms) != num) { + dpx_warning("Invalid DecodeParam object found."); + pdf_release_obj(parms); + return -1; + } + } + if (num == 0) { + filtered = pdf_link_obj(src); + } else { + filtered = NULL; + prev = pdf_link_obj(src); + for (i = 0; i < num && prev != NULL; i++) { + pdf_obj *tmp1, *tmp2; + + tmp1 = pdf_deref_obj(pdf_get_array(filter, i)); + if (parms) { + tmp2 = pdf_deref_obj(pdf_get_array(parms, i)); + } else { + tmp2 = NULL; + } + if (PDF_OBJ_NAMETYPE(tmp1)) { + filtered = filter_stream_decode(pdf_name_value(tmp1), prev, tmp2); + } else if (PDF_OBJ_NULLTYPE(tmp1)) { + filtered = pdf_link_obj(prev); + } else { + dpx_warning("Unexpected object found for /Filter..."); + filtered = NULL; + } + if (prev) + pdf_release_obj(prev); + if (tmp1) + pdf_release_obj(tmp1); + if (tmp2) + pdf_release_obj(tmp2); + prev = filtered; + } + } + } else if (PDF_OBJ_NAMETYPE(filter)) { + filtered = filter_stream_decode(pdf_name_value(filter), src, parms); + } else { + dpx_warning("Invalid value for /Filter found."); + filtered = NULL; + } + if (parms) + pdf_release_obj(parms); + if (filtered) { + pdf_add_stream(dst, pdf_stream_dataptr(filtered), pdf_stream_length(filtered)); + pdf_release_obj(filtered); + error = 0; + } else { + error = -1; + } + + return error; } static pdf_obj * @@ -3405,11 +3607,9 @@ parse_xref_stream (pdf_file *pf, int xref_pos, pdf_obj **trailer) while (i < index_len) { pdf_obj *first = pdf_get_array(index_obj, i++); size_obj = pdf_get_array(index_obj, i++); - if (!PDF_OBJ_NUMBERTYPE(first) || - !PDF_OBJ_NUMBERTYPE(size_obj) || + if (!PDF_OBJ_NUMBERTYPE(first) || !PDF_OBJ_NUMBERTYPE(size_obj) || parse_xrefstm_subsec(pf, &p, &length, W, wsum, - (int) pdf_number_value(first), - (int) pdf_number_value(size_obj))) + (int) pdf_number_value(first), (int) pdf_number_value(size_obj))) goto error; } } else if (parse_xrefstm_subsec(pf, &p, &length, W, wsum, 0, size)) @@ -3548,7 +3748,7 @@ pdf_files_init (void) ht_init_table(pdf_files, (void (*)(void *)) pdf_file_free); } -unsigned int +int pdf_file_get_version (pdf_file *pf) { assert(pf); @@ -3562,6 +3762,10 @@ pdf_file_get_trailer (pdf_file *pf) return pdf_link_obj(pf->trailer); } +/* FIXME: + * pdf_file_get_trailer() does pdf_link_obj() but + * pdf_file_get_catalog() does not. Why? + */ pdf_obj * pdf_file_get_catalog (pdf_file *pf) { @@ -3583,16 +3787,15 @@ pdf_open (const char *ident, rust_input_handle_t handle) pf->handle = handle; } else { pdf_obj *new_version; - unsigned int version = 0; - int r = parse_pdf_version(handle, &version); - - if (r < 0 || version < 1 || version > pdf_version) { - dpx_warning("pdf_open: Not a PDF 1.[1-%u] file.", pdf_version); -/* - Try to embed the PDF image, even if the PDF version is newer than - the setting. - return NULL; -*/ + int version = check_for_pdf_version(handle); + + if (version < 10) + dpx_warning("Unrecognized PDF version specified for input PDF file: %d.%d", + pdf_version/10, pdf_version%10); + else if (version > pdf_version) { + dpx_warning("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); } pf = pdf_file_new(handle); @@ -3614,17 +3817,17 @@ pdf_open (const char *ident, rust_input_handle_t handle) new_version = pdf_deref_obj(pdf_lookup_dict(pf->catalog, "Version")); if (new_version) { - unsigned int minor; + unsigned int major, minor; if (!PDF_OBJ_NAMETYPE(new_version) || - sscanf(pdf_name_value(new_version), "1.%u", &minor) != 1) { + sscanf(pdf_name_value(new_version), "%u.%u", &major, &minor) != 2) { pdf_release_obj(new_version); dpx_warning("Illegal Version entry in document catalog. Broken PDF file?"); goto error; } - if (pf->version < minor) - pf->version = minor; + if (pf->version < major*10+minor) + pf->version = major*10+minor; pdf_release_obj(new_version); } @@ -3656,37 +3859,33 @@ pdf_files_close (void) } static int -parse_pdf_version (rust_input_handle_t handle, unsigned int *ret_version) +check_for_pdf_version (rust_input_handle_t handle) { char buffer[10] = "\0\0\0\0\0\0\0\0\0"; - unsigned int minor; + unsigned int major, minor; ttstub_input_seek(handle, 0, SEEK_SET); if (ttstub_input_read(handle, buffer, sizeof(buffer) - 1) != sizeof(buffer) - 1) return -1; - if (sscanf(buffer, "%%PDF-1.%u", &minor) != 1) + if (sscanf(buffer, "%%PDF-%u.%u", &major, &minor) != 2) return -1; - *ret_version = minor; - - return 0; + return major*10+minor; } int check_for_pdf (rust_input_handle_t handle) { - int r; - unsigned int version; + int version; - r = parse_pdf_version(handle, &version); - if (r < 0) /* not a PDF file */ + version = check_for_pdf_version(handle); + if (version < 0) /* not a PDF file */ return 0; if (version <= pdf_version) return 1; - dpx_warning("Version of PDF file (1.%d) is newer than version limit specification.", version); return 1; } @@ -3707,15 +3906,12 @@ import_dict (pdf_obj *key, pdf_obj *value, void *pdata) return 0; } -static pdf_obj loop_marker = { PDF_OBJ_INVALID, 0, 0, 0, 0, NULL }; - static pdf_obj * pdf_import_indirect (pdf_obj *object) { pdf_file *pf = OBJ_FILE(object); unsigned int obj_num = OBJ_NUM(object); unsigned short obj_gen = OBJ_GEN(object); - pdf_obj *ref; assert(pf); @@ -3725,12 +3921,9 @@ pdf_import_indirect (pdf_obj *object) return pdf_new_null(); } - if ((ref = pf->xref_table[obj_num].indirect)) { - if (ref == &loop_marker) - _tt_abort("Loop in object hierarchy detected. Broken PDF file?"); - return pdf_link_obj(ref); - } else { - pdf_obj *obj, *tmp; + ref = pf->xref_table[obj_num].indirect; + if (!ref) { + pdf_obj *obj, *reserved, *imported; obj = pdf_get_object(pf, obj_num, obj_gen); if (!obj) { @@ -3738,18 +3931,35 @@ pdf_import_indirect (pdf_obj *object) return NULL; } - /* We mark the reference to be able to detect loops */ - pf->xref_table[obj_num].indirect = &loop_marker; - - tmp = pdf_import_object(obj); - - pf->xref_table[obj_num].indirect = ref = pdf_ref_obj(tmp); + /* Fix for circular reference issue + * + * Older version of dvipdfmx disallowed the following case of + * circular reference: + * obj #1 --> << /Kids [2 0 R] >> + * obj #2 --> << /Parents [1 0 R] >> + * The problem is in that dvipdfmx gives new labels to objects after they + * are completely read. + */ + reserved = pdf_new_null(); /* for reservation of label */ + pf->xref_table[obj_num].indirect = ref = pdf_new_ref(reserved); + imported = pdf_import_object(obj); + if (imported) { + if (imported->label) { + dpx_warning("Imported object already has a label: obj_id=%u", imported->label); + } + OBJ_OBJ(ref) = imported; + imported->label = reserved->label; + imported->generation = reserved->generation; + reserved->label = 0; + reserved->generation = 0; + pdf_release_obj(imported); + } - pdf_release_obj(tmp); + pdf_release_obj(reserved); pdf_release_obj(obj); - - return pdf_link_obj(ref); } + + return pdf_link_obj(ref); } /* diff --git a/tectonic/dpx-pdfobj.h b/tectonic/dpx-pdfobj.h index 7af4b112a7..88ba29d940 100644 --- a/tectonic/dpx-pdfobj.h +++ b/tectonic/dpx-pdfobj.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -59,17 +59,17 @@ typedef struct pdf_obj pdf_obj; typedef struct pdf_file pdf_file; /* External interface to pdf routines */ - -int pdf_obj_get_verbose (void); -void pdf_obj_set_verbose (int level); void pdf_obj_reset_global_state (void); void pdf_error_cleanup (void); void pdf_out_init (const char *filename, - bool enable_encrypt, bool enable_object_stream); + bool enable_encrypt, bool enable_objstm, + bool enable_predictor); void pdf_out_flush (void); -void pdf_set_version (unsigned version); -unsigned int pdf_get_version (void); +void pdf_set_version (int version); +int pdf_get_version (void); +int pdf_get_version_major (void); +int pdf_get_version_minor (void); void pdf_release_obj (pdf_obj *object); int pdf_obj_typeof (pdf_obj *object); @@ -148,11 +148,6 @@ pdf_obj *pdf_new_stream (int flags); void pdf_add_stream (pdf_obj *stream, const void *stream_data_ptr, int stream_data_len); -#if HAVE_ZLIB -int pdf_add_stream_flate (pdf_obj *stream, - const void *stream_data_ptr, - int stream_data_len); -#endif int pdf_concat_stream (pdf_obj *dst, pdf_obj *src); pdf_obj *pdf_stream_dict (pdf_obj *stream); int pdf_stream_length (pdf_obj *stream); @@ -169,7 +164,6 @@ int pdf_compare_reference (pdf_obj *ref1, pdf_obj *ref2); */ void pdf_set_compression (int level); -void pdf_set_use_predictor (int bval); void pdf_set_info (pdf_obj *obj); void pdf_set_root (pdf_obj *obj); @@ -182,8 +176,8 @@ int check_for_pdf (rust_input_handle_t handle); pdf_file *pdf_open (const char *ident, rust_input_handle_t handle); void pdf_close (pdf_file *pf); pdf_obj *pdf_file_get_trailer (pdf_file *pf); -unsigned int pdf_file_get_version (pdf_file *pf); pdf_obj *pdf_file_get_catalog (pdf_file *pf); +int pdf_file_get_version (pdf_file *pf); pdf_obj *pdf_deref_obj (pdf_obj *object); pdf_obj *pdf_import_object (pdf_obj *object); @@ -192,5 +186,6 @@ size_t pdfobj_escape_str (char *buffer, size_t size, const unsigned char *s, siz pdf_obj *pdf_new_indirect (pdf_file *pf, unsigned label, unsigned short generation); +int pdf_check_version (int major, int minor); #endif /* _PDFOBJ_H_ */ diff --git a/tectonic/dpx-pdfximage.c b/tectonic/dpx-pdfximage.c index 4ea807dee3..670978c142 100644 --- a/tectonic/dpx-pdfximage.c +++ b/tectonic/dpx-pdfximage.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -30,6 +30,7 @@ #include "core-bridge.h" #include "dpx-bmpimage.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" #include "dpx-dpxutil.h" #include "dpx-epdf.h" @@ -87,19 +88,13 @@ struct pdf_ximage_ /* verbose, verbose, verbose... */ struct opt_ { - int verbose; char *cmdtmpl; }; static struct opt_ _opts = { - 0, NULL + NULL }; -void pdf_ximage_set_verbose (int level) { - _opts.verbose = level; -} - - struct ic_ { int count, capacity; @@ -172,7 +167,7 @@ pdf_close_images (void) * We also use this to convert a PS file only once if multiple * pages are imported from that file. */ - if (_opts.verbose > 1 && keep_cache != 1) + if (dpx_conf.verbose_level > 1 && dpx_conf.file.keep_cache != 1) dpx_message("pdf_image>> deleting temporary file \"%s\"\n", I->filename); dpx_delete_temp_file(I->filename, false); /* temporary filename freed here */ I->filename = NULL; @@ -247,14 +242,14 @@ load_image (const char *ident, const char *fullname, int format, rust_input_hand switch (format) { case IMAGE_TYPE_JPEG: - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[JPEG]"); if (jpeg_include_image(I, handle) < 0) goto error; I->subtype = PDF_XOBJECT_TYPE_IMAGE; break; case IMAGE_TYPE_JP2: - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[JP2]"); /*if (jp2_include_image(I, fp) < 0)*/ dpx_warning("Tectonic: JP2 not yet supported"); @@ -262,21 +257,21 @@ load_image (const char *ident, const char *fullname, int format, rust_input_hand /*I->subtype = PDF_XOBJECT_TYPE_IMAGE; break;*/ case IMAGE_TYPE_PNG: - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[PNG]"); if (png_include_image(I, handle) < 0) goto error; I->subtype = PDF_XOBJECT_TYPE_IMAGE; break; case IMAGE_TYPE_BMP: - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[BMP]"); if (bmp_include_image(I, handle) < 0) goto error; I->subtype = PDF_XOBJECT_TYPE_IMAGE; break; case IMAGE_TYPE_PDF: - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[PDF]"); { int result = pdf_include_page(I, handle, fullname, options); @@ -284,18 +279,18 @@ load_image (const char *ident, const char *fullname, int format, rust_input_hand if (result != 0) goto error; } - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message(",Page:%d", I->attr.page_no); I->subtype = PDF_XOBJECT_TYPE_FORM; break; case IMAGE_TYPE_EPS: - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[EPS]"); dpx_warning("sorry, PostScript images are not supported by Tectonic"); dpx_warning("for details, please see https://github.com/tectonic-typesetting/tectonic/issues/27"); goto error; default: - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message("[UNKNOWN]"); /* Tectonic: this used to try ps_include_page() */ goto error; @@ -321,6 +316,10 @@ load_image (const char *ident, const char *fullname, int format, rust_input_hand } +#if defined(WIN32) +int utf8name_failed = 0; +#endif /* WIN32 */ + int pdf_ximage_findresource (const char *ident, load_options options) { @@ -361,7 +360,7 @@ pdf_ximage_findresource (const char *ident, load_options options) return -1; } - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message("(Image:%s", ident); format = source_image_type(handle); @@ -369,7 +368,7 @@ pdf_ximage_findresource (const char *ident, load_options options) ttstub_input_close(handle); - if (_opts.verbose) + if (dpx_conf.verbose_level > 0) dpx_message(")"); if (id < 0) diff --git a/tectonic/dpx-pdfximage.h b/tectonic/dpx-pdfximage.h index 92719067fb..8a0e01dedd 100644 --- a/tectonic/dpx-pdfximage.h +++ b/tectonic/dpx-pdfximage.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -24,7 +24,7 @@ #define _PDFXIMAGE_H_ #include "dpx-core.h" - +#include "dpx-pdfdoc.h" #include "dpx-pdfdev.h" #include "dpx-pdfobj.h" @@ -54,14 +54,12 @@ typedef struct { typedef struct { int page_no; - int bbox_type; + enum pdf_page_boundary bbox_type; pdf_obj *dict; } load_options; typedef struct pdf_ximage_ pdf_ximage; -void pdf_ximage_set_verbose (int level); - void pdf_init_images (void); void pdf_close_images (void); diff --git a/tectonic/dpx-pngimage.c b/tectonic/dpx-pngimage.c index f598d4cd8c..9b037b9cbe 100644 --- a/tectonic/dpx-pngimage.c +++ b/tectonic/dpx-pngimage.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -32,6 +32,7 @@ * */ +#include "dpx-dpxconf.h" #include "dpx-error.h" #include "dpx-mem.h" #include "dpx-numbers.h" @@ -202,7 +203,7 @@ png_include_image (pdf_ximage *ximage, rust_input_handle_t handle) bpc = png_get_bit_depth (png_ptr, png_info_ptr); if (bpc > 8) { - if (pdf_get_version() < 5) { + if (pdf_check_version(1, 5) < 0) { /* Ask libpng to convert down to 8-bpc. */ dpx_warning("%s: 16-bpc PNG requires PDF version 1.5.", PNG_DEBUG_STR); png_set_strip_16(png_ptr); @@ -372,7 +373,7 @@ png_include_image (pdf_ximage *ximage, rust_input_handle_t handle) * flag of iTxt chunks. */ #if PNG_LIBPNG_VER >= 10614 - if (pdf_get_version() >= 4) { + if (pdf_check_version(1, 4) >= 0) { png_textp text_ptr; pdf_obj *XMP_stream, *XMP_stream_dict; int i, num_text; @@ -456,13 +457,11 @@ static int check_transparency (png_structp png_ptr, png_infop info_ptr) { int trans_type; - unsigned int pdf_version; png_byte color_type; png_color_16p trans_values; png_bytep trans; int num_trans; - pdf_version = pdf_get_version(); color_type = png_get_color_type(png_ptr, info_ptr); /* @@ -504,8 +503,8 @@ check_transparency (png_structp png_ptr, png_infop info_ptr) * We can convert alpha cahnnels to explicit mask via user supplied alpha- * threshold value. But I will not do that. */ - if (( pdf_version < 3 && trans_type != PDF_TRANS_TYPE_NONE ) || - ( pdf_version < 4 && trans_type == PDF_TRANS_TYPE_ALPHA )) { + if (( pdf_check_version(1, 3) < 0 && trans_type != PDF_TRANS_TYPE_NONE ) || + ( pdf_check_version(1, 4) < 0 && trans_type == PDF_TRANS_TYPE_ALPHA )) { /* * No transparency supported but PNG uses transparency, or Soft-Mask * required but no support for it is available in this version of PDF. @@ -522,9 +521,9 @@ check_transparency (png_structp png_ptr, png_infop info_ptr) bg.red = 255; bg.green = 255; bg.blue = 255; bg.gray = 255; bg.index = 0; png_set_background(png_ptr, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); dpx_warning("%s: Transparency will be ignored. (no support in PDF ver. < 1.3)", PNG_DEBUG_STR); - if (pdf_version < 3) + if (pdf_check_version(1, 3) < 0) dpx_warning("%s: Please use -V 3 option to enable binary transparency support.", PNG_DEBUG_STR); - if (pdf_version < 4) + if (pdf_check_version(1, 4) < 0) dpx_warning("%s: Please use -V 4 option to enable full alpha channel support.", PNG_DEBUG_STR); trans_type = PDF_TRANS_TYPE_NONE; } @@ -973,12 +972,16 @@ create_soft_mask (png_structp png_ptr, png_infop info_ptr, png_bytep trans; int num_trans; png_uint_32 i; + png_byte bpc, mask, shift; if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) || !png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL)) { dpx_warning("%s: PNG does not have valid tRNS chunk but tRNS is requested.", PNG_DEBUG_STR); return NULL; } + bpc = png_get_bit_depth(png_ptr, info_ptr); + mask = 0xff >> (8 - bpc); + shift = 8 - bpc; smask = pdf_new_stream(STREAM_COMPRESS); dict = pdf_stream_dict(smask); @@ -990,7 +993,8 @@ create_soft_mask (png_structp png_ptr, png_infop info_ptr, pdf_add_dict(dict, pdf_new_name("ColorSpace"), pdf_new_name("DeviceGray")); pdf_add_dict(dict, pdf_new_name("BitsPerComponent"), pdf_new_number(8)); for (i = 0; i < width*height; i++) { - png_byte idx = image_data_ptr[i]; + /* data is packed for 1/2/4 bpc formats, msb first */ + png_byte idx = (image_data_ptr[bpc * i / 8] >> (shift - bpc * i % 8)) & mask; smask_data_ptr[i] = (idx < num_trans) ? trans[idx] : 0xff; } pdf_add_stream(smask, (char *)smask_data_ptr, width*height); diff --git a/tectonic/dpx-spc_dvips.c b/tectonic/dpx-spc_dvips.c index 5f5af717f3..cf65a738f9 100644 --- a/tectonic/dpx-spc_dvips.c +++ b/tectonic/dpx-spc_dvips.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-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks diff --git a/tectonic/dpx-spc_pdfm.c b/tectonic/dpx-spc_pdfm.c index a6df8e6ff5..5145f36d81 100644 --- a/tectonic/dpx-spc_pdfm.c +++ b/tectonic/dpx-spc_pdfm.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2020 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -29,6 +29,7 @@ #include #include +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" #include "dpx-dpxutil.h" #include "dpx-dvipdfmx.h" @@ -66,13 +67,15 @@ struct spc_pdf_ int lowest_level; /* current min level of outlines */ struct ht_table *resourcemap; /* see remark below (somewhere) */ struct tounicode cd; /* For to-UTF16-BE conversion :( */ + pdf_obj *pageresources; /* Add to all page resource dict */ }; static struct spc_pdf_ _pdf_stat = { NULL, 255, NULL, - { -1, 0, NULL } + { -1, 0, NULL }, + NULL }; /* PLEASE REMOVE THIS */ @@ -139,6 +142,7 @@ spc_handler_pdfm__init (void *dp) pdf_add_array(sd->cd.taintkeys, pdf_new_name(default_taintkeys[i])); } + sd->pageresources = NULL; return 0; } @@ -162,6 +166,9 @@ spc_handler_pdfm__clean (void *dp) pdf_release_obj(sd->cd.taintkeys); sd->cd.taintkeys = NULL; + if (sd->pageresources) + pdf_release_obj(sd->pageresources); + sd->pageresources = NULL; return 0; } @@ -230,10 +237,6 @@ safeputresdent (pdf_obj *kp, pdf_obj *vp, void *dp) return 0; } -#ifndef pdf_obj_isaref -#define pdf_obj_isaref(o) (pdf_obj_typeof((o)) == PDF_INDIRECT) -#endif - static int safeputresdict (pdf_obj *kp, pdf_obj *vp, void *dp) { @@ -245,7 +248,7 @@ safeputresdict (pdf_obj *kp, pdf_obj *vp, void *dp) key = pdf_name_value(kp); dict = pdf_lookup_dict(dp, key); - if (pdf_obj_isaref(vp)) { + if (pdf_obj_typeof(vp) == PDF_INDIRECT) { pdf_add_dict(dp, pdf_new_name(key), pdf_link_obj(vp)); } else if (pdf_obj_typeof(vp) == PDF_DICT) { if (dict) @@ -261,6 +264,94 @@ safeputresdict (pdf_obj *kp, pdf_obj *vp, void *dp) return 0; } +static +int putpageresources (pdf_obj *kp, pdf_obj *vp, void *dp) +{ + char *resource_name; + + assert(kp && vp); + + resource_name = pdf_name_value(kp); + pdf_doc_add_page_resource(dp, resource_name, pdf_link_obj(vp)); + + return 0; +} + +static +int forallresourcecategory (pdf_obj *kp, pdf_obj *vp, void *dp) +{ + int r = -1; + char *category; + + assert(kp && vp); + + category = pdf_name_value(kp); + switch (pdf_obj_typeof(vp)) { + case PDF_DICT: + r = pdf_foreach_dict(vp, putpageresources, category); + break; + case PDF_INDIRECT: + { + /* In case pdf:pageresouces << /Category @res >> */ + pdf_obj *obj; + obj = pdf_deref_obj(vp); + if (!obj) { + dpx_warning("Can't deref object for page resource: %s", category); + r = -1; + } else if (pdf_obj_typeof(obj) != PDF_DICT) { + dpx_warning("Invalid object type for page resource: %s", category); + r = -1; + } else { + pdf_obj *res_dict, *dict; + + res_dict = pdf_doc_current_page_resources(); + dict = pdf_lookup_dict(res_dict, category); + if (!dict) { + pdf_add_dict(res_dict, pdf_new_name(category), pdf_link_obj(vp)); + } else { + if (pdf_obj_typeof(dict) == PDF_INDIRECT) { + dict = pdf_deref_obj(dict); + pdf_release_obj(dict); /* FIXME: jus to decrement link counter */ + } +#if 1 + /* This will leave garbage (object "res") since object "res" + * supplied as resource dictionary will have label but we copy the + * content of res here and never use reference to it. + */ + pdf_foreach_dict(obj, safeputresdent, dict); +#else + /* With the below code resource dictionary is replaced by user + * supplied one, @res. However, there is a problem that all + * resources including internally generated one may go into single + * dictionary referenced by @res, and will be visible from any + * subsequent pages. + */ + pdf_foreach_dict(dict, safeputresdent, obj); + pdf_add_dict(res_dict, pdf_new_name(category), pdf_link_obj(vp)); +#endif + } + pdf_release_obj(obj); + } + } + break; + default: + dpx_warning("Invalid object type for page resource specified for \"%s\"", category); + } + + return r; +} + +int +spc_pdfm_at_end_page (void) +{ + struct spc_pdf_ *sd = &_pdf_stat; + + if (sd->pageresources) { + pdf_foreach_dict(sd->pageresources, forallresourcecategory, NULL); + } + + return 0; +} /* Think what happens if you do * @@ -492,7 +583,7 @@ modstrings (pdf_obj *kp, pdf_obj *vp, void *dp) CMap *cmap = CMap_cache_get(cd->cmap_id); if (needreencode(kp, vp, cd)) r = reencodestring(cmap, vp); - } else if (is_xdv && cd && cd->taintkeys) { + } else if ((dpx_conf.compat_mode == dpx_mode_xdv_mode) && cd && cd->taintkeys) { /* Please fix this... PDF string object is not always a text string. * needreencode() is assumed to do a simple check if given string * object is actually a text string. @@ -520,7 +611,7 @@ 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 (!is_xdv && cd->cmap_id < 0) + if ((dpx_conf.compat_mode != dpx_mode_xdv_mode) && cd->cmap_id < 0) return parse_pdf_dict(pp, endptr, NULL); /* :( */ @@ -535,6 +626,7 @@ parse_pdf_dict_with_tounicode (const char **pp, const char *endptr, struct touni return dict; } +#define SPC_PDFM_SUPPORT_ANNOT_TRANS 1 static int spc_handler_pdfm_annot (struct spc_env *spe, struct spc_arg *args) { @@ -542,7 +634,6 @@ spc_handler_pdfm_annot (struct spc_env *spe, struct spc_arg *args) pdf_obj *annot_dict; pdf_rect rect; char *ident = NULL; - pdf_coord cp; transform_info ti; skip_white(&args->curptr, args->endptr); @@ -576,19 +667,96 @@ spc_handler_pdfm_annot (struct spc_env *spe, struct spc_arg *args) return -1; } - cp.x = spe->x_user; cp.y = spe->y_user; - pdf_dev_transform(&cp, NULL); - if (ti.flags & INFO_HAS_USER_BBOX) { - rect.llx = ti.bbox.llx + cp.x; - rect.lly = ti.bbox.lly + cp.y; - rect.urx = ti.bbox.urx + cp.x; - rect.ury = ti.bbox.ury + cp.y; - } else { - rect.llx = cp.x; - rect.lly = cp.y - spe->mag * ti.depth; - rect.urx = cp.x + spe->mag * ti.width; - rect.ury = cp.y + spe->mag * ti.height; +#ifdef SPC_PDFM_SUPPORT_ANNOT_TRANS + { + pdf_coord cp1, cp2, cp3, cp4; + /* QuadPoints not working? */ +#ifdef USE_QUADPOINTS + pdf_obj *qpoints; +#endif + if (ti.flags & INFO_HAS_USER_BBOX) { + cp1.x = spe->x_user + ti.bbox.llx; + cp1.y = spe->y_user + ti.bbox.lly; + cp2.x = spe->x_user + ti.bbox.urx; + cp2.y = spe->y_user + ti.bbox.lly; + cp3.x = spe->x_user + ti.bbox.urx; + cp3.y = spe->y_user + ti.bbox.ury; + cp4.x = spe->x_user + ti.bbox.llx; + cp4.y = spe->y_user + ti.bbox.ury; + } else { + cp1.x = spe->x_user; + cp1.y = spe->y_user - spe->mag * ti.depth; + cp2.x = spe->x_user + spe->mag * ti.width; + cp2.y = spe->y_user - spe->mag * ti.depth; + cp3.x = spe->x_user + spe->mag * ti.width; + cp3.y = spe->y_user + spe->mag * ti.height; + cp4.x = spe->x_user; + cp4.y = spe->y_user + spe->mag * ti.height; + } + pdf_dev_transform(&cp1, NULL); + pdf_dev_transform(&cp2, NULL); + pdf_dev_transform(&cp3, NULL); + pdf_dev_transform(&cp4, NULL); + rect.llx = cp1.x; + if (cp2.x < rect.llx) + rect.llx = cp2.x; + if (cp3.x < rect.llx) + rect.llx = cp3.x; + if (cp4.x < rect.llx) + rect.llx = cp4.x; + rect.urx = cp1.x; + if (cp2.x > rect.urx) + rect.urx = cp2.x; + if (cp3.x > rect.urx) + rect.urx = cp3.x; + if (cp4.x > rect.urx) + rect.urx = cp4.x; + rect.lly = cp1.y; + if (cp2.y < rect.lly) + rect.lly = cp2.y; + if (cp3.y < rect.lly) + rect.lly = cp3.y; + if (cp4.y < rect.lly) + rect.lly = cp4.y; + rect.ury = cp1.y; + if (cp2.y > rect.ury) + rect.ury = cp2.y; + if (cp3.y > rect.ury) + rect.ury = cp3.y; + if (cp4.y > rect.ury) + rect.ury = cp4.y; +#ifdef USE_QUADPOINTS + qpoints = pdf_new_array(); + pdf_add_array(qpoints, pdf_new_number(ROUND(cp1.x, 0.01))); + pdf_add_array(qpoints, pdf_new_number(ROUND(cp1.y, 0.01))); + pdf_add_array(qpoints, pdf_new_number(ROUND(cp2.x, 0.01))); + pdf_add_array(qpoints, pdf_new_number(ROUND(cp2.y, 0.01))); + pdf_add_array(qpoints, pdf_new_number(ROUND(cp3.x, 0.01))); + pdf_add_array(qpoints, pdf_new_number(ROUND(cp3.y, 0.01))); + pdf_add_array(qpoints, pdf_new_number(ROUND(cp4.x, 0.01))); + pdf_add_array(qpoints, pdf_new_number(ROUND(cp4.y, 0.01))); + pdf_add_dict(annot_dict, pdf_new_name("QuadPoints"), qpoints); +#endif + } +#else + { + pdf_coord cp; + + cp.x = spe->x_user; cp.y = spe->y_user; + pdf_dev_transform(&cp, NULL); + if (ti.flags & INFO_HAS_USER_BBOX) { + rect.llx = ti.bbox.llx + cp.x; + rect.lly = ti.bbox.lly + cp.y; + rect.urx = ti.bbox.urx + cp.x; + rect.ury = ti.bbox.ury + cp.y; + } else { + rect.llx = cp.x; + rect.lly = cp.y - spe->mag * ti.depth; + rect.urx = cp.x + spe->mag * ti.width; + rect.ury = cp.y + spe->mag * ti.height; + } } +#endif /* Order is important... */ if (ident) @@ -1407,8 +1575,7 @@ spc_handler_pdfm_stream_with_type (struct spc_env *spe, struct spc_arg *args, in break; case STRING_STREAM: fstream = pdf_new_stream(STREAM_COMPRESS); - if (instring) - pdf_add_stream(fstream, instring, strlen(instring)); + pdf_add_stream(fstream, pdf_string_value(tmp), pdf_string_length(tmp)); break; default: pdf_release_obj(tmp); @@ -1562,7 +1729,8 @@ spc_handler_pdfm_bform (struct spc_env *spe, struct spc_arg *args) static int spc_handler_pdfm_eform (struct spc_env *spe, struct spc_arg *args) { - pdf_obj *attrib = NULL; + pdf_obj *attrib = NULL; + struct spc_pdf_ *sd = &_pdf_stat; skip_white(&args->curptr, args->endptr); @@ -1573,6 +1741,10 @@ spc_handler_pdfm_eform (struct spc_env *spe, struct spc_arg *args) attrib = NULL; } } + /* pageresources here too */ + if (sd->pageresources) { + pdf_foreach_dict(sd->pageresources, forallresourcecategory, NULL); + } pdf_doc_end_grabbing(attrib); return 0; @@ -1687,15 +1859,17 @@ spc_handler_pdfm_bgcolor (struct spc_env *spe, struct spc_arg *args) return error; } +#define THEBUFFLENGTH 1024 static int spc_handler_pdfm_mapline (struct spc_env *spe, struct spc_arg *ap) { fontmap_rec *mrec; char *map_name, opchr; int error = 0; - static char buffer[1024]; + static char buffer[THEBUFFLENGTH]; const char *p; char *q; + int count; skip_white(&ap->curptr, ap->endptr); if (ap->curptr >= ap->endptr) { @@ -1723,8 +1897,16 @@ spc_handler_pdfm_mapline (struct spc_env *spe, struct spc_arg *ap) default: p = ap->curptr; q = buffer; - while (p < ap->endptr) + count = 0; + while (p < ap->endptr && count < THEBUFFLENGTH - 1) { *q++ = *p++; + count++; + } + if (count == THEBUFFLENGTH - 1) { + spc_warn(spe, "Invalid fontmap line: Too long a line."); + *q = 0; + return -1; + } *q = '\0'; mrec = NEW(1, fontmap_rec); pdf_init_fontmap_record(mrec); @@ -1787,6 +1969,7 @@ spc_handler_pdfm_tounicode (struct spc_env *spe, struct spc_arg *args) { struct spc_pdf_ *sd = &_pdf_stat; char *cmap_name; + pdf_obj *taint_keys; /* First clear */ sd->cd.cmap_id = -1; @@ -1827,9 +2010,70 @@ spc_handler_pdfm_tounicode (struct spc_env *spe, struct spc_arg *args) sd->cd.unescape_backslash = 1; } free(cmap_name); + + /* Additional "taint key" + * An array of PDF name objects can be supplied optionally. + * Dictionary entries specified by this option will be added to the list + * of dictionary keys to be treated as the target of "ToUnicode" conversion. + */ + skip_white(&args->curptr, args->endptr); + if (args->curptr < args->endptr) { + taint_keys = parse_pdf_object(&args->curptr, args->endptr, NULL); + if (taint_keys) { + if (PDF_OBJ_ARRAYTYPE(taint_keys)) { + int i; + for (i = 0; i < pdf_array_length(taint_keys); i++) { + pdf_obj *key; + + key = pdf_get_array(taint_keys, i); + if (PDF_OBJ_NAMETYPE(key)) + pdf_add_array(sd->cd.taintkeys, pdf_link_obj(key)); + else { + spc_warn(spe, "Invalid argument specified in pdf:tounicode special."); + } + } + } else { + spc_warn(spe, "Invalid argument specified in pdf:unicode special."); + } + pdf_release_obj(taint_keys); + } + } + return 0; } +static int +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); + if (!dict) { + spc_warn(spe, "Dictionary object expected but not found."); + return -1; + } + + if (sd->pageresources) + pdf_release_obj(sd->pageresources); + sd->pageresources = dict; + + return 0; +} + +static int +spc_handler_pdft_compat_page (struct spc_env *spe, struct spc_arg *args) +{ + skip_white(&args->curptr, args->endptr); + if (args->curptr < args->endptr) { + pdf_doc_add_page_content(" ", 1); /* op: */ + pdf_doc_add_page_content(args->curptr, (int) (args->endptr - args->curptr)); /* op: ANY */ + } + + args->curptr = args->endptr; + + return 0; +} static struct spc_handler pdfm_handlers[] = { {"annotation", spc_handler_pdfm_annot}, @@ -1939,7 +2183,20 @@ static struct spc_handler pdfm_handlers[] = { {"code", spc_handler_pdfm_code}, {"minorversion", spc_handler_pdfm_do_nothing}, + {"majorversion", spc_handler_pdfm_do_nothing}, {"encrypt", spc_handler_pdfm_do_nothing}, + + {"pageresources", spc_handler_pdfm_pageresources}, + {"trailerid", spc_handler_pdfm_do_nothing}, +}; + +static struct spc_handler pdft_compat_handlers[] = { + /* Text supplied to "direct" command should go inside of BT/ET block + * but dvipdfmx currently can't be implemented so. + * Here, "direct" is for the moment just an alias of "page". + */ + {"direct", spc_handler_pdft_compat_page}, + {"page", spc_handler_pdft_compat_page}, }; bool @@ -1980,15 +2237,34 @@ spc_pdfm_setup_handler (struct spc_handler *sph, skip_white(&ap->curptr, ap->endptr); q = parse_c_ident(&ap->curptr, ap->endptr); if (q) { - for (i = 0; - i < sizeof(pdfm_handlers) / sizeof(struct spc_handler); i++) { - if (streq_ptr(q, pdfm_handlers[i].key)) { - ap->command = pdfm_handlers[i].key; - sph->key = "pdf:"; - sph->exec = pdfm_handlers[i].exec; - skip_white(&ap->curptr, ap->endptr); - error = 0; - break; + int is_pdft_compat = 0; + if (ap->curptr < ap->endptr) { + if (ap->curptr[0] == ':') { + is_pdft_compat = 1; + ap->curptr++; + } + } + if (is_pdft_compat) { + for (i = 0; i < sizeof(pdft_compat_handlers) / sizeof(struct spc_handler); i++) { + if (!strcmp(q, pdft_compat_handlers[i].key)) { + ap->command = pdft_compat_handlers[i].key; + sph->key = "pdf:"; + sph->exec = pdft_compat_handlers[i].exec; + skip_white(&ap->curptr, ap->endptr); + error = 0; + break; + } + } + } else { + for (i = 0; i < sizeof(pdfm_handlers) / sizeof(struct spc_handler); i++) { + if (!strcmp(q, pdfm_handlers[i].key)) { + ap->command = pdfm_handlers[i].key; + sph->key = "pdf:"; + sph->exec = pdfm_handlers[i].exec; + skip_white(&ap->curptr, ap->endptr); + error = 0; + break; + } } } free(q); diff --git a/tectonic/dpx-spc_pdfm.h b/tectonic/dpx-spc_pdfm.h index 409fdefc2e..2492afb89e 100644 --- a/tectonic/dpx-spc_pdfm.h +++ b/tectonic/dpx-spc_pdfm.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -32,6 +32,8 @@ int spc_pdfm_at_begin_document (void); int spc_pdfm_at_end_document (void); +int spc_pdfm_at_end_page (void); + bool spc_pdfm_check_special (const char *buffer, int size); int spc_pdfm_setup_handler (struct spc_handler *handle, struct spc_env *spe, struct spc_arg *args); diff --git a/tectonic/dpx-spc_tpic.c b/tectonic/dpx-spc_tpic.c index 5a4961baca..96672a01c5 100644 --- a/tectonic/dpx-spc_tpic.c +++ b/tectonic/dpx-spc_tpic.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -175,7 +175,7 @@ set_fillstyle (double g, double a, int f_ais) { pdf_obj *dict; char resname[32]; - char buf[38]; + char buf[256]; int alp, len = 0; if (a > 0.0) { @@ -758,7 +758,8 @@ spc_handler_tpic__init (struct spc_env *spe, void *dp) tp->num_points = 0; tp->max_points = 0; - if (tp->mode.fill != TPIC_MODE__FILL_SOLID && pdf_get_version() < 4) { + if (tp->mode.fill != TPIC_MODE__FILL_SOLID && + pdf_check_version(1, 4) < 0) { spc_warn(spe, "Tpic shading support requires PDF version 1.4."); tp->mode.fill = TPIC_MODE__FILL_SOLID; } @@ -949,7 +950,7 @@ spc_handler_tpic__setopts (struct spc_env *spe, error = pdf_foreach_dict(dict, tpic_filter_getopts, tp); if (!error) { if (tp->mode.fill != TPIC_MODE__FILL_SOLID && - pdf_get_version() < 4) { + pdf_check_version(1, 4) < 0) { spc_warn(spe, "Transparent fill mode requires PDF version 1.4."); tp->mode.fill = TPIC_MODE__FILL_SOLID; } diff --git a/tectonic/dpx-spc_util.c b/tectonic/dpx-spc_util.c index 61c44c269a..84983e4107 100644 --- a/tectonic/dpx-spc_util.c +++ b/tectonic/dpx-spc_util.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -30,6 +30,7 @@ #include "dpx-dpxutil.h" #include "dpx-pdfcolor.h" #include "dpx-pdfdev.h" +#include "dpx-pdfdoc.h" #include "dpx-pdfdraw.h" #include "dpx-pdfparse.h" #include "dpx-specials.h" @@ -716,7 +717,8 @@ spc_util_read_dimtrns (struct spc_env *spe, int spc_util_read_blahblah (struct spc_env *spe, - transform_info *p, int *page_no, int *bbox_type, + transform_info *p, int *page_no, + enum pdf_page_boundary *bbox_type, struct spc_arg *ap) { int has_scale, has_xscale, has_yscale, has_rotate, has_matrix; @@ -862,15 +864,15 @@ spc_util_read_blahblah (struct spc_env *spe, q = parse_c_ident (&ap->curptr, ap->endptr); if (q) { if (bbox_type) { - if (strcasecmp(q, "cropbox") == 0) *bbox_type = 1; - else if (strcasecmp(q, "mediabox") == 0) *bbox_type = 2; - else if (strcasecmp(q, "artbox") == 0) *bbox_type = 3; - else if (strcasecmp(q, "trimbox") == 0) *bbox_type = 4; - else if (strcasecmp(q, "bleedbox") == 0) *bbox_type = 5; + if (strcasecmp(q, "cropbox") == 0) *bbox_type = pdf_page_boundary_cropbox; + else if (strcasecmp(q, "mediabox") == 0) *bbox_type = pdf_page_boundary_mediabox; + else if (strcasecmp(q, "artbox") == 0) *bbox_type = pdf_page_boundary_artbox; + else if (strcasecmp(q, "trimbox") == 0) *bbox_type = pdf_page_boundary_trimbox; + else if (strcasecmp(q, "bleedbox") == 0) *bbox_type = pdf_page_boundary_bleedbox; } free(q); } else if (bbox_type) { - *bbox_type = 0; + *bbox_type = pdf_page_boundary__auto; } } break; diff --git a/tectonic/dpx-spc_util.h b/tectonic/dpx-spc_util.h index edf07c9e5a..b6fac9b5ae 100644 --- a/tectonic/dpx-spc_util.h +++ b/tectonic/dpx-spc_util.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -27,6 +27,7 @@ #include "dpx-pdfcolor.h" #include "dpx-pdfdev.h" +#include "dpx-pdfdoc.h" #include "dpx-specials.h" @@ -45,7 +46,7 @@ int spc_util_read_dimtrns (struct spc_env *spe, int spc_util_read_blahblah (struct spc_env *spe, transform_info *dimtrns, int *page_no, - int *bbox_type, + enum pdf_page_boundary *bbox_type, struct spc_arg *args); diff --git a/tectonic/dpx-spc_xtx.c b/tectonic/dpx-spc_xtx.c index 867d185d55..550ab40950 100644 --- a/tectonic/dpx-spc_xtx.c +++ b/tectonic/dpx-spc_xtx.c @@ -1,7 +1,7 @@ /* This is xdvipdfmx, an extended version of dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2013-2016 by the dvipdfmx project team. + Copyright (C) 2013-2019 by the dvipdfmx project team. Copyright (c) 2006 SIL International Originally written by Jonathan Kew @@ -185,15 +185,17 @@ spc_handler_xtx_backgroundcolor (struct spc_env *spe, struct spc_arg *args) } /* FIXME: xdv2pdf's x:fontmapline and x:fontmapfile may have slightly different syntax/semantics */ +#define THEBUFFLENGTH 1024 static int spc_handler_xtx_fontmapline (struct spc_env *spe, struct spc_arg *ap) { fontmap_rec *mrec; char *map_name, opchr; int error = 0; - static char buffer[1024]; + static char buffer[THEBUFFLENGTH]; const char *p; char *q; + int count; skip_white(&ap->curptr, ap->endptr); if (ap->curptr >= ap->endptr) { @@ -221,8 +223,16 @@ spc_handler_xtx_fontmapline (struct spc_env *spe, struct spc_arg *ap) default: p = ap->curptr; q = buffer; - while (p < ap->endptr) + count = 0; + while (p < ap->endptr && count < THEBUFFLENGTH - 1) { *q++ = *p++; + count++; + } + if (count == THEBUFFLENGTH - 1) { + spc_warn(spe, "Invalid fontmap line: Too long a line."); + *q = 0; + return -1; + } *q = '\0'; mrec = NEW(1, fontmap_rec); pdf_init_fontmap_record(mrec); diff --git a/tectonic/dpx-specials.c b/tectonic/dpx-specials.c index e99ae3a950..39c2395417 100644 --- a/tectonic/dpx-specials.c +++ b/tectonic/dpx-specials.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-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -31,6 +31,7 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dvi.h" #include "dpx-error.h" #include "dpx-numbers.h" @@ -49,14 +50,6 @@ #include "dpx-spc_tpic.h" #include "dpx-spc_xtx.h" -static int verbose = 0; -void -spc_set_verbose (int level) -{ - verbose = level; -} - - void spc_warn (struct spc_env *spe, const char *fmt, ...) { @@ -65,7 +58,7 @@ spc_warn (struct spc_env *spe, const char *fmt, ...) va_start(ap, fmt); - vsprintf(buf, fmt, ap); + vsnprintf(buf, 1024, fmt, ap); dpx_warning("%s", buf); va_end(ap); @@ -168,12 +161,12 @@ spc_lookup_reference (const char *key) switch (k) { /* xpos and ypos must be position in device space here. */ case K_OBJ__XPOS: - cp.x = dvi_dev_xpos(); cp.y = 0.0; + cp.x = dvi_dev_xpos(); cp.y = dvi_dev_ypos(); pdf_dev_transform(&cp, NULL); value = pdf_new_number(ROUND(cp.x, .01)); break; case K_OBJ__YPOS: - cp.x = 0.0; cp.y = dvi_dev_ypos(); + cp.x = dvi_dev_xpos(); cp.y = dvi_dev_ypos(); pdf_dev_transform(&cp, NULL); value = pdf_new_number(ROUND(cp.y, .01)); break; @@ -232,12 +225,12 @@ spc_lookup_object (const char *key) for (k = 0; _rkeys[k] && strcmp(key, _rkeys[k]); k++); switch (k) { case K_OBJ__XPOS: - cp.x = dvi_dev_xpos(); cp.y = 0.0; + cp.x = dvi_dev_xpos(); cp.y = dvi_dev_ypos(); pdf_dev_transform(&cp, NULL); value = pdf_new_number(ROUND(cp.x, .01)); break; case K_OBJ__YPOS: - cp.x = 0.0; cp.y = dvi_dev_ypos(); + cp.x = dvi_dev_xpos(); cp.y = dvi_dev_ypos(); pdf_dev_transform(&cp, NULL); value = pdf_new_number(ROUND(cp.y, .01)); break; @@ -364,7 +357,7 @@ static struct { spc_pdfm_at_begin_document, spc_pdfm_at_end_document, NULL, - NULL, + spc_pdfm_at_end_page, spc_pdfm_check_special, spc_pdfm_setup_handler }, @@ -565,7 +558,8 @@ spc_exec_special (const char *buffer, int32_t size, struct spc_arg args; struct spc_handler special; - if (verbose > 3) { + if (dpx_conf.verbose_level > 3) { + dpx_message("Executing special command: "); dump(buffer, buffer + size); } @@ -589,4 +583,3 @@ spc_exec_special (const char *buffer, int32_t size, return error; } - diff --git a/tectonic/dpx-specials.h b/tectonic/dpx-specials.h index 608c4a7325..a9fb6e3787 100644 --- a/tectonic/dpx-specials.h +++ b/tectonic/dpx-specials.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -46,9 +46,6 @@ struct spc_handler { spc_handler_fn_ptr exec; }; -/* This should not use pdf_. */ -void spc_set_verbose (int level); - #include #include diff --git a/tectonic/dpx-subfont.c b/tectonic/dpx-subfont.c index 913189b56f..e1f662dcb8 100644 --- a/tectonic/dpx-subfont.c +++ b/tectonic/dpx-subfont.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -27,18 +27,12 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" #include "dpx-error.h" #include "dpx-mem.h" #include "dpx-mfileio.h" -static int verbose = 0; -void -subfont_set_verbose (int level) -{ - verbose = level; -} - /* Don't forget fontmap reading now requires information * from SFD files. You must initialize at least sfd_file_ * cache before starting loading of fontmaps. @@ -247,7 +241,7 @@ scan_sfd_file (struct sfd_file_ *sfd, rust_input_handle_t handle) assert( sfd && handle ); - if (verbose > 3) { + if (dpx_conf.verbose_level > 3) { dpx_message("\nsubfont>> Scanning SFD file \"%s\"...\n", sfd->ident); } @@ -269,7 +263,7 @@ scan_sfd_file (struct sfd_file_ *sfd, rust_input_handle_t handle) sfd->sub_id = RENEW(sfd->sub_id, sfd->max_subfonts, char *); } - if (verbose > 3) { + if (dpx_conf.verbose_level > 3) { dpx_message("subfont>> id=\"%s\" at line=\"%d\"\n", id, lpos); } sfd->sub_id[sfd->num_subfonts] = id; @@ -281,7 +275,7 @@ scan_sfd_file (struct sfd_file_ *sfd, rust_input_handle_t handle) sfd->rec_id[n] = -1; /* Not loaded yet. We do lazy loading of map definitions. */ } - if (verbose > 3) { + if (dpx_conf.verbose_level > 3) { dpx_message("subfont>> %d entries found in SFD file \"%s\".\n", sfd->num_subfonts, sfd->ident); } @@ -385,7 +379,7 @@ sfd_load_record (const char *sfd_name, const char *subfont_id) return sfd->rec_id[i]; } - if (verbose > 3) { + if (dpx_conf.verbose_level > 3) { dpx_message("\nsubfont>> Loading SFD mapping table for <%s,%s>...", sfd->ident, subfont_id); } @@ -428,7 +422,7 @@ sfd_load_record (const char *sfd_name, const char *subfont_id) sfd->rec_id[i] = rec_id; ttstub_input_close(handle); - if (verbose > 3) { + if (dpx_conf.verbose_level > 3) { int __i; if (rec_id >= 0) { dpx_message(" at id=\"%d\"", rec_id); diff --git a/tectonic/dpx-subfont.h b/tectonic/dpx-subfont.h index ce104cc02a..138307ce25 100644 --- a/tectonic/dpx-subfont.h +++ b/tectonic/dpx-subfont.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -23,8 +23,6 @@ #include "dpx-core.h" -void subfont_set_verbose (int level); - void release_sfd_record (void); unsigned short lookup_sfd_record(int rec_id, unsigned char code); diff --git a/tectonic/dpx-system.h b/tectonic/dpx-system.h index 2a36d91e27..ed8572a74c 100644 --- a/tectonic/dpx-system.h +++ b/tectonic/dpx-system.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-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks diff --git a/tectonic/dpx-t1_char.c b/tectonic/dpx-t1_char.c index dbf493b378..3dafcc078d 100644 --- a/tectonic/dpx-t1_char.c +++ b/tectonic/dpx-t1_char.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -869,7 +869,7 @@ do_operator2 (t1_chardesc *cd, card8 **data, card8 *endptr) * (See, Adobe Technical Note #5177, Appendix C) */ if (!(cd->flags & T1_CS_FLAG_USE_HINTMASK)) { - if (__verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_warning("Obsolete Type 1 charstring operator \"dotsection\" not supported."); } #endif diff --git a/tectonic/dpx-tfm.c b/tectonic/dpx-tfm.c index cbf7e9b07f..ab048a6c5a 100644 --- a/tectonic/dpx-tfm.c +++ b/tectonic/dpx-tfm.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -30,6 +30,7 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dpxutil.h" #include "dpx-error.h" #include "dpx-mem.h" @@ -40,8 +41,6 @@ #define FWBASE ((double) (1<<20)) -static int verbose = 0; - #define CHARACTER_INDEX(i) ((i)) /* @@ -261,13 +260,6 @@ fms_need (unsigned n) } } -void -tfm_set_verbose (int level) -{ - verbose = level; -} - - static int fread_fwords (fixword *words, uint32_t nmemb, rust_input_handle_t handle) { @@ -742,7 +734,7 @@ tfm_open (const char *tfm_name, int must_exist) return -1; } - if (verbose) { + if (dpx_conf.verbose_level > 0) { if (format == TFM_FORMAT) dpx_message("(TFM:%s", tfm_name); else if (format == OFM_FORMAT) @@ -768,7 +760,7 @@ tfm_open (const char *tfm_name, int must_exist) fms[numfms].tex_name = NEW(strlen(tfm_name)+1, char); strcpy(fms[numfms].tex_name, tfm_name); - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_message(")"); return numfms++; diff --git a/tectonic/dpx-tfm.h b/tectonic/dpx-tfm.h index 217a50a2a8..d4eacedc4d 100644 --- a/tectonic/dpx-tfm.h +++ b/tectonic/dpx-tfm.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -30,7 +30,6 @@ #include "dpx-numbers.h" -void tfm_set_verbose (int level); void tfm_reset_global_state(void); int tfm_open (const char * tex_name, int must_exist); diff --git a/tectonic/dpx-truetype.c b/tectonic/dpx-truetype.c index deb0911459..9e0f37196c 100644 --- a/tectonic/dpx-truetype.c +++ b/tectonic/dpx-truetype.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -28,6 +28,7 @@ #include "core-bridge.h" #include "dpx-agl.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" #include "dpx-dpxutil.h" #include "dpx-error.h" @@ -122,18 +123,7 @@ pdf_font_open_truetype (pdf_font *font) length = tt_get_ps_fontname(sfont, fontname, 255); if (length < 1) { length = MIN(strlen(ident), 255); -/* Suppress some warnings on GCC. Clang supports the same warning control - * #pragmas (and #defines __GNUC__!), but not these particular warnings, which - * leads to a meta-warning if they're left unguarded. */ -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstringop-overflow" -#pragma GCC diagnostic ignored "-Wstringop-truncation" -#endif - strncpy(fontname, ident, length); -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif + memcpy(fontname, ident, length); } fontname[length] = '\0'; for (n = 0; n < length; n++) { @@ -275,8 +265,6 @@ do_widths (pdf_font *font, double *widths) return; } -static int verbose = 0; - #define PDFUNIT(v) ((double) (ROUND(1000.0*(v)/(glyphs->emsize), 1))) /* @@ -316,7 +304,7 @@ do_builtin_encoding (pdf_font *font, const char *usedchars, sfnt *sfont) glyphs = tt_build_init(); - if (verbose > 2) + if (dpx_conf.verbose_level > 2) dpx_message("[glyphs:/.notdef"); count = 1; /* .notdef */ @@ -324,7 +312,7 @@ do_builtin_encoding (pdf_font *font, const char *usedchars, sfnt *sfont) if (!usedchars[code]) continue; - if (verbose > 2) + if (dpx_conf.verbose_level > 2) dpx_message("/.c0x%02x", code); gid = tt_cmap_lookup(ttcm, code); @@ -342,7 +330,7 @@ do_builtin_encoding (pdf_font *font, const char *usedchars, sfnt *sfont) } tt_cmap_release(ttcm); - if (verbose > 2) + if (dpx_conf.verbose_level > 2) dpx_message("]"); if (tt_build_tables(sfont, glyphs) < 0) { @@ -362,7 +350,7 @@ do_builtin_encoding (pdf_font *font, const char *usedchars, sfnt *sfont) } do_widths(font, widths); - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("[%d glyphs]", glyphs->num_glyphs); tt_build_finish(glyphs); @@ -426,7 +414,7 @@ select_gsub (const char *feat, struct glyph_mapper *gm) if (idx >= 0) return 0; - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("\ntrutype>> Try loading OTL GSUB for \"*.*.%s\"...", feat); error = otl_gsub_add_feat(gm->gsub, "*", "*", feat, gm->sfont); if (!error) { @@ -643,11 +631,11 @@ findparanoiac (const char *glyphname, USHORT *gid, struct glyph_mapper *gm) if (agln->n_components == 1) idx = tt_cmap_lookup(gm->codetogid, agln->unicodes[0]); else if (agln->n_components > 1) { - if (verbose >= 0) /* give warning */ + if (dpx_conf.verbose_level >= 0) /* give warning */ dpx_warning("Glyph \"%s\" looks like a composite glyph...", agln->name); error = composeuchar(agln->unicodes, agln->n_components, NULL, gm, &idx); - if (verbose >= 0) { + if (dpx_conf.verbose_level >= 0) { if (error) dpx_warning("Not found..."); else { @@ -822,7 +810,7 @@ do_custom_encoding (pdf_font *font, dpx_warning("Glyph \"%s\" not available in font \"%s\".", encoding[code], pdf_font_get_ident(font)); } else { - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("truetype>> Glyph glyph-name=\"%s\" found at glyph-id=\"%u\".\n", encoding[code], gid); } idx = tt_find_glyph(glyphs, gid); @@ -852,7 +840,7 @@ do_custom_encoding (pdf_font *font, } do_widths(font, widths); - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("[%d glyphs]", glyphs->num_glyphs); tt_build_finish(glyphs); @@ -882,8 +870,6 @@ pdf_font_load_truetype (pdf_font *font) if (!pdf_font_is_in_use(font)) return 0; - verbose = pdf_font_get_verbose(); - handle = dpx_open_truetype_file(ident); if (handle == NULL) { handle = dpx_open_dfont_file(ident); @@ -969,7 +955,7 @@ pdf_font_load_truetype (pdf_font *font) sfnt_close(sfont); ttstub_input_close(handle); - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("[%d bytes]", pdf_stream_length(fontfile)); pdf_add_dict(descriptor, diff --git a/tectonic/dpx-tt_aux.c b/tectonic/dpx-tt_aux.c index d5c506b7f4..2e7708cd01 100644 --- a/tectonic/dpx-tt_aux.c +++ b/tectonic/dpx-tt_aux.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -24,6 +24,7 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-error.h" #include "dpx-numbers.h" #include "dpx-pdfobj.h" @@ -31,13 +32,6 @@ #include "dpx-tt_post.h" #include "dpx-tt_table.h" -static int verbose = 0; - -void tt_aux_set_verbose(int level) -{ - verbose = level; -} - ULONG ttc_read_offset (sfnt *sfont, int ttc_idx) { ULONG offset = 0, num_dirs = 0; @@ -177,17 +171,17 @@ pdf_obj *tt_get_fontdesc (sfnt *sfont, int *embed, int stemv, int type, const ch /* the least restrictive license granted takes precedence. */ *embed = 1; } else if (os2->fsType & 0x0004) { - if (verbose > 0) + if (dpx_conf.verbose_level > 0) dpx_warning("Font \"%s\" permits \"Preview & Print\" embedding only **\n", fontname); *embed = 1; } else { - if (always_embed) { - if (verbose > 0) + if (dpx_conf.ignore_font_license) { + if (dpx_conf.verbose_level > 0) dpx_warning("Font \"%s\" may be subject to embedding restrictions **\n", fontname); *embed = 1; } else { - if (verbose > 0) + if (dpx_conf.verbose_level > 0) dpx_warning("Embedding of font \"%s\" disabled due to license restrictions", fontname); *embed = 0; } diff --git a/tectonic/dpx-tt_aux.h b/tectonic/dpx-tt_aux.h index e5557cc7c2..9151007861 100644 --- a/tectonic/dpx-tt_aux.h +++ b/tectonic/dpx-tt_aux.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -28,8 +28,6 @@ extern int always_embed; /* flag declared in dvipdfmx.c */ -void tt_aux_set_verbose(int level); - /* TTC (TrueType Collection) */ ULONG ttc_read_offset (sfnt *sfont, int ttc_idx); diff --git a/tectonic/dpx-tt_cmap.c b/tectonic/dpx-tt_cmap.c index 8dfce4cb97..7b6f954931 100644 --- a/tectonic/dpx-tt_cmap.c +++ b/tectonic/dpx-tt_cmap.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -38,6 +38,7 @@ */ #include "dpx-cmap.h" #include "dpx-cmap_write.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" /* Hash */ #include "dpx-dpxutil.h" @@ -52,13 +53,6 @@ #include "dpx-unicode.h" #define VERBOSE_LEVEL_MIN 0 -static int verbose = 0; -void -otf_cmap_set_verbose (int level) -{ - otl_gsub_set_verbose(level); - verbose = level; -} /* format 0: byte encoding table */ struct cmap0 @@ -72,11 +66,12 @@ read_cmap0 (sfnt *sfont, ULONG len) struct cmap0 *map; unsigned int i; - if (len < 256) - _tt_abort("invalid cmap subtable"); + if (len < 256) { + dpx_warning("invalid format 0 TT cmap subtable"); + return NULL; + } map = NEW(1, struct cmap0); - for (i = 0; i < 256; i++) map->glyphIndexArray[i] = sfnt_get_byte(sfont); @@ -117,20 +112,25 @@ read_cmap2 (sfnt *sfont, ULONG len) struct cmap2 *map; USHORT i, n; - if (len < 512) - _tt_abort("invalid cmap subtable"); + if (len < 512) { + dpx_warning("invalid fromt2 TT cmap subtable"); + return NULL; + } map = NEW(1, struct cmap2); - for (i = 0; i < 256; i++) map->subHeaderKeys[i] = sfnt_get_ushort(sfont); - for (n = 0, i = 0; i < 256; i++) { map->subHeaderKeys[i] /= 8; if (n < map->subHeaderKeys[i]) n = map->subHeaderKeys[i]; } n += 1; /* the number of subHeaders is one plus the max of subHeaderKeys */ + if (len < 512 + n * 8 ) { + dpx_warning("invalid/truncated format2 TT cmap subtable"); + free(map); + return NULL; + } map->subHeaders = NEW(n, struct SubHeader); for (i = 0; i < n; i++) { @@ -223,8 +223,10 @@ read_cmap4(sfnt *sfont, ULONG len) struct cmap4 *map; USHORT i, n, segCount; - if (len < 8) - _tt_abort("invalid cmap subtable"); + if (len < 8) { + dpx_warning("invalid format 4 TT cmap subtable"); + return NULL; + } map = NEW(1, struct cmap4); @@ -289,7 +291,7 @@ lookup_cmap4 (struct cmap4 *map, USHORT cc) * Last segment maps 0xffff to gid 0 (?) */ i = segCount = map->segCountX2 / 2; - while (i-- > 0 && cc <= map->endCount[i]) { + while (i-- > 0 && cc <= map->endCount[i]) { if (cc >= map->startCount[i]) { if (map->idRangeOffset[i] == 0) { gid = (cc + map->idDelta[i]) & 0xffff; @@ -324,14 +326,15 @@ read_cmap6 (sfnt *sfont, ULONG len) struct cmap6 *map; USHORT i; - if (len < 4) - _tt_abort("invalid cmap subtable"); + if (len < 4) { + dpx_warning("invalid foramt 6 TT cmap subtable"); + return NULL; + } map = NEW(1, struct cmap6); map->firstCode = sfnt_get_ushort(sfont); map->entryCount = sfnt_get_ushort(sfont); map->glyphIndexArray = NEW(map->entryCount, USHORT); - for (i = 0; i < map->entryCount; i++) map->glyphIndexArray[i] = sfnt_get_ushort(sfont); @@ -390,13 +393,14 @@ read_cmap12 (sfnt *sfont, ULONG len) struct cmap12 *map; ULONG i; - if (len < 4) - _tt_abort("invalid cmap subtable"); + if (len < 4) { + dpx_warning("invalid format 12 TT cmap subtable"); + return NULL; + } map = NEW(1, struct cmap12); map->nGroups = sfnt_get_ulong(sfont); map->groups = NEW(map->nGroups, struct charGroup); - for (i = 0; i < map->nGroups; i++) { map->groups[i].startCharCode = sfnt_get_ulong(sfont); map->groups[i].endCharCode = sfnt_get_ulong(sfont); @@ -525,7 +529,7 @@ tt_cmap_release (tt_cmap *cmap) if (cmap) { if (cmap->map) { - switch(cmap->format) { + switch (cmap->format) { case 0: release_cmap0(cmap->map); break; @@ -542,7 +546,8 @@ tt_cmap_release (tt_cmap *cmap) release_cmap12(cmap->map); break; default: - _tt_abort("Unrecognized OpenType/TrueType cmap format."); + dpx_warning("Unrecognized OpenType/TrueType cmap format: %d", cmap->format); + break; } } free(cmap); @@ -581,210 +586,58 @@ tt_cmap_lookup (tt_cmap *cmap, ULONG cc) gid = lookup_cmap12(cmap->map, (ULONG) cc); break; default: - _tt_abort("Unrecognized OpenType/TrueType cmap subtable format"); + dpx_warning("Unrecognized OpenType/TrueType cmap subtable format: %d", cmap->format); break; } return gid; } -/* Sorry for placing this here. - * We need to rewrite TrueType font support code... - */ - -#define WBUF_SIZE 1024 -static unsigned char wbuf[WBUF_SIZE]; - static unsigned char srange_min[2] = {0x00, 0x00}; static unsigned char srange_max[2] = {0xff, 0xff}; static unsigned char lrange_min[4] = {0x00, 0x00, 0x00, 0x00}; static unsigned char lrange_max[4] = {0x7f, 0xff, 0xff, 0xff}; -static void -load_cmap4 (struct cmap4 *map, - unsigned char *GIDToCIDMap, - otl_gsub *gsub_vert, otl_gsub *gsub_list, - CMap *cmap, CMap *tounicode_add) -{ - USHORT c0, c1, gid, cid; - USHORT j, d, segCount; - USHORT ch; - int i; - - segCount = map->segCountX2 / 2; - for (i = segCount - 1; i >= 0 ; i--) { - c0 = map->startCount[i]; - c1 = map->endCount[i]; - d = map->idRangeOffset[i] / 2 - (segCount - i); - for (j = 0; j <= c1 - c0; j++) { - ch = c0 + j; - if (map->idRangeOffset[i] == 0) { - gid = (ch + map->idDelta[i]) & 0xffff; - } else if (c0 == 0xffff && c1 == 0xffff && map->idRangeOffset[i] == 0xffff) { - /* this is for protection against some old broken fonts... */ - gid = 0; - } else { - gid = (map->glyphIndexArray[j+d] + map->idDelta[i]) & 0xffff; - } - if (gid != 0 && gid != 0xffff) { - if (gsub_list) - otl_gsub_apply_chain(gsub_list, &gid); - if (gsub_vert) - otl_gsub_apply(gsub_vert, &gid); - if (GIDToCIDMap) { - cid = ((GIDToCIDMap[2*gid] << 8)|GIDToCIDMap[2*gid+1]); - if (cid == 0) - dpx_warning("GID %u does not have corresponding CID %u.", gid, cid); - } else { - cid = gid; - } - wbuf[0] = 0; - wbuf[1] = 0; - wbuf[2] = (ch >> 8) & 0xff; - wbuf[3] = ch & 0xff; - wbuf[4] = (cid >> 8) & 0xff; - wbuf[5] = cid & 0xff; - CMap_add_cidchar(cmap, wbuf, 4, cid); - if (tounicode_add) { - unsigned char *p = wbuf + 6; - size_t uc_len; - uc_len = UC_UTF16BE_encode_char(ch, &p, wbuf + WBUF_SIZE - 1); - CMap_add_bfchar(tounicode_add, wbuf + 4, 2, wbuf + 6, uc_len); - } - } - } - } - - return; -} - -static void -load_cmap12 (struct cmap12 *map, - unsigned char *GIDToCIDMap, - otl_gsub *gsub_vert, otl_gsub *gsub_list, - CMap *cmap, CMap *tounicode_add) -{ - ULONG i, ch; /* LONG ? */ - USHORT gid, cid; - - for (i = 0; i < map->nGroups; i++) { - for (ch = map->groups[i].startCharCode; - ch <= map->groups[i].endCharCode; - ch++) { - int d = ch - map->groups[i].startCharCode; - gid = (USHORT) ((map->groups[i].startGlyphID + d) & 0xffff); - if (gsub_list) - otl_gsub_apply_chain(gsub_list, &gid); - if (gsub_vert) - otl_gsub_apply(gsub_vert, &gid); - if (GIDToCIDMap) { - cid = ((GIDToCIDMap[2*gid] << 8)|GIDToCIDMap[2*gid+1]); - if (cid == 0) - dpx_warning("GID %u does not have corresponding CID %u.", gid, cid); - } else { - cid = gid; - } - wbuf[0] = (ch >> 24) & 0xff; - wbuf[1] = (ch >> 16) & 0xff; - wbuf[2] = (ch >> 8) & 0xff; - wbuf[3] = ch & 0xff; - wbuf[4] = (cid >> 8) & 0xff; - wbuf[5] = cid & 0xff; - CMap_add_cidchar(cmap, wbuf, 4, cid); - if (tounicode_add) { - unsigned char *p = wbuf + 6; - size_t uc_len; - uc_len = UC_UTF16BE_encode_char(ch, &p, wbuf + WBUF_SIZE - 1); - CMap_add_bfchar(tounicode_add, wbuf + 4, 2, wbuf + 6, uc_len); - } - } - } - - return; -} - -#include "dpx-cff.h" -#include "dpx-cff_dict.h" -#include "dpx-cff_types.h" /* OpenType CIDFont: * * We don't use GID for them. OpenType cmap table is for * charcode to GID mapping rather than to-CID mapping. */ +#include "dpx-cff.h" +#include "dpx-cff_dict.h" +#include "dpx-cff_types.h" #include "dpx-cid.h" #include "dpx-tt_table.h" -static int -handle_CIDFont (sfnt *sfont, - unsigned char **GIDToCIDMap, CIDSysInfo *csi) +static void +create_GIDToCIDMap (uint16_t *GIDToCIDMap, uint16_t num_glyphs, cff_font *cffont) { - cff_font *cffont; - int offset, i; - card16 num_glyphs, gid; - cff_charsets *charset; - unsigned char *map; - struct tt_maxp_table *maxp; - - assert(csi); - - offset = sfnt_find_table_pos(sfont, "CFF "); - if (offset == 0) { - csi->registry = NULL; - csi->ordering = NULL; - *GIDToCIDMap = NULL; - return 0; - } - - maxp = tt_read_maxp_table(sfont); - num_glyphs = (card16) maxp->numGlyphs; - free(maxp); - if (num_glyphs < 1) - _tt_abort("No glyph contained in this font..."); + cff_charsets *charset; + uint16_t gid, i; - cffont = cff_open(sfont->handle, offset, 0); - if (!cffont) - _tt_abort("Could not open CFF font..."); + assert(GIDToCIDMap); + if (!cffont || !(cffont->flag & FONTTYPE_CIDFONT)) { + for (gid = 0; gid < num_glyphs; gid++) { + GIDToCIDMap[gid] = gid; + } - if (!(cffont->flag & FONTTYPE_CIDFONT)) { - cff_close(cffont); - csi->registry = NULL; - csi->ordering = NULL; - *GIDToCIDMap = NULL; - return 0; + return; } - if (!cff_dict_known(cffont->topdict, "ROS")) { - _tt_abort("No CIDSystemInfo???"); - } else { - card16 reg, ord; - - reg = (card16) cff_dict_get(cffont->topdict, "ROS", 0); - ord = (card16) cff_dict_get(cffont->topdict, "ROS", 1); - - csi->registry = cff_get_string(cffont, reg); - csi->ordering = cff_get_string(cffont, ord); - csi->supplement = (int) cff_dict_get(cffont->topdict, "ROS", 2); - } + memset(GIDToCIDMap, 0, num_glyphs*sizeof(uint16_t)); - cff_read_charsets(cffont); charset = cffont->charsets; - if (!charset) { - _tt_abort("No CFF charset data???"); - } - - map = NEW(num_glyphs * 2, unsigned char); - memset(map, 0, num_glyphs * 2); + if (!charset) + return; switch (charset->format) { case 0: { s_SID *cids; /* CID... */ cids = charset->data.glyphs; - for (gid = 1, i = 0; - i < charset->num_entries; i++) { - map[2*gid ] = (cids[i] >> 8) & 0xff; - map[2*gid+1] = cids[i] & 0xff; + for (gid = 1, i = 0; i < charset->num_entries; i++) { + GIDToCIDMap[gid] = cids[i]; gid++; } } @@ -795,15 +648,13 @@ handle_CIDFont (sfnt *sfont, card16 cid, count; ranges = charset->data.range1; - for (gid = 1, i = 0; - i < charset->num_entries; i++) { + for (gid = 1, i = 0; i < charset->num_entries; i++) { cid = ranges[i].first; count = ranges[i].n_left + 1; /* card8 */ - while (count-- > 0 && - gid <= num_glyphs) { - map[2*gid ] = (cid >> 8) & 0xff; - map[2*gid + 1] = cid & 0xff; - gid++; cid++; + while (count-- > 0 && gid <= num_glyphs) { + GIDToCIDMap[gid] = cid; + gid++; + cid++; } } } @@ -814,47 +665,47 @@ handle_CIDFont (sfnt *sfont, card16 cid, count; ranges = charset->data.range2; - if (charset->num_entries == 1 && - ranges[0].first == 1) { + if (charset->num_entries == 1 && ranges[0].first == 1) { /* "Complete" CIDFont */ - map = mfree(map); + for (gid = 0; gid < num_glyphs; gid++) { + GIDToCIDMap[gid] = gid; + } } else { /* Not trivial mapping */ - for (gid = 1, i = 0; - i < charset->num_entries; i++) { + for (gid = 1, i = 0; i < charset->num_entries; i++) { cid = ranges[i].first; count = ranges[i].n_left + 1; while (count-- > 0 && gid <= num_glyphs) { - map[2*gid] = (cid >> 8) & 0xff; - map[2*gid+1] = cid & 0xff; - gid++; cid++; + GIDToCIDMap[gid] = cid; + gid++; + cid++; } } - } } break; default: - map = mfree(map); - _tt_abort("Unknown CFF charset format...: %d", charset->format); + dpx_warning("Unknown CFF charset format...: %d", charset->format); break; } - cff_close(cffont); - *GIDToCIDMap = map; - return 1; + return; } static bool is_PUA_or_presentation (unsigned int uni) { - /* KANGXI RADICALs are commonly double encoded. */ - return ((uni >= 0x2F00 && uni <= 0x2FD5) || - (uni >= 0xE000 && uni <= 0xF8FF) || (uni >= 0xFB00 && uni <= 0xFB4F) || - (uni >= 0xF0000 && uni <= 0xFFFFD) || (uni >= 0x100000 && uni <= 0x10FFFD)); + /* Some of CJK Radicals Supplement and Kangxi Radicals + * are commonly double encoded, lower the priority. + * CJK Compatibility Ideographs & Supplement added. + */ + return ((uni >= 0x2E80 && uni <= 0x2EF3) || (uni >= 0x2F00 && uni <= 0x2FD5) || + (uni >= 0xE000 && uni <= 0xF8FF) || (uni >= 0xFB00 && uni <= 0xFB4F) || + (uni >= 0xF900 && uni <= 0xFAFF) || (uni >= 0x2F800 && uni <= 0x2FA1F) || + (uni >= 0xF0000 && uni <= 0xFFFFD) || (uni >= 0x100000 && uni <= 0x10FFFD)); } static char* -sfnt_get_glyphname(struct tt_post_table *post, cff_font *cffont, USHORT gid) +lookup_glyph_name(struct tt_post_table *post, cff_font *cffont, USHORT gid) { char* name = NULL; @@ -876,92 +727,82 @@ sfnt_get_glyphname(struct tt_post_table *post, cff_font *cffont, USHORT gid) #define is_used_char2(b,c) (((b)[(c)/8]) & (1 << (7-((c)%8)))) #endif -static USHORT -handle_subst_glyphs (CMap *cmap, - CMap *cmap_add, - const char *used_glyphs, - sfnt *sfont, - cff_font *cffont) +static int32_t +handle_subst_glyphs (CMap *cmap, CMap *cmap_add, char *used_chars) { - USHORT count; - USHORT i; - struct tt_post_table *post = NULL; + int32_t count = 0; + int32_t cid; - if (!cmap_add) - post = tt_read_post_table(sfont); + for (cid = 0; cid < 65536; cid++) { + if (!is_used_char2(used_chars, cid)) + continue; + else { + unsigned char buf[256]; + size_t inbytesleft = 2, outbytesleft = 254; + size_t len; + unsigned char *outbuf = buf + 2; + const unsigned char *inbuf = buf; + + buf[0] = (cid >> 8) & 0xff; + buf[1] = cid & 0xff; + CMap_decode(cmap_add, &inbuf, &inbytesleft, &outbuf, &outbytesleft); + if (inbytesleft == 0) { + len = 254 - outbytesleft; + CMap_add_bfchar(cmap, buf, 2, buf + 2, len); + used_chars[cid / 8] &= ~(1 << (7 - (cid % 8))); + count++; + } + } + } - for (count = 0, i = 0; i < 8192; i++) { - unsigned int j; - size_t len; - size_t inbytesleft, outbytesleft; - const unsigned char *inbuf; - unsigned char *outbuf; + return count; +} - if (used_glyphs[i] == 0) - continue; +static int32_t +add_ToUnicode_via_glyph_name (CMap *cmap, char *used_chars, USHORT num_glyphs, + uint16_t *GIDToCIDMap, + sfnt *sfont, cff_font *cffont) +{ + int32_t count = 0; + USHORT gid; + struct tt_post_table *post = NULL; - for (j = 0; j < 8; j++) { - USHORT gid = 8 * i + j; - - if (!is_used_char2(used_glyphs, gid)) - continue; - - if (!cmap_add) { -#define MAX_UNICODES 16 - /* try to look up Unicode values from the glyph name... */ - char* name; - int32_t unicodes[MAX_UNICODES]; - int unicode_count = -1; - name = sfnt_get_glyphname(post, cffont, gid); - if (name) { - unicode_count = agl_get_unicodes(name, unicodes, MAX_UNICODES); - } + post = tt_read_post_table(sfont); + if (!post && !cffont) + return count; + + for (gid = 0; gid < num_glyphs; gid++) { + uint16_t cid = GIDToCIDMap[gid]; + if (is_used_char2(used_chars, cid)) { +#define MAX_UNICODES 32 + char *name; + int32_t unicodes[MAX_UNICODES]; + int unicode_count = -1; + + name = lookup_glyph_name(post, cffont, gid); + if (name) { + unicode_count = agl_get_unicodes(name, unicodes, MAX_UNICODES); #undef MAX_UNICODES - if (unicode_count == -1) { - if (name) - dpx_message("No Unicode mapping available: GID=%u, name=%s\n", gid, name); - else - dpx_message("No Unicode mapping available: GID=%u\n", gid); - } else { - /* the Unicode characters go into wbuf[2] and following, in UTF16BE */ - /* we rely on WBUF_SIZE being more than adequate for MAX_UNICODES */ - unsigned char* p = wbuf + 2; - int k; - len = 0; + free(name); + if (unicode_count > 0) { + unsigned char *buf; + unsigned char *p, *endptr; + int k; + size_t len = 0; + + buf = NEW(unicode_count*4+2, unsigned char); + p = buf + 2; + endptr = buf + (unicode_count * 4 + 2); for (k = 0; k < unicode_count; ++k) { - len += UC_UTF16BE_encode_char(unicodes[k], &p, wbuf+WBUF_SIZE); + len += UC_UTF16BE_encode_char(unicodes[k], &p, endptr); } - wbuf[0] = (gid >> 8) & 0xff; - wbuf[1] = gid & 0xff; - CMap_add_bfchar(cmap, wbuf, 2, wbuf + 2, len); - } - free(name); - } else { - wbuf[0] = (gid >> 8) & 0xff; - wbuf[1] = gid & 0xff; - - inbuf = wbuf; - inbytesleft = 2; - outbuf = wbuf + 2; - outbytesleft = WBUF_SIZE - 2; - CMap_decode(cmap_add, &inbuf, &inbytesleft, &outbuf, &outbytesleft); - - if (inbytesleft != 0) { - dpx_warning("CMap conversion failed..."); - } else { - len = WBUF_SIZE - 2 - outbytesleft; - CMap_add_bfchar(cmap, wbuf, 2, wbuf + 2, len); + buf[0] = (cid >> 8) & 0xff; + buf[1] = cid & 0xff; + CMap_add_bfchar(cmap, buf, 2, buf + 2, len); + used_chars[cid / 8] &= ~(1 << (7 - (cid % 8))); count++; - if (verbose > VERBOSE_LEVEL_MIN) { - size_t _i; - - dpx_message("otf_cmap>> Additional ToUnicode mapping: <%04X> <", gid); - for (_i = 0; _i < len; _i++) { - dpx_message("%02X", wbuf[2 + _i]); - } - dpx_message(">\n"); - } + free(buf); } } } @@ -973,198 +814,221 @@ handle_subst_glyphs (CMap *cmap, return count; } -static cff_font * -prepare_CIDFont_from_sfnt(sfnt* sfont) +static void +create_inverse_cmap4 (int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + struct cmap4 *map) { - cff_font *cffont; - unsigned int offset = 0; - - if (sfont->type != SFNT_TYPE_POSTSCRIPT || - sfnt_read_table_directory(sfont, 0) < 0 || - (offset = sfnt_find_table_pos(sfont, "CFF ")) == 0) { - return NULL; + USHORT segCount = map->segCountX2 / 2; + USHORT i, j; + + for (i = 0; i < segCount; i++) { + USHORT c0 = map->startCount[i]; + USHORT c1 = map->endCount[i]; + USHORT d = map->idRangeOffset[i] / 2 - (segCount - i); + for (j = 0; j <= c1 - c0; j++) { + USHORT ch = c0 + j; + USHORT gid; + + if (map->idRangeOffset[i] == 0) { + gid = (ch + map->idDelta[i]) & 0xffff; + } else if (c0 == 0xffff && c1 == 0xffff && map->idRangeOffset[i] == 0xffff) { + /* this is for protection against some old broken fonts... */ + gid = 0; + } else { + gid = (map->glyphIndexArray[j + d] + map->idDelta[i]) & 0xffff; + } + if (is_PUA_or_presentation(ch)) { + map_sub[gid] = ch; + } else { + map_base[gid] = ch; + } } - - cffont = cff_open(sfont->handle, offset, 0); - if (!cffont) - return NULL; - - cff_read_charsets(cffont); - return cffont; + } } -static USHORT -add_to_cmap_if_used (CMap *cmap, - cff_font *cffont, - char *used_chars, - USHORT gid, - ULONG ch) +static void +create_inverse_cmap12 (int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + struct cmap12 *map) { - USHORT count = 0; - USHORT cid = cffont ? cff_charsets_lookup_inverse(cffont, gid) : gid; - - /* Skip PUA characters and alphabetic presentation forms, allowing - * handle_subst_glyphs() as it might find better mapping. Fixes the - * mapping of ligatures encoded in PUA in fonts like Linux Libertine - * and old Adobe fonts. - */ - if (is_used_char2(used_chars, cid) && !is_PUA_or_presentation(ch)) { - int len; - unsigned char *p = wbuf + 2; - - count++; - - wbuf[0] = (cid >> 8) & 0xff; - wbuf[1] = (cid & 0xff); - len = UC_UTF16BE_encode_char((int32_t) ch, &p, wbuf + WBUF_SIZE); - CMap_add_bfchar(cmap, wbuf, 2, wbuf + 2, len); - - /* Avoid duplicate entry - * There are problem when two Unicode code is mapped to - * single glyph... - */ - used_chars[cid / 8] &= ~(1 << (7 - (cid % 8))); + ULONG i, ch; + + for (i = 0; i < map->nGroups; i++) { + for (ch = map->groups[i].startCharCode; + ch <= map->groups[i].endCharCode; ch++) { + int d = ch - map->groups[i].startCharCode; + USHORT gid = (USHORT) ((map->groups[i].startGlyphID + d) & 0xffff); + if (is_PUA_or_presentation(ch)) { + map_sub[gid] = ch; + } else { + map_base[gid] = ch; + } } - - return count; + } } -static USHORT -create_ToUnicode_cmap4 (CMap *cmap, - struct cmap4 *map, - char *used_chars, - cff_font *cffont) +/* NOTE: Reverse mapping code which had been placed here is removed since: + * - Implementation of reserve CMap mapping itself is imcomplete. + * - It is wrong to assume that all CMap passed here is Unicode to CID mapping. + * Especially, the second one causes problems. + */ +static pdf_obj * +create_ToUnicode_cmap (tt_cmap *ttcmap, + const char *cmap_name, + CMap *cmap_add, + const char *used_chars, + sfnt *sfont) { - USHORT count = 0, segCount = map->segCountX2 / 2; - USHORT i, j; + pdf_obj *stream = NULL; + int32_t *map_base = NULL, *map_sub = NULL; + USHORT gid, num_glyphs = 0; - for (i = 0; i < segCount; i++) { - USHORT c0 = map->startCount[i]; - USHORT c1 = map->endCount[i]; - USHORT d = map->idRangeOffset[i] / 2 - (segCount - i); - for (j = 0; j <= c1 - c0; j++) { - USHORT ch = c0 + j; - USHORT gid; + assert(ttcmap); - if (map->idRangeOffset[i] == 0) { - gid = (ch + map->idDelta[i]) & 0xffff; - } else if (c0 == 0xffff && c1 == 0xffff && map->idRangeOffset[i] == 0xffff) { - /* this is for protection against some old broken fonts... */ - gid = 0; - } else { - gid = (map->glyphIndexArray[j + d] + map->idDelta[i]) & 0xffff; - } + /* Get num_glyphs from maxp talbe */ + { + struct tt_maxp_table *maxp; - count += add_to_cmap_if_used(cmap, cffont, used_chars, gid, ch); + maxp = tt_read_maxp_table(sfont); + if (maxp) { + num_glyphs = maxp->numGlyphs; + free(maxp); } } - return count; -} + /* Initialize GID to Unicode mapping table */ + map_base = NEW(num_glyphs, int32_t); + map_sub = NEW(num_glyphs, int32_t); + for (gid = 0; gid < num_glyphs; gid++) { + map_base[gid] = -1; + map_sub [gid] = -1; + } -static USHORT -create_ToUnicode_cmap12 (CMap *cmap, - struct cmap12 *map, - char *used_chars, - cff_font *cffont) -{ - ULONG i, ch, count = 0; + /* Create "base" mapping from inverse mapping of OpenType cmap */ + switch (ttcmap->format) { + case 4: + create_inverse_cmap4(map_base, map_sub, num_glyphs, ttcmap->map); + break; + case 12: + create_inverse_cmap12(map_base, map_sub, num_glyphs, ttcmap->map); + break; + } - for (i = 0; i < map->nGroups; i++) { - for (ch = map->groups[i].startCharCode; - ch <= map->groups[i].endCharCode; ch++) { - int d = ch - map->groups[i].startCharCode; - USHORT gid = (USHORT) ((map->groups[i].startGlyphID + d) & 0xffff); - count += add_to_cmap_if_used(cmap, cffont, used_chars, gid, ch); + /* Now create ToUnicode CMap stream */ + { + CMap *cmap; + int32_t count; + cff_font *cffont = NULL; + char is_cidfont = 0; + uint16_t *GIDToCIDMap = NULL; + char *used_chars_copy = NULL; + + if (sfont->type == SFNT_TYPE_POSTSCRIPT) { + ULONG offset; + offset = sfnt_find_table_pos(sfont, "CFF "); + cffont = cff_open(sfont->handle, offset, 0); + cff_read_charsets(cffont); } - } + is_cidfont = cffont && (cffont->flag & FONTTYPE_CIDFONT); - return count; -} + /* GIT to CID mapping info. */ + GIDToCIDMap = NEW(num_glyphs, uint16_t); + if (is_cidfont) { + create_GIDToCIDMap(GIDToCIDMap, num_glyphs, cffont); + } else { + for (gid = 0; gid < num_glyphs; gid++) { + GIDToCIDMap[gid] = gid; + } + } + cmap = CMap_new(); + CMap_set_name (cmap, cmap_name); + CMap_set_wmode(cmap, 0); + CMap_set_type (cmap, CMAP_TYPE_TO_UNICODE); + CMap_set_CIDSysInfo(cmap, &CSI_UNICODE); + CMap_add_codespacerange(cmap, srange_min, srange_max, 2); -static pdf_obj * -create_ToUnicode_cmap (tt_cmap *ttcmap, - const char *cmap_name, - CMap *cmap_add, - const char *used_chars, - sfnt *sfont, - CMap *code_to_cid_cmap) -{ - pdf_obj *stream = NULL; - CMap *cmap; - USHORT count = 0; - cff_font *cffont = prepare_CIDFont_from_sfnt(sfont); - char is_cidfont = cffont && (cffont->flag & FONTTYPE_CIDFONT); - - cmap = CMap_new(); - CMap_set_name (cmap, cmap_name); - CMap_set_wmode(cmap, 0); - CMap_set_type (cmap, CMAP_TYPE_TO_UNICODE); - CMap_set_CIDSysInfo(cmap, &CSI_UNICODE); - CMap_add_codespacerange(cmap, srange_min, srange_max, 2); - - /* cmap_add here stores information about all unencoded glyphs which can be - * accessed only through OT Layout GSUB table. - */ - if (code_to_cid_cmap && cffont && is_cidfont && !cmap_add) { - USHORT i; - for (i = 0; i < 8192; i++) { - int j; - - if (used_chars[i] == 0) - continue; - - for (j = 0; j < 8; j++) { - USHORT cid = 8 * i + j; - int ch; - - if (!is_used_char2(used_chars, cid)) - continue; - - ch = CMap_reverse_decode(code_to_cid_cmap, cid); - if (ch >= 0) { - int len; - unsigned char *p = wbuf + 2; - wbuf[0] = (cid >> 8) & 0xff; - wbuf[1] = cid & 0xff; - len = UC_UTF16BE_encode_char(ch, &p, wbuf + WBUF_SIZE); - CMap_add_bfchar(cmap, wbuf, 2, wbuf + 2, len); + count = 0; + used_chars_copy = NEW(8192, char); + memcpy(used_chars_copy, used_chars, 8192); + for (gid = 0; gid < num_glyphs; gid++) { + uint16_t cid = GIDToCIDMap[gid]; + if (is_used_char2(used_chars_copy, cid)) { + int32_t ch; + unsigned char src[2], dst[4]; + unsigned char *p = dst, *endptr = dst + 4; + size_t len; + + ch = map_base[gid]; + if (UC_is_valid(ch)) { + src[0] = (cid >> 8) & 0xff; + src[1] = cid & 0xff; + len = UC_UTF16BE_encode_char(ch, &p, endptr); + CMap_add_bfchar(cmap, src, 2, dst, len); + used_chars_copy[cid / 8] &= ~(1 << (7 - (cid % 8))); count++; } } } - } else { - char used_chars_copy[8192]; - memcpy(used_chars_copy, used_chars, 8192); - /* For create_ToUnicode_cmap{4,12}(), cffont is for GID -> CID lookup, - * so it is only needed for CID fonts. */ - switch (ttcmap->format) { - case 4: - count = create_ToUnicode_cmap4(cmap, ttcmap->map, used_chars_copy, - is_cidfont ? cffont : NULL); - break; - case 12: - count = create_ToUnicode_cmap12(cmap, ttcmap->map, used_chars_copy, - is_cidfont ? cffont : NULL); - break; + /* cmap_add here stores information about all unencoded glyphs which can be + * accessed only through OT Layout GSUB table. + * This is only availabel when encoding is "unicode". + */ + if (cmap_add) { + count += handle_subst_glyphs(cmap, cmap_add, used_chars_copy); + } else { + /* Else, try gathering information from GSUB tables */ + count += otl_gsub_add_ToUnicode(cmap, used_chars_copy, + map_base, map_sub, num_glyphs, + GIDToCIDMap, sfont); + } + /* Find Unicode mapping via PostScript glyph names... */ + count += add_ToUnicode_via_glyph_name(cmap, used_chars_copy, num_glyphs, + GIDToCIDMap, sfont, is_cidfont ? NULL : cffont); + if (cffont) + cff_close(cffont); + + /* Finaly, PUA and presentation forms... */ + for (gid = 0; gid < num_glyphs; gid++) { + uint16_t cid = GIDToCIDMap[gid]; + if (is_used_char2(used_chars_copy, cid)) { + int32_t ch; + unsigned char src[2], dst[4]; + unsigned char *p = dst, *endptr = dst + 4; + size_t len; + + ch = map_sub[gid]; + if (UC_is_valid(ch)) { + src[0] = (cid >> 8) & 0xff; + src[1] = cid & 0xff; + len = UC_UTF16BE_encode_char(ch, &p, endptr); + CMap_add_bfchar(cmap, src, 2, dst, len); + used_chars_copy[cid / 8] &= ~(1 << (7 - (cid % 8))); + count++; + } + } } - /* For handle_subst_glyphs(), cffont is for GID -> glyph name lookup, so - * it is only needed for non-CID fonts. */ - count += handle_subst_glyphs(cmap, cmap_add, used_chars_copy, sfont, - is_cidfont ? NULL : cffont); - } + /* Check for missing mapping */ + if (dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { + for (gid = 0; gid < num_glyphs; gid++) { + uint16_t cid = GIDToCIDMap[gid]; + if (is_used_char2(used_chars_copy, cid)) { + dpx_warning("Unable to find ToUnicode mapping for glyph CID=%u (GID=%u)", cid, gid); + } + } + } + free(GIDToCIDMap); + free(used_chars_copy); - if (count < 1) - stream = NULL; - else { - stream = CMap_create_stream(cmap); + if (count < 1) + stream = NULL; + else { + stream = CMap_create_stream(cmap); + } + CMap_release(cmap); } - CMap_release(cmap); - - if (cffont) - cff_close(cffont); + free(map_base); + free(map_sub); return stream; } @@ -1185,46 +1049,30 @@ static cmap_plat_enc_rec cmap_plat_encs[] = { pdf_obj * otf_create_ToUnicode_stream (const char *font_name, int ttc_index, /* 0 for non-TTC */ - const char *used_chars, - int cmap_id) + const char *basefont, + const char *used_chars) { - pdf_obj *cmap_ref = NULL; - int res_id; - pdf_obj *cmap_obj = NULL; - CMap *cmap_add, *code_to_cid_cmap; - int cmap_add_id; - tt_cmap *ttcmap; - char *normalized_font_name; - char *cmap_name, *cmap_add_name; + pdf_obj *cmap_ref = NULL; /* returned value */ + CMap *cmap_add; + char *cmap_name; rust_input_handle_t handle = NULL; sfnt *sfont; ULONG offset = 0; - int cmap_type; + tt_cmap *ttcmap; + int cmap_id, cmap_add_id; size_t i; - /* replace slash in map name with dash to make the output cmap name valid, - * happens when XeTeX embeds full font path - * https://sourceforge.net/p/xetex/bugs/52/ - */ - normalized_font_name = NEW(strlen(font_name)+1, char); - strcpy(normalized_font_name, font_name); - for (i = 0; i < strlen(font_name); ++i) { - if (normalized_font_name[i] == '/') - normalized_font_name[i] = '-'; - } - - cmap_name = NEW(strlen(font_name)+strlen("-UTF16")+5, char); - sprintf(cmap_name, "%s,%03d-UTF16", normalized_font_name, ttc_index); - free(normalized_font_name); + cmap_name = NEW(strlen(font_name)+strlen("-UTF16")+1, char); + sprintf(cmap_name, "%s-UTF16", basefont); - res_id = pdf_findresource("CMap", cmap_name); - if (res_id >= 0) { + cmap_id = pdf_findresource("CMap", cmap_name); + if (cmap_id >= 0) { free(cmap_name); - cmap_ref = pdf_get_resource_reference(res_id); + cmap_ref = pdf_get_resource_reference(cmap_id); return cmap_ref; } - if (verbose > VERBOSE_LEVEL_MIN) { + if (dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("\n"); dpx_message("otf_cmap>> Creating ToUnicode CMap for \"%s\"...\n", font_name); } @@ -1240,7 +1088,10 @@ otf_create_ToUnicode_stream (const char *font_name, } if (!sfont) { - _tt_abort("Could not open OpenType/TrueType font file \"%s\"", font_name); + dpx_warning("Could not open OpenType/TrueType font file \"%s\"", font_name); + free(cmap_name); + ttstub_input_close(handle); + return NULL; } switch (sfont->type) { @@ -1250,7 +1101,11 @@ otf_create_ToUnicode_stream (const char *font_name, case SFNT_TYPE_TTC: offset = ttc_read_offset(sfont, ttc_index); if (offset == 0) { - _tt_abort("Invalid TTC index"); + dpx_warning("Invalid TTC index for font: %s", font_name); + sfnt_close(sfont); + ttstub_input_close(handle); + free(cmap_name); + return NULL; } break; default: @@ -1259,113 +1114,178 @@ otf_create_ToUnicode_stream (const char *font_name, } if (sfnt_read_table_directory(sfont, offset) < 0) { - _tt_abort("Could not read OpenType/TrueType table directory."); + dpx_warning("Could not read OpenType/TrueType table directory for font: %s", font_name); + sfnt_close(sfont); + ttstub_input_close(handle); + free(cmap_name); + return NULL; } - code_to_cid_cmap = CMap_cache_get(cmap_id); - cmap_type = CMap_get_type(code_to_cid_cmap); - if (cmap_type != CMAP_TYPE_CODE_TO_CID) - code_to_cid_cmap = NULL; - - cmap_add_name = NEW(strlen(font_name) + strlen(",000-UCS32-Add") + 1, char); - sprintf(cmap_add_name, "%s,%03d-UCS32-Add", font_name, ttc_index); - cmap_add_id = CMap_cache_find(cmap_add_name); - free(cmap_add_name); - if (cmap_add_id < 0) { - cmap_add = NULL; - } else { - cmap_add = CMap_cache_get(cmap_add_id); + /* cmap_add is used for storing information on ToUnicode mapping for + * unencoded glyphs which can be reached only through GSUB substitution. + * This is available only when "unicode" is specified in the encoding + * field of fontmap. We remember the inverse mapping via cmap_add in this + * case. + */ + { + char *cmap_add_name; + cmap_add_name = NEW(strlen(font_name) + strlen(",000-UCS32-Add") + 1, char); + sprintf(cmap_add_name, "%s,%03d-UCS32-Add", font_name, ttc_index); + cmap_add_id = CMap_cache_find(cmap_add_name); + free(cmap_add_name); + if (cmap_add_id < 0) { + cmap_add = NULL; + } else { + cmap_add = CMap_cache_get(cmap_add_id); + } } - CMap_set_silent(1); /* many warnings without this... */ + ttcmap = NULL; for (i = 0; i < sizeof(cmap_plat_encs) / sizeof(cmap_plat_enc_rec); ++i) { ttcmap = tt_cmap_read(sfont, cmap_plat_encs[i].platform, cmap_plat_encs[i].encoding); if (!ttcmap) continue; if (ttcmap->format == 4 || ttcmap->format == 12) { - cmap_obj = create_ToUnicode_cmap(ttcmap, cmap_name, cmap_add, used_chars, - sfont, code_to_cid_cmap); - break; + break; + } else { + tt_cmap_release(ttcmap); + ttcmap = NULL; } } - if (cmap_obj == NULL) - dpx_warning("Unable to read OpenType/TrueType Unicode cmap table."); - tt_cmap_release(ttcmap); - CMap_set_silent(0); - if (cmap_obj) { - res_id = pdf_defineresource("CMap", cmap_name, + if (ttcmap) { + pdf_obj *cmap_obj; + + CMap_set_silent(1); /* many warnings without this... */ + cmap_obj = create_ToUnicode_cmap(ttcmap, cmap_name, cmap_add, used_chars, sfont); + CMap_set_silent(0); + if (cmap_obj) { + cmap_id = pdf_defineresource("CMap", cmap_name, cmap_obj, PDF_RES_FLUSH_IMMEDIATE); - cmap_ref = pdf_get_resource_reference(res_id); - } else { - cmap_ref = NULL; + cmap_ref = pdf_get_resource_reference(cmap_id); + } + tt_cmap_release(ttcmap); } - free(cmap_name); + /* Cleanup */ + free(cmap_name); sfnt_close(sfont); if (handle) ttstub_input_close(handle); + if (!cmap_ref) { + dpx_warning("Creating ToUnicode CMap failed for \"%s\"", font_name); + } + return cmap_ref; } +/* Creating input CMaps from OT cmap table */ -static int -load_base_CMap (const char *cmap_name, CMap *tounicode_add, int wmode, - CIDSysInfo *csi, unsigned char *GIDToCIDMap, - otl_gsub *gsub_vert, otl_gsub *gsub_list, - tt_cmap *ttcmap) +static void +load_cmap4 (struct cmap4 *map, uint16_t *GIDToCIDMap, USHORT num_glyphs, + otl_gsub *gsub_vert, otl_gsub *gsub_list, + CMap *cmap, int32_t *map_base, int32_t *map_sub) { - int cmap_id; - - cmap_id = CMap_cache_find(cmap_name); - if (cmap_id < 0) { - CMap *cmap; + USHORT c0, c1, gid, cid; + USHORT j, d, segCount; + USHORT ch; + int i; + unsigned char buf[4]; + + segCount = map->segCountX2 / 2; + for (i = segCount - 1; i >= 0 ; i--) { + c0 = map->startCount[i]; + c1 = map->endCount[i]; + d = map->idRangeOffset[i] / 2 - (segCount - i); + for (j = 0; j <= c1 - c0; j++) { + ch = c0 + j; + if (map->idRangeOffset[i] == 0) { + gid = (ch + map->idDelta[i]) & 0xffff; + } else if (c0 == 0xffff && c1 == 0xffff && map->idRangeOffset[i] == 0xffff) { + /* this is for protection against some old broken fonts... */ + gid = 0; + } else { + gid = (map->glyphIndexArray[j+d] + map->idDelta[i]) & 0xffff; + } + if (gid != 0 && gid != 0xffff) { + /* Apply GSUB features */ + if (gsub_list) + otl_gsub_apply_chain(gsub_list, &gid); + if (gsub_vert) + otl_gsub_apply(gsub_vert, &gid); + cid = (gid < num_glyphs) ? GIDToCIDMap[gid] : 0; + buf[0] = 0; + buf[1] = 0; + buf[2] = (ch >> 8) & 0xff; + buf[3] = ch & 0xff; + CMap_add_cidchar(cmap, buf, 4, cid); + /* For ToUnicode creation */ + if (map_base && map_sub) { + if (is_PUA_or_presentation(ch)) { + map_sub[gid] = ch; + } else { + map_base[gid] = ch; + } + } + } + } + } - cmap = CMap_new(); - CMap_set_name (cmap, cmap_name); - CMap_set_type (cmap, CMAP_TYPE_CODE_TO_CID); - CMap_set_wmode(cmap, wmode); - CMap_add_codespacerange(cmap, lrange_min, lrange_max, 4); + return; +} - if (csi) { /* CID */ - CMap_set_CIDSysInfo(cmap, csi); +static void +load_cmap12 (struct cmap12 *map, uint16_t *GIDToCIDMap, USHORT num_glyphs, + otl_gsub *gsub_vert, otl_gsub *gsub_list, + CMap *cmap, int32_t *map_base, int32_t *map_sub) +{ + ULONG i, ch; + USHORT gid, cid; + unsigned char buf[4]; + + for (i = 0; i < map->nGroups; i++) { + for (ch = map->groups[i].startCharCode; + ch <= map->groups[i].endCharCode; ch++) { + int d = ch - map->groups[i].startCharCode; + gid = (USHORT) ((map->groups[i].startGlyphID + d) & 0xffff); + if (gsub_list) + otl_gsub_apply_chain(gsub_list, &gid); + if (gsub_vert) + otl_gsub_apply(gsub_vert, &gid); + cid = (gid < num_glyphs) ? GIDToCIDMap[gid] : 0; + buf[0] = (ch >> 24) & 0xff; + buf[1] = (ch >> 16) & 0xff; + buf[2] = (ch >> 8) & 0xff; + buf[3] = ch & 0xff; + CMap_add_cidchar(cmap, buf, 4, cid); + if (map_base && map_sub) { + if (is_PUA_or_presentation(ch)) { + map_sub[gid] = ch; } else { - CMap_set_CIDSysInfo(cmap, &CSI_IDENTITY); - } - - if (ttcmap->format == 12) { - load_cmap12(ttcmap->map, GIDToCIDMap, gsub_vert, gsub_list, cmap, tounicode_add); - } else if (ttcmap->format == 4) { - load_cmap4(ttcmap->map, GIDToCIDMap, gsub_vert, gsub_list, cmap, tounicode_add); + map_base[gid] = ch; } - - cmap_id = CMap_cache_add(cmap); + } } + } - return cmap_id; + return; } - int otf_load_Unicode_CMap (const char *map_name, int ttc_index, /* 0 for non-TTC font */ const char *otl_tags, int wmode) { int cmap_id = -1; - /* Additional ToUnicode mappings required by OTL GSUB substitusion */ - int tounicode_add_id = -1; - CMap *tounicode_add = NULL; - char *tounicode_add_name = NULL; - int is_cidfont = 0; - sfnt *sfont; + char *cmap_name = NULL; + sfnt *sfont = NULL; ULONG offset = 0; - char *base_name = NULL, *cmap_name = NULL; + uint16_t num_glyphs = 0; rust_input_handle_t handle = NULL; - otl_gsub *gsub_vert = NULL, *gsub_list = NULL; tt_cmap *ttcmap; CIDSysInfo csi = {NULL, NULL, 0}; - unsigned char *GIDToCIDMap = NULL; + uint16_t *GIDToCIDMap = NULL; if (!map_name) return -1; @@ -1374,28 +1294,67 @@ otf_load_Unicode_CMap (const char *map_name, int ttc_index, /* 0 for non-TTC fon return -1; /* Sorry for this... */ } + /* First look for cache if it was already loaded */ + cmap_name = NEW(strlen(map_name)+strlen("-UCS4-H")+5, char); + if (otl_tags) { + cmap_name = NEW(strlen(map_name)+strlen(otl_tags)+strlen("-UCS4-H")+6, char); + if (wmode) + sprintf(cmap_name, "%s,%03d,%s-UCS4-V", map_name, ttc_index, otl_tags); + else + sprintf(cmap_name, "%s,%03d,%s-UCS4-H", map_name, ttc_index, otl_tags); + } else { + if (wmode) + sprintf(cmap_name, "%s,%03d-UCS4-V", map_name, ttc_index); + else { + sprintf(cmap_name, "%s,%03d-UCS4-H", map_name, ttc_index); + } + } + cmap_id = CMap_cache_find(cmap_name); + if (cmap_id >= 0) { + free(cmap_name); + if (dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) + dpx_message("otf_cmap>> Found at cmap_id=%d.\n", cmap_id); + + return cmap_id; + } + + /* CMap not found */ + if (dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { + dpx_message("\n"); + dpx_message("otf_cmap>> Creating Unicode charmap for font=\"%s\" layout=\"%s\"\n", + map_name, (otl_tags ? otl_tags : "none")); + } + handle = dpx_open_truetype_file(map_name); if (handle == NULL) handle = dpx_open_opentype_file(map_name); if (handle == NULL) { handle = dpx_open_dfont_file(map_name); - if (handle == NULL) + if (handle == NULL) { + free(cmap_name); return -1; - + } sfont = dfont_open(handle, ttc_index); } else { sfont = sfnt_open(handle); } if (!sfont) { - _tt_abort("Could not open OpenType/TrueType/dfont font file \"%s\"", map_name); + dpx_warning("Could not open OpenType/TrueType/dfont font file \"%s\"", map_name); + free(cmap_name); + ttstub_input_close(handle); + return -1; } switch (sfont->type) { case SFNT_TYPE_TTC: offset = ttc_read_offset(sfont, ttc_index); if (offset == 0) { - _tt_abort("Invalid TTC index"); + dpx_warning("Offset=0 reurned for font=%s, TTC_index=%d", map_name, ttc_index); + free(cmap_name); + sfnt_close(sfont); + ttstub_input_close(handle); + return -1; } break; case SFNT_TYPE_TRUETYPE: @@ -1406,79 +1365,78 @@ otf_load_Unicode_CMap (const char *map_name, int ttc_index, /* 0 for non-TTC fon offset = sfont->offset; break; default: - _tt_abort("Not a OpenType/TrueType/TTC font?: %s", map_name); - break; + dpx_warning("Not a OpenType/TrueType/TTC font?: %s", map_name); + free(cmap_name); + sfnt_close(sfont); + ttstub_input_close(handle); + return -1; } - if (sfnt_read_table_directory(sfont, offset) < 0) - _tt_abort("Could not read OpenType/TrueType table directory."); - - base_name = NEW(strlen(map_name)+strlen("-UCS4-H")+5, char); - if (wmode) - sprintf(base_name, "%s,%03d-UCS4-V", map_name, ttc_index); - else { - sprintf(base_name, "%s,%03d-UCS4-H", map_name, ttc_index); + if (sfnt_read_table_directory(sfont, offset) < 0) { + dpx_warning("Could not read OpenType/TrueType table directory."); + free(cmap_name); + sfnt_close(sfont); + ttstub_input_close(handle); + return -1; } - if (otl_tags) { - cmap_name = NEW(strlen(map_name)+strlen(otl_tags)+strlen("-UCS4-H")+6, char); - if (wmode) - sprintf(cmap_name, "%s,%03d,%s-UCS4-V", map_name, ttc_index, otl_tags); - else - sprintf(cmap_name, "%s,%03d,%s-UCS4-H", map_name, ttc_index, otl_tags); - - /* tounicode_add here is later refered by otf_create_ToUnicode_stream() - * for finding additional CID to Unicode mapping entries required by - * OTL gsub substitution. - */ - tounicode_add_name = NEW(strlen(map_name) + strlen(",000-UCS32-Add") + 1, char); - sprintf(tounicode_add_name, "%s,%03d-UCS32-Add", map_name, ttc_index); - tounicode_add_id = CMap_cache_find(tounicode_add_name); - - if (tounicode_add_id >= 0) { - tounicode_add = CMap_cache_get(tounicode_add_id); - } else { - tounicode_add = CMap_new(); - CMap_set_name (tounicode_add, tounicode_add_name); - CMap_set_type (tounicode_add, CMAP_TYPE_TO_UNICODE); - CMap_set_wmode(tounicode_add, 0); - CMap_add_codespacerange(tounicode_add, srange_min, srange_max, 2); - CMap_set_CIDSysInfo(tounicode_add, &CSI_UNICODE); - CMap_add_bfchar(tounicode_add, srange_min, 2, srange_max, 2); - tounicode_add_id = CMap_cache_add(tounicode_add); - } + { + struct tt_maxp_table *maxp; - free(tounicode_add_name); - } else { - cmap_name = NEW(strlen(base_name)+1, char); - strcpy(cmap_name, base_name); + maxp = tt_read_maxp_table(sfont); + num_glyphs = (card16) maxp->numGlyphs; + free(maxp); } + GIDToCIDMap = NEW(num_glyphs, uint16_t); + memset(GIDToCIDMap, 0, num_glyphs*sizeof(uint16_t)); if (sfont->type == SFNT_TYPE_POSTSCRIPT) { - is_cidfont = handle_CIDFont(sfont, &GIDToCIDMap, &csi); - } else { - is_cidfont = 0; - } - - if (verbose > VERBOSE_LEVEL_MIN) { - dpx_message("\n"); - dpx_message("otf_cmap>> Unicode charmap for font=\"%s\" layout=\"%s\"\n", - map_name, (otl_tags ? otl_tags : "none")); - } - - cmap_id = CMap_cache_find(cmap_name); - if (cmap_id >= 0) { - free(cmap_name); - free(base_name); - free(GIDToCIDMap); - - sfnt_close(sfont); - ttstub_input_close(handle); + cff_font *cffont; + card16 gid; + + offset = sfnt_find_table_pos(sfont, "CFF "); + cffont = cff_open(sfont->handle, offset, 0); + if (!cffont) { + free(cmap_name); + free(GIDToCIDMap); + sfnt_close(sfont); + ttstub_input_close(handle); + return -1; + } + if (!(cffont->flag & FONTTYPE_CIDFONT)) { + csi.registry = strdup("Adobe"); + csi.ordering = strdup("Identity"); + csi.supplement = 0; + for (gid = 0; gid < num_glyphs; gid++) { + GIDToCIDMap[gid] = gid; + } + } else { + if (!cff_dict_known(cffont->topdict, "ROS")) { + csi.registry = strdup("Adobe"); + csi.ordering = strdup("Identity"); + csi.supplement = 0; + } else { + card16 reg, ord; - if (verbose > VERBOSE_LEVEL_MIN) - dpx_message("otf_cmap>> Found at cmap_id=%d.\n", cmap_id); + reg = (card16) cff_dict_get(cffont->topdict, "ROS", 0); + ord = (card16) cff_dict_get(cffont->topdict, "ROS", 1); + csi.registry = cff_get_string(cffont, reg); + csi.ordering = cff_get_string(cffont, ord); + csi.supplement = (int) cff_dict_get(cffont->topdict, "ROS", 2); + } + cff_read_charsets(cffont); + create_GIDToCIDMap(GIDToCIDMap, num_glyphs, cffont); + } + cff_close(cffont); + } else { + uint16_t gid; - return cmap_id; + csi.registry = strdup("Adobe"); + csi.ordering = strdup("Identity"); + csi.supplement = 0; + for (gid = 0; gid < num_glyphs; gid++) { + GIDToCIDMap[gid] = gid; + } } ttcmap = tt_cmap_read(sfont, 3, 10); /* Microsoft UCS4 */ @@ -1486,66 +1444,285 @@ otf_load_Unicode_CMap (const char *map_name, int ttc_index, /* 0 for non-TTC fon ttcmap = tt_cmap_read(sfont, 3, 1); /* Microsoft UCS2 */ if (!ttcmap) { ttcmap = tt_cmap_read(sfont, 0, 3); /* Unicode 2.0 or later */ - if (!ttcmap) { - _tt_abort("Unable to read OpenType/TrueType Unicode cmap table."); - } } } - if (wmode == 1) { - gsub_vert = otl_gsub_new(); - if (otl_gsub_add_feat(gsub_vert, "*", "*", "vrt2", sfont) < 0) { - if (otl_gsub_add_feat(gsub_vert, "*", "*", "vert", sfont) < 0) { - dpx_warning("GSUB feature vrt2/vert not found."); - otl_gsub_release(gsub_vert); - gsub_vert = NULL; + if (ttcmap) { + CMap *cmap = NULL; + int32_t *map_base, *map_sub; + otl_gsub *gsub_vert = NULL; + otl_gsub *gsub_list = NULL; + uint32_t gid; + + if (wmode == 1) { + gsub_vert = otl_gsub_new(); + if (otl_gsub_add_feat(gsub_vert, "*", "*", "vrt2", sfont) < 0) { + if (otl_gsub_add_feat(gsub_vert, "*", "*", "vert", sfont) < 0) { + dpx_warning("GSUB feature vrt2/vert not found."); + otl_gsub_release(gsub_vert); + gsub_vert = NULL; + } else { + otl_gsub_select(gsub_vert, "*", "*", "vert"); + } } else { - otl_gsub_select(gsub_vert, "*", "*", "vert"); + otl_gsub_select(gsub_vert, "*", "*", "vrt2"); } } else { - otl_gsub_select(gsub_vert, "*", "*", "vrt2"); + gsub_vert = NULL; } - } else { - gsub_vert = NULL; - } - - if (otl_tags) { - gsub_list = otl_gsub_new(); - if (otl_gsub_add_feat_list(gsub_list, otl_tags, sfont) < 0) { - dpx_warning("Reading GSUB feature table(s) failed for \"%s\"", otl_tags); + if (otl_tags) { + gsub_list = otl_gsub_new(); + if (otl_gsub_add_feat_list(gsub_list, otl_tags, sfont) < 0) { + dpx_warning("Reading GSUB feature table(s) failed for \"%s\"", otl_tags); + } else { + otl_gsub_set_chain(gsub_list, otl_tags); + } } else { - otl_gsub_set_chain(gsub_list, otl_tags); + gsub_list = NULL; } - } else { - gsub_list = NULL; + cmap = CMap_new(); + CMap_set_name(cmap, cmap_name); + CMap_set_type(cmap, CMAP_TYPE_CODE_TO_CID); + CMap_set_wmode(cmap, wmode); + CMap_add_codespacerange(cmap, lrange_min, lrange_max, 4); + CMap_set_CIDSysInfo(cmap, &csi); + map_base = NEW(num_glyphs, int32_t); + map_sub = NEW(num_glyphs, int32_t); + for (gid = 0; gid < num_glyphs; gid++) { + map_base[gid] = -1; + map_sub[gid] = -1; + } + switch (ttcmap->format) { + case 12: + load_cmap12(ttcmap->map, GIDToCIDMap, num_glyphs, + gsub_vert, gsub_list, + cmap, map_base, map_sub); + break; + case 4: + load_cmap4(ttcmap->map, GIDToCIDMap, num_glyphs, + gsub_vert, gsub_list, + cmap, map_base, map_sub); + break; + } + if (gsub_vert) + otl_gsub_release(gsub_vert); + if (gsub_list) + otl_gsub_release(gsub_list); + tt_cmap_release(ttcmap); + + if (otl_tags) { + CMap *tounicode = NULL; + char *tounicode_name; + int tounicode_id; + + tounicode_name = NEW(strlen(map_name)+strlen(",000-UCS32-Add")+1, char); + sprintf(tounicode_name, "%s,%03d-UCS32-Add", map_name, ttc_index); + tounicode_id = CMap_cache_find(tounicode_name); + + if (tounicode_id >= 0) { + tounicode = CMap_cache_get(tounicode_id); + } else { + tounicode = CMap_new(); + CMap_set_name (tounicode, tounicode_name); + CMap_set_type (tounicode, CMAP_TYPE_TO_UNICODE); + CMap_set_wmode(tounicode, 0); + CMap_add_codespacerange(tounicode, srange_min, srange_max, 2); + CMap_set_CIDSysInfo(tounicode, &CSI_UNICODE); + CMap_add_bfchar(tounicode, srange_min, 2, srange_max, 2); + tounicode_id = CMap_cache_add(tounicode); + } + + free(tounicode_name); + + for (gid = 0; gid < num_glyphs; gid++) { + uint16_t cid = GIDToCIDMap[gid]; + unsigned char src[2], dst[4]; + if (cid > 0) { + int32_t ch = UC_is_valid(map_base[gid]) ? map_base[gid] : map_sub[gid]; + if (UC_is_valid(ch)) { + unsigned char *p = dst; + unsigned char *endptr = dst + 4; + size_t len; + src[0] = (cid >> 8) & 0xff; + src[1] = cid & 0xff; + len = UC_UTF16BE_encode_char(ch, &p, endptr); + if (len > 0) { + CMap_add_bfchar(tounicode, src, 2, dst, len); + } + } + } + } + } + + cmap_id = CMap_cache_add(cmap); } - cmap_id = load_base_CMap(cmap_name, tounicode_add, wmode, - (is_cidfont ? &csi : NULL), GIDToCIDMap, - gsub_vert, gsub_list, ttcmap); + free(cmap_name); + free(GIDToCIDMap); + free(csi.registry); + free(csi.ordering); + sfnt_close(sfont); + ttstub_input_close(handle); - if (cmap_id < 0) - _tt_abort("Failed to read OpenType/TrueType cmap table."); + return cmap_id; +} - if (gsub_vert) - otl_gsub_release(gsub_vert); - gsub_vert = NULL; +int +otf_try_load_GID_to_CID_map (const char *map_name, int ttc_index, int wmode) +{ + int cmap_id = -1; + sfnt *sfont = NULL; + ULONG offset = 0; + char *cmap_name = NULL; + rust_input_handle_t handle = NULL; + + if (!map_name) + return -1; + + if (ttc_index > 999 || ttc_index < 0) { + return -1; /* Sorry for this... */ + } + + /* Check if already loaded */ + cmap_name = NEW(strlen(map_name)+strlen("-GID")+5, char); + sprintf(cmap_name, "%s:%3d-GID", map_name, ttc_index); + cmap_id = CMap_cache_find(cmap_name); + if (cmap_id >= 0) { + free(cmap_name); + if (dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) + dpx_message("otf_cmap>> GID-to-CID mapping found at cmap_id=%d.\n", cmap_id); - if (gsub_list) - otl_gsub_release(gsub_list); - gsub_list = NULL; + return cmap_id; + } + + handle = dpx_open_truetype_file(map_name); + if (handle == NULL) + handle = dpx_open_opentype_file(map_name); + if (handle == NULL) { + handle = dpx_open_dfont_file(map_name); + if (handle == NULL) { + free(cmap_name); + return -1; + } + sfont = dfont_open(handle, ttc_index); + } else { + sfont = sfnt_open(handle); + } + + if (!sfont) { + dpx_warning("Could not open OpenType/TrueType/dfont font file \"%s\"", map_name); + free(cmap_name); + ttstub_input_close(handle); + return -1; + } + switch (sfont->type) { + case SFNT_TYPE_TTC: + offset = ttc_read_offset(sfont, ttc_index); + if (offset == 0) { + dpx_warning("Invalid TTC index for font \"%s\": %d", map_name, ttc_index); + sfnt_close(sfont); + ttstub_input_close(handle); + free(cmap_name); + return -1; + } + break; + case SFNT_TYPE_TRUETYPE: + case SFNT_TYPE_POSTSCRIPT: + offset = 0; + break; + case SFNT_TYPE_DFONT: + offset = sfont->offset; + break; + default: + dpx_warning("Not a OpenType/TrueType/TTC font?: %s", map_name); + sfnt_close(sfont); + ttstub_input_close(handle); + free(cmap_name); + return -1; + } + if (sfnt_read_table_directory(sfont, offset) < 0) { + dpx_warning("Could not read OpenType/TrueType table directory: %s", map_name); + sfnt_close(sfont); + ttstub_input_close(handle); free(cmap_name); - free(base_name); - free(GIDToCIDMap); + return -1; + } + if (sfont->type != SFNT_TYPE_POSTSCRIPT) { + free(cmap_name); + sfnt_close(sfont); + ttstub_input_close(handle); + return -1; + } + + /* Read GID-to-CID mapping if CFF OpenType is found. */ + if (sfont->type == SFNT_TYPE_POSTSCRIPT) { + cff_font *cffont; + struct tt_maxp_table *maxp; + const unsigned char csrange[4] = {0x00, 0x00, 0xff, 0xff}; + uint16_t num_glyphs = 0; + + maxp = tt_read_maxp_table(sfont); + num_glyphs = (card16) maxp->numGlyphs; + free(maxp); - if (is_cidfont) { + offset = sfnt_find_table_pos(sfont, "CFF "); + cffont = cff_open(sfont->handle, offset, 0); + if (cffont && cffont->flag & FONTTYPE_CIDFONT) { + CMap *cmap; + uint16_t gid; + uint16_t *GIDToCIDMap = NULL; + CIDSysInfo csi = {NULL, NULL, 0}; + + if (!cff_dict_known(cffont->topdict, "ROS")) { + csi.registry = strdup("Adobe"); + csi.ordering = strdup("Identity"); + csi.supplement = 0; + } else { + card16 reg, ord; + + reg = (card16) cff_dict_get(cffont->topdict, "ROS", 0); + ord = (card16) cff_dict_get(cffont->topdict, "ROS", 1); + csi.registry = cff_get_string(cffont, reg); + csi.ordering = cff_get_string(cffont, ord); + csi.supplement = (int) cff_dict_get(cffont->topdict, "ROS", 2); + } + cff_read_charsets(cffont); + GIDToCIDMap = NEW(num_glyphs, uint16_t); + memset(GIDToCIDMap, 0, num_glyphs*sizeof(uint16_t)); + create_GIDToCIDMap(GIDToCIDMap, num_glyphs, cffont); + cmap = CMap_new(); + CMap_set_name (cmap, cmap_name); + CMap_set_type (cmap, CMAP_TYPE_CODE_TO_CID); + CMap_set_wmode(cmap, wmode); + CMap_add_codespacerange(cmap, &csrange[0], &csrange[2], 2); + CMap_set_CIDSysInfo(cmap, &csi); + for (gid = 0; gid < num_glyphs; gid++) { + unsigned char src[2], dst[2]; + src[0] = (gid >> 8) & 0xff; + src[1] = gid & 0xff; + dst[0] = (GIDToCIDMap[gid] >> 8) & 0xff; + dst[1] = GIDToCIDMap[gid] & 0xff; + CMap_add_bfchar(cmap, src, 2, dst, 2); + } + cmap_id = CMap_cache_add(cmap); + if (dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { + dpx_message("\n"); + dpx_message("otf_cmap>> Creating GID-to-CID mapping for font=\"%s\"\n", map_name); + } + free(GIDToCIDMap); + if (csi.registry) free(csi.registry); + if (csi.ordering) free(csi.ordering); } + if (cffont) + cff_close(cffont); + } - tt_cmap_release(ttcmap); - sfnt_close(sfont); - ttstub_input_close(handle); - return cmap_id; + free(cmap_name); + sfnt_close(sfont); + ttstub_input_close(handle); + + return cmap_id; } diff --git a/tectonic/dpx-tt_cmap.h b/tectonic/dpx-tt_cmap.h index bd04a0d257..1fe9702611 100644 --- a/tectonic/dpx-tt_cmap.h +++ b/tectonic/dpx-tt_cmap.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -25,8 +25,6 @@ #include "dpx-sfnt.h" -void otf_cmap_set_verbose (int level); - /* TrueType cmap table */ typedef struct { @@ -70,11 +68,11 @@ void tt_cmap_release (tt_cmap *cmap); /* Indirect reference */ pdf_obj *otf_create_ToUnicode_stream (const char *map_name, int ttc_index, - const char *used_chars, - int cmap_id); + const char *basefont, + const char *used_chars); /* CMap ID */ int otf_load_Unicode_CMap (const char *map_name, int ttc_index, const char *otl_opts, int wmode); - +int otf_try_load_GID_to_CID_map (const char *map_name, int ttc_index, int wmode); #endif /* _TT_CMAP_H_ */ diff --git a/tectonic/dpx-tt_gsub.c b/tectonic/dpx-tt_gsub.c index 55cb0d3783..f266897255 100644 --- a/tectonic/dpx-tt_gsub.c +++ b/tectonic/dpx-tt_gsub.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -30,18 +30,13 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-error.h" #include "dpx-mem.h" #include "dpx-otl_opt.h" #include "dpx-sfnt.h" -#define VERBOSE_LEVEL_MIN 0 -static int verbose = 0; -void -otl_gsub_set_verbose (int level) -{ - verbose = level; -} +#define VERBOSE_LEVEL_MIN 2 typedef USHORT Offset; typedef USHORT GlyphID; @@ -574,35 +569,31 @@ otl_gsub_read_alternate (struct otl_gsub_subtab *subtab, sfnt *sfont) data->AlternateSetCount = altset_offsets.count; if (data->AlternateSetCount == 0) { data->AlternateSet = NULL; - data->coverage.count = 0; - data->coverage.format = 0; - data->coverage.list = NULL; - return len; - } - data->AlternateSet = NEW(data->AlternateSetCount, - struct otl_gsub_altset); - for (i = 0; i < data->AlternateSetCount; i++) { - struct otl_gsub_altset *altset; - ULONG altset_offset; + } else { + data->AlternateSet = NEW(data->AlternateSetCount, + struct otl_gsub_altset); + for (i = 0; i < data->AlternateSetCount; i++) { + struct otl_gsub_altset *altset; + ULONG altset_offset; - altset = &(data->AlternateSet[i]); + altset = &(data->AlternateSet[i]); - altset_offset = offset + altset_offsets.value[i]; - sfnt_seek_set(sfont, altset_offset); - altset->GlyphCount = sfnt_get_ushort(sfont); - len += 2; - if (altset->GlyphCount == 0) { - altset->Alternate = NULL; - break; - } - altset->Alternate = NEW(altset->GlyphCount, GlyphID); - for (j = 0; j < altset->GlyphCount; j++) { - altset->Alternate[j] = sfnt_get_ushort(sfont); + altset_offset = offset + altset_offsets.value[i]; + sfnt_seek_set(sfont, altset_offset); + altset->GlyphCount = sfnt_get_ushort(sfont); len += 2; + if (altset->GlyphCount == 0) { + altset->Alternate = NULL; + continue; + } + altset->Alternate = NEW(altset->GlyphCount, GlyphID); + for (j = 0; j < altset->GlyphCount; j++) { + altset->Alternate[j] = sfnt_get_ushort(sfont); + len += 2; + } } + clt_release_number_list(&altset_offsets); } - clt_release_number_list(&altset_offsets); - sfnt_seek_set(sfont, offset + cov_offset); len += clt_read_coverage(&data->coverage, sfont); @@ -641,49 +632,46 @@ otl_gsub_read_ligature (struct otl_gsub_subtab *subtab, sfnt *sfont) data->LigSetCount = ligset_offsets.count; if (data->LigSetCount == 0) { data->LigatureSet = NULL; - data->coverage.count = 0; - data->coverage.format = 0; - data->coverage.list = NULL; - return len; - } - data->LigatureSet = NEW(data->LigSetCount, - struct otl_gsub_ligset); - for (i = 0; i < data->LigSetCount; i++) { - struct clt_number_list ligset_tab; - struct otl_gsub_ligset *ligset; - ULONG ligset_offset; - USHORT count; + } else { + data->LigatureSet = NEW(data->LigSetCount, + struct otl_gsub_ligset); + for (i = 0; i < data->LigSetCount; i++) { + struct clt_number_list ligset_tab; + struct otl_gsub_ligset *ligset; + ULONG ligset_offset; + USHORT count; - ligset = &(data->LigatureSet[i]); + ligset = &(data->LigatureSet[i]); - ligset_offset = offset + ligset_offsets.value[i]; - sfnt_seek_set(sfont, ligset_offset); - len += clt_read_number_list(&ligset_tab, sfont); + ligset_offset = offset + ligset_offsets.value[i]; + sfnt_seek_set(sfont, ligset_offset); + len += clt_read_number_list(&ligset_tab, sfont); - ligset->LigatureCount = ligset_tab.count; - if (ligset_tab.count == 0) { - ligset->Ligature = NULL; - break; - } - ligset->Ligature = NEW(ligset_tab.count, - struct otl_gsub_ligtab); - for (j = 0; j < ligset_tab.count; j++) { - sfnt_seek_set(sfont, ligset_offset + ligset_tab.value[j]); - ligset->Ligature[j].LigGlyph = sfnt_get_ushort(sfont); - ligset->Ligature[j].CompCount = sfnt_get_ushort(sfont); - if (ligset->Ligature[j].CompCount == 0) { - ligset->Ligature[j].Component = NULL; - break; + ligset->LigatureCount = ligset_tab.count; + if (ligset_tab.count == 0) { + ligset->Ligature = NULL; + continue; } - ligset->Ligature[j].Component = - NEW(ligset->Ligature[j].CompCount - 1, GlyphID); - for (count = 0; - count < ligset->Ligature[j].CompCount - 1; count++) { - ligset->Ligature[j].Component[count] = sfnt_get_ushort(sfont); + ligset->Ligature = NEW(ligset_tab.count, + struct otl_gsub_ligtab); + for (j = 0; j < ligset_tab.count; j++) { + sfnt_seek_set(sfont, ligset_offset + ligset_tab.value[j]); + ligset->Ligature[j].LigGlyph = sfnt_get_ushort(sfont); + ligset->Ligature[j].CompCount = sfnt_get_ushort(sfont); + if (ligset->Ligature[j].CompCount == 0) { + ligset->Ligature[j].Component = NULL; + continue; + } + ligset->Ligature[j].Component = + NEW(ligset->Ligature[j].CompCount - 1, GlyphID); + for (count = 0; + count < ligset->Ligature[j].CompCount - 1; count++) { + ligset->Ligature[j].Component[count] = sfnt_get_ushort(sfont); + } + len += 4 + count * 2; } - len += 4 + count * 2; + clt_release_number_list(&ligset_tab); } - clt_release_number_list(&ligset_tab); } clt_release_number_list(&ligset_offsets); @@ -872,7 +860,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) script_tab.DefaultLangSys != 0) { struct clt_langsys_table langsys_tab; - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("otl_gsub>> OTL script-language enabled: %c%c%c%c.dflt\n", script_list.record[script_idx].tag[0], script_list.record[script_idx].tag[1], @@ -902,7 +890,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) if (otl_match_optrule(language, langsys_rec->tag)) { struct clt_langsys_table langsys_tab; - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("otl_gsub>> OTL script-language enabled: %c%c%c%c.%c%c%c%c\n", script_list.record[script_idx].tag[0], script_list.record[script_idx].tag[1], @@ -940,7 +928,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) sfnt_seek_set(sfont, offset); clt_read_number_list(&lookup_list, sfont); - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("otl_gsub>> Reading OTL feature(s):"); } @@ -952,7 +940,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) struct clt_feature_table feature_table; int i; - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message(" %c%c%c%c", feature_list.record[feat_idx].tag[0], feature_list.record[feat_idx].tag[1], @@ -966,10 +954,11 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) sfnt_seek_set(sfont, offset); clt_read_feature_table(&feature_table, sfont); +#if 0 if (feature_table.FeatureParams != 0) { _tt_abort("unrecognized FeatureParams"); } - +#endif /* Lookup table */ for (i = 0; i < feature_table.LookupListIndex.count; i++) { struct clt_lookup_table lookup_table; @@ -988,7 +977,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) lookup_table.LookupType != OTL_GSUB_TYPE_ALTERNATE && lookup_table.LookupType != OTL_GSUB_TYPE_LIGATURE && lookup_table.LookupType != OTL_GSUB_TYPE_ESUBST) { - if (verbose > VERBOSE_LEVEL_MIN) + if (dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) dpx_warning("Skipping unsupported GSUB subtable: LookupType=%d", lookup_table.LookupType); continue; } @@ -1012,7 +1001,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) if (r <= 0) dpx_warning("Reading GSUB subtable (single) failed..."); else { - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("(single)"); } n_st++; @@ -1025,7 +1014,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) if (r <= 0) dpx_warning("Reading GSUB subtable (alternate) failed..."); else { - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("(alternate)"); } n_st++; @@ -1038,7 +1027,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) if (r <= 0) dpx_warning("Reading GSUB subtable (ligature) failed..."); else { - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("(ligature)"); } n_st++; @@ -1065,7 +1054,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) if (r <= 0) dpx_warning("Reading GSUB subtable (ext:single) failed..."); else { - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("(ext:single)"); } n_st++; @@ -1078,7 +1067,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) if (r <= 0) dpx_warning("Reading GSUB subtable (alternate) failed..."); else { - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("(alternate)"); } n_st++; @@ -1091,7 +1080,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) if (r <= 0) dpx_warning("Reading GSUB subtable (ext:ligature) failed..."); else { - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("(ext:ligature)"); } n_st++; @@ -1113,7 +1102,7 @@ otl_gsub_read_feat (struct otl_gsub_tab *gsub, sfnt *sfont) } } - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("\n"); dpx_message("otl_gsub>> %d subtable(s) read.\n", num_subtabs); } @@ -1326,7 +1315,7 @@ otl_gsub_add_feat (otl_gsub *gsub_list, gsub->feature = NEW(strlen(feature) +1, char); strcpy(gsub->feature, feature); - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("\n"); dpx_message("otl_gsub>> Reading \"%s.%s.%s\"...\n", script, language, feature); } @@ -1336,7 +1325,7 @@ otl_gsub_add_feat (otl_gsub *gsub_list, gsub_list->select = i; gsub_list->num_gsubs++; } else { - if(verbose > VERBOSE_LEVEL_MIN) { + if(dpx_conf.verbose_level > VERBOSE_LEVEL_MIN) { dpx_message("otl_gsub>> Failed\n"); } free(gsub->script); @@ -1679,3 +1668,349 @@ otl_gsub_apply_chain (otl_gsub *gsub_list, USHORT *gid) return retval; } + +#if 1 +#include "dpx-unicode.h" + +#ifndef is_used_char2 +#define is_used_char2(b,c) (((b)[(c)/8]) & (1 << (7-((c)%8)))) +#endif + +static int +add_glyph_if_valid (CMap *cmap, char *used_chars, + int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + uint16_t *GIDToCIDMap, USHORT gid, USHORT gid_sub) +{ + int count = 0; + unsigned char src[2], dst[4]; + unsigned char *p = dst, *endptr = dst + 4; + size_t len; + uint16_t cid_sub; + + if (gid_sub >= num_glyphs || gid >= num_glyphs) + return 0; + + cid_sub = GIDToCIDMap[gid_sub]; + if (is_used_char2(used_chars, cid_sub)) { + int32_t ch = map_base[gid]; + if (UC_is_valid(ch)) { + src[0] = (cid_sub >> 8) & 0xff; + src[1] = cid_sub & 0xff; + len = UC_UTF16BE_encode_char(ch, &p, endptr); + CMap_add_bfchar(cmap, src, 2, dst, len); + used_chars[cid_sub / 8] &= ~(1 << (7 - (cid_sub % 8))); + count = 1; + } else { + ch = map_sub[gid]; + if (UC_is_valid(ch)) { + src[0] = (cid_sub >> 8) & 0xff; + src[1] = cid_sub & 0xff; + len = UC_UTF16BE_encode_char(ch, &p, endptr); + CMap_add_bfchar(cmap, src, 2, dst, len); + used_chars[cid_sub / 8] &= ~(1 << (7 - (cid_sub % 8))); + count = 1; + } + } + } + return count; +} + +static int +add_ToUnicode_single (CMap *cmap, char *used_chars, + struct otl_gsub_subtab *subtab, + int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + uint16_t *GIDToCIDMap) +{ + int count = 0; + USHORT i, idx, gid; + USHORT gid_sub; + + assert(subtab); + + if (subtab->SubstFormat == 1) { + struct otl_gsub_single1 *data; + struct clt_coverage *cov; + + data = (subtab->table).single1; + cov = &data->coverage; + switch (cov->format) { + case 1: /* list */ + for (idx = 0; idx < cov->count; idx++) { + gid = cov->list[idx]; + gid_sub = gid + data->DeltaGlyphID; + count += add_glyph_if_valid(cmap, used_chars, + map_base, map_sub, num_glyphs, + GIDToCIDMap, gid, gid_sub); + } + break; + case 2: /* range */ + for (i = 0; i < cov->count; i++) { + for (gid = cov->range[i].Start; + gid <= cov->range[i].End && gid < num_glyphs; gid++) { + idx = cov->range[i].StartCoverageIndex + gid - cov->range[i].Start; + gid_sub = gid + data->DeltaGlyphID; + count += add_glyph_if_valid(cmap, used_chars, + map_base, map_sub, num_glyphs, + GIDToCIDMap, gid, gid_sub); + } + } + break; + } + } else if (subtab->SubstFormat == 2) { + struct otl_gsub_single2 *data; + struct clt_coverage *cov; + + data = (subtab->table).single2; + cov = &data->coverage; + switch (cov->format) { + case 1: /* list */ + for (idx = 0; idx < cov->count; idx++) { + gid = cov->list[idx]; + if (idx >= 0 && idx < data->GlyphCount) { + gid_sub = (data->Substitute)[idx]; + count += add_glyph_if_valid(cmap, used_chars, + map_base, map_sub, num_glyphs, + GIDToCIDMap, gid, gid_sub); + } + } + break; + case 2: /* range */ + for (i = 0; i < cov->count; i++) { + for (gid = cov->range[i].Start; + gid <= cov->range[i].End && gid < num_glyphs; gid++) { + idx = cov->range[i].StartCoverageIndex + gid - cov->range[i].Start; + if (idx >= 0 && idx < data->GlyphCount) { + gid_sub = (data->Substitute)[idx]; + count += add_glyph_if_valid(cmap, used_chars, + map_base, map_sub, num_glyphs, + GIDToCIDMap, gid, gid_sub); + } + } + } + break; + } + } + + return count; +} + +static int32_t +add_alternate1_inverse_map (CMap *cmap, char *used_chars, + int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + uint16_t *GIDToCIDMap, USHORT gid, int idx, + struct otl_gsub_alternate1 *data) +{ + int32_t count = 0; + + if (idx >= 0 && idx < data->AlternateSetCount) { + struct otl_gsub_altset *altset; + USHORT i; + + altset = &(data->AlternateSet[idx]); + if (altset->GlyphCount == 0) + return count; + for (i = 0; i < altset->GlyphCount; i++) { + USHORT gid_alt = altset->Alternate[i]; + count += add_glyph_if_valid(cmap, used_chars, + map_base, map_sub, num_glyphs, + GIDToCIDMap, gid, gid_alt); + } + } + return count; +} + +static int32_t +add_ToUnicode_alternate (CMap *cmap, char *used_chars, + struct otl_gsub_subtab *subtab, + int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + uint16_t *GIDToCIDMap) +{ + int32_t count = 0; + USHORT i, gid, idx; + + assert(subtab); + + if (subtab->SubstFormat == 1) { + struct otl_gsub_alternate1 *data; + struct clt_coverage *cov; + data = subtab->table.alternate1; + cov = &data->coverage; + switch (cov->format) { + case 1: /* list */ + for (idx = 0; idx < cov->count; idx++) { + gid = cov->list[idx]; + if (gid < num_glyphs) { + count += add_alternate1_inverse_map(cmap, used_chars, + map_base, map_sub, num_glyphs, + GIDToCIDMap, gid, idx, data); + } + } + break; + case 2: /* range */ + for (i = 0; i < cov->count; i++) { + for (gid = cov->range[i].Start; + gid <= cov->range[i].End && gid < num_glyphs; gid++) { + idx = cov->range[i].StartCoverageIndex + gid - cov->range[i].Start; + count += add_alternate1_inverse_map(cmap, used_chars, + map_base, map_sub, num_glyphs, + GIDToCIDMap, gid, idx, data); + } + } + break; + } + } + return count; +} + +static int32_t +add_ligature1_inverse_map (CMap *cmap, char *used_chars, + int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + uint16_t *GIDToCIDMap, USHORT gid_1, int idx, + struct otl_gsub_ligature1 *data) +{ + int32_t count = 0; + + if (idx >= 0 && idx < data->LigSetCount) { + struct otl_gsub_ligset *ligset; + USHORT i, j; + + ligset = &(data->LigatureSet[idx]); + for (j = 0; j < ligset->LigatureCount; j++) { + USHORT gid_sub = ligset->Ligature[j].LigGlyph; + if (gid_sub < num_glyphs) { + uint16_t cid = GIDToCIDMap[gid_sub]; + if (is_used_char2(used_chars, cid)) { + int32_t ch, *ucv; + USHORT comp_count = ligset->Ligature[j].CompCount; + int fail_count = 0; + + ucv = NEW(comp_count, int32_t); + ch = UC_is_valid(map_base[gid_1]) ? map_base[gid_1] : map_sub[gid_1]; + ucv[0] = ch; + fail_count += UC_is_valid(ch) ? 0 : 1; + for (i = 0; i < ligset->Ligature[j].CompCount - 1; i++) { + USHORT gid = ligset->Ligature[j].Component[i]; + if (gid < num_glyphs) { + ch = UC_is_valid(map_base[gid]) ? map_base[gid] : map_sub[gid]; + ucv[i+1] = ch; + fail_count += UC_is_valid(ch) ? 0 : 1; + } else { + fail_count += 1; + } + } + if (fail_count == 0) { + unsigned char src[2], *dst; + unsigned char *p, *endptr; + size_t len = 0; + + src[0] = (cid >> 8) & 0xff; + src[1] = cid & 0xff; + dst = NEW(comp_count*4, unsigned char); + p = dst; + endptr = dst + comp_count * 4; + for (i = 0; i < comp_count; i++) { + len += UC_UTF16BE_encode_char(ucv[i], &p, endptr); + } + CMap_add_bfchar(cmap, src, 2, dst, len); + used_chars[cid / 8] &= ~(1 << (7 - (cid % 8))); + count++; + free(dst); + } + free(ucv); + } + } + } + } + + return count; +} + +static int32_t +add_ToUnicode_ligature (CMap *cmap, char *used_chars, + struct otl_gsub_subtab *subtab, + int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + uint16_t *GIDToCIDMap) +{ + int32_t count = 0; + USHORT i, idx, gid; + + assert(subtab); + + if (subtab->SubstFormat == 1) { + struct otl_gsub_ligature1 *data; + struct clt_coverage *cov; + + data = subtab->table.ligature1; + cov = &data->coverage; + switch (cov->format) { + case 1: /* list */ + for (idx = 0; idx < cov->count; idx++) { + gid = cov->list[idx]; + if (gid < num_glyphs) { + count += add_ligature1_inverse_map(cmap, used_chars, + map_base, map_sub, num_glyphs, + GIDToCIDMap, gid, idx, data); + } + } + break; + case 2: /* range */ + for (i = 0; i < cov->count; i++) { + for (gid = cov->range[i].Start; + gid <= cov->range[i].End && gid < num_glyphs; gid++) { + idx = cov->range[i].StartCoverageIndex + gid - cov->range[i].Start; + if (gid < num_glyphs) { + count += add_ligature1_inverse_map(cmap, used_chars, + map_base, map_sub, num_glyphs, + GIDToCIDMap, gid, idx, data); + } + } + } + break; + } + } + + return 0; +} + +int +otl_gsub_add_ToUnicode (CMap *cmap, char *used_chars, + int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + uint16_t *GIDToCIDMap, sfnt *sfont) +{ + int count = 0; + otl_gsub *gsub_list; + struct otl_gsub_tab *gsub; + struct otl_gsub_subtab *subtab; + int i, j; + + gsub_list = otl_gsub_new(); + otl_gsub_add_feat(gsub_list, "*", "*", "*", sfont); + + for (i = 0; i < gsub_list->num_gsubs; i++) { + gsub = &(gsub_list->gsubs[i]); + for (j = 0; j < gsub->num_subtables; j++) { + subtab = &(gsub->subtables[j]); + switch ((int) subtab->LookupType){ + case OTL_GSUB_TYPE_SINGLE: + count += add_ToUnicode_single(cmap, used_chars, subtab, + map_base, map_sub, num_glyphs, + GIDToCIDMap); + break; + case OTL_GSUB_TYPE_ALTERNATE: + count += add_ToUnicode_alternate(cmap, used_chars, subtab, + map_base, map_sub, num_glyphs, + GIDToCIDMap); + break; + case OTL_GSUB_TYPE_LIGATURE: + count += add_ToUnicode_ligature(cmap, used_chars, subtab, + map_base, map_sub, num_glyphs, + GIDToCIDMap); + break; + } + } + } + otl_gsub_release(gsub_list); + + return count; +} +#endif diff --git a/tectonic/dpx-tt_gsub.h b/tectonic/dpx-tt_gsub.h index 4ebbd00c56..8d541fcc47 100644 --- a/tectonic/dpx-tt_gsub.h +++ b/tectonic/dpx-tt_gsub.h @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2002-2017 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2002-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -21,13 +21,11 @@ #ifndef _TT_GSUB_H_ #define _TT_GSUB_H_ +#include "dpx-cmap.h" #include "dpx-core.h" - #include "dpx-otl_opt.h" #include "dpx-sfnt.h" -void otl_gsub_set_verbose (int level); - typedef struct otl_gsub otl_gsub; /* LookupType for GSUB */ @@ -62,4 +60,7 @@ int otl_gsub_add_feat_list (otl_gsub *gsub_list, const char *otl_tags, sfnt *sfo int otl_gsub_set_chain (otl_gsub *gsub_list, const char *otl_tags); int otl_gsub_apply_chain (otl_gsub *gsub_list, USHORT *gid); +int otl_gsub_add_ToUnicode (CMap *cmap, char *used_chars, + int32_t *map_base, int32_t *map_sub, USHORT num_glyphs, + uint16_t *GIDToCIDMap, sfnt *sfont); #endif /* _TT_GSUB_H_ */ diff --git a/tectonic/dpx-tt_post.c b/tectonic/dpx-tt_post.c index 12f7de3954..c3dfe94657 100644 --- a/tectonic/dpx-tt_post.c +++ b/tectonic/dpx-tt_post.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-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -42,28 +42,12 @@ read_v2_post_names (struct tt_post_table *post, sfnt *sfont) indices = NEW(post->numberOfGlyphs, USHORT); maxidx = 257; - for (i = 0; - i < post->numberOfGlyphs; i++) { + for (i = 0; i < post->numberOfGlyphs; i++) { idx = sfnt_get_ushort(sfont); if (idx >= 258) { if (idx > maxidx) maxidx = idx; - if (idx > 32767) { - /* Although this is strictly speaking out of spec, it seems to work - and there are real-life fonts that use it. - We show a warning only once, instead of thousands of times */ - static char warning_issued = 0; - if (!warning_issued) { - dpx_warning("TrueType post table name index %u > 32767", idx); - warning_issued = 1; - } - /* In a real-life large font, (x)dvipdfmx crashes if we use - nonvanishing idx in the case of idx > 32767. - If we set idx = 0, (x)dvipdfmx works fine for the font and - created pdf seems fine. The post table may not be important - in such a case */ - idx = 0; - } + /* Tectonic: #if 0 stanza removed */ } indices[i] = idx; } @@ -156,9 +140,8 @@ tt_lookup_post_table (struct tt_post_table *post, const char *glyphname) assert(post && glyphname); - for (gid = 0; gid < post->count; gid++) { - if (post->glyphNamePtr[gid] && - streq_ptr(glyphname, post->glyphNamePtr[gid])) { + for (gid = 0; gid < post->numberOfGlyphs; gid++) { + if (post->glyphNamePtr[gid] && streq_ptr(glyphname, post->glyphNamePtr[gid])) { return gid; } } @@ -169,7 +152,7 @@ tt_lookup_post_table (struct tt_post_table *post, const char *glyphname) char* tt_get_glyphname (struct tt_post_table *post, USHORT gid) { - if (gid < post->count && post->glyphNamePtr[gid]) + if (gid < post->numberOfGlyphs && post->glyphNamePtr[gid]) return xstrdup(post->glyphNamePtr[gid]); return NULL; } diff --git a/tectonic/dpx-tt_table.c b/tectonic/dpx-tt_table.c index dcf7b47ff6..f0d51c53ba 100644 --- a/tectonic/dpx-tt_table.c +++ b/tectonic/dpx-tt_table.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-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -398,9 +398,12 @@ tt_get_name (sfnt *sfont, char *dest, USHORT destlen, USHORT length = 0; USHORT num_names, string_offset; ULONG name_offset; - int i; + int i, j; + int is_utf16_be; name_offset = sfnt_locate_table (sfont, "name"); + is_utf16_be = (plat_id == 3) && (enco_id == 1) && + (lang_id == 0x0409u) && (name_id == 6); if (sfnt_get_ushort(sfont)) _tt_abort("Expecting zero"); @@ -420,12 +423,22 @@ tt_get_name (sfnt *sfont, char *dest, USHORT destlen, /* language ID value 0xffffu for `accept any language ID' */ if ((p_id == plat_id) && (e_id == enco_id) && (lang_id == 0xffffu || l_id == lang_id) && (n_id == name_id)) { + if (is_utf16_be) { + length /= 2; + } if (length > destlen - 1) { dpx_warning("Name string too long (%u), truncating to %u", length, destlen); length = destlen - 1; } sfnt_seek_set (sfont, name_offset+string_offset+offset); - sfnt_read((unsigned char*)dest, length, sfont); + if (is_utf16_be) { + for (j=0;jdescendant; - return otf_create_ToUnicode_stream(CIDFont_get_ident(cidfont), - CIDFont_get_opt_index(cidfont), - Type0Font_get_usedchars(font), - font->cmap_id); -} - /* Try to load ToUnicode CMap from file system first, if not found fallback to - * font CMap reverse lookup. */ + * font CMap reverse lookup. + * CHANGED: CMap here is not always Unicode to CID mapping. Don't use reverse lookup. + */ static pdf_obj * Type0Font_try_load_ToUnicode_stream(Type0Font *font, char *cmap_base) { - char *cmap_name = NEW(strlen(cmap_base) + strlen("-UTF-16"), char); pdf_obj *tounicode; + char *cmap_name; + cmap_name = NEW(strlen(cmap_base)+strlen("-UTF16")+1, char); sprintf(cmap_name, "%s-UTF16", cmap_base); tounicode = pdf_read_ToUnicode_file(cmap_name); if (!tounicode) { sprintf(cmap_name, "%s-UCS2", cmap_base); tounicode = pdf_read_ToUnicode_file(cmap_name); } - free(cmap_name); - if (!tounicode) - tounicode = Type0Font_create_ToUnicode_stream(font); + if (!tounicode) { + CIDFont *cidfont = font->descendant; + tounicode = otf_create_ToUnicode_stream(CIDFont_get_ident(cidfont), + CIDFont_get_opt_index(cidfont), + CIDFont_get_fontname(cidfont), + Type0Font_get_usedchars(font)); + } return tounicode; } static void -add_ToUnicode (Type0Font *font) +Type0Font_attach_ToUnicode_stream (Type0Font *font) { pdf_obj *tounicode; CIDFont *cidfont; @@ -215,21 +206,30 @@ add_ToUnicode (Type0Font *font) csi = CIDFont_get_CIDSysInfo(cidfont); fontname = CIDFont_get_fontname(cidfont); if (CIDFont_get_embedding(cidfont)) { - fontname += 7; /* FIXME */ + fontname += 7; /* FIXME: Skip pseudo unique tag... */ } - if (streq_ptr(csi->registry, "Adobe") && - streq_ptr(csi->ordering, "Identity")) { + if (streq_ptr(csi->registry, "Adobe") && streq_ptr(csi->ordering, "Identity")) { switch (CIDFont_get_subtype(cidfont)) { case CIDFONT_TYPE2: /* PLEASE FIX THIS */ - tounicode = Type0Font_create_ToUnicode_stream(font); + { + tounicode = otf_create_ToUnicode_stream(CIDFont_get_ident(cidfont), + CIDFont_get_opt_index(cidfont), + CIDFont_get_fontname(cidfont), + Type0Font_get_usedchars(font)); + } break; default: - if (CIDFont_get_flag(cidfont, CIDFONT_FLAG_TYPE1C)) { /* FIXME */ - tounicode = Type0Font_create_ToUnicode_stream(font); - } else if (CIDFont_get_flag(cidfont, CIDFONT_FLAG_TYPE1)) { /* FIXME */ - /* Font loader will create ToUnicode and set. */ + if (CIDFont_get_flag(cidfont, CIDFONT_FLAG_TYPE1C)) { + tounicode = otf_create_ToUnicode_stream(CIDFont_get_ident(cidfont), + CIDFont_get_opt_index(cidfont), + CIDFont_get_fontname(cidfont), + Type0Font_get_usedchars(font)); + } else if (CIDFont_get_flag(cidfont, CIDFONT_FLAG_TYPE1)) { + /* FIXME: handled on very different timing. + * Font loader will create ToUnicode and set. + */ return; } else { tounicode = Type0Font_try_load_ToUnicode_stream(font, fontname); @@ -268,8 +268,9 @@ Type0Font_dofont (Type0Font *font) if (!font || !font->indirect) return; - if (!pdf_lookup_dict(font->fontdict, "ToUnicode")) { /* FIXME */ - add_ToUnicode(font); + /* FIXME: Should move to pdffont.c */ + if (!pdf_lookup_dict(font->fontdict, "ToUnicode")) { + Type0Font_attach_ToUnicode_stream(font); } } @@ -368,10 +369,8 @@ Type0Font_cache_find (const char *map_name, int cmap_id, fontmap_opt *fmap_opt) CIDSysInfo *csi; char *fontname = NULL; int cid_id = -1, parent_id = -1, wmode = 0; - int pdf_ver; - pdf_ver = pdf_get_version(); - if (!map_name || cmap_id < 0 || pdf_ver < 2) + if (!map_name || cmap_id < 0 || pdf_check_version(1, 2) < 0) return -1; /* @@ -461,7 +460,7 @@ Type0Font_cache_find (const char *map_name, int cmap_id, fontmap_opt *fmap_opt) */ fontname = CIDFont_get_fontname(cidfont); - if (__verbose) { + if (dpx_conf.verbose_level > 0) { if (CIDFont_get_embedding(cidfont) && strlen(fontname) > 7) dpx_message("(CID:%s)", fontname+7); /* skip XXXXXX+ */ else diff --git a/tectonic/dpx-type0.h b/tectonic/dpx-type0.h index 5fe19841c5..f9fa693068 100644 --- a/tectonic/dpx-type0.h +++ b/tectonic/dpx-type0.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. This program is free software; you can redistribute it and/or modify @@ -30,8 +30,6 @@ typedef struct Type0Font Type0Font; -void Type0Font_set_verbose (int level); - int Type0Font_get_wmode (Type0Font *font); char *Type0Font_get_usedchars (Type0Font *font); diff --git a/tectonic/dpx-type1.c b/tectonic/dpx-type1.c index c9df9a4300..1eb43d3530 100644 --- a/tectonic/dpx-type1.c +++ b/tectonic/dpx-type1.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2008-2016 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, + Copyright (C) 2008-2018 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -34,6 +34,7 @@ #include "dpx-cff_dict.h" #include "dpx-cff_limits.h" #include "dpx-cff_types.h" +#include "dpx-dpxconf.h" #include "dpx-error.h" #include "dpx-mem.h" #include "dpx-numbers.h" @@ -499,7 +500,7 @@ pdf_font_load_type1 (pdf_font *font) double *widths; card16 *GIDMap, num_glyphs = 0; int offset; - int code, verbose; + int code; rust_input_handle_t handle; assert(font); @@ -507,8 +508,6 @@ pdf_font_load_type1 (pdf_font *font) if (!pdf_font_is_in_use(font)) return 0; - verbose = pdf_font_get_verbose(); - encoding_id = pdf_font_get_encoding (font); fontdict = pdf_font_get_resource (font); @@ -604,7 +603,7 @@ pdf_font_load_type1 (pdf_font *font) if (gid < 0) _tt_abort("Type 1 font with no \".notdef\" glyph???"); GIDMap[0] = (card16) gid; - if (verbose > 2) + if (dpx_conf.verbose_level > 2) dpx_message("[glyphs:/.notdef"); num_glyphs = 1; @@ -654,7 +653,7 @@ pdf_font_load_type1 (pdf_font *font) prev = code; num_glyphs++; - if (verbose > 2) + if (dpx_conf.verbose_level > 2) dpx_message("/%s", glyph); /* CharSet is actually string object. */ @@ -743,11 +742,16 @@ pdf_font_load_type1 (pdf_font *font) } if (i == num_glyphs) { - if (verbose > 2) + if (dpx_conf.verbose_level > 2) dpx_message("/%s", achar_name); GIDMap[num_glyphs++] = achar_gid; charset->data.glyphs[charset->num_entries] = cff_get_seac_sid(cffont, achar_name); charset->num_entries += 1; + /* CharSet is actually string object. */ + { + pdf_add_stream(pdfcharset, "/", 1); + pdf_add_stream(pdfcharset, achar_name, strlen(achar_name)); + } } for (i = 0; i < num_glyphs; i++) { @@ -755,11 +759,16 @@ pdf_font_load_type1 (pdf_font *font) break; } if (i == num_glyphs) { - if (verbose > 2) + if (dpx_conf.verbose_level > 2) dpx_message("/%s", bchar_name); GIDMap[num_glyphs++] = bchar_gid; charset->data.glyphs[charset->num_entries] = cff_get_seac_sid(cffont, bchar_name); charset->num_entries += 1; + /* CharSet is actually string object. */ + { + pdf_add_stream(pdfcharset, "/", 1); + pdf_add_stream(pdfcharset, achar_name, strlen(achar_name)); + } } } widths[gid] = gm.wx; @@ -777,7 +786,7 @@ pdf_font_load_type1 (pdf_font *font) cffont->charsets = charset; } - if (verbose > 2) + if (dpx_conf.verbose_level > 2) dpx_message("]"); /* Now we can update the String Index */ @@ -788,7 +797,7 @@ pdf_font_load_type1 (pdf_font *font) add_metrics(font, cffont, enc_vec, widths, num_glyphs); offset = write_fontfile(font, cffont, pdfcharset); - if (verbose > 1) + if (dpx_conf.verbose_level > 1) dpx_message("[%u glyphs][%d bytes]", num_glyphs, offset); pdf_release_obj(pdfcharset); @@ -805,6 +814,5 @@ pdf_font_load_type1 (pdf_font *font) free(widths); free(GIDMap); - /* Maybe writing Charset is recommended for subsetted font. */ return 0; } diff --git a/tectonic/dpx-type1c.c b/tectonic/dpx-type1c.c index dacb38d1da..322dfdb85e 100644 --- a/tectonic/dpx-type1c.c +++ b/tectonic/dpx-type1c.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2008-2016 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, + Copyright (C) 2008-2018 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -46,6 +46,7 @@ #include "dpx-cff_limits.h" #include "dpx-cff_types.h" #include "dpx-cs_type2.h" +#include "dpx-dpxconf.h" #include "dpx-dpxfile.h" #include "dpx-error.h" #include "dpx-mem.h" @@ -248,12 +249,9 @@ pdf_font_load_type1c (pdf_font *font) cs_ginfo ginfo; double nominal_width, default_width, notdef_width; double widths[256]; - int verbose; assert(font); - verbose = pdf_font_get_verbose(); - if (!pdf_font_is_in_use(font)) { return 0; } @@ -427,7 +425,7 @@ pdf_font_load_type1c (pdf_font *font) /* First we add .notdef glyph. * All Type 1 font requires .notdef glyph to be present. */ - if (verbose > 2) { + if (dpx_conf.verbose_level > 2) { dpx_message("[glyphs:/.notdef"); } size = cs_idx->offset[1] - cs_idx->offset[0]; @@ -501,7 +499,7 @@ pdf_font_load_type1c (pdf_font *font) pdf_add_stream(pdfcharset, "/", 1); pdf_add_stream(pdfcharset, enc_vec[code], strlen(enc_vec[code])); - if (verbose > 2) { + if (dpx_conf.verbose_level > 2) { dpx_message("/%s", enc_vec[code]); } @@ -527,7 +525,7 @@ pdf_font_load_type1c (pdf_font *font) charset->num_entries += 1; num_glyphs++; } - if (verbose > 2) { + if (dpx_conf.verbose_level > 2) { dpx_message("]"); } free(data); @@ -713,7 +711,7 @@ pdf_font_load_type1c (pdf_font *font) sfnt_close(sfont); ttstub_input_close(handle); - if (verbose > 1) { + if (dpx_conf.verbose_level > 1) { dpx_message("[%u/%u glyphs][%d bytes]", num_glyphs, cs_count, offset); } diff --git a/tectonic/dpx-unicode.c b/tectonic/dpx-unicode.c index 3221ae47ac..947620a7b7 100644 --- a/tectonic/dpx-unicode.c +++ b/tectonic/dpx-unicode.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-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -71,7 +71,7 @@ UC_UTF16BE_is_valid_string (const unsigned char *p, const unsigned char *endptr) bool UC_UTF8_is_valid_string (const unsigned char *p, const unsigned char *endptr) { - if (p + 1 >= endptr) + if (p >= endptr) return false; while (p < endptr) { int32_t ucv = UC_UTF8_decode_char(&p, endptr); @@ -116,7 +116,7 @@ UC_UTF16BE_encode_char (int32_t ucv, unsigned char **pp, unsigned char *endptr) unsigned char *p = *pp; if (ucv >= 0 && ucv <= 0xFFFF) { - if (p + 2 >= endptr) + if (p + 2 > endptr) return 0; p[0] = (ucv >> 8) & 0xff; p[1] = ucv & 0xff; @@ -124,7 +124,7 @@ UC_UTF16BE_encode_char (int32_t ucv, unsigned char **pp, unsigned char *endptr) } else if (ucv >= 0x010000 && ucv <= 0x10FFFF) { unsigned short high, low; - if (p + 4 >= endptr) + if (p + 4 > endptr) return 0; ucv -= 0x00010000; high = (ucv >> UC_SUR_SHIFT) + UC_SUR_HIGH_START; @@ -135,7 +135,7 @@ UC_UTF16BE_encode_char (int32_t ucv, unsigned char **pp, unsigned char *endptr) p[3] = (low & 0xff); count = 4; } else { - if (p + 2 >= endptr) + if (p + 2 > endptr) return 0; p[0] = (UC_REPLACEMENT_CHAR >> 8) & 0xff; p[1] = (UC_REPLACEMENT_CHAR & 0xff); @@ -200,25 +200,25 @@ UC_UTF8_encode_char (int32_t ucv, unsigned char **pp, unsigned char *endptr) return 0; if (ucv < 0x7f) { - if (p >= endptr - 1) + if (p + 1 > endptr) return 0; p[0] = (unsigned char) ucv; count = 1; } else if (ucv <= 0x7ff) { - if (p >= endptr -2) + if (p + 2 > endptr) return 0; p[0] = (unsigned char) (0xc0 | (ucv >> 6)); p[1] = (unsigned char) (0x80 | (ucv & 0x3f)); count = 2; } else if (ucv <= 0xffff) { - if (p >= endptr - 3) + if (p + 3 > endptr) return 0; p[0] = (unsigned char) (0xe0 | (ucv >> 12)); p[1] = (unsigned char) (0x80 | ((ucv >> 6) & 0x3f)); p[2] = (unsigned char) (0x80 | (ucv & 0x3f)); count = 3; } else if (ucv <= 0x1fffff) { - if (p >= endptr - 4) + if (p + 4 > endptr) return 0; p[0] = (unsigned char) (0xf0 | (ucv >> 18)); p[1] = (unsigned char) (0x80 | ((ucv >> 12) & 0x3f)); @@ -226,7 +226,7 @@ UC_UTF8_encode_char (int32_t ucv, unsigned char **pp, unsigned char *endptr) p[3] = (unsigned char) (0x80 | (ucv & 0x3f)); count = 4; } else if (ucv <= 0x3ffffff) { - if (p >= endptr - 5) + if (p + 5 > endptr) return 0; p[0] = (unsigned char) (0xf8 | (ucv >> 24)); p[1] = (unsigned char) (0x80 | ((ucv >> 18) & 0x3f)); @@ -235,7 +235,7 @@ UC_UTF8_encode_char (int32_t ucv, unsigned char **pp, unsigned char *endptr) p[4] = (unsigned char) (0x80 | (ucv & 0x3f)); count = 5; } else if (ucv <= 0x7fffffff) { - if (p >= endptr - 6) + if (p + 6 > endptr) return 0; p[0] = (unsigned char) (0xfc | (ucv >> 30)); p[1] = (unsigned char) (0x80 | ((ucv >> 24) & 0x3f)); diff --git a/tectonic/dpx-vf.c b/tectonic/dpx-vf.c index 1b73500864..98a03482b3 100644 --- a/tectonic/dpx-vf.c +++ b/tectonic/dpx-vf.c @@ -1,6 +1,6 @@ /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - Copyright (C) 2007-2016 by Jin-Hwan Cho and Shunsaku Hirata, + Copyright (C) 2007-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -27,6 +27,7 @@ #include #include "core-bridge.h" +#include "dpx-dpxconf.h" #include "dpx-dvi.h" #include "dpx-dvicodes.h" #include "dpx-error.h" @@ -43,13 +44,6 @@ #define TEXPT2PT (72.0/72.27) #define FW2PT (TEXPT2PT/((double)(FIX_WORD_BASE))) -static unsigned char verbose = 0; - -void vf_set_verbose(int level) -{ - verbose = level; -} - struct font_def { int32_t font_id /* id used internally in vf file */; uint32_t checksum, size, design_size; @@ -270,7 +264,7 @@ int vf_locate_font (const char *tex_name, spt_t ptsize) if (vf_handle == NULL) return -1; - if (verbose == 1) + if (dpx_conf.verbose_level > 0) fprintf (stderr, "(VF:%s", tex_name); if (num_vf_fonts >= max_vf_fonts) @@ -289,7 +283,7 @@ int vf_locate_font (const char *tex_name, spt_t ptsize) read_header(vf_handle, thisfont); process_vf_file (vf_handle, thisfont); - if (verbose) + if (dpx_conf.verbose_level > 0) fprintf (stderr, ")"); ttstub_input_close (vf_handle); @@ -391,7 +385,7 @@ static void vf_xxx (int32_t len, unsigned char **start, unsigned char *end) * Warning message from virtual font. */ if (!memcmp((char *)p, "Warning:", 8)) { - if (verbose) + if (dpx_conf.verbose_level > 0) dpx_warning("VF:%s", p+8); } else { dvi_do_special(buffer, len); diff --git a/tectonic/dpx-vf.h b/tectonic/dpx-vf.h index e62e88541e..f7c9fc76ad 100644 --- a/tectonic/dpx-vf.h +++ b/tectonic/dpx-vf.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-2018 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks @@ -29,7 +29,6 @@ #include "dpx-pdfdev.h" -void vf_set_verbose (int level); void vf_reset_global_state (void); int vf_locate_font (const char *tex_name, spt_t ptsize); void vf_set_char (int32_t ch, int vf_font); From d47454ba362b95bb9191835a27f6e555478e903d Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Sat, 24 Oct 2020 16:50:22 -0400 Subject: [PATCH 02/24] tests/tex-outputs: update PDF outputs for new xdvipdfmx behavior --- tests/tex-outputs/a4paper.pdf | Bin 1824 -> 2246 bytes tests/tex-outputs/md5_of_hello.pdf | Bin 3144 -> 3631 bytes tests/tex-outputs/png_formats.pdf | Bin 409623 -> 410046 bytes tests/tex-outputs/redbox_png.pdf | Bin 3964 -> 4526 bytes tests/tex-outputs/the_letter_a.pdf | Bin 1815 -> 2237 bytes 5 files changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/tex-outputs/a4paper.pdf b/tests/tex-outputs/a4paper.pdf index 3c77556326cbce1a72c21f8a9a28c4dd130adfe8..785453acfdde65fc4e9704e3917f2d4c6c2410de 100644 GIT binary patch delta 653 zcmah`&x_MQ6mGhu~5vMMl0i8`8`PDE0H`l`qxA1jCx!3!+2RS_YCxJU$H8t^2lcDL3Sr9m!}&w~7A zkRqtGS?uxXY|7}9`E1NA;20Bi(}c{{IfAUwIOKo+x~wprh&Th+B>?JF{v!FT;piF9 zLVVQt&I^u3A{KBoANj4vU*-8bOi@%oiRZQD*p^e2aV+y7!Xgk0Brc^MxZ|-$a3lCX zkJ>gRjH6{x5Lah1lu~JkYi+SK1O?wkNYpmF?=@N#g(T4`(kjp}Nd)di%d@=6Z}+|C z+-WUQGYQ7NevY~~PyWv1#M0^q2gAFJf=(?kz>r8vZtC{8>A`p9{w$k|r0D{hVNTVH zgjdTF7_D#jP8F@5_dY1B{?&V`==HmxPWiMDkejN&DKoGOgv`#KB;->B^e6lCMJ_tv8W1JDi|A>DVQjj7#b)T8Y-9? z8E$^WvW<}=JTs*vqgcUm@Fd9uh#I6@_W?*S-Xp)qYXqsqg zkYZ$(mYQs6Y+{_4W@MCVk(!cfXG2g$tbTB2RVtUEv3_{8p@NZuQ7p`DW~P(Ou@Al&NOE%K-ZOX3$<6(54?kb;9H5W}SHyMomnc@{8ca6w zJW`Z7`U%m;)6=PlOVD5EDW78rQ7pn7i*%E7gaB8uAZ!R>%**zx=6K>~viZ!WH2 z35IQg%xpx5KRz6M(H<<)rHGXcp#FxLei4V|x&TJ2yW~_GR!j0pW7RLR){JV}KY2UC zh&w@GhUi2TM<(USjUccBM4#J^<+=Z@xYXzIMEv}AO7`!;2kU#0s(b50_ delta 230 zcmZ24b3$UmF(yNU%`=#?*?G+LeNyw%OEMJ9O)Mt!bEyhhDi|9WD3~Z1o0}*Y8Y-Ar zm~M9Gn#9Nvo|#gTQLJD&`4hJbqv2$8o-Rg%$%l9{7>y=t^XkQ0m>C-aE6bo~knd#&myn50c of(#5y4D1X{AcB>V;TVL=&dBXPnT=15+sMMgoJ&>J)!&T^0An&ZbRgZks?uw@}o+iN;uweVoGewaSq{< zN<pk1)nb z7*Q@jhJLoWm6$*ClEV4eOP+f(1f8kH_u9vO&K`}1UETnR0bP|Q!)1a{#3%rjZ?K$a zIO|10430wq^nQ`0;IoAKQyGu(p~6m5iD?*3pgw93N@TD|lD9a+C<8`aw+zRxIr*`~ zdE)t)deH=_!lyFRp+MHg{CGU_~j3q{M4#eGyir#>URYLW1oQuhTQ-m zz!KJF%^{z(`@?t?g^E9vbL{JySL4P1dA4JDrm*{R7~t#~J_t delta 251 zcmdnjEIGYFvY~~sg{g(Pg{6gc3)^i=CL@FGxz=p28JSEBrbpSbX$TuyDi~WBD3~Z1 zTbd~t87i0>SZtqa%eI1%Gdwe;B%@ft&~kdXJ(~-o;q*E7Y+Z~7)72f=Tp5j~=Q^hHz{0KV%#f&c&j diff --git a/tests/tex-outputs/redbox_png.pdf b/tests/tex-outputs/redbox_png.pdf index 4fed959721aeb893f6002c90c71000192f29af51..795dcbf7697eb0d8fb2b70e6fdde60075cbcdd07 100644 GIT binary patch delta 813 zcmaiy&5G1O5P&B;3@fd>ibs*9L|0Zs)17oC8)yPDKQQRJGC%BLStLn!W+F}!I~myV zGIzm)anb$(Z10v+0m@fr}WKo7!Z$&IPC#wL;xDSr?^Pj?y>-#t?uxR=22p)^PNK zXQ6mf>rN#XGD+ufH0w}8Yo+gl|alU4J&~dJ#JVD#JWzyN+{NPB@}yF@73JX+^e~-x$ke( zW~etR9p-9hC6Gw@HihjY!g!m#YbghpHeQOgr9M+mP38X-K3YksD$=y4X-8d_Bo)^k zd;oct*Abdk|F(@+RF4I*u8MZP+x9T2exk>B3D}ke6dVf!v7zhWtAm@5cJ58HS(?<9 z1XVu_WAiNG<)Q#Ws+W5M!>+#UeKM@-{{Fc^tIPf8ZwU*9KZU8m~Ywnw*qv|2l@8?7Cq{XtX5=zP|+Yux$T ZYW@4*q6}ntDb*-a%kj|R;ox+LegjHh<9q-B delta 247 zcmZ3d{6}s>5i_IV=6==!c4i9;lgUiHYC;AI#zsa8CJLrT1`38o3TDQ}o2__Nm^i~T zQ%W+56$}j~SMa+s8cp8E-^FM+*;62z(RlJw0lj$BRP$8hq%=cIGs_gyWFyPeM9XBe z#N;Fc^F%XK0~1R-8-glg^@B63Qn?IG^uwbK6^s;&V)cDe^U_N)6wD1K8wnb_aP44V zU}E54U;+`WjLd})E;}P%83O}XYF#HFh0 I>hHz{07v3Jz5oCK diff --git a/tests/tex-outputs/the_letter_a.pdf b/tests/tex-outputs/the_letter_a.pdf index e7076a6660f7ce5f0f04706ec6fe50ec06011911..da41c743c5d8c935ff49a048fcd871cb0ee2f1e1 100644 GIT binary patch delta 652 zcmah`Pm9w)6mPn=g+T<-!+P>v3M-_JvYXI|TgnS>-gbT7So z5_0ep$l^`$;K|S7x9~GKNoo&X9GH2(dGp?z-}}8!_kQ00c)J?_g=F!Lc%FWNa#gIs zw5jityvQ(&i9Q^kk7ZPV{yIx|fCVfgDKgBHO~w%xxQZlU28f6k`&;efahR&)%P@Tv z#t1sC7JE9poHF`sJ{vIy1TKlbt3qbm6hYOf9O}Pdn->_5>;+af^QmPE`oCYgHP>OwoLUpr;Uil`=6p31qT7im5B=I0xnxs{Jy&qQR zUTcM_Nig>93vb_b|IWj;o$~mo|A0|2DFq8GYJrm6HjVF-qp#YdSu&SV)df_;oa$GR zDAqYJTJ}2Uno(YKK4`4`)j8A5^0=$Nb(kxdF!^9$b82B|xrX5Elu>a?L)Y>>{9nYi z9z-`tn5AF6VQO;5^?@ucKX;$Qoo%btZuMGit##X=j@EV>)YE!D%HQ3`WZ>GQ-+wt7 Fkv}%NyW0Q& delta 254 zcmdlhIGu08awbEA%@$0_Ogv`#KB;->B^e6l#uk&8v#1JLDi|9WD3~ai7?>y+8Y-9? znr^<&vVoB!JTs*vqgcUm@(MN=M#IT(*}51FCReaKFd9wX$*v!lm}r!onr32bl4hD@ zY;I~~nv!IYYGGoKY?*4Fl4@#alS)WMtbTB2RVtUEv3_{8p@NZuQ7p`9W~P(fIP_eY zUNJB*F|ac*fe2PchUE}0J0qJI0|QrTUP^IEQEFl?h?Sp|#Z_FASX5F`l$yq6XliP~ LrK;-c@5TiH9cV*J From ed456ff7cac4b07df04a8d4d68a33987a0602a38 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Sat, 24 Oct 2020 17:10:48 -0400 Subject: [PATCH 03/24] Cargo.toml: update vcpkg in hopes of fixing Windows/vcpkg build --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bdc85c2bda..6b21528f33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -87,7 +87,7 @@ tokio = "0.1.22" [package.metadata.vcpkg] git = "https://github.com/microsoft/vcpkg" -rev = "76a7e9248fb3c57350b559966dcaa2d52a5e4458" +rev = "527c0e04332db88a7906e469dca1d9f0a35726fc" [package.metadata.vcpkg.target] x86_64-apple-darwin = { install = ["freetype","harfbuzz[icu,graphite2]"] } From 5c91b0075df54c4e95c1915c82b340c69e8c460a Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Sat, 24 Oct 2020 17:11:10 -0400 Subject: [PATCH 04/24] tectonic/xdvipdfmx: remove some inappropriate Win32-isms that snuck in --- tectonic/dpx-dpxfile.c | 18 ------------------ tectonic/dpx-pdfximage.c | 5 ----- 2 files changed, 23 deletions(-) diff --git a/tectonic/dpx-dpxfile.c b/tectonic/dpx-dpxfile.c index f568490f37..7ecdafd4eb 100644 --- a/tectonic/dpx-dpxfile.c +++ b/tectonic/dpx-dpxfile.c @@ -371,21 +371,3 @@ dpx_file_apply_filter (const char *cmdtmpl, /* Tectonic: defused */ return -1; } - -#if defined(WIN32) -FILE *generic_fsyscp_fopen (const char *filename, const char *mode) -{ - FILE *f; - - f = fsyscp_fopen (filename, mode); - - if (f == NULL && file_system_codepage != win32_codepage) { - int tmpcp = file_system_codepage; - file_system_codepage = win32_codepage; - f = fsyscp_fopen (filename, mode); - file_system_codepage = tmpcp; - } - - return f; -} -#endif /* WIN32 */ diff --git a/tectonic/dpx-pdfximage.c b/tectonic/dpx-pdfximage.c index 670978c142..15692c66e6 100644 --- a/tectonic/dpx-pdfximage.c +++ b/tectonic/dpx-pdfximage.c @@ -315,11 +315,6 @@ load_image (const char *ident, const char *fullname, int format, rust_input_hand return -1; } - -#if defined(WIN32) -int utf8name_failed = 0; -#endif /* WIN32 */ - int pdf_ximage_findresource (const char *ident, load_options options) { From 08c4250dd2c55fa323538fb6511a1e83c4c0e9ca Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Sat, 24 Oct 2020 17:46:27 -0400 Subject: [PATCH 05/24] Update synctex to the TeXLive 2020.0 reference Compared to xdvipdfmx this is a *much* smaller delta. Just two small modifications. Yay. --- tectonic/xetex-synctex.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tectonic/xetex-synctex.c b/tectonic/xetex-synctex.c index 6e3b9cdcc3..a57d5d425b 100644 --- a/tectonic/xetex-synctex.c +++ b/tectonic/xetex-synctex.c @@ -262,7 +262,8 @@ synctex_dot_open(void) /*printf("\nSyncTeX warning: no synchronization, problem with %s\n", the_name);*/ goto fail; - synctex_ctxt.magnification = 1000; + if (synctex_ctxt.magnification == 0) + synctex_ctxt.magnification = 1000; synctex_ctxt.unit = 1; the_name = mfree(the_name); @@ -403,17 +404,17 @@ void synctex_sheet(int32_t mag) } return; } + if (total_pages == 0) { + /* Now it is time to properly set up the scale factor. */ + if (mag > 0) { + synctex_ctxt.magnification = mag; + } + } if (NULL != synctex_prepare_content()) { /* First possibility: the .synctex file is already open because SyncTeX was activated on the CLI * or it was activated with the \synctex macro and the first page is already shipped out. * Second possibility: tries to open the .synctex, useful if synchronization was enabled * from the source file and not from the CLI. */ - if (total_pages == 0) { - /* Now it is time to properly set up the scale factor. */ - if (mag > 0) { - synctex_ctxt.magnification = mag; - } - } synctex_record_sheet(total_pages + 1); } return; From 7a158df50a851a4d9685d76155d2e2d0bd8c6d57 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Sat, 24 Oct 2020 18:13:39 -0400 Subject: [PATCH 06/24] Update TECKit to the TeXLive 2020.0 reference Not much new here. Omitted the conversion of various #ifndef/#define header guards to `#pragma once` due to (entirely hypothetical) concerns about portability. --- tectonic/teckit-Engine.cpp | 98 ++++++++++++++--------------- tectonic/teckit-NormalizationData.c | 21 ++++--- tectonic/teckit-c-Engine.h | 12 ++-- 3 files changed, 68 insertions(+), 63 deletions(-) diff --git a/tectonic/teckit-Engine.cpp b/tectonic/teckit-Engine.cpp index e380403241..005d4e5b3c 100644 --- a/tectonic/teckit-Engine.cpp +++ b/tectonic/teckit-Engine.cpp @@ -403,12 +403,12 @@ Pass::Pass(const TableHeader* inTable, Converter* cnv) bSupplementaryChars = (READ(tableHeader->flags) & kTableFlags_Supplementary) != 0; numPageMaps = 1; - pageBase = (const Byte*)tableHeader + READ(tableHeader->pageBase); - lookupBase = (const Lookup*)((const Byte*)tableHeader + READ(tableHeader->lookupBase)); - matchClassBase = (const Byte*)tableHeader + READ(tableHeader->matchClassBase); - repClassBase = (const Byte*)tableHeader + READ(tableHeader->repClassBase); - stringListBase = (const Byte*)tableHeader + READ(tableHeader->stringListBase); - stringRuleData = (const Byte*)tableHeader + READ(tableHeader->stringRuleData); + pageBase = reinterpret_cast(tableHeader) + READ(tableHeader->pageBase); + lookupBase = reinterpret_cast(reinterpret_cast(tableHeader) + READ(tableHeader->lookupBase)); + matchClassBase = reinterpret_cast(tableHeader) + READ(tableHeader->matchClassBase); + repClassBase = reinterpret_cast(tableHeader) + READ(tableHeader->repClassBase); + stringListBase = reinterpret_cast(tableHeader) + READ(tableHeader->stringListBase); + stringRuleData = reinterpret_cast(tableHeader) + READ(tableHeader->stringRuleData); if (bInputIsUnicode && bSupplementaryChars) { // support supplementary plane chars @@ -583,7 +583,7 @@ binary_search(const T* array, UInt32 count, UInt32 value) long Pass::classMatch(UInt32 classNumber, UInt32 inChar) const { - const UInt32* classPtr = (const UInt32*)(matchClassBase + READ(*((const UInt32*)matchClassBase + classNumber))); + const UInt32* classPtr = reinterpret_cast(matchClassBase + READ(*(reinterpret_cast(matchClassBase) + classNumber))); UInt32 memberCount = READ(*classPtr++); if (bInputIsUnicode) { if (bSupplementaryChars) { @@ -594,16 +594,16 @@ Pass::classMatch(UInt32 classNumber, UInt32 inChar) const } else { // classes are 16-bit - const UInt16* p = binary_search((const UInt16*)classPtr, memberCount, inChar); + const UInt16* p = binary_search(reinterpret_cast(classPtr), memberCount, inChar); if (READ(*p) == inChar) - return p - (const UInt16*)classPtr; + return p - reinterpret_cast(classPtr); } } else { // classes are 8-bit - const UInt8* p = binary_search((const UInt8*)classPtr, memberCount, inChar); + const UInt8* p = binary_search(reinterpret_cast(classPtr), memberCount, inChar); if (READ(*p) == inChar) - return p - (const UInt8*)classPtr; + return p - reinterpret_cast(classPtr); } return -1; } @@ -611,16 +611,16 @@ Pass::classMatch(UInt32 classNumber, UInt32 inChar) const UInt32 Pass::repClassMember(UInt32 classNumber, UInt32 index) const { - const UInt32* classPtr = (const UInt32*)(repClassBase + READ(*((const UInt32*)repClassBase + classNumber))); + const UInt32* classPtr = reinterpret_cast(repClassBase + READ(*(reinterpret_cast(repClassBase) + classNumber))); UInt32 memberCount = READ(*classPtr++); if (index < memberCount) if (bOutputIsUnicode) if (bSupplementaryChars) return READ(classPtr[index]); else - return READ(((const UInt16*)classPtr)[index]); + return READ(reinterpret_cast(classPtr)[index]); else { - return READ(((const UInt8*)classPtr)[index]); + return READ(reinterpret_cast(classPtr)[index]); } else return 0; // this can't happen if the compiler is right! @@ -1000,7 +1000,7 @@ Pass::DoMapping() if (bInputIsUnicode) { // Unicode lookup UInt16 charIndex = 0; - if ((const UInt8*)lookupBase == pageBase) { + if (reinterpret_cast(lookupBase) == pageBase) { // leave charIndex == 0 : pass with no rules } else { @@ -1008,7 +1008,7 @@ Pass::DoMapping() const UInt8* pageMap = 0; if (bSupplementaryChars) { if ((plane < 17) && (READ(planeMap[plane]) != 0xff)) { - pageMap = (const UInt8*)(pageBase + 256 * READ(planeMap[plane])); + pageMap = reinterpret_cast(pageBase + 256 * READ(planeMap[plane])); goto GOT_PAGE_MAP; } } @@ -1017,7 +1017,7 @@ Pass::DoMapping() GOT_PAGE_MAP: UInt8 page = (inChar >> 8) & 0xff; if (READ(pageMap[page]) != 0xff) { - const UInt16* charMapBase = (const UInt16*)(pageBase + 256 * numPageMaps); + const UInt16* charMapBase = reinterpret_cast(pageBase + 256 * numPageMaps); const UInt16* charMap = charMapBase + 256 * READ(pageMap[page]); charIndex = READ(charMap[inChar & 0xff]); } @@ -1027,7 +1027,7 @@ Pass::DoMapping() } else { // byte-oriented lookup - if (pageBase != (const Byte*)tableHeader) { + if (pageBase != reinterpret_cast(tableHeader)) { // dbcsPage present long pageNumber = READ(pageBase[inChar]); if (pageNumber == 0) @@ -1057,14 +1057,14 @@ Pass::DoMapping() UInt8 ruleType = READ(lookup->rules.type); if (ruleType == kLookupType_StringRules || (ruleType & kLookupType_RuleTypeMask) == kLookupType_ExtStringRules) { // process string rule list - const UInt32* ruleList = (const UInt32*)stringListBase + READ(lookup->rules.ruleIndex); + const UInt32* ruleList = reinterpret_cast(stringListBase) + READ(lookup->rules.ruleIndex); bool matched = false; bool allowInsertion = true; int ruleCount = READ(lookup->rules.ruleCount); if ((ruleType & kLookupType_RuleTypeMask) == kLookupType_ExtStringRules) ruleCount += 256 * (ruleType & kLookupType_ExtRuleCountMask); for ( ; ruleCount > 0; --ruleCount) { - const StringRule* rule = (const StringRule*)(stringRuleData + READ(*ruleList)); + const StringRule* rule = reinterpret_cast(stringRuleData + READ(*ruleList)); #ifdef TRACING if (traceLevel > 0) { cerr << "** trying match: "; @@ -1078,7 +1078,7 @@ if (traceLevel > 0) { if (matchElems == 0 && allowInsertion == false) continue; patternLength = matchElems + READ(rule->postLength); - pattern = (const MatchElem*)(rule + 1); // point past the defined struct for the rule header + pattern = reinterpret_cast(rule + 1); // point past the defined struct for the rule header direction = 1; infoLimit = matchElems; @@ -1119,7 +1119,7 @@ if (traceLevel > 0) { cerr << "** GENERATES:"; } #endif - const RepElem* r = (const RepElem*)(pattern + patternLength); + const RepElem* r = reinterpret_cast(pattern + patternLength); for (int i = 0; i < READ(rule->repLength); ++i, ++r) { #ifdef TRACING if (traceLevel > 0) @@ -1288,11 +1288,11 @@ Converter::Converter(const Byte* inTable, UInt32 inTableSize, bool inForward, finalStage = this; UInt16 normForm = 0; if (inTable != 0) { - const FileHeader* fh = (const FileHeader*)inTable; + const FileHeader* fh = reinterpret_cast(inTable); if (READ(fh->type) == kMagicNumberCmp) { // the table is compressed; allocate a new buffer and decompress unsigned long uncompressedLen = READ(fh->version); - table = (Byte*)malloc(uncompressedLen); + table = static_cast(malloc(uncompressedLen)); if (table == 0) { status = kStatus_OutOfMemory; return; @@ -1302,7 +1302,7 @@ Converter::Converter(const Byte* inTable, UInt32 inTableSize, bool inForward, status = kStatus_InvalidMapping; return; } - fh = (const FileHeader*)table; + fh = reinterpret_cast(table); } if (READ(fh->type) != kMagicNumber) { @@ -1315,7 +1315,7 @@ Converter::Converter(const Byte* inTable, UInt32 inTableSize, bool inForward, } if (table == 0) { - table = (Byte*)malloc(inTableSize); + table = static_cast(malloc(inTableSize)); if (table == 0) { status = kStatus_OutOfMemory; return; @@ -1323,8 +1323,8 @@ Converter::Converter(const Byte* inTable, UInt32 inTableSize, bool inForward, memcpy(table, inTable, inTableSize); } - fh = (const FileHeader*)table; - const UInt32* nameOffsets = (const UInt32*)(table + sizeof(FileHeader)); + fh = reinterpret_cast(table); + const UInt32* nameOffsets = reinterpret_cast(table + sizeof(FileHeader)); const UInt32* tableBase = nameOffsets + READ(fh->numNames); UInt32 numTables = READ(fh->numFwdTables); if (!forward) { @@ -1379,7 +1379,7 @@ Converter::Converter(const Byte* inTable, UInt32 inTableSize, bool inForward, // create the processing pipeline for (UInt32 i = 0; i < numTables; ++i) { - const TableHeader* t = (const TableHeader*)(table + READ(tableBase[i])); + const TableHeader* t = reinterpret_cast(table + READ(tableBase[i])); Stage* p = 0; switch (READ(t->type)) { case kTableType_BB: @@ -1690,7 +1690,7 @@ Converter::IsForward() const void Converter::GetFlags(UInt32& sourceFlags, UInt32& targetFlags) const { - const FileHeader* fh = (const FileHeader*)table; + const FileHeader* fh = reinterpret_cast(table); if (forward) { sourceFlags = READ(fh->formFlagsLHS); targetFlags = READ(fh->formFlagsRHS); @@ -1704,13 +1704,13 @@ Converter::GetFlags(UInt32& sourceFlags, UInt32& targetFlags) const static bool getNamePtrFromTable(const Byte* table, UInt16 nameID, const Byte*& outNamePtr, UInt32& outNameLen) { - const FileHeader* fh = (const FileHeader*)table; - const UInt32* nameOffsets = (const UInt32*)(table + sizeof(FileHeader)); + const FileHeader* fh = reinterpret_cast(table); + const UInt32* nameOffsets = reinterpret_cast(table + sizeof(FileHeader)); for (UInt32 i = 0; i < READ(fh->numNames); ++i) { - const NameRec* n = (const NameRec*)(table + READ(nameOffsets[i])); + const NameRec* n = reinterpret_cast(table + READ(nameOffsets[i])); if (READ(n->nameID) == nameID) { outNameLen = READ(n->nameLength); - outNamePtr = (const Byte*)n + sizeof(NameRec); + outNamePtr = reinterpret_cast(n) + sizeof(NameRec); return true; } } @@ -1917,7 +1917,7 @@ Converter::Validate(const Converter* cnv) if (cnv->status != kStatus_NoError) return false; if (cnv->table != 0) { - const FileHeader* fh = (const FileHeader*)cnv->table; + const FileHeader* fh = reinterpret_cast(cnv->table); if (READ(fh->type) != kMagicNumber) return false; } @@ -1940,7 +1940,7 @@ TECkit_CreateConverter( cnv = new Converter(mapping, mappingSize, mapForward, inputForm, outputForm); status = cnv->creationStatus(); if (status == kStatus_NoError) - *converter = (TECkit_Converter)cnv; + *converter = reinterpret_cast(cnv); else delete cnv; return status; @@ -1952,7 +1952,7 @@ TECkit_DisposeConverter( TECkit_Converter converter) { TECkit_Status status = kStatus_NoError; - Converter* cnv = (Converter*)converter; + Converter* cnv = reinterpret_cast(converter); if (!Converter::Validate(cnv)) status = kStatus_InvalidConverter; else @@ -1970,7 +1970,7 @@ TECkit_GetConverterName( UInt32* nameLength) { TECkit_Status status = kStatus_NoError; - Converter* cnv = (Converter*)converter; + Converter* cnv = reinterpret_cast(converter); if (!Converter::Validate(cnv)) status = kStatus_InvalidConverter; else { @@ -1994,7 +1994,7 @@ TECkit_GetConverterFlags( UInt32* targetFlags) { TECkit_Status status = kStatus_NoError; - Converter* cnv = (Converter*)converter; + Converter* cnv = reinterpret_cast(converter); if (!Converter::Validate(cnv)) status = kStatus_InvalidConverter; else @@ -2008,7 +2008,7 @@ TECkit_ResetConverter( TECkit_Converter converter) { TECkit_Status status = kStatus_NoError; - Converter* cnv = (Converter*)converter; + Converter* cnv = reinterpret_cast(converter); if (!Converter::Validate(cnv)) status = kStatus_InvalidConverter; else @@ -2030,7 +2030,7 @@ TECkit_ConvertBufferOpt( UInt32* lookaheadCount) { TECkit_Status status = kStatus_NoError; - Converter* cnv = (Converter*)converter; + Converter* cnv = reinterpret_cast(converter); if (!Converter::Validate(cnv)) status = kStatus_InvalidConverter; else @@ -2065,7 +2065,7 @@ TECkit_FlushOpt( UInt32* lookaheadCount) { TECkit_Status status = kStatus_NoError; - Converter* cnv = (Converter*)converter; + Converter* cnv = reinterpret_cast(converter); if (!Converter::Validate(cnv)) status = kStatus_InvalidConverter; else @@ -2097,12 +2097,12 @@ TECkit_GetMappingFlags( if (mapping == 0) status = kStatus_InvalidMapping; else { - const FileHeader* fh = (const FileHeader*)mapping; + const FileHeader* fh = reinterpret_cast(mapping); FileHeader header; if (READ(fh->type) == kMagicNumberCmp) { // compressed mapping, so we need to decompress enough of it to read the flags unsigned long uncompressedLen = sizeof(FileHeader); - int result = uncompress((Byte*)&header, &uncompressedLen, mapping + 2 * sizeof(UInt32), mappingSize - 2 * sizeof(UInt32)); + int result = uncompress(reinterpret_cast(&header), &uncompressedLen, mapping + 2 * sizeof(UInt32), mappingSize - 2 * sizeof(UInt32)); if (result != Z_BUF_ERROR) status = kStatus_InvalidMapping; fh = &header; @@ -2136,13 +2136,13 @@ TECkit_GetMappingName( if (mapping == 0) status = kStatus_InvalidMapping; else { - const FileHeader* fh = (const FileHeader*)mapping; + const FileHeader* fh = reinterpret_cast(mapping); FileHeader header; if (READ(fh->type) == kMagicNumberCmp) { // compressed mapping, so we need to decompress the fixed header to read the headerLength field, // and then decompress the complete header to get the names unsigned long uncompressedLen = sizeof(FileHeader); - int result = uncompress((Byte*)&header, &uncompressedLen, mapping + 2 * sizeof(UInt32), mappingSize - 2 * sizeof(UInt32)); + int result = uncompress(reinterpret_cast(&header), &uncompressedLen, mapping + 2 * sizeof(UInt32), mappingSize - 2 * sizeof(UInt32)); if (result != Z_BUF_ERROR) status = kStatus_InvalidMapping; else { @@ -2152,10 +2152,10 @@ TECkit_GetMappingName( if (buf == 0) status = kStatus_OutOfMemory; else { - result = uncompress((Byte*)buf, &uncompressedLen, mapping + 2 * sizeof(UInt32), mappingSize - 2 * sizeof(UInt32)); + result = uncompress(static_cast(buf), &uncompressedLen, mapping + 2 * sizeof(UInt32), mappingSize - 2 * sizeof(UInt32)); if (result != Z_BUF_ERROR) status = kStatus_InvalidMapping; - fh = (const FileHeader*)buf; + fh = static_cast(buf); } } } @@ -2164,7 +2164,7 @@ TECkit_GetMappingName( status = kStatus_BadMappingVersion; else { const Byte* namePtr; - if (getNamePtrFromTable((const Byte*)fh, nameID, namePtr, *nameLength)) { + if (getNamePtrFromTable(reinterpret_cast(fh), nameID, namePtr, *nameLength)) { UInt16 copyBytes = *nameLength < bufferSize ? *nameLength : bufferSize; if (copyBytes > 0) memcpy(nameBuffer, namePtr, copyBytes); diff --git a/tectonic/teckit-NormalizationData.c b/tectonic/teckit-NormalizationData.c index c8ff9ab27c..051c46c785 100644 --- a/tectonic/teckit-NormalizationData.c +++ b/tectonic/teckit-NormalizationData.c @@ -2,7 +2,7 @@ const UInt8 ccPlaneMap[] = {0,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}; const UInt8 ccPageMaps[][256] = { {0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,0,0,15,0,0,0,16,17,18,19,20,21,22,0,0,23,0,0,0,0,0,0,0,0,0,0,0,24,25,0,0,26,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,0,28,29,30,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,33,0}, - {0,34,35,36,0,0,0,0,0,0,37,0,0,0,0,0,38,39,40,41,42,43,44,45,0,0,46,0,47,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,51,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,53,0,0,0,0,0,0,0,0,0,0,0,0,0,54,0,0,0,0,0,0,0,55,56,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,34,35,36,0,0,0,0,0,0,37,0,0,38,0,39,40,41,42,43,44,45,46,47,48,49,50,0,51,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,53,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,56,57,0,0,0,0,0,0,0,0,0,0,0,0,0,58,54,59,0,0,0,0,0,60,61,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, }; @@ -12,14 +12,14 @@ const UInt8 ccCharClass[][256] = { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,230,230,230,230,220,230,230,230,222,220,230,230,230,230,230,230,220,220,220,220,220,220,230,230,220,230,230,222,228,230,10,11,12,13,14,15,16,17,18,19,19,20,21,22,0,23,0,24,25,0,230,220,0,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,230,30,31,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,28,29,30,31,32,33,34,230,230,220,220,230,230,230,230,230,220,230,230,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,0,0,230,230,230,230,220,230,0,0,230,230,0,220,230,230,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,220,230,230,220,230,230,220,220,220,230,220,220,230,220,230,230,230,220,230,220,230,220,230,220,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,220,230,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,0,230,230,230,230,230,230,230,230,230,0,230,230,230,0,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,220,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,230,230,230,230,230,230,230,0,220,230,230,220,230,230,220,230,230,230,220,220,220,27,28,29,230,230,230,220,230,230,220,220,230,230,230,230,230}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,230,220,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,220,230,230,220,230,230,220,220,220,230,220,220,230,220,230,230,230,220,230,220,230,220,230,220,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,220,230,0,0,0,0,0,0,0,0,0,220,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,0,230,230,230,230,230,230,230,230,230,0,230,230,230,0,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,220,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,230,230,230,230,230,230,230,230,230,230,230,230,230,230,0,220,230,230,220,230,230,220,230,230,230,220,220,220,27,28,29,230,230,230,220,230,230,220,220,230,230,230,230,230}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,230,220,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,84,91,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,9,0,0,0,0,0,0,0,0,0,0,0,0,0,107,107,107,107,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,118,118,0,0,0,0,0,0,0,0,0,0,0,0,0,0,122,122,122,122,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,103,9,0,0,0,0,0,0,0,0,0,0,0,0,0,107,107,107,107,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,118,118,9,0,0,0,0,0,0,0,0,0,0,0,0,0,122,122,122,122,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,0,220,0,216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,130,0,132,0,0,0,0,0,130,130,130,130,0,0,130,0,230,230,9,0,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, @@ -45,23 +45,28 @@ const UInt8 ccCharClass[][256] = { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,220,0,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,1,220,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,220,230,230,230,220,230,220,220,220,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,0,0,0,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,0,0,0,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,216,216,1,1,1,0,0,0,226,216,216,216,216,216,0,0,0,0,0,0,0,0,220,220,220,220,220,220,220,220,0,0,230,230,230,230,230,220,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {230,230,230,230,230,230,230,0,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,0,0,230,230,230,230,230,230,230,0,230,230,0,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,220,220,220,220,220,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, }; diff --git a/tectonic/teckit-c-Engine.h b/tectonic/teckit-c-Engine.h index e7f0484cd9..8e5a02d191 100644 --- a/tectonic/teckit-c-Engine.h +++ b/tectonic/teckit-c-Engine.h @@ -32,16 +32,16 @@ Last reviewed: Not yet. #include "teckit-Common.h" /* formFlags bits for normalization; if none are set, then this side of the mapping is normalization-form-agnostic on input, and may generate an unspecified mixture */ -#define kFlags_ExpectsNFC 0x00000001 /* expects fully composed text (NC) */ -#define kFlags_ExpectsNFD 0x00000002 /* expects fully decomposed text (NCD) */ -#define kFlags_GeneratesNFC 0x00000004 /* generates fully composed text (NC) */ -#define kFlags_GeneratesNFD 0x00000008 /* generates fully decomposed text (NCD) */ +#define kFlags_ExpectsNFC 0x00000001U /* expects fully composed text (NC) */ +#define kFlags_ExpectsNFD 0x00000002U /* expects fully decomposed text (NCD) */ +#define kFlags_GeneratesNFC 0x00000004U /* generates fully composed text (NC) */ +#define kFlags_GeneratesNFD 0x00000008U /* generates fully decomposed text (NCD) */ /* if VisualOrder is set, this side of the mapping deals with visual-order rather than logical-order text (only relevant for bidi scripts) */ -#define kFlags_VisualOrder 0x00008000 /* visual rather than logical order */ +#define kFlags_VisualOrder 0x00008000U /* visual rather than logical order */ /* if Unicode is set, the encoding is Unicode on this side of the mapping */ -#define kFlags_Unicode 0x00010000 /* this is Unicode rather than a byte encoding */ +#define kFlags_Unicode 0x00010000U /* this is Unicode rather than a byte encoding */ /* required names */ #define kNameID_LHS_Name 0 /* "source" or LHS encoding name, e.g. "SIL-EEG_URDU-2001" */ From dc3429851f3b4d007bffa85458f79fa454d8d238 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Sat, 24 Oct 2020 18:46:34 -0400 Subject: [PATCH 07/24] Update bibtex to the TeXLive 2020.0 reference Very little new here: - Instead of exiting when buffers fill up, increase their sizes and keep on going. - Avoid adding redundant filename extensions in some outputs. --- tectonic/bibtex.c | 173 ++++++++++++++++++++++++---------------------- 1 file changed, 92 insertions(+), 81 deletions(-) diff --git a/tectonic/bibtex.c b/tectonic/bibtex.c index aca94f58f2..85bfc1e48b 100644 --- a/tectonic/bibtex.c +++ b/tectonic/bibtex.c @@ -727,12 +727,38 @@ aux_err_white_space_in_argument_print(void) puts_log("White space in argument"); } +static bool +str_ends_with(str_number s, str_number ext) +{ + int32_t str_idx, ext_idx; + ASCII_code str_char, ext_char; + + if ((str_start[ext + 1] - str_start[ext]) > (str_start[s + 1] - str_start[s])) + return false; + + str_idx = (str_start[s + 1] - str_start[s]) - 1; + ext_idx = (str_start[ext + 1] - str_start[ext]) - 1; + + while (ext_idx >= 0) { + str_char = str_pool[str_start[s] + str_idx]; + ext_char = str_pool[str_start[ext] + ext_idx]; + + if (str_char != ext_char) + return false; + + str_idx--; + ext_idx--; + } + + return true; +} static void print_bib_name(void) { print_a_pool_str(bib_list[bib_ptr]); - print_a_pool_str(s_bib_extension); + if (!str_ends_with(bib_list[bib_ptr], s_bib_extension)) + print_a_pool_str(s_bib_extension); putc_log('\n'); } @@ -741,7 +767,8 @@ static void log_pr_bib_name(void) { out_pool_str(log_file, bib_list[bib_ptr]); - out_pool_str(log_file, s_bib_extension); + if (!str_ends_with(bib_list[bib_ptr], s_bib_extension)) + out_pool_str(log_file, s_bib_extension); ttstub_output_putc (log_file, '\n'); } @@ -978,12 +1005,6 @@ static void bib_unbalanced_braces_print(void) bib_err_print(); } -static void bib_field_too_long_print(void) -{ - printf_log("Your field is more than %ld characters", (long) buf_size); - bib_err_print(); -} - static void macro_warn_print(void) { puts_log("Warning--string name \""); @@ -2128,13 +2149,12 @@ static bool compress_bib_white(void) { { if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - - ex_buf[ex_buf_ptr] = 32 /*space */ ; - ex_buf_ptr = ex_buf_ptr + 1; + ttstub_fprintf(log_file, "Field filled up at ' ', reallocating.\n"); + buffer_overflow(); } + + ex_buf[ex_buf_ptr] = 32 /*space */ ; + ex_buf_ptr = ex_buf_ptr + 1; } while ((!scan_white_space())) { @@ -2171,18 +2191,17 @@ static bool scan_balanced_braces(void) if (store_field) { /*257: */ while ((buffer[buf_ptr2] != right_str_delim)) switch ((buffer[buf_ptr2])) { - case 123: + case 123: /*'{'*/ { bib_brace_level = bib_brace_level + 1; { - if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - - ex_buf[ex_buf_ptr] = 123 /*left_brace */ ; - ex_buf_ptr = ex_buf_ptr + 1; + if (ex_buf_ptr >= buf_size) { + ttstub_fprintf(log_file, "Field filled up at '{', reallocating.\n"); + buffer_overflow(); } + + ex_buf[ex_buf_ptr] = 123 /*left_brace */ ; + ex_buf_ptr = ex_buf_ptr + 1; } buf_ptr2 = buf_ptr2 + 1; { @@ -2195,18 +2214,17 @@ static bool scan_balanced_braces(void) { while (true) switch ((buffer[buf_ptr2])) { - case 125: + case 125: /*'}'*/ { bib_brace_level = bib_brace_level - 1; { - if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - - ex_buf[ex_buf_ptr] = 125 /*right_brace */ ; - ex_buf_ptr = ex_buf_ptr + 1; + if (ex_buf_ptr >= buf_size) { + ttstub_fprintf(log_file, "Field filled up at '}', reallocating.\n"); + buffer_overflow(); } + + ex_buf[ex_buf_ptr] = 125 /*right_brace */ ; + ex_buf_ptr = ex_buf_ptr + 1; } buf_ptr2 = buf_ptr2 + 1; { @@ -2221,18 +2239,17 @@ static bool scan_balanced_braces(void) goto loop_exit; } break; - case 123: + case 123: /*'{'*/ { bib_brace_level = bib_brace_level + 1; { - if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - - ex_buf[ex_buf_ptr] = 123 /*left_brace */ ; - ex_buf_ptr = ex_buf_ptr + 1; + if (ex_buf_ptr >= buf_size) { + ttstub_fprintf(log_file, "Field filled up at '{', reallocating.\n"); + buffer_overflow(); } + + ex_buf[ex_buf_ptr] = 123 /*left_brace */ ; + ex_buf_ptr = ex_buf_ptr + 1; } buf_ptr2 = buf_ptr2 + 1; { @@ -2248,14 +2265,13 @@ static bool scan_balanced_braces(void) default: { { - if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - - ex_buf[ex_buf_ptr] = buffer[buf_ptr2]; - ex_buf_ptr = ex_buf_ptr + 1; + if (ex_buf_ptr >= buf_size) { + ttstub_fprintf(log_file, "Field filled up at %ld, reallocating.\n", (long) buffer[buf_ptr2]); + buffer_overflow(); } + + ex_buf[ex_buf_ptr] = buffer[buf_ptr2]; + ex_buf_ptr = ex_buf_ptr + 1; } buf_ptr2 = buf_ptr2 + 1; { @@ -2283,14 +2299,13 @@ static bool scan_balanced_braces(void) default: { { - if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - - ex_buf[ex_buf_ptr] = buffer[buf_ptr2]; - ex_buf_ptr = ex_buf_ptr + 1; + if (ex_buf_ptr >= buf_size) { + ttstub_fprintf(log_file, "Field filled up at %ld, reallocating.\n", (long) buffer[buf_ptr2]); + buffer_overflow(); } + + ex_buf[ex_buf_ptr] = buffer[buf_ptr2]; + ex_buf_ptr = ex_buf_ptr + 1; } buf_ptr2 = buf_ptr2 + 1; { @@ -2402,14 +2417,13 @@ static bool scan_a_field_token_and_eat_white(void) while ((tmp_ptr < buf_ptr2)) { { - if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - - ex_buf[ex_buf_ptr] = buffer[tmp_ptr]; - ex_buf_ptr = ex_buf_ptr + 1; + if (ex_buf_ptr >= buf_size) { + ttstub_fprintf(log_file, "Field filled up at %ld, reallocating.\n", (long) buffer[tmp_ptr]); + buffer_overflow(); } + + ex_buf[ex_buf_ptr] = buffer[tmp_ptr]; + ex_buf_ptr = ex_buf_ptr + 1; } tmp_ptr = tmp_ptr + 1; } @@ -2457,14 +2471,13 @@ static bool scan_a_field_token_and_eat_white(void) if ((tmp_ptr < tmp_end_ptr) && (lex_class[str_pool[tmp_ptr]] == 1 /*white_space */ )) { { - if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - - ex_buf[ex_buf_ptr] = 32 /*space */ ; - ex_buf_ptr = ex_buf_ptr + 1; + if (ex_buf_ptr >= buf_size) { + ttstub_fprintf(log_file, "Field filled up at ' ', reallocating.\n"); + buffer_overflow(); } + + ex_buf[ex_buf_ptr] = 32 /*space */ ; + ex_buf_ptr = ex_buf_ptr + 1; } tmp_ptr = tmp_ptr + 1; while ((tmp_ptr < tmp_end_ptr) && (lex_class[str_pool[tmp_ptr]] == 1 /*white_space */ )) @@ -2474,23 +2487,21 @@ static bool scan_a_field_token_and_eat_white(void) while ((tmp_ptr < tmp_end_ptr)) { if (lex_class[str_pool[tmp_ptr]] != 1 /*white_space */ ) { - if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - - ex_buf[ex_buf_ptr] = str_pool[tmp_ptr]; - ex_buf_ptr = ex_buf_ptr + 1; + if (ex_buf_ptr >= buf_size) { + ttstub_fprintf(log_file, "Field filled up at %ld, reallocating.\n", (long) str_pool[tmp_ptr]); + buffer_overflow(); } - } else if (ex_buf[ex_buf_ptr - 1] != 32 /*space */ ) { - if (ex_buf_ptr == buf_size) { - bib_field_too_long_print(); - return false; - } else { - ex_buf[ex_buf_ptr] = 32 /*space */ ; - ex_buf_ptr = ex_buf_ptr + 1; + ex_buf[ex_buf_ptr] = str_pool[tmp_ptr]; + ex_buf_ptr = ex_buf_ptr + 1; + } else if (ex_buf[ex_buf_ptr - 1] != 32 /*space */ ) { + if (ex_buf_ptr >= buf_size) { + ttstub_fprintf(log_file, "Field filled up at ' ', reallocating.\n"); + buffer_overflow(); } + + ex_buf[ex_buf_ptr] = 32 /*space */ ; + ex_buf_ptr = ex_buf_ptr + 1; } tmp_ptr = tmp_ptr + 1; } @@ -5411,7 +5422,7 @@ static void aux_input_command(void) } printf_log("A level-%ld auxiliary file: ", (long) aux_ptr); - print_aux_name(); + log_pr_aux_name(); aux_ln_stack[aux_ptr] = 0; } } From 1449a2492e2b03fd2f5a30a02909fdccacb2c3e9 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Sat, 24 Oct 2020 20:08:32 -0400 Subject: [PATCH 08/24] tectonic/dpx-pdfdoc.h: fix values for box type enum As I recall, the concrete values of the enum options here need to stay in sync with other parts of the engine. I'm not 100%, but can't hurt to keep the values consistent with what they were before the catch-up. --- tectonic/dpx-pdfdoc.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tectonic/dpx-pdfdoc.h b/tectonic/dpx-pdfdoc.h index cd7c9888c6..f3f3033759 100644 --- a/tectonic/dpx-pdfdoc.h +++ b/tectonic/dpx-pdfdoc.h @@ -32,12 +32,13 @@ enum pdf_page_boundary { + /* Tectonic note: enum values must align with XeTeX notions */ pdf_page_boundary__auto = 0, - pdf_page_boundary_mediabox, - pdf_page_boundary_cropbox, - pdf_page_boundary_artbox, - pdf_page_boundary_trimbox, - pdf_page_boundary_bleedbox + pdf_page_boundary_mediabox = 2, + pdf_page_boundary_cropbox = 1, + pdf_page_boundary_artbox = 3, + pdf_page_boundary_trimbox = 4, + pdf_page_boundary_bleedbox = 5 }; #define PDF_DOC_GRABBING_NEST_MAX 4 From c718a6b290231a1bbc00caf40fb2cd60d14dd5f6 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Sat, 24 Oct 2020 20:12:08 -0400 Subject: [PATCH 09/24] tectonic/dpx-pdfximage.c: fix uninitialized value This typo is upstream. --- tectonic/dpx-pdfximage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tectonic/dpx-pdfximage.c b/tectonic/dpx-pdfximage.c index 15692c66e6..d87dc26eb3 100644 --- a/tectonic/dpx-pdfximage.c +++ b/tectonic/dpx-pdfximage.c @@ -490,7 +490,7 @@ pdf_ximage_set_form (pdf_ximage *I, void *form_info, pdf_obj *resource) */ p1.x = info->bbox.llx; p1.y = info->bbox.lly; pdf_dev_transform(&p1, &info->matrix); - p2.x = info->bbox.urx; p1.y = info->bbox.lly; + p2.x = info->bbox.urx; p2.y = info->bbox.lly; pdf_dev_transform(&p2, &info->matrix); p3.x = info->bbox.urx; p3.y = info->bbox.ury; pdf_dev_transform(&p3, &info->matrix); From 05ea01f307ec4c0a2007eea7647a464c1740943a Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Sat, 24 Oct 2020 20:15:55 -0400 Subject: [PATCH 10/24] tectonic/dpx-tt_cmap.c: fix mistaken variable name Transcription error. --- tectonic/dpx-tt_cmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tectonic/dpx-tt_cmap.c b/tectonic/dpx-tt_cmap.c index 7b6f954931..1ab2b4abbc 100644 --- a/tectonic/dpx-tt_cmap.c +++ b/tectonic/dpx-tt_cmap.c @@ -1062,7 +1062,7 @@ otf_create_ToUnicode_stream (const char *font_name, int cmap_id, cmap_add_id; size_t i; - cmap_name = NEW(strlen(font_name)+strlen("-UTF16")+1, char); + cmap_name = NEW(strlen(basefont)+strlen("-UTF16")+1, char); sprintf(cmap_name, "%s-UTF16", basefont); cmap_id = pdf_findresource("CMap", cmap_name); From 07c7bf358fec3ff1ae1a8b404e4fa296eb65528b Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Sun, 25 Oct 2020 16:27:51 -0400 Subject: [PATCH 11/24] Add `-Z continue-on-errors` unstable option. --- src/engines/tex.rs | 8 +++++++- src/unstable_opts.rs | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/engines/tex.rs b/src/engines/tex.rs index d9bc06f3f2..2a9c8d54aa 100644 --- a/src/engines/tex.rs +++ b/src/engines/tex.rs @@ -126,10 +126,16 @@ impl TexEngine { unsafe { super::tt_xetex_set_int_variable(b"shell_escape_enabled\0".as_ptr() as _, v); } - let v = if self.halt_on_error { 1 } else { 0 }; + + let mut halt_on_error = self.halt_on_error; + if unstables.continue_on_errors { + halt_on_error = false; // command-line override + } + let v = if halt_on_error { 1 } else { 0 }; unsafe { super::tt_xetex_set_int_variable(b"halt_on_error_p\0".as_ptr() as _, v); } + let v = if self.initex_mode { 1 } else { 0 }; unsafe { super::tt_xetex_set_int_variable(b"in_initex_mode\0".as_ptr() as _, v); diff --git a/src/unstable_opts.rs b/src/unstable_opts.rs index c5a5be14e6..fd5aade615 100644 --- a/src/unstable_opts.rs +++ b/src/unstable_opts.rs @@ -15,6 +15,7 @@ use std::str::FromStr; const HELPMSG: &str = r#"Available unstable options: -Z help Lists all unstable options + -Z continue-on-errors Keep compiling even when severe errors occur -Z min-crossrefs= Equivalent to bibtex's -min-crossrefs flag - "include after crossrefs" [default: 2] -Z paper-size= Change the default paper size [default: letter] @@ -26,9 +27,10 @@ const HELPMSG: &str = r#"Available unstable options: // Each entry of this should correspond to a field of UnstableOptions. #[derive(Debug)] pub enum UnstableArg { + ContinueOnErrors, Help, - PaperSize(String), MinCrossrefs(i32), + PaperSize(String), ShellEscapeEnabled, } @@ -47,6 +49,8 @@ impl FromStr for UnstableArg { match arg { "help" => Ok(UnstableArg::Help), + "continue-on-errors" => Ok(UnstableArg::ContinueOnErrors), + "min-crossrefs" => value .ok_or_else(|| { "'-Z min-crossrefs ' requires a value but none was supplied".into() @@ -71,6 +75,7 @@ impl FromStr for UnstableArg { #[derive(Debug, Default)] pub struct UnstableOptions { + pub continue_on_errors: bool, pub paper_size: Option, pub shell_escape: bool, pub min_crossrefs: Option, @@ -90,6 +95,7 @@ impl UnstableOptions { print!("{}", HELPMSG); std::process::exit(0); } + ContinueOnErrors => opts.continue_on_errors = true, MinCrossrefs(num) => opts.min_crossrefs = Some(num), PaperSize(size) => opts.paper_size = Some(size), ShellEscapeEnabled => opts.shell_escape = true, From 4c4e388f49cd1707771896562d0ed184525a49c4 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Sun, 25 Oct 2020 14:35:16 -0400 Subject: [PATCH 12/24] Update XeTeX to the TeXLive 2020.0 reference - Tweaks to how font design sizes are mapped to TeX values - Instead of having a separate `prim_eqtb`, merge it into the main eqtb. - This forces us to bump the format file serial number. - New primitives, mostly unimplemented: - \creationdate - \elapsedtime - \expanded - \filedump - \filemoddate - \filesize - \normaldeviate - \randomseed - \resettimer - \setrandomseed - \uniformdeviate - Some uc_hyph tweak deep in the linebreaking algorithm - print_raw_char when using pseudo selector in print_char - New magic numbers used in PDF last x/y position accounting, instead of cur_[hv]_offset. - Don't print_raw_char in show_context with trick_buf - Back up cur_cs in scan_keyword - Handle XETEX_MATH_GIVEN in scan_something_internal - If encountering an unexpandable primitive in scan_something_internal, try to deal with it. - Ditto for scan_int. - Do something different with active chars in str_toks_cat - Rework how file names are scanned. - Defend against undefined eTeX registers in main_control - Back up cur_cs in compare_strings. --- src/lib.rs | 5 +- tectonic/xetex-XeTeXFontMgr.cpp | 39 +- tectonic/xetex-XeTeXFontMgr.h | 8 +- tectonic/xetex-XeTeXLayoutInterface.cpp | 15 +- tectonic/xetex-constants.h | 160 ++--- tectonic/xetex-ini.c | 84 ++- tectonic/xetex-linebreak.c | 5 +- tectonic/xetex-output.c | 12 +- tectonic/xetex-scaledmath.c | 359 +++++++++++- tectonic/xetex-shipout.c | 10 +- tectonic/xetex-texmfmp.c | 246 +++++++- tectonic/xetex-xetex0.c | 747 ++++++++++++++++++------ tectonic/xetex-xetexd.h | 25 +- 13 files changed, 1387 insertions(+), 328 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9aa809c64c..9abae36d64 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,10 +70,9 @@ pub use crate::engines::xdvipdfmx::XdvipdfmxEngine; pub use crate::errors::{Error, ErrorKind, Result}; // Increase this whenever the engine internals change such that the contents -// of the "format" files must be regenerated -- this includes changes to the -// string pool. +// of the "format" files must be regenerated. -pub const FORMAT_SERIAL: u32 = 28; +pub const FORMAT_SERIAL: u32 = 29; /// Compile LaTeX text to a PDF. /// diff --git a/tectonic/xetex-XeTeXFontMgr.cpp b/tectonic/xetex-XeTeXFontMgr.cpp index e1876f078b..4366a9fea5 100644 --- a/tectonic/xetex-XeTeXFontMgr.cpp +++ b/tectonic/xetex-XeTeXFontMgr.cpp @@ -105,7 +105,7 @@ XeTeXFontMgr::findFont(const char* name, char* variant, double ptSize) { std::string nameStr(name); Font* font = NULL; - int dsize = 100; + double dsize = 10.0; loaded_font_design_size = 655360L; for (int pass = 0; pass < 2; ++pass) { @@ -113,7 +113,7 @@ XeTeXFontMgr::findFont(const char* name, char* variant, double ptSize) std::map::iterator i = m_nameToFont.find(nameStr); if (i != m_nameToFont.end()) { font = i->second; - if (font->opSizeInfo.designSize != 0) + if (font->opSizeInfo.designSize != 0.0) dsize = font->opSizeInfo.designSize; break; } @@ -128,7 +128,7 @@ XeTeXFontMgr::findFont(const char* name, char* variant, double ptSize) i = f->second->styles->find(style); if (i != f->second->styles->end()) { font = i->second; - if (font->opSizeInfo.designSize != 0) + if (font->opSizeInfo.designSize != 0.0) dsize = font->opSizeInfo.designSize; break; } @@ -139,7 +139,7 @@ XeTeXFontMgr::findFont(const char* name, char* variant, double ptSize) i = m_psNameToFont.find(nameStr); if (i != m_psNameToFont.end()) { font = i->second; - if (font->opSizeInfo.designSize != 0) + if (font->opSizeInfo.designSize != 0.0) dsize = font->opSizeInfo.designSize; break; } @@ -372,9 +372,8 @@ XeTeXFontMgr::findFont(const char* name, char* variant, double ptSize) // if there's optical size info, try to apply it if (ptSize < 0.0) - ptSize = dsize / 10.0; + ptSize = dsize; if (font != NULL && font->opSizeInfo.subFamilyID != 0 && ptSize > 0.0) { - ptSize = ptSize * 10.0; // convert to decipoints for comparison with the opSize values double bestMismatch = my_fmax(font->opSizeInfo.minSize - ptSize, ptSize - font->opSizeInfo.maxSize); if (bestMismatch > 0.0) { Font* bestMatch = font; @@ -393,8 +392,8 @@ XeTeXFontMgr::findFont(const char* name, char* variant, double ptSize) } } - if (font != NULL && font->opSizeInfo.designSize != 0) - loaded_font_design_size = (font->opSizeInfo.designSize << 16L) / 10; + if (font != NULL && font->opSizeInfo.designSize != 0.0) + loaded_font_design_size = unsigned(font->opSizeInfo.designSize * 65536.0 + 0.5); if (get_tracing_fonts_state() > 0) { begin_diagnostic(); @@ -469,15 +468,21 @@ XeTeXFontMgr::getOpSize(XeTeXFont font) hb_face_t *face = hb_font_get_face(hbFont); OpSizeRec *pSizeRec = (OpSizeRec*) xmalloc(sizeof(OpSizeRec)); + unsigned int designSize, minSize, maxSize; bool ok = hb_ot_layout_get_size_params(face, - &pSizeRec->designSize, + &designSize, &pSizeRec->subFamilyID, &pSizeRec->nameCode, - &pSizeRec->minSize, - &pSizeRec->maxSize); - - if (ok) + &minSize, + &maxSize); + + if (ok) { + // Convert sizes from PostScript deci-points to TeX points + pSizeRec->designSize = designSize * 72.27 / 72.0 / 10.0; + pSizeRec->minSize = minSize * 72.27 / 72.0 / 10.0; + pSizeRec->maxSize = maxSize * 72.27 / 72.0 / 10.0; return pSizeRec; + } free(pSizeRec); return NULL; @@ -492,7 +497,8 @@ XeTeXFontMgr::getDesignSize(XeTeXFont font) if (pSizeRec == NULL) return 10.0; - double result = pSizeRec->designSize / 10.0; + /* Tectonic: make sure not to leak pSizeRec */ + double result = pSizeRec->designSize; free(pSizeRec); return result; } @@ -510,8 +516,9 @@ XeTeXFontMgr::getOpSizeRecAndStyleFlags(Font* theFont) theFont->opSizeInfo.designSize = pSizeRec->designSize; if (pSizeRec->subFamilyID == 0 && pSizeRec->nameCode == 0 - && pSizeRec->minSize == 0 - && pSizeRec->maxSize == 0) { + && pSizeRec->minSize == 0.0 + && pSizeRec->maxSize == 0.0) { + /* Tectonic: make sure not to leak pSizeRec */ free(pSizeRec); goto done_size; // feature is valid, but no 'size' range } diff --git a/tectonic/xetex-XeTeXFontMgr.h b/tectonic/xetex-XeTeXFontMgr.h index 61f0c9bba5..5d7d59bd4b 100644 --- a/tectonic/xetex-XeTeXFontMgr.h +++ b/tectonic/xetex-XeTeXFontMgr.h @@ -97,11 +97,11 @@ class XeTeXFontMgr class Family; struct OpSizeRec { - unsigned int designSize; + double designSize; + double minSize; + double maxSize; unsigned int subFamilyID; unsigned int nameCode; - unsigned int minSize; - unsigned int maxSize; }; class Font { @@ -112,7 +112,7 @@ class XeTeXFontMgr , fontRef(ref), weight(0), width(0), slant(0) , isReg(false), isBold(false), isItalic(false) { opSizeInfo.subFamilyID = 0; - opSizeInfo.designSize = 100; } /* default to 10bp */ + opSizeInfo.designSize = 10.0; } /* default to 10.0pt */ ~Font() { delete m_fullName; delete m_psName; } diff --git a/tectonic/xetex-XeTeXLayoutInterface.cpp b/tectonic/xetex-XeTeXLayoutInterface.cpp index 2241efe946..58929214f0 100644 --- a/tectonic/xetex-XeTeXLayoutInterface.cpp +++ b/tectonic/xetex-XeTeXLayoutInterface.cpp @@ -39,8 +39,11 @@ authorization from the copyright holders. #include #include +#include #include +#if !HB_VERSION_ATLEAST(2,5,0) #include +#endif #include #include "xetex-web.h" @@ -732,6 +735,7 @@ deleteLayoutEngine(XeTeXLayoutEngine engine) delete engine; } +#if !HB_VERSION_ATLEAST(2,5,0) static unsigned int _decompose_compat(hb_unicode_funcs_t* ufuncs, hb_codepoint_t u, @@ -748,8 +752,7 @@ _get_unicode_funcs(void) hb_unicode_funcs_set_decompose_compatibility_func(ufuncs, _decompose_compat, NULL, NULL); return ufuncs; } - -static hb_unicode_funcs_t* hbUnicodeFuncs = NULL; +#endif int layoutChars(XeTeXLayoutEngine engine, uint16_t chars[], int32_t offset, int32_t count, int32_t max, @@ -770,11 +773,15 @@ layoutChars(XeTeXLayoutEngine engine, uint16_t chars[], int32_t offset, int32_t script = hb_ot_tag_to_script (engine->script); + hb_buffer_reset(engine->hbBuffer); + +#if !HB_VERSION_ATLEAST(2,5,0) + static hb_unicode_funcs_t* hbUnicodeFuncs = NULL; if (hbUnicodeFuncs == NULL) hbUnicodeFuncs = _get_unicode_funcs(); - - hb_buffer_reset(engine->hbBuffer); hb_buffer_set_unicode_funcs(engine->hbBuffer, hbUnicodeFuncs); +#endif + hb_buffer_add_utf16(engine->hbBuffer, chars, max, offset, count); hb_buffer_set_direction(engine->hbBuffer, direction); hb_buffer_set_script(engine->hbBuffer, script); diff --git a/tectonic/xetex-constants.h b/tectonic/xetex-constants.h index ad858d20b1..39a7100d71 100644 --- a/tectonic/xetex-constants.h +++ b/tectonic/xetex-constants.h @@ -82,9 +82,11 @@ #define FROZEN_DONT_EXPAND (FROZEN_CONTROL_SEQUENCE + 9) #define FROZEN_SPECIAL (FROZEN_CONTROL_SEQUENCE + 10) #define FROZEN_PRIMITIVE (FROZEN_CONTROL_SEQUENCE + 11) -#define FROZEN_NULL_FONT (FROZEN_CONTROL_SEQUENCE + 12) +#define PRIM_SIZE 500 +#define FROZEN_NULL_FONT (FROZEN_CONTROL_SEQUENCE + 12 + PRIM_SIZE) #define FONT_ID_BASE FROZEN_NULL_FONT /* nominally minus FONT_BASE, but that's 0 */ #define UNDEFINED_CONTROL_SEQUENCE (FROZEN_NULL_FONT + MAX_FONT_MAX + 1) +#define PRIM_EQTB_BASE (FROZEN_PRIMITIVE + 1) #define GLUE_BASE (UNDEFINED_CONTROL_SEQUENCE + 1) /* "region 3": glue values */ @@ -600,62 +602,70 @@ #define INT_VAL 0 #define DIMEN_VAL 1 #define GLUE_VAL 2 -#define MU_VAL 3 #define LAST_NODE_TYPE_CODE 3 #define INPUT_LINE_NO_CODE 4 #define BADNESS_CODE 5 -#define ETEX_VERSION_CODE 6 -#define CURRENT_GROUP_LEVEL_CODE 7 -#define CURRENT_GROUP_TYPE_CODE 8 -#define CURRENT_IF_LEVEL_CODE 9 -#define CURRENT_IF_TYPE_CODE 10 -#define CURRENT_IF_BRANCH_CODE 11 -#define GLUE_STRETCH_ORDER_CODE 12 -#define GLUE_SHRINK_ORDER_CODE 13 -#define XETEX_VERSION_CODE 14 -#define XETEX_COUNT_GLYPHS_CODE 15 -#define XETEX_COUNT_VARIATIONS_CODE 16 -#define XETEX_VARIATION_CODE 17 -#define XETEX_FIND_VARIATION_BY_NAME_CODE 18 -#define XETEX_VARIATION_MIN_CODE 19 -#define XETEX_VARIATION_MAX_CODE 20 -#define XETEX_VARIATION_DEFAULT_CODE 21 -#define XETEX_COUNT_FEATURES_CODE 22 -#define XETEX_FEATURE_CODE_CODE 23 -#define XETEX_FIND_FEATURE_BY_NAME_CODE 24 -#define XETEX_IS_EXCLUSIVE_FEATURE_CODE 25 -#define XETEX_COUNT_SELECTORS_CODE 26 -#define XETEX_SELECTOR_CODE_CODE 27 -#define XETEX_FIND_SELECTOR_BY_NAME_CODE 28 -#define XETEX_IS_DEFAULT_SELECTOR_CODE 29 -#define XETEX_OT_COUNT_SCRIPTS_CODE 30 -#define XETEX_OT_COUNT_LANGUAGES_CODE 31 -#define XETEX_OT_COUNT_FEATURES_CODE 32 -#define XETEX_OT_SCRIPT_CODE 33 -#define XETEX_OT_LANGUAGE_CODE 34 -#define XETEX_OT_FEATURE_CODE 35 -#define XETEX_MAP_CHAR_TO_GLYPH_CODE 36 -#define XETEX_GLYPH_INDEX_CODE 37 -#define XETEX_FONT_TYPE_CODE 38 -#define XETEX_FIRST_CHAR_CODE 39 -#define XETEX_LAST_CHAR_CODE 40 -#define PDF_LAST_X_POS_CODE 41 -#define PDF_LAST_Y_POS_CODE 42 -#define PDF_SHELL_ESCAPE_CODE 45 -#define XETEX_PDF_PAGE_COUNT_CODE 46 -#define XETEX_GLYPH_BOUNDS_CODE 47 -#define FONT_CHAR_WD_CODE 48 -#define FONT_CHAR_HT_CODE 49 -#define FONT_CHAR_DP_CODE 50 -#define FONT_CHAR_IC_CODE 51 -#define PAR_SHAPE_LENGTH_CODE 52 -#define PAR_SHAPE_INDENT_CODE 53 -#define PAR_SHAPE_DIMEN_CODE 54 -#define GLUE_STRETCH_CODE 55 -#define GLUE_SHRINK_CODE 56 -#define MU_TO_GLUE_CODE 57 -#define GLUE_TO_MU_CODE 58 -#define ETEX_EXPR 59 +#define PDF_LAST_X_POS_CODE 12 +#define PDF_LAST_Y_POS_CODE 13 +#define ELAPSED_TIME_CODE 16 +#define PDF_SHELL_ESCAPE_CODE 17 +#define RANDOM_SEED_CODE 18 +#define ETEX_VERSION_CODE 19 +#define CURRENT_GROUP_LEVEL_CODE 20 +#define CURRENT_GROUP_TYPE_CODE 21 +#define CURRENT_IF_LEVEL_CODE 22 +#define CURRENT_IF_TYPE_CODE 23 +#define CURRENT_IF_BRANCH_CODE 24 +#define GLUE_STRETCH_ORDER_CODE 25 +#define GLUE_SHRINK_ORDER_CODE 26 +#define XETEX_INT 27 /* base number for XeTeX special integer codes */ +#define XETEX_VERSION_CODE 27 +#define XETEX_COUNT_GLYPHS_CODE 28 +#define XETEX_COUNT_VARIATIONS_CODE 29 +#define XETEX_VARIATION_CODE 30 +#define XETEX_FIND_VARIATION_BY_NAME_CODE 31 +#define XETEX_VARIATION_MIN_CODE 32 +#define XETEX_VARIATION_MAX_CODE 33 +#define XETEX_VARIATION_DEFAULT_CODE 34 +#define XETEX_COUNT_FEATURES_CODE 35 +#define XETEX_FEATURE_CODE_CODE 36 +#define XETEX_FIND_FEATURE_BY_NAME_CODE 37 +#define XETEX_IS_EXCLUSIVE_FEATURE_CODE 38 +#define XETEX_COUNT_SELECTORS_CODE 39 +#define XETEX_SELECTOR_CODE_CODE 40 +#define XETEX_FIND_SELECTOR_BY_NAME_CODE 41 +#define XETEX_IS_DEFAULT_SELECTOR_CODE 42 +#define XETEX_OT_COUNT_SCRIPTS_CODE 43 +#define XETEX_OT_COUNT_LANGUAGES_CODE 44 +#define XETEX_OT_COUNT_FEATURES_CODE 45 +#define XETEX_OT_SCRIPT_CODE 46 +#define XETEX_OT_LANGUAGE_CODE 47 +#define XETEX_OT_FEATURE_CODE 48 +#define XETEX_MAP_CHAR_TO_GLYPH_CODE 49 +#define XETEX_GLYPH_INDEX_CODE 50 +#define XETEX_FONT_TYPE_CODE 51 +#define XETEX_FIRST_CHAR_CODE 52 +#define XETEX_LAST_CHAR_CODE 53 +#define XETEX_PDF_PAGE_COUNT_CODE 54 +#define XETEX_LAST_ITEM_CODES XETEX_PDF_PAGE_COUNT_CODE /*54*/ +#define XETEX_DIM (XETEX_LAST_ITEM_CODES + 1) /*55*/ +#define XETEX_GLYPH_BOUNDS_CODE (XETEX_DIM + 0) /*55*/ +#define XETEX_LAST_DIM_CODES XETEX_GLYPH_BOUNDS_CODE /*55*/ +#define ETEX_DIM (XETEX_LAST_DIM_CODES + 1) /*56*/ +#define ETEX_GLUE (ETEX_DIM + 9) /*65*/ +#define ETEX_MU (ETEX_GLUE + 1) /*66*/ +#define FONT_CHAR_WD_CODE 56 +#define FONT_CHAR_HT_CODE 57 +#define FONT_CHAR_DP_CODE 58 +#define FONT_CHAR_IC_CODE 59 +#define PAR_SHAPE_LENGTH_CODE 60 +#define PAR_SHAPE_INDENT_CODE 61 +#define PAR_SHAPE_DIMEN_CODE 62 +#define GLUE_STRETCH_CODE 63 +#define GLUE_SHRINK_CODE 64 +#define MU_TO_GLUE_CODE 65 +#define GLUE_TO_MU_CODE 66 +#define ETEX_EXPR 67 /* = ETEX_MU + 1 */ /* args to CONVERT -- also heavily overloaded */ #define NUMBER_CODE 0 @@ -663,19 +673,26 @@ #define STRING_CODE 2 #define MEANING_CODE 3 #define FONT_NAME_CODE 4 -#define ETEX_REVISION_CODE 5 -#define XETEX_REVISION_CODE 6 -#define XETEX_VARIATION_NAME_CODE 7 -#define XETEX_FEATURE_NAME_CODE 8 -#define XETEX_SELECTOR_NAME_CODE 9 -#define XETEX_GLYPH_NAME_CODE 10 -#define LEFT_MARGIN_KERN_CODE 11 -#define RIGHT_MARGIN_KERN_CODE 12 -#define XETEX_UCHAR_CODE 13 -#define XETEX_UCHARCAT_CODE 14 -#define JOB_NAME_CODE 15 -#define PDF_STRCMP_CODE 43 -#define PDF_MDFIVE_SUM_CODE 44 +#define ETEX_REVISION_CODE 5 /* = ETEX_CONVERT_BASE */ +#define EXPANDED_CODE 6 /* = ETEX_CONVERT_CODES */ +#define LEFT_MARGIN_KERN_CODE 16 +#define RIGHT_MARGIN_KERN_CODE 17 +#define PDF_STRCMP_CODE 18 +#define PDF_CREATION_DATE_CODE 22 +#define PDF_FILE_MOD_DATE_CODE 23 +#define PDF_FILE_SIZE_CODE 24 +#define PDF_MDFIVE_SUM_CODE 25 +#define PDF_FILE_DUMP_CODE 26 +#define UNIFORM_DEVIATE_CODE 29 +#define NORMAL_DEVIATE_CODE 30 +#define XETEX_VARIATION_NAME_CODE 32 +#define XETEX_REVISION_CODE 33 +#define XETEX_FEATURE_NAME_CODE 35 +#define XETEX_SELECTOR_NAME_CODE 36 +#define XETEX_GLYPH_NAME_CODE 37 +#define XETEX_UCHAR_CODE 38 +#define XETEX_UCHARCAT_CODE 39 +#define JOB_NAME_CODE 40 /* args to IF_TEST */ #define IF_CHAR_CODE 0 @@ -779,7 +796,9 @@ #define IMMEDIATE_CODE 4 #define SET_LANGUAGE_CODE 5 #define PDFTEX_FIRST_EXTENSION_CODE 6 -#define PDF_SAVE_POS_NODE 6 +#define PDF_SAVE_POS_NODE (PDFTEX_FIRST_EXTENSION_CODE + 15) +#define RESET_TIMER_CODE (PDFTEX_FIRST_EXTENSION_CODE + 25) +#define SET_RANDOM_SEED_CODE (PDFTEX_FIRST_EXTENSION_CODE + 27) #define PIC_FILE_CODE 41 /* not to be confused with PIC_NODE = 43! */ #define PDF_FILE_CODE 42 /* not to be confused with PDF_NODE = 44! */ #define GLYPH_CODE 43 /* not to be confused with GLYPH_NODE = 42! */ @@ -887,6 +906,7 @@ #define MATH_SHIFT 3 #define SPACE_ADJUSTMENT 3 #define SUB_MLIST 3 +#define MU_VAL 3 #define IDENT_VAL 4 #define MATH_TEXT_CHAR 4 #define RESTORE_SA 4 @@ -922,15 +942,11 @@ #define VRULE 35 #define FRACTIONNUMERATORGAPMIN 36 #define FRACTIONNUMDISPLAYSTYLEGAPMIN 37 -#define XETEX_FIRST_CHAR_CODE 39 #define FRACTIONDENOMINATORGAPMIN 39 #define FRACTIONDENOMDISPLAYSTYLEGAPMIN 40 -#define XETEX_DIM 47 #define RADICALVERTICALGAP 49 #define RADICALDISPLAYSTYLEVERTICALGAP 50 #define RADICALRULETHICKNESS 51 -#define ETEX_GLUE 57 -#define ETEX_MU 58 #define COND_MATH_GLUE 98 #define MU_GLUE 99 #define MAX_COMMAND 102 diff --git a/tectonic/xetex-ini.c b/tectonic/xetex-ini.c index 0bff9bdc77..e610138dea 100644 --- a/tectonic/xetex-ini.c +++ b/tectonic/xetex-ini.c @@ -78,6 +78,11 @@ unsigned char help_ptr; bool use_err_help; bool arith_error; scaled_t tex_remainder; +int32_t randoms[55]; +unsigned char j_random; +scaled_t random_seed; +int32_t two_to_the[31]; +int32_t spec_log[29]; int32_t temp_ptr; memory_word *mem; int32_t lo_mem_max; @@ -111,7 +116,6 @@ bool no_new_control_sequence; int32_t cs_count; b32x2 prim[501]; int32_t prim_used; -memory_word prim_eqtb[501]; memory_word *save_stack; int32_t save_ptr; int32_t max_save_stack; @@ -222,6 +226,8 @@ int32_t dead_cycles; bool doing_leaders; scaled_t rule_ht, rule_dp, rule_wd; scaled_t cur_h, cur_v; +int32_t epochseconds; +int32_t microseconds; scaled_t total_stretch[4], total_shrink[4]; int32_t last_badness; int32_t adjust_tail; @@ -607,9 +613,9 @@ primitive(const char* ident, uint16_t c, int32_t o) eqtb[cur_val].b16.s0 = LEVEL_ONE; eqtb[cur_val].b16.s1 = c; eqtb[cur_val].b32.s1 = o; - prim_eqtb[prim_val].b16.s0 = LEVEL_ONE; - prim_eqtb[prim_val].b16.s1 = c; - prim_eqtb[prim_val].b32.s1 = o; + eqtb[PRIM_EQTB_BASE + prim_val].b16.s0 = LEVEL_ONE; + eqtb[PRIM_EQTB_BASE + prim_val].b16.s1 = c; + eqtb[PRIM_EQTB_BASE + prim_val].b32.s1 = o; } /*:925*//*977: */ @@ -2303,9 +2309,6 @@ store_fmt_file(void) for (p = 0; p <= PRIM_SIZE; p++) dump_b32(prim[p]); - for (p = 0; p <= PRIM_SIZE; p++) - dump_b64(prim_eqtb[p]); - /* control sequences */ dump_int(hash_used); @@ -2714,9 +2717,6 @@ load_fmt_file(void) for (p = 0; p <= PRIM_SIZE; p++) undump_b32(prim[p]); - for (p = 0; p <= PRIM_SIZE; p++) - undump_b64(prim_eqtb[p]); - undump_int(x); if (x < HASH_BASE || x > FROZEN_CONTROL_SEQUENCE) goto bad_fmt; @@ -3087,6 +3087,27 @@ initialize_more_variables(void) help_ptr = 0; use_err_help = false; + two_to_the[0] = 1; + for (k = 1; k <= 30; k++) + two_to_the[k] = 2 * two_to_the[k - 1]; + + spec_log[1] = 93032640L; + spec_log[2] = 38612034L; + spec_log[3] = 17922280L; + spec_log[4] = 8662214L; + spec_log[5] = 4261238L; + spec_log[6] = 2113709L; + spec_log[7] = 1052693L; + spec_log[8] = 525315L; + spec_log[9] = 262400L; + spec_log[10] = 131136L; + spec_log[11] = 65552L; + spec_log[12] = 32772L; + spec_log[13] = 16385; + for (k = 14; k <= 27; k++) + spec_log[k] = two_to_the[27 - k]; + spec_log[28] = 1; + nest_ptr = 0; max_nest_stack = 0; cur_list.mode = VMODE; @@ -3102,6 +3123,7 @@ initialize_more_variables(void) last_glue = MAX_HALFWORD; last_penalty = 0; last_kern = 0; + last_node_type = -1; page_so_far[7] = 0; for (k = INT_BASE; k <= EQTB_SIZE; k++) @@ -3114,13 +3136,6 @@ initialize_more_variables(void) for (k = 1; k <= PRIM_SIZE; k++) prim[k] = prim[0]; - prim_eqtb[0].b16.s0 = LEVEL_ZERO; - prim_eqtb[0].b16.s1 = UNDEFINED_CS; - prim_eqtb[0].b32.s1 = TEX_NULL; - - for (k = 1; k <= PRIM_SIZE; k++) - prim_eqtb[k] = prim_eqtb[0]; - save_ptr = 0; cur_level = LEVEL_ONE; cur_group = BOTTOM_LEVEL; @@ -3199,6 +3214,8 @@ initialize_more_variables(void) for (k = 0; k <= 17; k++) write_open[k] = false; + get_seconds_and_micros(&epochseconds, µseconds); + init_start_time(); LR_ptr = TEX_NULL; LR_problems = 0; cur_dir = LEFT_TO_RIGHT; @@ -3615,15 +3632,29 @@ initialize_primitives(void) primitive("lastskip", LAST_ITEM, GLUE_VAL); primitive("inputlineno", LAST_ITEM, INPUT_LINE_NO_CODE); primitive("badness", LAST_ITEM, BADNESS_CODE); + primitive("pdflastxpos", LAST_ITEM, PDF_LAST_X_POS_CODE); + primitive("pdflastypos", LAST_ITEM, PDF_LAST_Y_POS_CODE); + primitive("elapsedtime", LAST_ITEM, ELAPSED_TIME_CODE); + primitive("shellescape", LAST_ITEM, PDF_SHELL_ESCAPE_CODE); + primitive("randomseed", LAST_ITEM, RANDOM_SEED_CODE); primitive("number", CONVERT, NUMBER_CODE); primitive("romannumeral", CONVERT, ROMAN_NUMERAL_CODE); primitive("string", CONVERT, STRING_CODE); primitive("meaning", CONVERT, MEANING_CODE); primitive("fontname", CONVERT, FONT_NAME_CODE); - primitive("jobname", CONVERT, JOB_NAME_CODE); + primitive("expanded", CONVERT, EXPANDED_CODE); primitive("leftmarginkern", CONVERT, LEFT_MARGIN_KERN_CODE); primitive("rightmarginkern", CONVERT, RIGHT_MARGIN_KERN_CODE); + primitive("creationdate", CONVERT, PDF_CREATION_DATE_CODE); + primitive("filemoddate", CONVERT, PDF_FILE_MOD_DATE_CODE); + primitive("filesize", CONVERT, PDF_FILE_SIZE_CODE); + primitive("mdfivesum", CONVERT, PDF_MDFIVE_SUM_CODE); + primitive("filedump", CONVERT, PDF_FILE_DUMP_CODE); + primitive("strcmp", CONVERT, PDF_STRCMP_CODE); + primitive("uniformdeviate", CONVERT, UNIFORM_DEVIATE_CODE); + primitive("normaldeviate", CONVERT, NORMAL_DEVIATE_CODE); + primitive("jobname", CONVERT, JOB_NAME_CODE); primitive("Uchar", CONVERT, XETEX_UCHAR_CODE); primitive("Ucharcat", CONVERT, XETEX_UCHARCAT_CODE); @@ -3838,6 +3869,8 @@ initialize_primitives(void) eqtb[FROZEN_SPECIAL] = eqtb[cur_val]; primitive("immediate", EXTENSION, IMMEDIATE_CODE); primitive("setlanguage", EXTENSION, SET_LANGUAGE_CODE); + primitive("resettimer", EXTENSION, RESET_TIMER_CODE); + primitive("setrandomseed", EXTENSION, SET_RANDOM_SEED_CODE); primitive("synctex", ASSIGN_INT, INT_BASE + INT_PAR__synctex); @@ -4137,7 +4170,7 @@ tt_run_engine(const char *dump_name, const char *input_file_name, time_t build_d primitive("XeTeXpdffile", EXTENSION, PDF_FILE_CODE); primitive("XeTeXglyph", EXTENSION, GLYPH_CODE); primitive("XeTeXlinebreaklocale", EXTENSION, XETEX_LINEBREAK_LOCALE_EXTENSION_CODE); - primitive("pdfsavepos", EXTENSION, PDFTEX_FIRST_EXTENSION_CODE + 0); + primitive("pdfsavepos", EXTENSION, PDF_SAVE_POS_NODE); primitive("lastnodetype", LAST_ITEM, LAST_NODE_TYPE_CODE); primitive("eTeXversion", LAST_ITEM, ETEX_VERSION_CODE); @@ -4183,16 +4216,8 @@ tt_run_engine(const char *dump_name, const char *input_file_name, time_t build_d primitive("XeTeXfonttype", LAST_ITEM, XETEX_FONT_TYPE_CODE); primitive("XeTeXfirstfontchar", LAST_ITEM, XETEX_FIRST_CHAR_CODE); primitive("XeTeXlastfontchar", LAST_ITEM, XETEX_LAST_CHAR_CODE); - primitive("pdflastxpos", LAST_ITEM, PDF_LAST_X_POS_CODE); - primitive("pdflastypos", LAST_ITEM, PDF_LAST_Y_POS_CODE); - - primitive("strcmp", CONVERT, PDF_STRCMP_CODE); - primitive("mdfivesum", CONVERT, PDF_MDFIVE_SUM_CODE); - primitive("pdfmdfivesum", CONVERT, PDF_MDFIVE_SUM_CODE); - - primitive("shellescape", LAST_ITEM, PDF_SHELL_ESCAPE_CODE); primitive("XeTeXpdfpagecount", LAST_ITEM, XETEX_PDF_PAGE_COUNT_CODE); - + /* everyeof moved to be with other assign_toks */ primitive("tracingassigns", ASSIGN_INT, INT_BASE + INT_PAR__tracing_assigns); primitive("tracinggroups", ASSIGN_INT, INT_BASE + INT_PAR__tracing_groups); @@ -4395,6 +4420,9 @@ tt_run_engine(const char *dump_name, const char *input_file_name, time_t build_d for (font_k = 0; font_k <= font_max; font_k++) font_used[font_k] = false; + random_seed = (microseconds * 1000) + (epochseconds % 1000000L); + init_randoms(random_seed); + if (interaction == BATCH_MODE) selector = SELECTOR_NO_PRINT; else diff --git a/tectonic/xetex-linebreak.c b/tectonic/xetex-linebreak.c index d45a14f8cf..f338dd38b5 100644 --- a/tectonic/xetex-linebreak.c +++ b/tectonic/xetex-linebreak.c @@ -372,7 +372,10 @@ line_break(bool d) if (LC_CODE(c) != 0) { hf = NATIVE_NODE_font(s); prev_s = s; - goto done2; + if (LC_CODE(c) == c || INTPAR(uc_hyph) > 0) + goto done2; + else + goto done1; } if (c >= 65536L) diff --git a/tectonic/xetex-output.c b/tectonic/xetex-output.c index 1d8041b162..62797eb3b4 100644 --- a/tectonic/xetex-output.c +++ b/tectonic/xetex-output.c @@ -220,6 +220,8 @@ print_char(int32_t s) print_raw_char('0' + l, true); else print_raw_char('a' + l - 10, true); + } else if (selector == SELECTOR_PSEUDO) { + print_raw_char(s, true); } else { if (s < 2048) { print_raw_char(192 + s / 64, false); @@ -411,7 +413,10 @@ print_cs(int32_t p) } else if (hash[p].s1 >= str_ptr) { print_esc_cstr("NONEXISTENT."); } else { - print_esc(hash[p].s1); + if (p >= PRIM_EQTB_BASE && p < FROZEN_NULL_FONT) + print_esc(prim[p - PRIM_EQTB_BASE].s1 - 1); + else + print_esc(hash[p].s1); print_char(' '); } } @@ -429,8 +434,11 @@ sprint_cs(int32_t p) print_esc_cstr("csname"); print_esc_cstr("endcsname"); } - } else + } else if (p >= PRIM_EQTB_BASE && p < FROZEN_NULL_FONT) { + print_esc(prim[p - PRIM_EQTB_BASE].s1 - 1); + } else { print_esc(hash[p].s1); + } } diff --git a/tectonic/xetex-scaledmath.c b/tectonic/xetex-scaledmath.c index 829413bedf..98163002fc 100644 --- a/tectonic/xetex-scaledmath.c +++ b/tectonic/xetex-scaledmath.c @@ -11,11 +11,11 @@ int32_t tex_round (double r) { /* We must reproduce very particular rounding semantics to pass the TRIP - * test. Specifically, values within the 32-bit range of TeX integers are - * rounded to the nearest integer with half-integral values going away + * test. Specifically, values within the 32-bit range of TeX int32_ts are + * rounded to the nearest int32_t with half-integral values going away * from zero: 0.5 => 1, -0.5 => -1. * - * `r` does not necessarily lie within the range of a 32-bit TeX integer; + * `r` does not necessarily lie within the range of a 32-bit TeX int32_t; * if it doesn't, we clip. The following LaTeX document allegedly triggers * that codepath: * @@ -34,7 +34,7 @@ tex_round (double r) if (r < -2147483648.0) /* -0x80000000 */ return -2147483648; - /* ANSI defines the float-to-integer cast to truncate towards zero, so the + /* ANSI defines the float-to-int32_t cast to truncate towards zero, so the * following code is all that's necessary to get the desired behavior. The * truncation technically causes an uncaught "inexact" floating-point * exception, but exception is virtually impossible to avoid in real @@ -160,3 +160,354 @@ round_xn_over_d(scaled_t x, int32_t n, int32_t d) else return -(int32_t) u; } + +static int32_t +make_frac(int32_t p, int32_t q) +{ + int32_t f; + int32_t n; + bool negative; + int32_t be_careful; + + if (p >= 0) + negative = false; + else { + p = -p; + negative = true; + } + + if (q <= 0) { + q = -q; + negative = !negative; + } + + n = p / q; + p = p % q; + + if (n >= 8) { + arith_error = true; + if (negative) + return -0x7FFFFFFF; + else + return 0x7FFFFFFF; + } else { + n = (n - 1) * 0x10000000; + f = 1; + + do { + be_careful = p - q; + p = be_careful + p; + if (p >= 0) + f = f + f + 1; + else { + f = f + f; + p = p + q; + } + } while (f < 0x10000000); + + be_careful = p - q; + if (be_careful + p >= 0) + f += 1; + + if (negative) + return -(f + n); + else + return f + n; + } +} + +static int32_t +take_frac(int32_t q, int32_t f) +{ + int32_t p; + bool negative; + int32_t n; + int32_t be_careful; + + if (f >= 0) + negative = false; + else { + f = -f; + negative = true; + } + + if (q < 0) { + q = -q; + negative = !negative; + } + + if (f < 0x10000000) + n = 0; + else { + n = f / 0x10000000; + f = f % 0x10000000; + + if (q <= 0x7FFFFFFF / n) + n = n * q; + else { + arith_error = true; + n = 0x7FFFFFFF; + } + } + + f = f + 0x10000000; + p = 0x08000000; + + if (q < 0x40000000) { + do { + if (odd(f)) + p = (p + q) / 2; + else + p = p / 2; + f = f / 2; + } while (f != 1); + } else { + do { + if (odd(f)) + p = p + (q - p) / 2; + else + p = p / 2; + f = f / 2; + } while (f != 1); /*:120 */ + } + + be_careful = n - 0x7FFFFFFF; + if (be_careful + p > 0) { + arith_error = true; + n = 0x7FFFFFFF - p; + } + + if (negative) + return -(n + p); + else + return n + p; +} + +static int32_t +m_log(int32_t x) +{ + int32_t y, z; + int32_t k; + + if (x <= 0) { /*125: */ + error_here_with_diagnostic("Logarithm of "); + print_scaled(x); + print_cstr(" has been replaced by 0"); + capture_to_diagnostic(NULL); + help_ptr = 2; + help_line[1] = "Since I don't take logs of non-positive numbers,"; + help_line[0] = "I'm zeroing this one. Proceed, with fingers crossed."; + error(); + return 0; + } else { + y = 1302456860L; + z = 6581195L; + + while (x < 0x40000000) { + x = x + x; + y = y - 93032639L; + z = z - 48782L; + } + + y = y + (z / 65536L); + k = 2; + + while (x > 0x40000004) { /*124: */ + z = ((x - 1) / two_to_the[k]) + 1; + + while (x < 0x40000000 + z) { + z = (z + 1) / 2; + k = k + 1; + } + + y = y + spec_log[k]; + x = x - z; + } + + return y / 8; + } +} + +static int32_t +ab_vs_cd(int32_t a, int32_t b, int32_t c, int32_t d) +{ + int32_t q, r; + + if (a < 0) { + a = -a; + b = -b; + } + + if (c < 0) { + c = -c; + d = -d; + } + + if (d <= 0) { + if (b >= 0) { + if ((a == 0 || b == 0) && (c == 0 || d == 0)) { + return 0; + } else { + return 1; + } + } + + if (d == 0) { + if (a == 0) { + return 0; + } else { + return -1; + } + } + + q = a; + a = c; + c = q; + q = -b; + b = -d; + d = q; + } else if (b <= 0) { + if (b < 0) { + if (a > 0) { + return -1; + } + } + + if (c == 0) { + return 0; + } else { + return -1; + } + } + + while (true) { + q = a / d; + r = c / b; + + if (q != r) { + if (q > r) { + return 1; + } else { + return -1; + } + } + + q = a % d; + r = c % b; + + if (r == 0) { + if (q == 0) { + return 0; + } else { + return 1; + } + } + + if (q == 0) { + return -1; + } + + a = b; + b = q; + c = d; + d = r; + } +} + +static void +new_randoms(void) +{ + unsigned char k; + int32_t x; + + for (k = 0; k < 24; k++) { + x = randoms[k] - randoms[k + 31]; + if (x < 0) + x = x + 0x10000000; + randoms[k] = x; + } + + for (k = 24; k < 55; k++) { + x = randoms[k] - randoms[k - 24]; + if (x < 0) + x = x + 0x10000000; + randoms[k] = x; + } + + j_random = 54; +} + +void +init_randoms(int32_t seed) +{ + int32_t j, jj, k; + unsigned char i; + + j = abs(seed); + + while (j >= 0x10000000) + j = j / 2; + + k = 1; + + for (i = 0; i < 55; i++) { + jj = k; + k = j - k; + j = jj; + if (k < 0) + k = k + 0x10000000; + randoms[(i * 21) % 55] = j; + } + + new_randoms(); + new_randoms(); + new_randoms(); +} + +int32_t +unif_rand(int32_t x) +{ + int32_t y; + + if (j_random == 0) + new_randoms(); + else + j_random--; + + y = take_frac(abs(x), randoms[j_random]); + if (y == abs(x)) + return 0; + else if (x > 0) + return y; + else + return -y; +} + +int32_t +norm_rand(void) +{ + int32_t x, u, l; + + do { + do { + if (j_random == 0) + new_randoms(); + else + j_random--; + + x = take_frac(112429L, randoms[j_random] - 0x08000000); + + if (j_random == 0) + new_randoms(); + else + j_random--; + + u = randoms[j_random]; + } while (abs(x) >= u); + + x = make_frac(x, u); + l = 139548960L - m_log(u); + } while (ab_vs_cd(1024, l, x, x) < 0); + + return x; +} diff --git a/tectonic/xetex-shipout.c b/tectonic/xetex-shipout.c index 88b9578c13..49fe8ad377 100644 --- a/tectonic/xetex-shipout.c +++ b/tectonic/xetex-shipout.c @@ -782,8 +782,9 @@ hlist_out(void) break; case PDF_SAVE_POS_NODE: - pdf_last_x_pos = cur_h + cur_h_offset; - pdf_last_y_pos = cur_page_height - cur_v - cur_v_offset; + /* These magic numbers are in the original XeTeX source. */ + pdf_last_x_pos = cur_h + 4736286L; + pdf_last_y_pos = cur_page_height - cur_v - 4736286L; break; default: @@ -1282,8 +1283,9 @@ vlist_out(void) break; case PDF_SAVE_POS_NODE: - pdf_last_x_pos = cur_h + cur_h_offset; - pdf_last_y_pos = cur_page_height - cur_v - cur_v_offset; + /* These magic numbers are in the original XeTeX source. */ + pdf_last_x_pos = cur_h + 4736286L; + pdf_last_y_pos = cur_page_height - cur_v - 4736286L; break; default: diff --git a/tectonic/xetex-texmfmp.c b/tectonic/xetex-texmfmp.c index 0d23de7c98..6343d8cad9 100644 --- a/tectonic/xetex-texmfmp.c +++ b/tectonic/xetex-texmfmp.c @@ -10,11 +10,106 @@ #include "xetex-ext.h" #include /* For `struct tm'. Moved here for Visual Studio 2005. */ - +#include static char *last_source_name = NULL; static int last_lineno; + + +#define TIME_STR_SIZE 30 +static time_t start_time = 0; +char start_time_str[TIME_STR_SIZE]; +static char time_str[TIME_STR_SIZE]; +/* minimum size for time_str is 24: "D:YYYYmmddHHMMSS+HH'MM'" */ + +static void +makepdftime(time_t t, char *time_str, bool utc) +{ +#if 0 + struct tm lt, gmt; + size_t size; + int i, off, off_hours, off_mins; + + /* get the time */ + if (utc) { + lt = *gmtime(&t); + } + else { + lt = *localtime(&t); + } + size = strftime(time_str, TIME_STR_SIZE, "D:%Y%m%d%H%M%S", <); + /* expected format: "YYYYmmddHHMMSS" */ + if (size == 0) { + /* unexpected, contents of time_str is undefined */ + time_str[0] = '\0'; + return; + } + + /* correction for seconds: %S can be in range 00..61, + the PDF reference expects 00..59, + therefore we map "60" and "61" to "59" */ + if (time_str[14] == '6') { + time_str[14] = '5'; + time_str[15] = '9'; + time_str[16] = '\0'; /* for safety */ + } + + /* get the time zone offset */ + gmt = *gmtime(&t); + + /* this calculation method was found in exim's tod.c */ + off = 60 * (lt.tm_hour - gmt.tm_hour) + lt.tm_min - gmt.tm_min; + if (lt.tm_year != gmt.tm_year) { + off += (lt.tm_year > gmt.tm_year) ? 1440 : -1440; + } else if (lt.tm_yday != gmt.tm_yday) { + off += (lt.tm_yday > gmt.tm_yday) ? 1440 : -1440; + } + + if (off == 0) { + time_str[size++] = 'Z'; + time_str[size] = 0; + } else { + off_hours = off / 60; + off_mins = abs(off - off_hours * 60); + i = snprintf(&time_str[size], 9, "%+03d'%02d'", off_hours, off_mins); + check_nprintf(i, 9); + } +#endif +} + +void +init_start_time(void) +{ + /* set start_time */ + makepdftime (start_time, start_time_str, /* utc= */true); +} + +void getcreationdate(void) +{ +#if 0 + size_t len; + int i; + + init_start_time(); + /* put creation date on top of string pool and update pool_ptr */ + len = strlen(start_time_str); + + /* In e-pTeX, "init len => call init_start_time()" (as pdftexdir/utils.c) + yields unintentional output. */ + + if ((unsigned) (pool_ptr + len) >= (unsigned) (pool_size)) { + pool_ptr = pool_size; + /* error by str_toks that calls str_room(1) */ + return; + } + + for (i = 0; i < len; i++) + str_pool[pool_ptr++] = (uint16_t)start_time_str[i]; +#endif +} + + void get_date_and_time (time_t source_date_epoch, int32_t *minutes, int32_t *day, @@ -27,6 +122,155 @@ get_date_and_time (time_t source_date_epoch, *year = tmptr->tm_year + 1900; } +void +get_seconds_and_micros (int32_t *seconds, int32_t *micros) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + *seconds = tv.tv_sec; + *micros = tv.tv_usec; +} + + +void getfilemoddate(int32_t s) +{ +#if 0 + struct stat file_data; + + char *file_name = find_input_file(s); + if (file_name == NULL) { + return; /* empty string */ + } + if (! kpse_in_name_ok(file_name)) { + return; /* no permission */ + } + + recorder_record_input(file_name); + /* get file status */ +#ifdef _WIN32 + if (fsyscp_stat(file_name, &file_data) == 0) { +#else + if (stat(file_name, &file_data) == 0) { +#endif + size_t len; + bool use_utc = FORCE_SOURCE_DATE_set && SOURCE_DATE_EPOCH_set; + makepdftime(file_data.st_mtime, time_str, use_utc); + len = strlen(time_str); + if ((unsigned) (pool_ptr + len) >= (unsigned) (pool_size)) { + pool_ptr = pool_size; + /* error by str_toks that calls str_room(1) */ + } else { + int i; + + for (i = 0; i < len; i++) + str_pool[pool_ptr++] = (uint16_t)time_str[i]; + } + } + /* else { errno contains error code } */ + + xfree(file_name); +#endif +} + +void getfilesize(int32_t s) +{ +#if 0 + struct stat file_data; + int i; + + char *file_name = find_input_file(s); + if (file_name == NULL) { + return; /* empty string */ + } + if (! kpse_in_name_ok(file_name)) { + return; /* no permission */ + } + + recorder_record_input(file_name); + /* get file status */ +#ifdef _WIN32 + if (fsyscp_stat(file_name, &file_data) == 0) { +#else + if (stat(file_name, &file_data) == 0) { +#endif + size_t len; + char buf[20]; + + /* st_size has type off_t */ + i = snprintf(buf, sizeof(buf), + "%lu", (long unsigned int) file_data.st_size); + check_nprintf(i, sizeof(buf)); + len = strlen(buf); + if ((unsigned) (pool_ptr + len) >= (unsigned) (pool_size)) { + pool_ptr = pool_size; + /* error by str_toks that calls str_room(1) */ + } else { + for (i = 0; i < len; i++) + str_pool[pool_ptr++] = (uint16_t)buf[i]; + } + } + /* else { errno contains error code } */ + + xfree(file_name); +#endif +} + +void getfiledump(int32_t s, int offset, int length) +{ +#if 0 + FILE *f; + int read, i; + unsigned char *readbuffer; + char strbuf[3]; + int j, k; + char *file_name; + + if (length == 0) { + /* empty result string */ + return; + } + + if (pool_ptr + 2 * length + 1 >= pool_size) { + /* no place for result */ + pool_ptr = pool_size; + /* error by str_toks that calls str_room(1) */ + return; + } + + file_name = find_input_file(s); + if (file_name == NULL) { + return; /* empty string */ + } + if (! kpse_in_name_ok(file_name)) { + return; /* no permission */ + } + + /* read file data */ + f = fopen(file_name, FOPEN_RBIN_MODE); + if (f == NULL) { + xfree(file_name); + return; + } + recorder_record_input(file_name); + if (fseek(f, offset, SEEK_SET) != 0) { + xfree(file_name); + return; + } + + readbuffer = (unsigned char *)xmalloc (length + 1); + read = fread(readbuffer, sizeof(char), length, f); + fclose(f); + for (j = 0; j < read; j++) { + i = snprintf (strbuf, 3, "%.2X", (unsigned int)readbuffer[j]); + check_nprintf(i, 3); + for (k = 0; k < i; k++) + str_pool[pool_ptr++] = (uint16_t)strbuf[k]; + } + xfree (readbuffer); + xfree(file_name); +#endif +} + static void checkpool_pointer (pool_pointer pool_ptr, size_t len) diff --git a/tectonic/xetex-xetex0.c b/tectonic/xetex-xetex0.c index 81abea2c1f..5176d44c97 100644 --- a/tectonic/xetex-xetex0.c +++ b/tectonic/xetex-xetex0.c @@ -465,6 +465,21 @@ int32_t prev_rightmost(int32_t s, int32_t e) return p; } +int32_t +get_microinterval(void) +{ + int32_t s, m; + + get_seconds_and_micros(&s, &m); + + if ((s - epochseconds) > 0x7FFF) + return -1; + else if (microseconds > m) + return ((s - 1 - epochseconds) * 65536) + (((m + 1000000L - microseconds) / 100.0) * 65536) / 10000.0; + else + return ((s - epochseconds) * 65536) + (((m - microseconds) / 100.0) * 65536) / 10000.0; +} + void short_display(int32_t p) { @@ -922,6 +937,9 @@ show_node_list(int32_t p) print_int(mem[p + 1].b16.s0); print_char(')'); break; + case PDF_SAVE_POS_NODE: + print_esc_cstr("pdfsavepos"); + break; case NATIVE_WORD_NODE: case NATIVE_WORD_NODE_AT: print_esc(hash[FONT_ID_BASE + mem[p + 4].b16.s2].s1); @@ -945,9 +963,6 @@ show_node_list(int32_t p) print_raw_char(PIC_NODE_path(p)[i], true); print('"'); break; - case PDF_SAVE_POS_NODE: - print_esc_cstr("pdfsavepos"); - break; default: print_cstr("whatsit?"); break; @@ -2686,9 +2701,6 @@ print_cmd_chr(uint16_t cmd, int32_t chr_code) case INPUT_LINE_NO_CODE: print_esc_cstr("inputlineno"); break; - case PDF_SHELL_ESCAPE_CODE: - print_esc_cstr("shellescape"); - break; case LAST_NODE_TYPE_CODE: print_esc_cstr("lastnodetype"); break; @@ -2779,12 +2791,6 @@ print_cmd_chr(uint16_t cmd, int32_t chr_code) case XETEX_LAST_CHAR_CODE: print_esc_cstr("XeTeXlastfontchar"); break; - case PDF_LAST_X_POS_CODE: - print_esc_cstr("pdflastxpos"); - break; - case PDF_LAST_Y_POS_CODE: - print_esc_cstr("pdflastypos"); - break; case XETEX_PDF_PAGE_COUNT_CODE: print_esc_cstr("XeTeXpdfpagecount"); break; @@ -2854,6 +2860,21 @@ print_cmd_chr(uint16_t cmd, int32_t chr_code) case GLUE_TO_MU_CODE: print_esc_cstr("gluetomu"); break; + case PDF_LAST_X_POS_CODE: + print_esc_cstr("pdflastxpos"); + break; + case PDF_LAST_Y_POS_CODE: + print_esc_cstr("pdflastypos"); + break; + case ELAPSED_TIME_CODE: + print_esc_cstr("elapsedtime"); + break; + case PDF_SHELL_ESCAPE_CODE: + print_esc_cstr("shellescape"); + break; + case RANDOM_SEED_CODE: + print_esc_cstr("randomseed"); + break; default: print_esc_cstr("badness"); break; @@ -2877,11 +2898,11 @@ print_cmd_chr(uint16_t cmd, int32_t chr_code) case FONT_NAME_CODE: print_esc_cstr("fontname"); break; - case PDF_STRCMP_CODE: - print_esc_cstr("strcmp"); + case ETEX_REVISION_CODE: + print_esc_cstr("eTeXrevision"); break; - case PDF_MDFIVE_SUM_CODE: - print_esc_cstr("mdfivesum"); + case EXPANDED_CODE: + print_esc_cstr("expanded"); break; case LEFT_MARGIN_KERN_CODE: print_esc_cstr("leftmarginkern"); @@ -2889,8 +2910,29 @@ print_cmd_chr(uint16_t cmd, int32_t chr_code) case RIGHT_MARGIN_KERN_CODE: print_esc_cstr("rightmarginkern"); break; - case ETEX_REVISION_CODE: - print_esc_cstr("eTeXrevision"); + case PDF_CREATION_DATE_CODE: + print_esc_cstr("creationdate"); + break; + case PDF_FILE_MOD_DATE_CODE: + print_esc_cstr("filemoddate"); + break; + case PDF_FILE_SIZE_CODE: + print_esc_cstr("filesize"); + break; + case PDF_MDFIVE_SUM_CODE: + print_esc_cstr("mdfivesum"); + break; + case PDF_FILE_DUMP_CODE: + print_esc_cstr("filedump"); + break; + case PDF_STRCMP_CODE: + print_esc_cstr("strcmp"); + break; + case UNIFORM_DEVIATE_CODE: + print_esc_cstr("uniformdeviate"); + break; + case NORMAL_DEVIATE_CODE: + print_esc_cstr("normaldeviate"); break; case XETEX_REVISION_CODE: print_esc_cstr("XeTeXrevision"); @@ -3562,6 +3604,15 @@ print_cmd_chr(uint16_t cmd, int32_t chr_code) case SET_LANGUAGE_CODE: print_esc_cstr("setlanguage"); break; + case PDF_SAVE_POS_NODE: + print_esc_cstr("pdfsavepos"); + break; + case RESET_TIMER_CODE: + print_esc_cstr("resettimer"); + break; + case SET_RANDOM_SEED_CODE: + print_esc_cstr("setrandomseed"); + break; case PIC_FILE_CODE: print_esc_cstr("XeTeXpicfile"); break; @@ -3580,9 +3631,6 @@ print_cmd_chr(uint16_t cmd, int32_t chr_code) case XETEX_DEFAULT_ENCODING_EXTENSION_CODE: print_esc_cstr("XeTeXdefaultencoding"); break; - case PDF_SAVE_POS_NODE: - print_esc_cstr("pdfsavepos"); - break; default: print_cstr("[unknown extension!]"); break; @@ -4791,7 +4839,7 @@ void show_context(void) for_end = first_count - 1; if (q <= for_end) do - print_raw_char(trick_buf[q % error_line], true); + print_char(trick_buf[q % error_line]); while (q++ < for_end); } print_ln(); @@ -4814,7 +4862,7 @@ void show_context(void) for_end = p - 1; if (q <= for_end) do - print_raw_char(trick_buf[q % error_line], true); + print_char(trick_buf[q % error_line]); while (q++ < for_end); } if (m + n > error_line) @@ -6200,10 +6248,10 @@ expand(void) cur_cs = prim_lookup(hash[cur_cs].s1); if (cur_cs != UNDEFINED_PRIMITIVE) { - t = prim_eqtb[cur_cs].b16.s1; + t = eqtb[PRIM_EQTB_BASE + cur_cs].b16.s1; if (t > MAX_COMMAND) { cur_cmd = t; - cur_chr = prim_eqtb[cur_cs].b32.s1; + cur_chr = eqtb[PRIM_EQTB_BASE + cur_cs].b32.s1; cur_tok = (cur_cmd * MAX_CHAR_VAL) + cur_chr; cur_cs = 0; goto reswitch; @@ -6448,10 +6496,13 @@ bool scan_keyword(const char* s) { int32_t p = BACKUP_HEAD; int32_t q; + int32_t save_cur_cs; + mem[p].b32.s1 = TEX_NULL; if (strlen(s) == 1) { char c = s[0]; + save_cur_cs = cur_cs; while (true) { get_x_token(); @@ -6468,6 +6519,7 @@ bool scan_keyword(const char* s) back_input(); if (p != BACKUP_HEAD) begin_token_list(mem[BACKUP_HEAD].b32.s1, BACKED_UP); + cur_cs = save_cur_cs; return false; } } @@ -7025,6 +7077,7 @@ scan_something_internal(small_number level, bool negative) b16x4 i; int32_t p; +restart: m = cur_chr; switch (cur_cmd) { @@ -7293,6 +7346,7 @@ scan_something_internal(small_number level, bool negative) case CHAR_GIVEN: case MATH_GIVEN: + case XETEX_MATH_GIVEN: cur_val = cur_chr; cur_val_level = INT_VAL; break; @@ -7531,6 +7585,14 @@ scan_something_internal(small_number level, bool negative) cur_val = last_badness; break; + case ELAPSED_TIME_CODE: + cur_val = get_microinterval(); + break; + + case RANDOM_SEED_CODE: + cur_val = random_seed; + break; + case PDF_SHELL_ESCAPE_CODE: cur_val = 0; /* shellenabledp */ break; @@ -7547,9 +7609,9 @@ scan_something_internal(small_number level, bool negative) scan_font_ident(); n = cur_val; if (font_area[n] == AAT_FONT_FLAG) - cur_val = aat_font_get(m - 14, font_layout_engine[n]); + cur_val = aat_font_get(m - XETEX_INT, font_layout_engine[n]); else if (font_area[n] == OTGR_FONT_FLAG) - cur_val = ot_font_get(m - 14, font_layout_engine[n]); + cur_val = ot_font_get(m - XETEX_INT, font_layout_engine[n]); else cur_val = 0; break; @@ -7558,9 +7620,9 @@ scan_something_internal(small_number level, bool negative) scan_font_ident(); n = cur_val; if (font_area[n] == AAT_FONT_FLAG) - cur_val = aat_font_get(m - 14, font_layout_engine[n]); + cur_val = aat_font_get(m - XETEX_INT, font_layout_engine[n]); else if (font_area[n] == OTGR_FONT_FLAG && usingGraphite(font_layout_engine[n])) - cur_val = ot_font_get(m - 14, font_layout_engine[n]); + cur_val = ot_font_get(m - XETEX_INT, font_layout_engine[n]); else cur_val = 0; break; @@ -7583,11 +7645,11 @@ scan_something_internal(small_number level, bool negative) if (font_area[n] == AAT_FONT_FLAG) { scan_int(); k = cur_val; - cur_val = aat_font_get_1(m - 14, font_layout_engine[n], k); + cur_val = aat_font_get_1(m - XETEX_INT, font_layout_engine[n], k); } else if (font_area[n] == OTGR_FONT_FLAG && usingGraphite(font_layout_engine[n])) { scan_int(); k = cur_val; - cur_val = ot_font_get_1(m - 14, font_layout_engine[n], k); + cur_val = ot_font_get_1(m - XETEX_INT, font_layout_engine[n], k); } else { not_aat_gr_font_error(LAST_ITEM, m, n); cur_val = -1; @@ -7602,12 +7664,12 @@ scan_something_internal(small_number level, bool negative) scan_int(); k = cur_val; scan_int(); - cur_val = aat_font_get_2(m - 14, font_layout_engine[n], k, cur_val); + cur_val = aat_font_get_2(m - XETEX_INT, font_layout_engine[n], k, cur_val); } else if (font_area[n] == OTGR_FONT_FLAG && usingGraphite(font_layout_engine[n])) { scan_int(); k = cur_val; scan_int(); - cur_val = ot_font_get_2(m - 14, font_layout_engine[n], k, cur_val); + cur_val = ot_font_get_2(m - XETEX_INT, font_layout_engine[n], k, cur_val); } else { not_aat_gr_font_error(LAST_ITEM, m, n); cur_val = -1; @@ -7619,7 +7681,7 @@ scan_something_internal(small_number level, bool negative) n = cur_val; if (font_area[n] == AAT_FONT_FLAG) { scan_and_pack_name(); - cur_val = aat_font_get_named(m - 14, font_layout_engine[n]); + cur_val = aat_font_get_named(m - XETEX_INT, font_layout_engine[n]); } else { not_aat_font_error(LAST_ITEM, m, n); cur_val = -1; @@ -7631,10 +7693,10 @@ scan_something_internal(small_number level, bool negative) n = cur_val; if (font_area[n] == AAT_FONT_FLAG) { scan_and_pack_name(); - cur_val = aat_font_get_named(m - 14, font_layout_engine[n]); + cur_val = aat_font_get_named(m - XETEX_INT, font_layout_engine[n]); } else if (font_area[n] == OTGR_FONT_FLAG && usingGraphite(font_layout_engine[n])) { scan_and_pack_name(); - cur_val = gr_font_get_named(m - 14, font_layout_engine[n]); + cur_val = gr_font_get_named(m - XETEX_INT, font_layout_engine[n]); } else { not_aat_gr_font_error(LAST_ITEM, m, n); cur_val = -1; @@ -7648,12 +7710,12 @@ scan_something_internal(small_number level, bool negative) scan_int(); k = cur_val; scan_and_pack_name(); - cur_val = aat_font_get_named_1(m - 14, font_layout_engine[n], k); + cur_val = aat_font_get_named_1(m - XETEX_INT, font_layout_engine[n], k); } else if (font_area[n] == OTGR_FONT_FLAG && usingGraphite(font_layout_engine[n])) { scan_int(); k = cur_val; scan_and_pack_name(); - cur_val = gr_font_get_named_1(m - 14, font_layout_engine[n], k); + cur_val = gr_font_get_named_1(m - XETEX_INT, font_layout_engine[n], k); } else { not_aat_gr_font_error(LAST_ITEM, m, n); cur_val = -1; @@ -7664,7 +7726,7 @@ scan_something_internal(small_number level, bool negative) scan_font_ident(); n = cur_val; if (font_area[n] == OTGR_FONT_FLAG && usingOpenType(font_layout_engine[n])) { - cur_val = ot_font_get(m - 14, font_layout_engine[n]); + cur_val = ot_font_get(m - XETEX_INT, font_layout_engine[n]); } else { cur_val = 0; } @@ -7676,7 +7738,7 @@ scan_something_internal(small_number level, bool negative) n = cur_val; if (font_area[n] == OTGR_FONT_FLAG && usingOpenType(font_layout_engine[n])) { scan_int(); - cur_val = ot_font_get_1(m - 14, font_layout_engine[n], cur_val); + cur_val = ot_font_get_1(m - XETEX_INT, font_layout_engine[n], cur_val); } else { not_ot_font_error(LAST_ITEM, m, n); cur_val = -1; @@ -7691,7 +7753,7 @@ scan_something_internal(small_number level, bool negative) scan_int(); k = cur_val; scan_int(); - cur_val = ot_font_get_2(m - 14, font_layout_engine[n], k, cur_val); + cur_val = ot_font_get_2(m - XETEX_INT, font_layout_engine[n], k, cur_val); } else { not_ot_font_error(LAST_ITEM, m, n); cur_val = -1; @@ -7707,7 +7769,7 @@ scan_something_internal(small_number level, bool negative) scan_int(); kk = cur_val; scan_int(); - cur_val = ot_font_get_3(m - 14, font_layout_engine[n], k, kk, cur_val); + cur_val = ot_font_get_3(m - XETEX_INT, font_layout_engine[n], k, kk, cur_val); } else { not_ot_font_error(LAST_ITEM, m, n); cur_val = -1; @@ -7891,6 +7953,31 @@ scan_something_internal(small_number level, bool negative) } break; + case IGNORE_SPACES: + if (cur_chr == 1) { /*406: */ + get_token(); + + if (cur_cs < HASH_BASE) { + cur_cs = prim_lookup(cur_cs - SINGLE_BASE); + } else { + cur_cs = prim_lookup(hash[cur_cs].s1); + } + + if (cur_cs != UNDEFINED_PRIMITIVE) { + cur_cmd = eqtb[PRIM_EQTB_BASE + cur_cs].b16.s1; + cur_chr = eqtb[PRIM_EQTB_BASE + cur_cs].b32.s1; + cur_cs = PRIM_EQTB_BASE + cur_cs; + cur_tok = CS_TOKEN_FLAG + cur_cs; + } else { + cur_cmd = RELAX; + cur_chr = 0; + cur_tok = CS_TOKEN_FLAG + FROZEN_RELAX; + cur_cs = FROZEN_RELAX; + } + goto restart; + } + break; + default: error_here_with_diagnostic("You can't use `"); print_cmd_chr(cur_cmd, cur_chr); @@ -7957,6 +8044,7 @@ scan_int(void) } } while (cur_tok == OTHER_TOKEN + '+'); +restart: if (cur_tok == ALPHA_TOKEN) { /*460:*/ get_token(); @@ -7988,6 +8076,27 @@ scan_int(void) if (cur_cmd != SPACER) back_input(); } + } else if (cur_tok == CS_TOKEN_FLAG + FROZEN_PRIMITIVE) { /*406:*/ + get_token(); + + if (cur_cs < HASH_BASE) { + cur_cs = prim_lookup(cur_cs - SINGLE_BASE); + } else { + cur_cs = prim_lookup(hash[cur_cs].s1); + } + + if (cur_cs != UNDEFINED_PRIMITIVE) { + cur_cmd = eqtb[PRIM_EQTB_BASE + cur_cs].b16.s1; + cur_chr = eqtb[PRIM_EQTB_BASE + cur_cs].b32.s1; + cur_cs = PRIM_EQTB_BASE + cur_cs; + cur_tok = CS_TOKEN_FLAG + cur_cs; + } else { + cur_cmd = RELAX; + cur_chr = 0; + cur_tok = CS_TOKEN_FLAG + FROZEN_RELAX; + cur_cs = FROZEN_RELAX; + } + goto restart; } else if (cur_cmd >= MIN_INTERNAL && cur_cmd <= MAX_INTERNAL) { scan_something_internal(INT_VAL, false); } else { /*462:*/ @@ -9018,6 +9127,8 @@ int32_t str_toks_cat(pool_pointer b, small_number cat) } if (cat == 0) t = OTHER_TOKEN + t; + else if (cat == ACTIVE_CHAR) + t = CS_TOKEN_FLAG + 1 + t; else t = MAX_CHAR_VAL * cat + t; } @@ -9161,7 +9272,7 @@ conv_toks(void) UTF16_code quote_char; small_number cat; UnicodeScalar saved_chr; - int32_t p = TEX_NULL, q; + int32_t p = TEX_NULL, q, j; cat = 0; c = cur_chr; @@ -9184,36 +9295,52 @@ conv_toks(void) scan_font_ident(); break; - case XETEX_UCHAR_CODE: - scan_usv_num(); + case ETEX_REVISION_CODE: break; - case XETEX_UCHARCAT_CODE: - scan_usv_num(); - saved_chr = cur_val; - scan_int(); + case EXPANDED_CODE: + save_scanner_status = scanner_status; + save_warning_index = warning_index; + save_def_ref = def_ref; + if (str_start[str_ptr - TOO_BIG_CHAR] < pool_ptr) + u = make_string(); + else + u = 0; + scan_pdf_ext_toks(); + warning_index = save_warning_index; + scanner_status = save_scanner_status; + begin_token_list(mem[def_ref].b32.s1, INSERTED); + def_ref = save_def_ref; + if (u != 0) + str_ptr--; + return; - if (cur_val < LEFT_BRACE || cur_val > OTHER_CHAR || cur_val == OUT_PARAM || cur_val == IGNORE) { - error_here_with_diagnostic("Invalid code ("); - print_int(cur_val); - print_cstr("), should be in the ranges 1..4, 6..8, 10..12"); - capture_to_diagnostic(NULL); + case LEFT_MARGIN_KERN_CODE: + case RIGHT_MARGIN_KERN_CODE: + scan_register_num(); - help_ptr = 1; - help_line[0] = "I'm going to use 12 instead of that illegal code value."; - error(); - cat = 12; + if (cur_val < 256) { + p = BOX_REG(cur_val); } else { - cat = cur_val; + find_sa_element(4, cur_val, false); + if (cur_ptr == TEX_NULL) + p = TEX_NULL; + else + p = mem[cur_ptr + 1].b32.s1; } - cur_val = saved_chr; + if (p == TEX_NULL || NODE_type(p) != HLIST_NODE) + pdf_error("marginkern", "a non-empty hbox expected"); break; - case ETEX_REVISION_CODE: + case PDF_CREATION_DATE_CODE: + b = pool_ptr; + getcreationdate(); + mem[GARBAGE].b32.s1 = str_toks(b); + begin_token_list(mem[TEMP_HEAD].b32.s1, INSERTED); break; - case PDF_STRCMP_CODE: + case PDF_FILE_MOD_DATE_CODE: save_scanner_status = scanner_status; save_warning_index = warning_index; save_def_ref = def_ref; @@ -9221,13 +9348,69 @@ conv_toks(void) u = make_string(); else u = 0; - compare_strings(); + scan_pdf_ext_toks(); + + if (selector == SELECTOR_NEW_STRING) + pdf_error("tokens", "tokens_to_string() called while selector = new_string"); + + old_setting = selector; + selector = SELECTOR_NEW_STRING; + show_token_list(mem[def_ref].b32.s1, TEX_NULL, pool_size - pool_ptr); + selector = old_setting; + s = make_string(); + delete_token_ref(def_ref); def_ref = save_def_ref; warning_index = save_warning_index; scanner_status = save_scanner_status; + b = pool_ptr; + getfilemoddate(s); /* <= the difference-maker */ + mem[GARBAGE].b32.s1 = str_toks(b); + + if (s == str_ptr - 1) { + str_ptr--; + pool_ptr = str_start[str_ptr - TOO_BIG_CHAR]; + } + + begin_token_list(mem[TEMP_HEAD].b32.s1, INSERTED); if (u != 0) str_ptr--; - break; + return; + + case PDF_FILE_SIZE_CODE: + save_scanner_status = scanner_status; + save_warning_index = warning_index; + save_def_ref = def_ref; + if (str_start[str_ptr - TOO_BIG_CHAR] < pool_ptr) + u = make_string(); + else + u = 0; + scan_pdf_ext_toks(); + + if (selector == SELECTOR_NEW_STRING) + pdf_error("tokens", "tokens_to_string() called while selector = new_string"); + + old_setting = selector; + selector = SELECTOR_NEW_STRING; + show_token_list(mem[def_ref].b32.s1, TEX_NULL, pool_size - pool_ptr); + selector = old_setting; + s = make_string(); + delete_token_ref(def_ref); + def_ref = save_def_ref; + warning_index = save_warning_index; + scanner_status = save_scanner_status; + b = pool_ptr; + getfilesize(s); /* <= the difference-maker */ + mem[GARBAGE].b32.s1 = str_toks(b); + + if (s == str_ptr - 1) { + str_ptr--; + pool_ptr = str_start[str_ptr - TOO_BIG_CHAR]; + } + + begin_token_list(mem[TEMP_HEAD].b32.s1, INSERTED); + if (u != 0) + str_ptr--; + return; case PDF_MDFIVE_SUM_CODE: save_scanner_status = scanner_status; @@ -9246,7 +9429,81 @@ conv_toks(void) pdf_error("tokens", "tokens_to_string() called while selector = new_string"); old_setting = selector; - selector = SELECTOR_NEW_STRING ; + selector = SELECTOR_NEW_STRING; + show_token_list(mem[def_ref].b32.s1, TEX_NULL, pool_size - pool_ptr); + selector = old_setting; + s = make_string(); + delete_token_ref(def_ref); + def_ref = save_def_ref; + warning_index = save_warning_index; + scanner_status = save_scanner_status; + b = pool_ptr; + getmd5sum(s, boolvar); /* <== the difference-maker */ + mem[GARBAGE].b32.s1 = str_toks(b); + + if (s == str_ptr - 1) { + str_ptr--; + pool_ptr = str_start[str_ptr - TOO_BIG_CHAR]; + } + + begin_token_list(mem[TEMP_HEAD].b32.s1, INSERTED); + if (u != 0) + str_ptr--; + return; + break; + + case PDF_FILE_DUMP_CODE: + save_scanner_status = scanner_status; + save_warning_index = warning_index; + save_def_ref = def_ref; + + if (str_start[str_ptr - TOO_BIG_CHAR] < pool_ptr) + u = make_string(); + else + u = 0; + + cur_val = 0; + + if (scan_keyword("offset")) { + scan_int(); + + if (cur_val < 0) { + error_here_with_diagnostic("Bad file offset"); + capture_to_diagnostic(NULL); + help_ptr = 2; + help_line[1] = "A file offset must be between 0 and 2^_31_-1,"; + help_line[0] = "I changed this one to zero."; + int_error(cur_val); + cur_val = 0; + } + } + + i = cur_val; + cur_val = 0; + + if (scan_keyword("length")) { + scan_int(); + + if (cur_val < 0) { + error_here_with_diagnostic("Bad dump length"); + capture_to_diagnostic(NULL); + help_ptr = 2; + help_line[1] = "A dump length must be between 0 and 2^_31_-1,"; + help_line[0] = "I changed this one to zero."; + int_error(cur_val); + cur_val = 0; + } + } + + j = cur_val; + + scan_pdf_ext_toks(); + + if (selector == SELECTOR_NEW_STRING) + pdf_error("tokens", "tokens_to_string() called while selector = new_string"); + + old_setting = selector; + selector = SELECTOR_NEW_STRING; show_token_list(mem[def_ref].b32.s1, TEX_NULL, pool_size - pool_ptr); selector = old_setting; s = make_string(); @@ -9255,7 +9512,7 @@ conv_toks(void) warning_index = save_warning_index; scanner_status = save_scanner_status; b = pool_ptr; - getmd5sum(s, boolvar); + getfiledump(s, i, j); /* <=== non-boilerplate */ mem[GARBAGE].b32.s1 = str_toks(b); if (s == str_ptr - 1) { @@ -9267,6 +9524,47 @@ conv_toks(void) if (u != 0) str_ptr--; return; + + case PDF_STRCMP_CODE: + save_scanner_status = scanner_status; + save_warning_index = warning_index; + save_def_ref = def_ref; + if (str_start[str_ptr - TOO_BIG_CHAR] < pool_ptr) + u = make_string(); + else + u = 0; + compare_strings(); + def_ref = save_def_ref; + warning_index = save_warning_index; + scanner_status = save_scanner_status; + if (u != 0) + str_ptr--; + break; + + case XETEX_UCHAR_CODE: + scan_usv_num(); + break; + + case XETEX_UCHARCAT_CODE: + scan_usv_num(); + saved_chr = cur_val; + scan_int(); + + if (cur_val < LEFT_BRACE || cur_val > OTHER_CHAR || cur_val == OUT_PARAM || cur_val == IGNORE) { + error_here_with_diagnostic("Invalid code ("); + print_int(cur_val); + print_cstr("), should be in the ranges 1..4, 6..8, 10..12"); + capture_to_diagnostic(NULL); + + help_ptr = 1; + help_line[0] = "I'm going to use 12 instead of that illegal code value."; + error(); + cat = 12; + } else { + cat = cur_val; + } + + cur_val = saved_chr; break; case XETEX_REVISION_CODE: @@ -9322,28 +9620,17 @@ conv_toks(void) } break; - case LEFT_MARGIN_KERN_CODE: - case RIGHT_MARGIN_KERN_CODE: - scan_register_num(); - - if (cur_val < 256) { - p = BOX_REG(cur_val); - } else { - find_sa_element(4, cur_val, false); - if (cur_ptr == TEX_NULL) - p = TEX_NULL; - else - p = mem[cur_ptr + 1].b32.s1; - } - - if (p == TEX_NULL || NODE_type(p) != HLIST_NODE) - pdf_error("marginkern", "a non-empty hbox expected"); - break; - case JOB_NAME_CODE: if (job_name == 0) open_log_file(); break; + + case UNIFORM_DEVIATE_CODE: + scan_int(); + break; + + case NORMAL_DEVIATE_CODE: + break; } old_setting = selector; @@ -9394,41 +9681,10 @@ conv_toks(void) } break; - case XETEX_UCHAR_CODE: - case XETEX_UCHARCAT_CODE: - print_char(cur_val); - break; - case ETEX_REVISION_CODE: print_cstr(".6"); break; - case PDF_STRCMP_CODE: - print_int(cur_val); - break; - - case XETEX_REVISION_CODE: - print_cstr(".99998"); - break; - - case XETEX_VARIATION_NAME_CODE: - if (font_area[fnt] == AAT_FONT_FLAG) - aat_print_font_name(c, font_layout_engine[fnt], arg1, arg2); - break; - - case XETEX_FEATURE_NAME_CODE: - case XETEX_SELECTOR_NAME_CODE: - if (font_area[fnt] == AAT_FONT_FLAG) - aat_print_font_name(c, font_layout_engine[fnt], arg1, arg2); - else if (font_area[fnt] == OTGR_FONT_FLAG && usingGraphite(font_layout_engine[fnt])) - gr_print_font_name(c, font_layout_engine[fnt], arg1, arg2); - break; - - case XETEX_GLYPH_NAME_CODE: - if (font_area[fnt] == AAT_FONT_FLAG || font_area[fnt] == OTGR_FONT_FLAG) - print_glyph_name(fnt, arg1); - break; - case LEFT_MARGIN_KERN_CODE: p = mem[p + 5].b32.s1; while (p != TEX_NULL && @@ -9498,6 +9754,45 @@ conv_toks(void) print_cstr("pt"); break; + case PDF_STRCMP_CODE: + print_int(cur_val); + break; + + case UNIFORM_DEVIATE_CODE: + print_int(unif_rand(cur_val)); + break; + + case NORMAL_DEVIATE_CODE: + print_int(norm_rand()); + break; + + case XETEX_UCHAR_CODE: + case XETEX_UCHARCAT_CODE: + print_char(cur_val); + break; + + case XETEX_REVISION_CODE: + print_cstr(".999992"); + break; + + case XETEX_VARIATION_NAME_CODE: + if (font_area[fnt] == AAT_FONT_FLAG) + aat_print_font_name(c, font_layout_engine[fnt], arg1, arg2); + break; + + case XETEX_FEATURE_NAME_CODE: + case XETEX_SELECTOR_NAME_CODE: + if (font_area[fnt] == AAT_FONT_FLAG) + aat_print_font_name(c, font_layout_engine[fnt], arg1, arg2); + else if (font_area[fnt] == OTGR_FONT_FLAG && usingGraphite(font_layout_engine[fnt])) + gr_print_font_name(c, font_layout_engine[fnt], arg1, arg2); + break; + + case XETEX_GLYPH_NAME_CODE: + if (font_area[fnt] == AAT_FONT_FLAG || font_area[fnt] == OTGR_FONT_FLAG) + print_glyph_name(fnt, arg1); + break; + case JOB_NAME_CODE: print_file_name(job_name, 0, 0); break; @@ -10194,8 +10489,10 @@ conditional(void) m = prim_lookup(cur_cs - SINGLE_BASE); else m = prim_lookup(hash[cur_cs].s1); - b = (cur_cmd != UNDEFINED_CS && m != UNDEFINED_PRIMITIVE - && cur_cmd == prim_eqtb[m].b16.s1 && cur_chr == prim_eqtb[m].b32.s1); + b = (cur_cmd != UNDEFINED_CS + && m != UNDEFINED_PRIMITIVE + && cur_cmd == eqtb[PRIM_EQTB_BASE + m].b16.s1 + && cur_chr == eqtb[PRIM_EQTB_BASE + m].b32.s1); break; } @@ -10436,30 +10733,80 @@ make_name_string(void) } +static void +scan_file_name_braced(void) +{ + small_number save_scanner_status; + int32_t save_def_ref, save_cur_cs; + str_number s; + int32_t i; + bool save_stop_at_space; + + save_scanner_status = scanner_status; + save_def_ref = def_ref; + save_cur_cs = cur_cs; + cur_cs = warning_index; + scan_toks(false, true); + + old_setting = selector; + selector = SELECTOR_NEW_STRING; + show_token_list(mem[def_ref].b32.s1, TEX_NULL, pool_size - pool_ptr); + selector = old_setting; + s = make_string(); + delete_token_ref(def_ref); + def_ref = save_def_ref; + cur_cs = save_cur_cs; + scanner_status = save_scanner_status; + save_stop_at_space = stop_at_space; + + begin_name(); + + for (i = str_start[s - TOO_BIG_CHAR]; i < str_start[s + 1 - TOO_BIG_CHAR]; i++) + more_name(str_pool[i]); + + stop_at_space = save_stop_at_space; +} + + void scan_file_name(void) { - name_in_progress = true; - begin_name(); + int32_t save_warning_index; + save_warning_index = warning_index; + warning_index = cur_cs; do { get_x_token(); - } while (cur_cmd == SPACER); + } while (cur_cmd == SPACER || cur_cmd == RELAX); - while (true) { - if (cur_cmd > OTHER_CHAR || cur_chr > BIGGEST_CHAR) { - back_input(); - break; - } + back_input(); - if (!more_name(cur_chr)) - break; + if (cur_cmd == LEFT_BRACE) { + scan_file_name_braced(); + } else { + name_in_progress = true; + begin_name(); - get_x_token(); + do { + get_x_token(); + } while(cur_cmd == SPACER); + + while (true) { + if (cur_cmd > OTHER_CHAR || cur_chr > BIGGEST_CHAR) { + back_input(); + break; + } + + if (!more_name(cur_chr)) + break; + + get_x_token(); + } } end_name(); name_in_progress = false; + warning_index = save_warning_index; } @@ -15969,7 +16316,7 @@ void do_extension(void) int32_t p; switch (cur_chr) { - case 0: + case OPEN_NODE: { new_write_whatsit(OPEN_NODE_SIZE); scan_optional_equals(); @@ -15979,7 +16326,8 @@ void do_extension(void) mem[cur_list.tail + 2].b32.s1 = cur_ext; } break; - case 1: + + case WRITE_NODE: { k = cur_cs; new_write_whatsit(WRITE_NODE_SIZE); @@ -15988,13 +16336,15 @@ void do_extension(void) mem[cur_list.tail + 1].b32.s1 = def_ref; } break; - case 2: + + case CLOSE_NODE: { new_write_whatsit(WRITE_NODE_SIZE); mem[cur_list.tail + 1].b32.s1 = TEX_NULL; } break; - case 3: + + case SPECIAL_NODE: { new_whatsit(SPECIAL_NODE, WRITE_NODE_SIZE); mem[cur_list.tail + 1].b32.s0 = TEX_NULL; @@ -16002,7 +16352,8 @@ void do_extension(void) mem[cur_list.tail + 1].b32.s1 = def_ref; } break; - case 4: + + case IMMEDIATE_CODE: { get_x_token(); if ((cur_cmd == EXTENSION) && (cur_chr <= CLOSE_NODE)) { @@ -16016,11 +16367,11 @@ void do_extension(void) back_input(); } break; - case 5: + + case SET_LANGUAGE_CODE: if (abs(cur_list.mode) != HMODE) report_illegal_case(); else { - new_whatsit(LANGUAGE_NODE, SMALL_NODE_SIZE); scan_int(); if (cur_val <= 0) @@ -16034,19 +16385,38 @@ void do_extension(void) mem[cur_list.tail + 1].b16.s0 = norm_min(INTPAR(right_hyphen_min)); } break; - case 41: + + case PDF_SAVE_POS_NODE: + new_whatsit(PDF_SAVE_POS_NODE, SMALL_NODE_SIZE); + break; + + case RESET_TIMER_CODE: + get_seconds_and_micros(&epochseconds, µseconds); + break; + + case SET_RANDOM_SEED_CODE: + scan_int(); + if (cur_val < 0) + cur_val = -cur_val; + random_seed = cur_val; + init_randoms(random_seed); + break; + + case PIC_FILE_CODE: if (abs(cur_list.mode) == MMODE) report_illegal_case(); else load_picture(false); break; - case 42: + + case PDF_FILE_CODE: if (abs(cur_list.mode) == MMODE) report_illegal_case(); else load_picture(true); break; - case 43: + + case GLYPH_CODE: { if (abs(cur_list.mode) == VMODE) { back_input(); @@ -16081,7 +16451,8 @@ void do_extension(void) } } break; - case 44: + + case XETEX_INPUT_ENCODING_EXTENSION_CODE: { scan_and_pack_name(); i = get_encoding_mode_and_info(&j); @@ -16098,7 +16469,8 @@ void do_extension(void) set_input_file_encoding(input_file[in_open], i, j); } break; - case 45: + + case XETEX_DEFAULT_ENCODING_EXTENSION_CODE: { scan_and_pack_name(); i = get_encoding_mode_and_info(&j); @@ -16106,7 +16478,8 @@ void do_extension(void) INTPAR(xetex_default_input_encoding) = j; } break; - case 46: + + case XETEX_LINEBREAK_LOCALE_EXTENSION_CODE: { scan_file_name(); if (length(cur_name) == 0) @@ -16115,11 +16488,7 @@ void do_extension(void) INTPAR(xetex_linebreak_locale) = cur_name; } break; - case 6: - { - new_whatsit(PDFTEX_FIRST_EXTENSION_CODE, SMALL_NODE_SIZE); - } - break; + default: confusion("ext1"); break; @@ -16450,7 +16819,7 @@ void main_control(void) find_sa_element(INTER_CHAR_VAL, space_class * CHAR_CLASS_LIMIT + ((CHAR_CLASS_LIMIT - 1)), false); - if (cur_ptr != TEX_NULL) { + if (cur_ptr != TEX_NULL && ETEX_SA_ptr(cur_ptr) != TEX_NULL) { if (cur_cs == 0) { if (cur_cmd == CHAR_NUM) cur_cmd = OTHER_CHAR; @@ -16502,8 +16871,9 @@ void main_control(void) else cur_cs = prim_lookup(hash[cur_cs].s1); if (cur_cs != UNDEFINED_PRIMITIVE) { - cur_cmd = prim_eqtb[cur_cs].b16.s1; - cur_chr = prim_eqtb[cur_cs].b32.s1; + cur_cmd = eqtb[PRIM_EQTB_BASE + cur_cs].b16.s1; + cur_chr = eqtb[PRIM_EQTB_BASE + cur_cs].b32.s1; + cur_tok = CS_TOKEN_FLAG + PRIM_EQTB_BASE + cur_cs; goto reswitch; } } @@ -17104,7 +17474,7 @@ void main_control(void) find_sa_element(INTER_CHAR_VAL, ((CHAR_CLASS_LIMIT - 1)) * CHAR_CLASS_LIMIT + space_class, false); - if (cur_ptr != TEX_NULL) { + if (cur_ptr != TEX_NULL && ETEX_SA_ptr(cur_ptr) != TEX_NULL) { if (cur_cmd != LETTER) cur_cmd = OTHER_CHAR; cur_tok = (cur_cmd * MAX_CHAR_VAL) + cur_chr; @@ -17117,7 +17487,7 @@ void main_control(void) } else { find_sa_element(INTER_CHAR_VAL, prev_class * CHAR_CLASS_LIMIT + space_class, false); - if (cur_ptr != TEX_NULL) { + if (cur_ptr != TEX_NULL && ETEX_SA_ptr(cur_ptr) != TEX_NULL) { if (cur_cmd != LETTER) cur_cmd = OTHER_CHAR; cur_tok = (cur_cmd * MAX_CHAR_VAL) + cur_chr; @@ -17176,7 +17546,7 @@ void main_control(void) prev_class = ((CHAR_CLASS_LIMIT - 1)); find_sa_element(INTER_CHAR_VAL, space_class * CHAR_CLASS_LIMIT + ((CHAR_CLASS_LIMIT - 1)), false); - if (cur_ptr != TEX_NULL) { + if (cur_ptr != TEX_NULL && ETEX_SA_ptr(cur_ptr) != TEX_NULL) { if (cur_cs == 0) { if (cur_cmd == CHAR_NUM) cur_cmd = OTHER_CHAR; @@ -17235,24 +17605,23 @@ void main_control(void) main_pp = cur_list.tail; if (cur_list.mode == HMODE) { main_ppp = cur_list.head; - if (main_ppp != main_pp) - while ((mem[main_ppp].b32.s1 != main_pp)) { - if (!is_char_node(main_ppp) && NODE_type(main_ppp) == DISC_NODE) { - temp_ptr = main_ppp; - { - register int32_t for_end; - main_p = 1; - for_end = mem[temp_ptr].b16.s0; - if (main_p <= for_end) - do - main_ppp = LLIST_link(main_ppp); - while (main_p++ < for_end); - } + while (main_ppp != main_pp && mem[main_ppp].b32.s1 != main_pp) { + if (!is_char_node(main_ppp) && NODE_type(main_ppp) == DISC_NODE) { + temp_ptr = main_ppp; + { + register int32_t for_end; + main_p = 1; + for_end = mem[temp_ptr].b16.s0; + if (main_p <= for_end) + do + main_ppp = LLIST_link(main_ppp); + while (main_p++ < for_end); } - if (main_ppp != main_pp) - main_ppp = LLIST_link(main_ppp); } + if (main_ppp != main_pp) + main_ppp = LLIST_link(main_ppp); + } temp_ptr = 0; do { if (main_h == 0) @@ -17335,24 +17704,22 @@ void main_control(void) } else { main_ppp = cur_list.head; - if (main_ppp != main_pp) - while ((mem[main_ppp].b32.s1 != main_pp)) { - - if (!is_char_node(main_ppp) && NODE_type(main_ppp) == DISC_NODE) { - temp_ptr = main_ppp; - { - register int32_t for_end; - main_p = 1; - for_end = mem[temp_ptr].b16.s0; - if (main_p <= for_end) - do - main_ppp = LLIST_link(main_ppp); - while (main_p++ < for_end); - } + while (main_ppp != main_pp && mem[main_ppp].b32.s1 != main_pp) { + if (!is_char_node(main_ppp) && NODE_type(main_ppp) == DISC_NODE) { + temp_ptr = main_ppp; + { + register int32_t for_end; + main_p = 1; + for_end = mem[temp_ptr].b16.s0; + if (main_p <= for_end) + do + main_ppp = LLIST_link(main_ppp); + while (main_p++ < for_end); } - if (main_ppp != main_pp) - main_ppp = LLIST_link(main_ppp); } + if (main_ppp != main_pp) + main_ppp = LLIST_link(main_ppp); + } if ((((main_pp) != TEX_NULL && (!(is_char_node(main_pp))) && (NODE_type(main_pp) == WHATSIT_NODE) && ((mem[main_pp].b16.s0 == NATIVE_WORD_NODE) || (mem[main_pp].b16.s0 == NATIVE_WORD_NODE_AT)))) && (mem[main_pp + 4].b16.s2 == main_f) @@ -17496,7 +17863,7 @@ void main_control(void) if ((cur_input.state != TOKEN_LIST) || (cur_input.index != BACKED_UP_CHAR)) { find_sa_element(INTER_CHAR_VAL, ((CHAR_CLASS_LIMIT - 1)) * CHAR_CLASS_LIMIT + space_class, false); - if (cur_ptr != TEX_NULL) { + if (cur_ptr != TEX_NULL && ETEX_SA_ptr(cur_ptr) != TEX_NULL) { if (cur_cmd != LETTER) cur_cmd = OTHER_CHAR; cur_tok = (cur_cmd * MAX_CHAR_VAL) + cur_chr; @@ -17509,7 +17876,7 @@ void main_control(void) } else { find_sa_element(INTER_CHAR_VAL, prev_class * CHAR_CLASS_LIMIT + space_class, false); - if (cur_ptr != TEX_NULL) { + if (cur_ptr != TEX_NULL && ETEX_SA_ptr(cur_ptr) != TEX_NULL) { if (cur_cmd != LETTER) cur_cmd = OTHER_CHAR; cur_tok = (cur_cmd * MAX_CHAR_VAL) + cur_chr; @@ -17652,7 +18019,7 @@ void main_control(void) if ((cur_input.state != TOKEN_LIST) || (cur_input.index != BACKED_UP_CHAR)) { find_sa_element(INTER_CHAR_VAL, ((CHAR_CLASS_LIMIT - 1)) * CHAR_CLASS_LIMIT + space_class, false); - if (cur_ptr != TEX_NULL) { + if (cur_ptr != TEX_NULL && ETEX_SA_ptr(cur_ptr) != TEX_NULL) { if (cur_cmd != LETTER) cur_cmd = OTHER_CHAR; cur_tok = (cur_cmd * MAX_CHAR_VAL) + cur_chr; @@ -17665,7 +18032,7 @@ void main_control(void) } else { find_sa_element(INTER_CHAR_VAL, prev_class * CHAR_CLASS_LIMIT + space_class, false); - if (cur_ptr != TEX_NULL) { + if (cur_ptr != TEX_NULL && ETEX_SA_ptr(cur_ptr) != TEX_NULL) { if (cur_cmd != LETTER) cur_cmd = OTHER_CHAR; cur_tok = (cur_cmd * MAX_CHAR_VAL) + cur_chr; @@ -17877,7 +18244,7 @@ void main_control(void) prev_class = ((CHAR_CLASS_LIMIT - 1)); find_sa_element(INTER_CHAR_VAL, space_class * CHAR_CLASS_LIMIT + ((CHAR_CLASS_LIMIT - 1)), false); - if (cur_ptr != TEX_NULL) { + if (cur_ptr != TEX_NULL && ETEX_SA_ptr(cur_ptr) != TEX_NULL) { if (cur_cs == 0) { if (cur_cmd == CHAR_NUM) cur_cmd = OTHER_CHAR; @@ -17972,11 +18339,15 @@ void compare_strings(void) { str_number s1, s2; pool_pointer i1, i2, j1, j2; + int32_t save_cur_cs; + + save_cur_cs = cur_cs; { scan_toks(false, true); } s1 = tokens_to_string(def_ref); delete_token_ref(def_ref); + cur_cs = save_cur_cs; { scan_toks(false, true); } diff --git a/tectonic/xetex-xetexd.h b/tectonic/xetex-xetexd.h index c05ef85995..40949eb1c8 100644 --- a/tectonic/xetex-xetexd.h +++ b/tectonic/xetex-xetexd.h @@ -303,6 +303,11 @@ typedef union { #define TOKEN_LIST_ref_count(p) mem[p].b32.s0 +/* e-TeX sparse arrays for large-numebered registers, etc. */ +#define ETEX_SA_ref(p) mem[(p) + 1].b32.s0 +#define ETEX_SA_ptr(p) mem[(p) + 1].b32.s1 +#define ETEX_SA_num(p) ETEX_SA_ptr(p) + /* e-TeX extended marks stuff ... not sure where to put these */ #define ETEX_MARK_sa_top_mark(p) mem[(p) + 1].b32.s0 /* \topmarks */ #define ETEX_MARK_sa_first_mark(p) mem[(p) + 1].b32.s1 /* \firstmarks */ @@ -343,7 +348,15 @@ typedef struct { /* Functions originating in texmfmp.c */ void getmd5sum(int32_t s, bool file); + +void init_start_time(void); void get_date_and_time (time_t, int32_t *, int32_t *, int32_t *, int32_t *); +void get_seconds_and_micros (int32_t *seconds, int32_t *micros); + +void getcreationdate(void); +void getfilemoddate(int32_t s); +void getfilesize(int32_t s); +void getfiledump(int32_t s, int offset, int length); char *gettexstring(str_number); bool is_new_source(str_number, int); @@ -425,6 +438,11 @@ extern unsigned char help_ptr; extern bool use_err_help; extern bool arith_error; extern scaled_t tex_remainder; +extern int32_t randoms[55]; +extern unsigned char j_random; +extern scaled_t random_seed; +extern int32_t two_to_the[31]; +extern int32_t spec_log[29]; extern int32_t temp_ptr; extern memory_word *mem; extern int32_t lo_mem_max; @@ -458,7 +476,6 @@ extern bool no_new_control_sequence; extern int32_t cs_count; extern b32x2 prim[501]; extern int32_t prim_used; -extern memory_word prim_eqtb[501]; extern memory_word *save_stack; extern int32_t save_ptr; extern int32_t max_save_stack; @@ -569,6 +586,8 @@ extern int32_t dead_cycles; extern bool doing_leaders; extern scaled_t rule_ht, rule_dp, rule_wd; extern scaled_t cur_h, cur_v; /* should be internal to shipout, but accessed by synctex */ +extern int32_t epochseconds; +extern int32_t microseconds; extern scaled_t total_stretch[4], total_shrink[4]; extern int32_t last_badness; extern int32_t adjust_tail; @@ -728,6 +747,7 @@ int32_t new_penalty(int32_t m); void check_mem(bool print_locs); void search_mem(int32_t p); int32_t prev_rightmost(int32_t s, int32_t e); +int32_t get_microinterval(void); scaled_t round_xn_over_d(scaled_t x, int32_t n, int32_t d); void short_display(int32_t p); void print_font_and_char(int32_t p); @@ -1099,6 +1119,9 @@ int32_t half(int32_t x); scaled_t mult_and_add(int32_t n, scaled_t x, scaled_t y, scaled_t max_answer); scaled_t x_over_n(scaled_t x, int32_t n); scaled_t xn_over_d(scaled_t x, int32_t n, int32_t d); +void init_randoms(int32_t seed); +int32_t unif_rand(int32_t x); +int32_t norm_rand(void); /* xetex-shipout */ From b29c6dd837c9944b0ab140cf8d739ce71e717446 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Sun, 25 Oct 2020 20:16:57 -0400 Subject: [PATCH 13/24] Update test cases for the engine updates Note that the `trip` reference outputs do not need updating if the `print_char` and `show_context` changes are reverte. --- tests/formats.rs | 2 +- tests/tex-outputs/otf_basic.log | 2 +- tests/tex-outputs/otf_basic.xdv | Bin 6300 -> 6304 bytes tests/trip/trip.fot | 10 +++++----- tests/trip/trip.log | 20 ++++++++++++-------- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/tests/formats.rs b/tests/formats.rs index 87ed6161ec..1193632bc2 100644 --- a/tests/formats.rs +++ b/tests/formats.rs @@ -137,6 +137,6 @@ fn plain_format() { test_format_generation( "plain.tex", "plain.fmt", - "83684a4992274fdae8de1b142146f85b0bf1a4f3489c54a04e12739d578dd863", + "8e33c4c9af66ddb064a36749db1e0ba681bbebd1a896d2886745a0efa9a745a1", ) } diff --git a/tests/tex-outputs/otf_basic.log b/tests/tex-outputs/otf_basic.log index 0dbee8b45d..d654a6dfa7 100644 --- a/tests/tex-outputs/otf_basic.log +++ b/tests/tex-outputs/otf_basic.log @@ -2,4 +2,4 @@ (otf_basic.tex Missing character: There is no 𐐷 in font [lmroman12-regular]! [1] ) -Output written on otf_basic.xdv (1 page, 6300 bytes). +Output written on otf_basic.xdv (1 page, 6304 bytes). diff --git a/tests/tex-outputs/otf_basic.xdv b/tests/tex-outputs/otf_basic.xdv index 0219961d81122a510a43c80e0b3b21b7f22f601a..f416c702ab1f6fac80bc9494a6116d8f7d3ca9a1 100644 GIT binary patch literal 6304 zcmcgx4N%m_6<@eRKu|cog#!T*l%~RA&7yX)Rmo=|m##Lni?2JoIy7Y?j9VF~`x&-e*HNOW8Ij|Nm^5O}=xWumj$3MRUuwE6b0+p&t zRfe*4nRe&6RAj+C<%2d7(T|!H4;Ys;3eZOTEmaLFPt78-Q&L`5Bk`Rd=1)WM9`NIh zfR@VDfZ<;j0LFZD7hu8|JwD-iO*7@vetgf^v>q^(HfB{-^h+gnZS-a*S|cC%gYw2W zKSVeVRZ3$)uY@Vn;F!-Rm+&rv%Oe~PniVklpaH{(HqBiFu&2#DuKWfu$e3Ud0Y(&Q z&aE4?bjF@=U`^7Z4*IZrH0@RXH&G94UW{*+ z04=wO%Q5I%Kh&HitnNd9;-a?z(=TYnSU4cPJmSWx7UHBrukSS|h^g=xR`@^q3E=2R z-Dj?~MB`d=4B8>`@PBtA<_Euc8Zi8F8esI+>wp=w?{zq_{Pt%omp8PL07jP?1Td&( z11iGmCpcCDrv7jdVAh#80jC|;<1;EYq0ch4lO?cbIq1EV_RH4MLd?(VJf#9K ziytF$wVsIHgnIoMV`Fx};i|aa9q3PZ@CIONem`Kw>DK@!$7x@e<6}pEmTF<`A-YU) zfHqNOyl$NqYZIzgnw>$jQg%9wes#bl1zEI>hh41$4dE@`s(nC`=@7S&CM}->IO*Uuz|35&6WIw`C$v4X2V@QB6JYw~ z9p?TPt?BM#koY3(-%WyZw(lkjjM@BwQ9J`C&vwa8wmF}iIyv4hvo}d7Z0|(F5|NNd zR+h4FZiZ)Ns~kG~$eDBaDN;qHtBiS|G|k@qnB{&RS)?r4*=3+B%) z6cM85E(W-#`Ifi080L#aB$kg#xd#jvK^0g9N1Qu+O9@URT%%US8^-)HwIgss{ezpl z4CX8Di-RLK3Wu2WzuXHq{^`$PmKawN+z|)5*z?&2u?s~BEFp)sVcnQKox?b3T@|HF z9N0P4aLY+3318w?+*wlHOa4lmHlrMLKM6WG1|QYIp93DZ=^oWpiLE-&PW;^x zjHfN$37C1M9x%J_LBN?SP5|Z~dK7TZm(u}@y0w#BkbD9Ca#sLgWo{K<&08k{*$uM6 zYWJ6xIQZAr)E!q6(&>A9qskFfl@>2}!R$ ziSMjYRYaLN;LtI@%iP=KQk`4ODjE~`aZ{`q@KjNq)tDomD#`T_`f0hp1a=`i;? zU5W{7(u_~yzW?7lfnI{Qq#1+3`-FDjX}_w#yo?Jv<;`x|fPUT~ofysCpcA5^6EETW z0+ZI3vX1-FuNbe#s{{JcUw%(MAlV*mqyRyeAr%$qSI{P`v;o={SYr29g7Qw^ncEyyG+mh+@-8}JqAxVDE)z2%i=c%yN!HeDW`e+3@Sueo`u z@+6ZT-`Q>+CYve1L2wx6oXlMzievVaz9bNm$#H<nBT|$Q!*wn1d+gX#hJDL9NZ~$M`^?{u zy-4jt=R|u(y-GNS5e%3JL2S6)Qw3Ma?ke z;5YgF+tdff{GS6g=YMV;6n&ta6t)+;eyu@j62v^6l4wixRDHjK3K$N7>bJj4Bf(MS z`ddioSdHAA%X})= zXe|EC0;6!|=!h=4pcMFFrMeteviLo5WX0Z7nxK8AQBT zRiakqB-g!C>_q&gq{Nb-vcE)VC&q`op@M~_e!9`%=ZE5meIhq&hQ1+5d{x(;$$NV7 zo$uDzKT9p?GozSX-g~bZ^mDM540{?&JTF0GGIX+bH?hvKyi(b_OqX(9NXEUegdbMg z(e!r%4IaqfyA`9JL2_)jj!nt;R$)AI!41H>RFCzu@Ksch#w;5DN zgcSVIzcF_$&B~%#LwbH1`|kIY}-*=U24G%a0*`AU_yw?7r7 zR9mOISheShn*X1wR@^L)q;a2R4bH6016l3cuTn44_%8(S?#X>#@BMKe;q>~328X@u Pza?5qNTTw6&+7JHV9(q_ literal 6300 zcmcgx3vg6d89vG8N#4(0l1)eg386_$vY`nyg`{bltb`!J*hUIo zrM8cwcI(awv$Yn45$Wt?2kDAxuD8E;Z#~@dKI_*Rqm1S#O*9o+qM4v z=#Q@+2&#FX^{W_uN0;bDtN6F{PuqKp?_Kl%#xg&?j-?0dZC8D&UNvCOnzx=;v-mk( zqF(Xw?}T1*C`{gVoMqPOCYHHJ?qyl<_HS4g-?xnA6;D3MvhqefRvA|1RzCcdL01oc z`7zh5tp`;k_oItgCZO7}mXt^1lq2*m`eiTw7OT}`i~vSRDE+5xgqR&=+^dgAFV7fM zaiJ09os1yX%dV;6KJE>DEayC;H7fB`@cmrq>Ve+PuyUKKhi3GprI~0g1^kf5kF+))JPaH7p8^@;~mhMTgiU{^v)yU+VsoEVEAPc+A=K6~3>;y0@{% z8prmh{jO~ku0g0;1_*_j2@wjXz=Wexs2Xu*9xR`%S+@!yuy)t{~DSn>+om`g1waqNcoTDr&zezX=r2NZnmWvDq zHmD(r9!yP>n(1LO8rSAhlWj7q8@(&h>xwPkvg4}3qZEfR>>pP1T%y~Y;Ca3;K6N$A ze#U?R#%fmqi z)yfZj79;1hE9sp?Yj{3oG~G|HmGilGSmq_^s!?b>QF4t�B@v;rCUE8WFEFp3wP7 z2uKl59-#R<$D_`}`2_fu8>GI7`b%NB{;`LUfw`Zur@p92c}Y!{*$Pkx@J>WIZwji+ z@qo>uVxf>_L)FKl1{hf>D=iO%*BmaJ}-gS#!0xO0kp?}ZHKPqrL)1=rZX5Gb4QopVV3l%(SIsM;dnRifwUQuTn z-_HmAp;m56ch!@cgw%fR_xyZGMKa6A&HGti`~9m}dI7oAR+!S)Y35sdx{05!H`IV& zkP=oSxK3ZUn#*j@4{$>@L61hx&?^55Tlo)qK<=kArF)EFy|1#W1MH9_~=j!q~i_os`bi7-lGsIhYhN4Y{z5#O{&j}$y$f~NuP|J+!*GgD!-Ur$?Wy_V7qJW+e~aa&A2hNYXnBm~ z@SQB+8LDL+NPntlI!WlBlA#aDL4Kl2O}xKzJnnnxC`R?`ZFnVkC`F}*%*9#sKPJ)G z+r{srC1n99n}ELG!qk;)@b<7_3Kw`bz{1Uqbp4_Dim#_EN#S! zQeS9O%j*V1x7ICwkX?Id<70TeY<%D+teH2f&}=5HouF1$ofLn?3w4L5sim2Xz9xNT ziuAwSoyr10cPx)amvF#;zs-T2{8N=C@@K`M!~+N^=U$$#$!0aFVBw%7(URlVY=F1F z3<%h~ojeA^VcTU*BF4eyYtk`wVg^<-;h1^}2QSDvi%3kDnmNl(p>suyN0m}9)8_!98(2CL=a&~EpzFuEUoN&low6at} zNw7k4M~;IkF?pN1nK!D$aIG&TPXsrG4+}dbyyVgjb4+_Y#Tiz1c*KVD(`iJQNX?zO zon_JF!z@d0`zuR2SR;IvjbwD)azOnLm)qhqw2_R}=VRd~pt*)236+l<3p-ib>Z(5`0K%FrB6L>v#eMk zZP^i?leT@-3UTZ}txGLaxvE9A;L9qIO$*awJ5#xb9P!H0Zh<-LDQ(r%vxVlxKWKn4 zT);mobi_!hzj%hn8bq&Z^qL9zKlmZ#ygg6Y>?t54Q7OlSS!S>0I^D#&(QyYgu5h4T zOe~@6OswM4jxF=C7qU__Zl#XB3=?~~U^LW<;E9i_a?BXB=a3B~9c%P)rc#|_V|!dm zjqX-wd|y4MTL11F=3`|#4vt>e*I!-rNcGr#L@b^5|38SFteJ{<{zwbPjGz;&8Bh8z OI_%p@xt7G9;`U$J+uo%B diff --git a/tests/trip/trip.fot b/tests/trip/trip.fot index 559aadf0b1..cb002cd306 100644 --- a/tests/trip/trip.fot +++ b/tests/trip/trip.fot @@ -31,22 +31,22 @@ l.442 ...l\tracingoutput1\global\escapechar256\end {end-group character }} > 3. {Āshowthe Ādeadcycles - Āglobal Āadvance Ācountz by1Āglobal Āg... + Āglobal Āadvance Ācountz by1Āglobal Āglobalde... Āend l.442 ...l\tracingoutput1\global\escapechar256\end ! You can't use `Āend' in internal vertical mode. Āend - - ...-1 Āgdef Ālocal {}Āunvbox 255Āend + + ...efs -1 Āgdef Ālocal {}Āunvbox 255Āend Ārb } Āend l.442 ...l\tracingoutput1\global\escapechar256\end ! Unbalanced output routine. - ...gdef Ālocal {}Āunvbox 255Āend Ārb + ...-1 Āgdef Ālocal {}Āunvbox 255Āend Ārb } Āend @@ -62,7 +62,7 @@ Completed box being shipped out [-1.2.-1118806.0.11.196608.327680.1572864.10737 41823] ! Unbalanced write command. Āif 01{Āelse unbal}Āfi - + }Āendwrite diff --git a/tests/trip/trip.log b/tests/trip/trip.log index 0f82ea6ba9..04788d6973 100644 --- a/tests/trip/trip.log +++ b/tests/trip/trip.log @@ -4009,14 +4009,18 @@ Completed box being shipped out [-2.2.-1118806.0.11.196608.327680.1572864.10737 ou can't use a prefix with `\unskip'. \unskip -l.345 \newlinechar`Y\global\unskip - \show^^Y\newlinechar\lastpenalty\unpenalty... +l.345 \newlinechar` +\global\unskip + \show^^ +\newlinechar\lastpenalty\unpenalty... I'll pretend you didn't say \long or \outer or \global or \protected. {\unskip} {\show} > the character ^^Y. -l.345 \newlinechar`Y\global\unskip\show^^Y +l.345 \newlinechar` +\global\unskip\show^^ + \newlinechar\lastpenalty\unpenalty... @@ -6230,7 +6234,7 @@ my insertion and my current dilemma will both disappear. {internal vertical mode: Āshowthe} > 3. {Āshowthe Ādeadcycles - Āglobal Āadvance Ācountz by1Āglobal Āg... + Āglobal Āadvance Ācountz by1Āglobal Āglobalde... Āend l.442 ...l\tracingoutput1\global\escapechar256\end @@ -6243,8 +6247,8 @@ l.442 ...l\tracingoutput1\global\escapechar256\end {Āend} ! You can't use `Āend' in internal vertical mode. Āend - - ...-1 Āgdef Ālocal {}Āunvbox 255Āend + + ...efs -1 Āgdef Ālocal {}Āunvbox 255Āend Ārb } Āend @@ -6257,7 +6261,7 @@ return to the right one by typing `I}' or `I$' or `I\par'. {end-group character }} ! Unbalanced output routine. - ...gdef Ālocal {}Āunvbox 255Āend Ārb + ...-1 Āgdef Ālocal {}Āunvbox 255Āend Ārb } Āend @@ -6295,7 +6299,7 @@ Completed box being shipped out [-1.2.-1118806.0.11.196608.327680.1572864.10737 ! Unbalanced write command. Āif 01{Āelse unbal}Āfi - + }Āendwrite From 01f282002989cd756f5eac650a7103a2d82aacda Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Sun, 25 Oct 2020 20:56:17 -0400 Subject: [PATCH 14/24] tectonic/xetex-XeTeXLayoutInterface.cpp: fix new Harfbuzz include --- tectonic/xetex-XeTeXLayoutInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tectonic/xetex-XeTeXLayoutInterface.cpp b/tectonic/xetex-XeTeXLayoutInterface.cpp index 58929214f0..19b8dd4d45 100644 --- a/tectonic/xetex-XeTeXLayoutInterface.cpp +++ b/tectonic/xetex-XeTeXLayoutInterface.cpp @@ -39,7 +39,7 @@ authorization from the copyright holders. #include #include -#include +#include #include #if !HB_VERSION_ATLEAST(2,5,0) #include From 40c432b9e92659b04c34e215ff852f2b2b678bdb Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Mon, 26 Oct 2020 18:56:29 -0400 Subject: [PATCH 15/24] xdvipdfmx: attempt to fix new segfault in Arxiv regression suite Looking at the diff in the update to TeXLive 2020.0, I think the upstream changes introduced some bugs. --- tectonic/dpx-dvipdfmx.c | 1 + tectonic/dpx-mpost.c | 21 +++++++++++++++++++-- tectonic/dpx-mpost.h | 2 ++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/tectonic/dpx-dvipdfmx.c b/tectonic/dpx-dvipdfmx.c index 786c0f40da..76ec78fc9d 100644 --- a/tectonic/dpx-dvipdfmx.c +++ b/tectonic/dpx-dvipdfmx.c @@ -419,6 +419,7 @@ dvipdfmx_main ( max_page_ranges = 0; dvi_reset_global_state(); + mps_reset_global_state(); tfm_reset_global_state(); vf_reset_global_state(); pdf_dev_reset_global_state(); diff --git a/tectonic/dpx-mpost.c b/tectonic/dpx-mpost.c index 024a0ecffb..00fece727a 100644 --- a/tectonic/dpx-mpost.c +++ b/tectonic/dpx-mpost.c @@ -161,7 +161,7 @@ save_font (void) next->font_id = current->font_id; next->pt_size = current->pt_size; next->subfont_id = current->subfont_id; - next->tfm_id = current->tfm_id; + next->tfm_id = current->tfm_id; } else { next->font_name = NULL; next->font_id = -1; @@ -181,7 +181,8 @@ restore_font (void) clear_mp_font_struct(current); } - currentfont--; + if (currentfont > 0) /* Tectonic safety fix */ + currentfont--; } static void @@ -191,6 +192,8 @@ clear_fonts (void) clear_mp_font_struct(&font_stack[currentfont]); currentfont--; } + + currentfont = 0; /* Tectonic fix */ } static bool @@ -1545,3 +1548,17 @@ mps_do_page (FILE *image_file) */ return (error ? -1 : 0); } + +void +mps_reset_global_state(void) /* Tectonic */ +{ + translate_origin = 0; + currentfont = 0; + font_stack[0].font_name = NULL; + font_stack[0].font_id = -1; + font_stack[0].tfm_id = -1; + font_stack[0].subfont_id = -1; + font_stack[0].pt_size = 0.0; + mp_cmode = MP_CMODE_MPOST; + top_stack = 0; +} diff --git a/tectonic/dpx-mpost.h b/tectonic/dpx-mpost.h index 605af62bd4..cac37c8a04 100644 --- a/tectonic/dpx-mpost.h +++ b/tectonic/dpx-mpost.h @@ -31,6 +31,8 @@ #include "dpx-pdfdev.h" #include "dpx-pdfximage.h" +void mps_reset_global_state(void); /* Tectonic */ + void mps_set_translate_origin (int boolean_value); int mps_scan_bbox (const char **pp, const char *endptr, pdf_rect *bbox); From e6e81ca0d67832778facb4daef03d0494c8a2a7a Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Mon, 26 Oct 2020 22:44:12 -0400 Subject: [PATCH 16/24] Wire in the \creationdate implementation and add a test --- tectonic/xetex-ini.c | 5 +-- tectonic/xetex-texmfmp.c | 14 ++++----- tectonic/xetex-xetexd.h | 4 +-- tests/tex-outputs.rs | 47 ++++++++++++++++------------- tests/tex-outputs/creationdate.log | 3 ++ tests/tex-outputs/creationdate.tex | 1 + tests/tex-outputs/creationdate.xdv | Bin 0 -> 228 bytes 7 files changed, 41 insertions(+), 33 deletions(-) create mode 100644 tests/tex-outputs/creationdate.log create mode 100644 tests/tex-outputs/creationdate.tex create mode 100644 tests/tex-outputs/creationdate.xdv diff --git a/tectonic/xetex-ini.c b/tectonic/xetex-ini.c index e610138dea..6b5b1f6e11 100644 --- a/tectonic/xetex-ini.c +++ b/tectonic/xetex-ini.c @@ -3214,8 +3214,6 @@ initialize_more_variables(void) for (k = 0; k <= 17; k++) write_open[k] = false; - get_seconds_and_micros(&epochseconds, µseconds); - init_start_time(); LR_ptr = TEX_NULL; LR_problems = 0; cur_dir = LEFT_TO_RIGHT; @@ -4120,6 +4118,9 @@ tt_run_engine(const char *dump_name, const char *input_file_name, time_t build_d initialize_pagebuilder_variables(); initialize_shipout_variables(); + get_seconds_and_micros(&epochseconds, µseconds); + init_start_time(build_date); + selector = SELECTOR_TERM_ONLY; tally = 0; term_offset = 0; diff --git a/tectonic/xetex-texmfmp.c b/tectonic/xetex-texmfmp.c index 6343d8cad9..66b4769bf3 100644 --- a/tectonic/xetex-texmfmp.c +++ b/tectonic/xetex-texmfmp.c @@ -15,7 +15,9 @@ static char *last_source_name = NULL; static int last_lineno; - +#define check_nprintf(size_get, size_want) \ + if ((unsigned)(size_get) >= (unsigned)(size_want)) \ + _tt_abort ("snprintf failed: file %s, line %d", __FILE__, __LINE__); #define TIME_STR_SIZE 30 static time_t start_time = 0; @@ -26,7 +28,6 @@ static char time_str[TIME_STR_SIZE]; static void makepdftime(time_t t, char *time_str, bool utc) { -#if 0 struct tm lt, gmt; size_t size; int i, off, off_hours, off_mins; @@ -75,23 +76,21 @@ makepdftime(time_t t, char *time_str, bool utc) i = snprintf(&time_str[size], 9, "%+03d'%02d'", off_hours, off_mins); check_nprintf(i, 9); } -#endif } void -init_start_time(void) +init_start_time(time_t source_date_epoch) { - /* set start_time */ + start_time = source_date_epoch; makepdftime (start_time, start_time_str, /* utc= */true); } void getcreationdate(void) { -#if 0 size_t len; int i; - init_start_time(); + /* init_start_time(); -- Tectonic: not needed*/ /* put creation date on top of string pool and update pool_ptr */ len = strlen(start_time_str); @@ -106,7 +105,6 @@ void getcreationdate(void) for (i = 0; i < len; i++) str_pool[pool_ptr++] = (uint16_t)start_time_str[i]; -#endif } diff --git a/tectonic/xetex-xetexd.h b/tectonic/xetex-xetexd.h index 40949eb1c8..941bef2237 100644 --- a/tectonic/xetex-xetexd.h +++ b/tectonic/xetex-xetexd.h @@ -349,8 +349,8 @@ typedef struct { void getmd5sum(int32_t s, bool file); -void init_start_time(void); -void get_date_and_time (time_t, int32_t *, int32_t *, int32_t *, int32_t *); +void init_start_time(time_t source_date_epoch); +void get_date_and_time (time_t source_date_epoch, int32_t *minutes, int32_t *day, int32_t *month, int32_t *year); void get_seconds_and_micros (int32_t *seconds, int32_t *micros); void getcreationdate(void); diff --git a/tests/tex-outputs.rs b/tests/tex-outputs.rs index 019bc01392..73090ac916 100644 --- a/tests/tex-outputs.rs +++ b/tests/tex-outputs.rs @@ -181,6 +181,32 @@ impl TestCase { // Keep these alphabetized. +#[test] +fn a4paper() { + let mut unstables = UnstableOptions::default(); + unstables.paper_size = Some(String::from("a4")); + TestCase::new("a4paper") + .with_unstables(unstables) + .check_pdf(true) + .go() +} + +#[test] +fn creationdate() { + TestCase::new("creationdate").go() +} + +#[test] +fn file_encoding() { + // Need to do this here since we call test_path unusually early. + util::set_test_root(); + + TestCase::new("file_encoding.tex") + .with_fs(&test_path(&["tex-outputs"])) + .expect(Ok(TexResult::Warnings)) + .go() +} + /// An issue triggered by a bug in how the I/O subsystem reported file offsets /// after an ungetc() call. #[test] @@ -239,17 +265,6 @@ fn unicode_file_name() { .go() } -#[test] -fn file_encoding() { - // Need to do this here since we call test_path unusually early. - util::set_test_root(); - - TestCase::new("file_encoding.tex") - .with_fs(&test_path(&["tex-outputs"])) - .expect(Ok(TexResult::Warnings)) - .go() -} - #[test] fn tectoniccodatokens_errinside() { TestCase::new("tectoniccodatokens_errinside") @@ -281,13 +296,3 @@ fn tectoniccodatokens_ok() { fn the_letter_a() { TestCase::new("the_letter_a").check_pdf(true).go() } - -#[test] -fn a4paper() { - let mut unstables = UnstableOptions::default(); - unstables.paper_size = Some(String::from("a4")); - TestCase::new("a4paper") - .with_unstables(unstables) - .check_pdf(true) - .go() -} diff --git a/tests/tex-outputs/creationdate.log b/tests/tex-outputs/creationdate.log new file mode 100644 index 0000000000..8ffc2b1969 --- /dev/null +++ b/tests/tex-outputs/creationdate.log @@ -0,0 +1,3 @@ +** +(creationdate.tex [1] ) +Output written on creationdate.xdv (1 page, 228 bytes). diff --git a/tests/tex-outputs/creationdate.tex b/tests/tex-outputs/creationdate.tex new file mode 100644 index 0000000000..a28dcbe344 --- /dev/null +++ b/tests/tex-outputs/creationdate.tex @@ -0,0 +1 @@ +\creationdate\bye diff --git a/tests/tex-outputs/creationdate.xdv b/tests/tex-outputs/creationdate.xdv new file mode 100644 index 0000000000000000000000000000000000000000..b63fb08aed360b72d51eaff17fe469e67b26285f GIT binary patch literal 228 zcmey)&e%NZfQ&T*5HP>sC`nB&$UH(!E*p?4C)i-g67eLX*bO2v^K$~4>f7UR`}?hH%}j988Q3DmKS{XQ4~ E0D Date: Mon, 26 Oct 2020 22:45:44 -0400 Subject: [PATCH 17/24] tests/tex-outputs.rs: try reenabling the_letter_a on Windows --- tests/tex-outputs.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/tex-outputs.rs b/tests/tex-outputs.rs index 73090ac916..8cdc21f114 100644 --- a/tests/tex-outputs.rs +++ b/tests/tex-outputs.rs @@ -284,14 +284,6 @@ fn tectoniccodatokens_ok() { TestCase::new("tectoniccodatokens_ok").go() } -// FIXME(#244): For reasons I absolutely cannot figure out, this test -// currently (2018 Oct) fails on AppVeyor's CI, while it works on both GNU and -// MSVC Windows toolchains when I (PKGW) run it manually. (The failure is that -// the observed PDF doesn't match the expected one.) Seeing as everything else -// seems to work and this test doesn't cover anything that special compared to -// the other tests in this file, just skip it on Windows so that we can keep -// on CI'ing. -#[cfg(not(target_os = "windows"))] #[test] fn the_letter_a() { TestCase::new("the_letter_a").check_pdf(true).go() From 3f43d5643916f87a42d908ae4c25ccc7197d4370 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Mon, 26 Oct 2020 23:46:23 -0400 Subject: [PATCH 18/24] tectonic/xetex-texmfmp.c: work on \filesize and \filedump The only one that needs implementing is \filemoddate, although these need actual testing as well. --- tectonic/xetex-texmfmp.c | 215 +++++++++++++++++---------------------- 1 file changed, 96 insertions(+), 119 deletions(-) diff --git a/tectonic/xetex-texmfmp.c b/tectonic/xetex-texmfmp.c index 66b4769bf3..7522a75a37 100644 --- a/tectonic/xetex-texmfmp.c +++ b/tectonic/xetex-texmfmp.c @@ -22,7 +22,7 @@ static int last_lineno; #define TIME_STR_SIZE 30 static time_t start_time = 0; char start_time_str[TIME_STR_SIZE]; -static char time_str[TIME_STR_SIZE]; +static char filemod_time_str[TIME_STR_SIZE]; /* minimum size for time_str is 24: "D:YYYYmmddHHMMSS+HH'MM'" */ static void @@ -85,7 +85,8 @@ init_start_time(time_t source_date_epoch) makepdftime (start_time, start_time_str, /* utc= */true); } -void getcreationdate(void) +void +getcreationdate(void) { size_t len; int i; @@ -120,6 +121,7 @@ get_date_and_time (time_t source_date_epoch, *year = tmptr->tm_year + 1900; } + void get_seconds_and_micros (int32_t *seconds, int32_t *micros) { @@ -130,143 +132,118 @@ get_seconds_and_micros (int32_t *seconds, int32_t *micros) } -void getfilemoddate(int32_t s) +/* Given a file name stored in the string pool, insert into the string pool text + * giving its modification date in PDF-style format. */ +void +getfilemoddate(str_number s) { #if 0 - struct stat file_data; + char *xname; + time_t mtime = 0; + size_t len; - char *file_name = find_input_file(s); - if (file_name == NULL) { - return; /* empty string */ - } - if (! kpse_in_name_ok(file_name)) { - return; /* no permission */ - } + xname = gettexstring(s); - recorder_record_input(file_name); - /* get file status */ -#ifdef _WIN32 - if (fsyscp_stat(file_name, &file_data) == 0) { -#else - if (stat(file_name, &file_data) == 0) { -#endif - size_t len; - bool use_utc = FORCE_SOURCE_DATE_set && SOURCE_DATE_EPOCH_set; - makepdftime(file_data.st_mtime, time_str, use_utc); - len = strlen(time_str); - if ((unsigned) (pool_ptr + len) >= (unsigned) (pool_size)) { - pool_ptr = pool_size; - /* error by str_toks that calls str_room(1) */ - } else { - int i; - - for (i = 0; i < len; i++) - str_pool[pool_ptr++] = (uint16_t)time_str[i]; - } - } - /* else { errno contains error code } */ + /* .... get mtime ... */ + + free(file_name); + makepdftime(mtime, filemod_time_str, use_utc); + len = strlen(time_str); - xfree(file_name); + if ((unsigned) (pool_ptr + len) >= (unsigned) pool_size) { + pool_ptr = pool_size; + /* error by str_toks that calls str_room(1) */ + } else { + int i; + + for (i = 0; i < len; i++) + str_pool[pool_ptr++] = (uint16_t) time_str[i]; + } #endif } -void getfilesize(int32_t s) +/* Given a file name stored in the string pool, insert into the string pool text + * giving its size in bytes. */ +void +getfilesize(str_number s) { -#if 0 - struct stat file_data; - int i; + char *name; + size_t file_len, text_len; + rust_input_handle_t handle; + char buf[20]; + int i; - char *file_name = find_input_file(s); - if (file_name == NULL) { - return; /* empty string */ - } - if (! kpse_in_name_ok(file_name)) { - return; /* no permission */ - } + name = gettexstring(s); + handle = ttstub_input_open(name, TTIF_TEX, 0); + free(name); - recorder_record_input(file_name); - /* get file status */ -#ifdef _WIN32 - if (fsyscp_stat(file_name, &file_data) == 0) { -#else - if (stat(file_name, &file_data) == 0) { -#endif - size_t len; - char buf[20]; - - /* st_size has type off_t */ - i = snprintf(buf, sizeof(buf), - "%lu", (long unsigned int) file_data.st_size); - check_nprintf(i, sizeof(buf)); - len = strlen(buf); - if ((unsigned) (pool_ptr + len) >= (unsigned) (pool_size)) { - pool_ptr = pool_size; - /* error by str_toks that calls str_room(1) */ - } else { - for (i = 0; i < len; i++) - str_pool[pool_ptr++] = (uint16_t)buf[i]; - } - } - /* else { errno contains error code } */ + if (handle == NULL) + return; /* => evaluate to the empty string; intentional */ - xfree(file_name); -#endif + file_len = ttstub_input_get_size(handle); + ttstub_input_close(handle); + + i = snprintf(buf, sizeof(buf), "%lu", (long unsigned int) file_len); + check_nprintf(i, sizeof(buf)); + text_len = strlen(buf); + + if ((unsigned) (pool_ptr + text_len) >= (unsigned) pool_size) { + pool_ptr = pool_size; + /* error by str_toks that calls str_room(1) */ + } else { + int i; + + for (i = 0; i < text_len; i++) + str_pool[pool_ptr++] = (uint16_t) buf[i]; + } } void getfiledump(int32_t s, int offset, int length) { -#if 0 - FILE *f; - int read, i; - unsigned char *readbuffer; - char strbuf[3]; - int j, k; - char *file_name; - - if (length == 0) { - /* empty result string */ - return; - } + char *name; + size_t text_len; + rust_input_handle_t handle; + unsigned char *buffer; + int i, j, k; + ssize_t actual; + char strbuf[3]; + + if (length == 0) + return; /* => evaluate to the empty string; intentional */ + + if (pool_ptr + 2 * length + 1 >= pool_size) { + /* not enough room to hold the result; trigger an error back in TeX: */ + pool_ptr = pool_size; + return; + } - if (pool_ptr + 2 * length + 1 >= pool_size) { - /* no place for result */ - pool_ptr = pool_size; - /* error by str_toks that calls str_room(1) */ - return; - } + buffer = (unsigned char *) xmalloc(length + 1); + if (buffer == NULL) { + pool_ptr = pool_size; + return; + } - file_name = find_input_file(s); - if (file_name == NULL) { - return; /* empty string */ - } - if (! kpse_in_name_ok(file_name)) { - return; /* no permission */ - } + name = gettexstring(s); + handle = ttstub_input_open(name, TTIF_TEX, 0); + free(name); - /* read file data */ - f = fopen(file_name, FOPEN_RBIN_MODE); - if (f == NULL) { - xfree(file_name); - return; - } - recorder_record_input(file_name); - if (fseek(f, offset, SEEK_SET) != 0) { - xfree(file_name); - return; - } + if (handle == NULL) { + free(buffer); + return; /* => evaluate to the empty string; intentional */ + } - readbuffer = (unsigned char *)xmalloc (length + 1); - read = fread(readbuffer, sizeof(char), length, f); - fclose(f); - for (j = 0; j < read; j++) { - i = snprintf (strbuf, 3, "%.2X", (unsigned int)readbuffer[j]); - check_nprintf(i, 3); - for (k = 0; k < i; k++) - str_pool[pool_ptr++] = (uint16_t)strbuf[k]; - } - xfree (readbuffer); - xfree(file_name); -#endif + ttstub_input_seek(handle, offset, SEEK_SET); + actual = ttstub_input_read(handle, (char *) buffer, length); + ttstub_input_close(handle); + + for (j = 0; j < actual; j++) { + i = snprintf(strbuf, 3, "%.2X", (unsigned int) buffer[j]); + check_nprintf(i, 3); + for (k = 0; k < i; k++) + str_pool[pool_ptr++] = (uint16_t) strbuf[k]; + } + + free(buffer); } From a0fdaa189bc4152eb779b6874d659969dc42dffc Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Tue, 27 Oct 2020 09:22:03 -0400 Subject: [PATCH 19/24] tests: add some basic tests for \filedump and \filesize --- tests/tex-outputs.rs | 20 +++++++++++++----- tests/tex-outputs/creationdate.log | 3 --- tests/tex-outputs/prim_creationdate.log | 3 +++ ...creationdate.tex => prim_creationdate.tex} | 0 ...creationdate.xdv => prim_creationdate.xdv} | Bin tests/tex-outputs/prim_filedump.log | 3 +++ tests/tex-outputs/prim_filedump.tex | 4 ++++ tests/tex-outputs/prim_filedump.xdv | Bin 0 -> 212 bytes tests/tex-outputs/prim_filesize.log | 3 +++ tests/tex-outputs/prim_filesize.tex | 1 + tests/tex-outputs/prim_filesize.xdv | Bin 0 -> 212 bytes 11 files changed, 29 insertions(+), 8 deletions(-) delete mode 100644 tests/tex-outputs/creationdate.log create mode 100644 tests/tex-outputs/prim_creationdate.log rename tests/tex-outputs/{creationdate.tex => prim_creationdate.tex} (100%) rename tests/tex-outputs/{creationdate.xdv => prim_creationdate.xdv} (100%) create mode 100644 tests/tex-outputs/prim_filedump.log create mode 100644 tests/tex-outputs/prim_filedump.tex create mode 100644 tests/tex-outputs/prim_filedump.xdv create mode 100644 tests/tex-outputs/prim_filesize.log create mode 100644 tests/tex-outputs/prim_filesize.tex create mode 100644 tests/tex-outputs/prim_filesize.xdv diff --git a/tests/tex-outputs.rs b/tests/tex-outputs.rs index 8cdc21f114..5bbf0ffc90 100644 --- a/tests/tex-outputs.rs +++ b/tests/tex-outputs.rs @@ -191,11 +191,6 @@ fn a4paper() { .go() } -#[test] -fn creationdate() { - TestCase::new("creationdate").go() -} - #[test] fn file_encoding() { // Need to do this here since we call test_path unusually early. @@ -233,6 +228,21 @@ fn otf_basic() { .go() } +#[test] +fn prim_creationdate() { + TestCase::new("prim_creationdate").go() +} + +#[test] +fn prim_filedump() { + TestCase::new("prim_filedump").go() +} + +#[test] +fn prim_filesize() { + TestCase::new("prim_filesize").go() +} + #[test] fn tex_logo() { TestCase::new("tex_logo").go() diff --git a/tests/tex-outputs/creationdate.log b/tests/tex-outputs/creationdate.log deleted file mode 100644 index 8ffc2b1969..0000000000 --- a/tests/tex-outputs/creationdate.log +++ /dev/null @@ -1,3 +0,0 @@ -** -(creationdate.tex [1] ) -Output written on creationdate.xdv (1 page, 228 bytes). diff --git a/tests/tex-outputs/prim_creationdate.log b/tests/tex-outputs/prim_creationdate.log new file mode 100644 index 0000000000..ee4abe476e --- /dev/null +++ b/tests/tex-outputs/prim_creationdate.log @@ -0,0 +1,3 @@ +** +(prim_creationdate.tex [1] ) +Output written on prim_creationdate.xdv (1 page, 228 bytes). diff --git a/tests/tex-outputs/creationdate.tex b/tests/tex-outputs/prim_creationdate.tex similarity index 100% rename from tests/tex-outputs/creationdate.tex rename to tests/tex-outputs/prim_creationdate.tex diff --git a/tests/tex-outputs/creationdate.xdv b/tests/tex-outputs/prim_creationdate.xdv similarity index 100% rename from tests/tex-outputs/creationdate.xdv rename to tests/tex-outputs/prim_creationdate.xdv diff --git a/tests/tex-outputs/prim_filedump.log b/tests/tex-outputs/prim_filedump.log new file mode 100644 index 0000000000..77eacd1cd2 --- /dev/null +++ b/tests/tex-outputs/prim_filedump.log @@ -0,0 +1,3 @@ +** +(prim_filedump.tex [1] ) +Output written on prim_filedump.xdv (1 page, 212 bytes). diff --git a/tests/tex-outputs/prim_filedump.tex b/tests/tex-outputs/prim_filedump.tex new file mode 100644 index 0000000000..bbc056a255 --- /dev/null +++ b/tests/tex-outputs/prim_filedump.tex @@ -0,0 +1,4 @@ +% 0123456789abcdefghijklmnopqrstuvwxyz long first line to avoid caring what EOL is +X\filedump offset 2 length 10 {prim_filedump.tex}% +Y\filedump offset 9999 length 0 {nosuchfile.tex}% +Z\bye diff --git a/tests/tex-outputs/prim_filedump.xdv b/tests/tex-outputs/prim_filedump.xdv new file mode 100644 index 0000000000000000000000000000000000000000..bc7a17bce2051abe33e2fef27d6ba9e88e5dba3b GIT binary patch literal 212 zcmey)&e%NZfQ&T*5HP>sC`nB&$b>8nr(cG@#;Z$1||kZtcLsq>X^ZP9|!<1t~{~; literal 0 HcmV?d00001 diff --git a/tests/tex-outputs/prim_filesize.log b/tests/tex-outputs/prim_filesize.log new file mode 100644 index 0000000000..5523196f02 --- /dev/null +++ b/tests/tex-outputs/prim_filesize.log @@ -0,0 +1,3 @@ +** +(prim_filesize.tex [1] ) +Output written on prim_filesize.xdv (1 page, 212 bytes). diff --git a/tests/tex-outputs/prim_filesize.tex b/tests/tex-outputs/prim_filesize.tex new file mode 100644 index 0000000000..86b1038a39 --- /dev/null +++ b/tests/tex-outputs/prim_filesize.tex @@ -0,0 +1 @@ +X\filesize{nosuchfile}Y\filesize{prim_filesize.tex}Z\bye%no-EOL-newline-to-keep-size-same-on-Windows \ No newline at end of file diff --git a/tests/tex-outputs/prim_filesize.xdv b/tests/tex-outputs/prim_filesize.xdv new file mode 100644 index 0000000000000000000000000000000000000000..bc7a17bce2051abe33e2fef27d6ba9e88e5dba3b GIT binary patch literal 212 zcmey)&e%NZfQ&T*5HP>sC`nB&$b>8nr(cG@#;Z$1||kZtcLsq>X^ZP9|!<1t~{~; literal 0 HcmV?d00001 From e3d00e071bfee9020291fb9d7d1ca38e05a50b92 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Tue, 27 Oct 2020 15:19:31 -0400 Subject: [PATCH 20/24] Implement the new \filemoddate primitive This requires us to add a new feature to the I/O API and so involves touching a lot of code. In particular, I think that it is probably important for the memory I/O layer to produce meaningful-ish mtimes, which adds some complexity there. The `InputFeatures` trait has added a new method, `get_unix_mtime`, to support this primitive. It has a default implementation to return `Ok(None)`, which indicates that the input does not have a well-defined modification time. **BREAKING CHANGE** In order to implement file modtimes for the memory I/O provider, we need to add more data to its data structures, breaking the APIs for users of its `files` field. This is a very clear signal that this API should be cleaned up and made more future-prof. That being said, migration should be pretty easy: instead of `files` containing a bunch of `Vec`s, it now contains a bunch of `MemoryFileInfo` structs that contain a `Vec` field named `data`. So you just need to add some `.data` field accessors to existing code. --- src/bin/tectonic.rs | 2 +- src/driver.rs | 43 ++++++++++------- src/engines/mod.rs | 25 ++++++++++ src/errors.rs | 1 + src/io/filesystem.rs | 15 ++++++ src/io/memory.rs | 103 ++++++++++++++++++++++++++++++++--------- src/io/mod.rs | 22 +++++++++ src/io/stdstreams.rs | 4 ++ src/lib.rs | 2 +- tectonic/core-bridge.c | 6 +++ tectonic/core-bridge.h | 5 +- tests/trip.rs | 4 +- tests/util/mod.rs | 41 +++++++++------- 13 files changed, 210 insertions(+), 63 deletions(-) diff --git a/src/bin/tectonic.rs b/src/bin/tectonic.rs index 9277642647..7d5901141c 100644 --- a/src/bin/tectonic.rs +++ b/src/bin/tectonic.rs @@ -195,7 +195,7 @@ fn inner(args: CliOptions, config: PersistentConfig, status: &mut dyn StatusBack engine ); - status.dump_error_logs(&output); + status.dump_error_logs(&output.data); } } } diff --git a/src/driver.rs b/src/driver.rs index 4e7c45598e..385cb819e7 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -18,18 +18,25 @@ use std::fs::File; use std::io::Write; use std::path::{Path, PathBuf}; use std::rc::Rc; +use std::result::Result as StdResult; use std::str::FromStr; use std::time::SystemTime; -use crate::digest::DigestData; -use crate::engines::IoEventBackend; -use crate::errors::{ErrorKind, Result, ResultExt}; -use crate::io::{Bundle, InputOrigin, IoProvider, IoSetup, IoSetupBuilder, OpenResult}; -use crate::status::StatusBackend; -use crate::unstable_opts::UnstableOptions; -use crate::{ctry, errmsg, tt_error, tt_note, tt_warning}; -use crate::{BibtexEngine, Spx2HtmlEngine, TexEngine, TexResult, XdvipdfmxEngine}; -use std::result::Result as StdResult; +use crate::{ + ctry, + digest::DigestData, + engines::IoEventBackend, + errmsg, + errors::{ErrorKind, Result, ResultExt}, + io::{ + memory::MemoryFileCollection, Bundle, InputOrigin, IoProvider, IoSetup, IoSetupBuilder, + OpenResult, + }, + status::StatusBackend, + tt_error, tt_note, tt_warning, + unstable_opts::UnstableOptions, + BibtexEngine, Spx2HtmlEngine, TexEngine, TexResult, XdvipdfmxEngine, +}; /// Different patterns with which files may have been accessed by the /// underlying engines. Once a file is marked as ReadThenWritten or @@ -845,7 +852,7 @@ impl ProcessingSession { let mut n_skipped_intermediates = 0; - for (name, contents) in &*self.io.mem.files.borrow() { + for (name, file) in &*self.io.mem.files.borrow() { if name == self.io.mem.stdout_key() { continue; } @@ -882,7 +889,7 @@ impl ProcessingSession { continue; } - if contents.is_empty() { + if file.data.is_empty() { status.note_highlighted( "Not writing ", &format!("`{}`", sname), @@ -892,7 +899,7 @@ impl ProcessingSession { } let real_path = root.join(name); - let byte_len = Byte::from_bytes(contents.len() as u128); + let byte_len = Byte::from_bytes(file.data.len() as u128); status.note_highlighted( "Writing ", &format!("`{}`", real_path.to_string_lossy()), @@ -900,7 +907,7 @@ impl ProcessingSession { ); let mut f = File::create(&real_path)?; - f.write_all(contents)?; + f.write_all(&file.data)?; summ.got_written_to_disk = true; if let Some(ref mut mf_dest) = mf_dest_maybe { @@ -1009,10 +1016,10 @@ impl ProcessingSession { .files .borrow() .get(&self.tex_aux_path) - .map(|data| { + .map(|file| { // We used to use aho-corasick crate here, but it was removed to reduce the code // size. - data.windows(BIBDATA.len()).any(|s| s == BIBDATA) + file.data.windows(BIBDATA.len()).any(|s| s == BIBDATA) }) .unwrap_or(false) } @@ -1081,7 +1088,7 @@ impl ProcessingSession { let format_cache = &mut *self.io.format_cache.as_mut().unwrap(); - for (name, contents) in &*self.io.mem.files.borrow() { + for (name, file) in &*self.io.mem.files.borrow() { if name == self.io.mem.stdout_key() { continue; } @@ -1093,7 +1100,7 @@ impl ProcessingSession { } // Note that we intentionally pass 'stem', not 'name'. - ctry!(format_cache.write_format(stem, contents, status); "cannot write format file {}", sname); + ctry!(format_cache.write_format(stem, &file.data, status); "cannot write format file {}", sname); } // All done. Clear the memory layer since this was a special preparatory step. @@ -1229,7 +1236,7 @@ impl ProcessingSession { /// This will panic if you there are multiple strong references to the /// `files` map. This should only happen if you create and keep a clone of /// the `Rc<>` wrapping it before calling this function. - pub fn into_file_data(self) -> HashMap> { + pub fn into_file_data(self) -> MemoryFileCollection { Rc::try_unwrap(self.io.mem.files) .expect("multiple strong refs to MemoryIo files") .into_inner() diff --git a/src/engines/mod.rs b/src/engines/mod.rs index 842b1c1b26..260192b35d 100644 --- a/src/engines/mod.rs +++ b/src/engines/mod.rs @@ -418,6 +418,23 @@ impl<'a> ExecutionState<'a> { } } + fn input_get_mtime(&mut self, handle: *mut InputHandle) -> libc::time_t { + let rhandle: &mut InputHandle = unsafe { &mut *handle }; + let maybe_time = match rhandle.get_unix_mtime() { + Ok(t) => t, + Err(e) => { + tt_warning!(self.status, "failed to get the modification time of an input"; e); + Some(0) + } + }; + + if let Some(t) = maybe_time { + t as libc::time_t + } else { + 1 // Intentionally make this distinguishable from the error value 0 + } + } + fn input_seek(&mut self, handle: *mut InputHandle, pos: SeekFrom) -> Result { let rhandle: &mut InputHandle = unsafe { &mut *handle }; rhandle.try_seek(pos) @@ -697,6 +714,14 @@ pub extern "C" fn input_get_size( es.input_get_size(handle) } +#[no_mangle] +pub extern "C" fn input_get_mtime( + es: &mut ExecutionState, + handle: *mut InputHandle, +) -> libc::time_t { + es.input_get_mtime(handle) +} + #[no_mangle] pub extern "C" fn input_seek( es: &mut ExecutionState, diff --git a/src/errors.rs b/src/errors.rs index 028913a97b..2431a679b4 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -63,6 +63,7 @@ error_chain! { Reqwest(reqwest::Error); ConfigRead(ReadError); ConfigWrite(WriteError); + Time(std::time::SystemTimeError); Utf8(str::Utf8Error); Xdv(tectonic_xdv::XdvError); Zip(ZipError); diff --git a/src/io/filesystem.rs b/src/io/filesystem.rs index 4aadc58807..2b3210b36a 100644 --- a/src/io/filesystem.rs +++ b/src/io/filesystem.rs @@ -161,6 +161,15 @@ impl InputFeatures for File { Ok(self.metadata()?.len() as usize) } + fn get_unix_mtime(&mut self) -> Result> { + let sys_time = self.metadata()?.modified()?; + + // No cleaner way to convert a SystemTime to time_t, as far as I can + // tell. + let dur = sys_time.duration_since(std::time::SystemTime::UNIX_EPOCH)?; + Ok(Some(dur.as_secs() as i64)) + } + fn try_seek(&mut self, pos: SeekFrom) -> Result { Ok(self.seek(pos)?) } @@ -171,6 +180,12 @@ impl InputFeatures for BufReader { Ok(self.get_mut().metadata()?.len() as usize) } + fn get_unix_mtime(&mut self) -> Result> { + let sys_time = self.get_mut().metadata()?.modified()?; + let dur = sys_time.duration_since(std::time::SystemTime::UNIX_EPOCH)?; + Ok(Some(dur.as_secs() as i64)) + } + fn try_seek(&mut self, pos: SeekFrom) -> Result { Ok(self.seek(pos)?) } diff --git a/src/io/memory.rs b/src/io/memory.rs index 8032dfaf79..f829d6bd4b 100644 --- a/src/io/memory.rs +++ b/src/io/memory.rs @@ -1,12 +1,17 @@ // src/io/memory.rs -- I/O to in-memory buffers -// Copyright 2016-2017 the Tectonic Project +// Copyright 2016-2020 the Tectonic Project // Licensed under the MIT License. -use std::cell::RefCell; -use std::collections::HashMap; -use std::ffi::{OsStr, OsString}; -use std::io::{self, Cursor, Read, Seek, SeekFrom, Write}; -use std::rc::Rc; +//! MemoryIo is an IoProvider that stores "files" in in-memory buffers. + +use std::{ + cell::RefCell, + collections::HashMap, + ffi::{OsStr, OsString}, + io::{self, Cursor, Read, Seek, SeekFrom, Write}, + rc::Rc, + time::SystemTime, +}; use super::{ normalize_tex_path, InputFeatures, InputHandle, InputOrigin, IoProvider, OpenResult, @@ -15,41 +20,70 @@ use super::{ use crate::errors::Result; use crate::status::StatusBackend; -// MemoryIo is an IoProvider that stores "files" in in-memory buffers. -// -// When a file is "opened", we create a MemoryIoItem struct that tracks the -// data, seek cursor state, etc. - -struct MemoryIoItem { +/// Information about a file created or used inside the memory-backed I/O +/// provider. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct MemoryFileInfo { // TODO: smarter buffering structure than Vec? E.g., linked list of 4k // chunks or something. In the current scheme reallocations will get // expensive. - files: Rc>>>, + pub data: Vec, + pub unix_mtime: Option, +} + +/// A collection of files created or used inside a memory-backed I/O provider. +pub type MemoryFileCollection = HashMap; + +/// When a file is "opened", we create a MemoryIoItem struct that tracks the +/// data, seek cursor state, etc. +struct MemoryIoItem { + // This is the best way I can come up with to allow the file object to + // update its data in its parent data structure. + files: Rc>, + name: OsString, state: Cursor>, + unix_mtime: Option, + was_modified: bool, +} + +/// Get the current time as a Unix time, in a manner consistent with our Unix +/// file modification time API. We choose to make this function infallible +/// rather than injecting a bunch of Results. +fn now_as_unix_time() -> Option { + // No cleaner way to convert a SystemTime to time_t, as far as I can + // tell. + let now = SystemTime::now(); + let dur = match now.duration_since(SystemTime::UNIX_EPOCH) { + Ok(d) => d, + Err(_) => return Some(0), // indicates error to C code, if it cres + }; + Some(dur.as_secs() as i64) } impl MemoryIoItem { pub fn new( - files: &Rc>>>, + files: &Rc>, name: &OsStr, truncate: bool, ) -> MemoryIoItem { - let cur = match files.borrow_mut().remove(name) { - Some(data) => { + let (cur_data, cur_mtime) = match files.borrow_mut().remove(name) { + Some(info) => { if truncate { - Vec::new() + (Vec::new(), now_as_unix_time()) } else { - data + (info.data, info.unix_mtime) } } - None => Vec::new(), + None => (Vec::new(), now_as_unix_time()), }; MemoryIoItem { files: files.clone(), name: name.to_os_string(), - state: Cursor::new(cur), + state: Cursor::new(cur_data), + unix_mtime: cur_mtime, + was_modified: false, } } } @@ -62,6 +96,7 @@ impl Read for MemoryIoItem { impl Write for MemoryIoItem { fn write(&mut self, buf: &[u8]) -> io::Result { + self.was_modified = true; self.state.write(buf) } @@ -81,6 +116,10 @@ impl InputFeatures for MemoryIoItem { Ok(self.state.get_ref().len()) } + fn get_unix_mtime(&mut self) -> Result> { + Ok(self.unix_mtime) + } + fn try_seek(&mut self, pos: SeekFrom) -> Result { Ok(self.state.seek(pos)?) } @@ -88,16 +127,28 @@ impl InputFeatures for MemoryIoItem { impl Drop for MemoryIoItem { fn drop(&mut self) { + let unix_mtime = if self.was_modified { + now_as_unix_time() + } else { + self.unix_mtime + }; + // I think split_off() is an efficient way to move our data vector // back into the hashmap? Ideally we could "consume" self but I don't // believe that's possible in a Drop implementation. let mut mfiles = self.files.borrow_mut(); - mfiles.insert(self.name.clone(), self.state.get_mut().split_off(0)); + mfiles.insert( + self.name.clone(), + MemoryFileInfo { + data: self.state.get_mut().split_off(0), + unix_mtime, + }, + ); } } pub struct MemoryIo { - pub files: Rc>>>, + pub files: Rc>, stdout_allowed: bool, } @@ -111,7 +162,13 @@ impl MemoryIo { pub fn create_entry(&mut self, name: &OsStr, data: Vec) { let mut mfiles = self.files.borrow_mut(); - mfiles.insert(name.to_os_string(), data); + mfiles.insert( + name.to_os_string(), + MemoryFileInfo { + data, + unix_mtime: now_as_unix_time(), + }, + ); } pub fn stdout_key(&self) -> &OsStr { diff --git a/src/io/mod.rs b/src/io/mod.rs index c740125d87..0ca62795aa 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -30,6 +30,13 @@ pub mod zipbundle; pub trait InputFeatures: Read { fn get_size(&mut self) -> Result; fn try_seek(&mut self, pos: SeekFrom) -> Result; + + /// Get the modification time of this file as a Unix time. If that quantity + /// is not meaningfully defined for this input, return `Ok(None)`. This is + /// what the default implementation does. + fn get_unix_mtime(&mut self) -> Result> { + Ok(None) + } } /// What kind of source an input file ultimately came from. We keep track of @@ -207,6 +214,10 @@ impl InputFeatures for InputHandle { self.inner.get_size() } + fn get_unix_mtime(&mut self) -> Result> { + self.inner.get_unix_mtime() + } + fn try_seek(&mut self, pos: SeekFrom) -> Result { match pos { SeekFrom::Start(0) => { @@ -494,6 +505,13 @@ impl InputFeatures for GzDecoder { Err(ErrorKind::NotSizeable.into()) } + fn get_unix_mtime(&mut self) -> Result> { + // In principle we could arrange to potentially get an mtime from the + // underlying stream, but this API is only used for the \filemodtime + // primitive which shouldn't be getting access to gzipped streams. + Ok(None) + } + fn try_seek(&mut self, _: SeekFrom) -> Result { Err(ErrorKind::NotSeekable.into()) } @@ -504,6 +522,10 @@ impl InputFeatures for Cursor> { Ok(self.get_ref().len()) } + fn get_unix_mtime(&mut self) -> Result> { + Ok(None) + } + fn try_seek(&mut self, pos: SeekFrom) -> Result { Ok(self.seek(pos)?) } diff --git a/src/io/stdstreams.rs b/src/io/stdstreams.rs index acc6df404f..0629cb029e 100644 --- a/src/io/stdstreams.rs +++ b/src/io/stdstreams.rs @@ -52,6 +52,10 @@ impl InputFeatures for Cursor { Ok(self.get_ref().0.len()) } + fn get_unix_mtime(&mut self) -> Result> { + Ok(None) + } + fn try_seek(&mut self, pos: SeekFrom) -> Result { Ok(self.seek(pos)?) } diff --git a/src/lib.rs b/src/lib.rs index 9abae36d64..3ee6bb91d2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -149,7 +149,7 @@ pub fn latex_to_pdf>(latex: T) -> Result> { }; match files.remove(OsStr::new("texput.pdf")) { - Some(data) => Ok(data), + Some(file) => Ok(file.data), None => Err(errmsg!( "LaTeX didn't report failure, but no PDF was created (??)" )), diff --git a/tectonic/core-bridge.c b/tectonic/core-bridge.c index a170fb9e0d..c0c795124d 100644 --- a/tectonic/core-bridge.c +++ b/tectonic/core-bridge.c @@ -264,6 +264,12 @@ ttstub_input_get_size(rust_input_handle_t handle) return input_get_size(TGB->context, handle); } +time_t +ttstub_input_get_mtime (rust_input_handle_t handle) +{ + return input_get_mtime(TGB->context, handle); +} + size_t ttstub_input_seek(rust_input_handle_t handle, ssize_t offset, int whence) { diff --git a/tectonic/core-bridge.h b/tectonic/core-bridge.h index 0f50f7d311..9947e0df09 100644 --- a/tectonic/core-bridge.h +++ b/tectonic/core-bridge.h @@ -1,5 +1,5 @@ /* tectonic/core-bridge.h: declarations of C/C++ => Rust bridge API - Copyright 2016-2018 the Tectonic Project + Copyright 2016-2020 the Tectonic Project Licensed under the MIT License. */ @@ -9,6 +9,8 @@ #include "core-foundation.h" #include "core-bindgen.h" +#include /* time_t */ + /* Both XeTeX and bibtex use this enum: */ typedef enum { @@ -97,6 +99,7 @@ int ttstub_output_close (rust_output_handle_t handle); rust_input_handle_t ttstub_input_open (char const *path, tt_input_format_type format, int is_gz); rust_input_handle_t ttstub_input_open_primary (void); size_t ttstub_input_get_size (rust_input_handle_t handle); +time_t ttstub_input_get_mtime (rust_input_handle_t handle); size_t ttstub_input_seek (rust_input_handle_t handle, ssize_t offset, int whence); ssize_t ttstub_input_read (rust_input_handle_t handle, char *data, size_t len); int ttstub_input_getc (rust_input_handle_t handle); diff --git a/tests/trip.rs b/tests/trip.rs index dff4123d06..9af57e6b9b 100644 --- a/tests/trip.rs +++ b/tests/trip.rs @@ -90,7 +90,7 @@ fn trip_test() { expected_log.test_from_collection(files); expected_xdv.test_from_collection(files); expected_os.test_from_collection(files); - expected_fot.test_data(files.get(OsStr::new("")).unwrap()); + expected_fot.test_data(&files.get(OsStr::new("")).unwrap().data); } #[test] @@ -157,5 +157,5 @@ fn etrip_test() { expected_log.test_from_collection(files); expected_xdv.test_from_collection(files); expected_out.test_from_collection(files); - expected_fot.test_data(files.get(OsStr::new("")).unwrap()); + expected_fot.test_data(&files.get(OsStr::new("")).unwrap().data); } diff --git a/tests/util/mod.rs b/tests/util/mod.rs index b737bf07de..9518756c19 100644 --- a/tests/util/mod.rs +++ b/tests/util/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018 the Tectonic Project +// Copyright 2018-2020 the Tectonic Project // Licensed under the MIT License. //! Note: we need to store this code as `tests/util/mod.rs` rather than @@ -10,18 +10,19 @@ // using this testing setup... #![allow(dead_code)] +use flate2::read::GzDecoder; +use std::{ + collections::HashSet, + default::Default, + env, + ffi::{OsStr, OsString}, + fs::File, + io::{Read, Write}, + path::{Path, PathBuf}, +}; -use ::flate2::read::GzDecoder; -use std::collections::{HashMap, HashSet}; -use std::default::Default; -use std::env; -use std::ffi::{OsStr, OsString}; -use std::fs::File; -use std::io::{Read, Write}; -use std::path::{Path, PathBuf}; - -use ::tectonic::errors::Result; -pub use ::tectonic::test_util::{test_path, TestBundle}; +pub use tectonic::test_util::{test_path, TestBundle}; +use tectonic::{errors::Result, io::memory::MemoryFileCollection}; /// Set the magic environment variable that enables the testing infrastructure /// embedded in the main Tectonic crate. This function is separated out from @@ -94,7 +95,13 @@ pub fn ensure_plain_format() -> Result { .prefix("plain_fmt") .rand_bytes(6) .tempfile_in(test_path(&[]))?; - temp_fmt.write_all(mem.files.borrow().get(OsStr::new("plain.fmt")).unwrap())?; + temp_fmt.write_all( + &mem.files + .borrow() + .get(OsStr::new("plain.fmt")) + .unwrap() + .data, + )?; temp_fmt.persist(&fmt_path)?; } @@ -194,10 +201,10 @@ impl ExpectedInfo { ); } - pub fn test_from_collection(&self, files: &HashMap>) { + pub fn test_from_collection(&self, files: &MemoryFileCollection) { if !self.gzipped { - if let Some(data) = files.get(&self.name) { - self.test_data(data) + if let Some(file) = files.get(&self.name) { + self.test_data(&file.data) } else { panic!( "{:?} not in {:?}", @@ -207,7 +214,7 @@ impl ExpectedInfo { } } else { let mut buf = Vec::new(); - let mut dec = GzDecoder::new(&files.get(&self.name).unwrap()[..]); + let mut dec = GzDecoder::new(&files.get(&self.name).unwrap().data[..]); dec.read_to_end(&mut buf).unwrap(); self.test_data(&buf); } From b318d918a55faf5003cf5468f30b6f59bbce0940 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Tue, 27 Oct 2020 18:13:15 -0400 Subject: [PATCH 21/24] Wire up \filemoddate and add a test --- Cargo.lock | 13 +++++++ Cargo.toml | 1 + tectonic/xetex-texmfmp.c | 49 ++++++++++++++----------- tests/tex-outputs.rs | 12 ++++++ tests/tex-outputs/prim_filemoddate.log | 3 ++ tests/tex-outputs/prim_filemoddate.tex | 5 +++ tests/tex-outputs/prim_filemoddate.xdv | Bin 0 -> 212 bytes 7 files changed, 61 insertions(+), 22 deletions(-) create mode 100644 tests/tex-outputs/prim_filemoddate.log create mode 100644 tests/tex-outputs/prim_filemoddate.tex create mode 100644 tests/tex-outputs/prim_filemoddate.xdv diff --git a/Cargo.lock b/Cargo.lock index f2f21c761c..25d8e3f313 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -452,6 +452,18 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +[[package]] +name = "filetime" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "redox_syscall", + "winapi 0.3.9", +] + [[package]] name = "flate2" version = "1.0.14" @@ -1663,6 +1675,7 @@ dependencies = [ "cc", "cfg-if 1.0.0", "error-chain", + "filetime", "flate2", "fs2", "futures", diff --git a/Cargo.toml b/Cargo.toml index 6b21528f33..a5c1414d28 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,6 +79,7 @@ profile = [] # libz-sys = "^1.0" [dev-dependencies] +filetime = "^0.2" futures = "0.1" headers = "0.2" hyper = "0.12" diff --git a/tectonic/xetex-texmfmp.c b/tectonic/xetex-texmfmp.c index 7522a75a37..e34518786c 100644 --- a/tectonic/xetex-texmfmp.c +++ b/tectonic/xetex-texmfmp.c @@ -19,11 +19,9 @@ static int last_lineno; if ((unsigned)(size_get) >= (unsigned)(size_want)) \ _tt_abort ("snprintf failed: file %s, line %d", __FILE__, __LINE__); -#define TIME_STR_SIZE 30 -static time_t start_time = 0; -char start_time_str[TIME_STR_SIZE]; -static char filemod_time_str[TIME_STR_SIZE]; /* minimum size for time_str is 24: "D:YYYYmmddHHMMSS+HH'MM'" */ +#define TIME_STR_SIZE 30 +static char start_time_str[TIME_STR_SIZE]; static void makepdftime(time_t t, char *time_str, bool utc) @@ -78,13 +76,14 @@ makepdftime(time_t t, char *time_str, bool utc) } } + void init_start_time(time_t source_date_epoch) { - start_time = source_date_epoch; - makepdftime (start_time, start_time_str, /* utc= */true); + makepdftime(source_date_epoch, start_time_str, /* utc= */true); } + void getcreationdate(void) { @@ -137,29 +136,35 @@ get_seconds_and_micros (int32_t *seconds, int32_t *micros) void getfilemoddate(str_number s) { -#if 0 - char *xname; - time_t mtime = 0; - size_t len; + char *name; + time_t mtime; + size_t text_len; + rust_input_handle_t handle; + char buf[20]; + int i; - xname = gettexstring(s); + name = gettexstring(s); + handle = ttstub_input_open(name, TTIF_TEX, 0); + free(name); - /* .... get mtime ... */ + if (handle == NULL) + return; /* => evaluate to the empty string; intentional */ - free(file_name); - makepdftime(mtime, filemod_time_str, use_utc); - len = strlen(time_str); + mtime = ttstub_input_get_mtime(handle); + ttstub_input_close(handle); - if ((unsigned) (pool_ptr + len) >= (unsigned) pool_size) { - pool_ptr = pool_size; - /* error by str_toks that calls str_room(1) */ + makepdftime(mtime, buf, /* utc= */true); + text_len = strlen(buf); + + if ((unsigned) (pool_ptr + text_len) >= (unsigned) pool_size) { + pool_ptr = pool_size; + /* error by str_toks that calls str_room(1) */ } else { - int i; + int i; - for (i = 0; i < len; i++) - str_pool[pool_ptr++] = (uint16_t) time_str[i]; + for (i = 0; i < text_len; i++) + str_pool[pool_ptr++] = (uint16_t) buf[i]; } -#endif } /* Given a file name stored in the string pool, insert into the string pool text diff --git a/tests/tex-outputs.rs b/tests/tex-outputs.rs index 5bbf0ffc90..424445f709 100644 --- a/tests/tex-outputs.rs +++ b/tests/tex-outputs.rs @@ -238,6 +238,18 @@ fn prim_filedump() { TestCase::new("prim_filedump").go() } +#[test] +fn prim_filemoddate() { + // Git doesn't preserve mtimes, so manually force the mtime of the input + // file to something repeatable. + util::set_test_root(); + let path = test_path(&["tex-outputs", "prim_filemoddate.tex"]); + let t = filetime::FileTime::from_unix_time(1_603_835_905, 0); + filetime::set_file_mtime(path, t).expect("failed to set input file mtime"); + + TestCase::new("prim_filemoddate").go() +} + #[test] fn prim_filesize() { TestCase::new("prim_filesize").go() diff --git a/tests/tex-outputs/prim_filemoddate.log b/tests/tex-outputs/prim_filemoddate.log new file mode 100644 index 0000000000..f95ad9af10 --- /dev/null +++ b/tests/tex-outputs/prim_filemoddate.log @@ -0,0 +1,3 @@ +** +(prim_filemoddate.tex [1] ) +Output written on prim_filemoddate.xdv (1 page, 212 bytes). diff --git a/tests/tex-outputs/prim_filemoddate.tex b/tests/tex-outputs/prim_filemoddate.tex new file mode 100644 index 0000000000..a2ad0466c3 --- /dev/null +++ b/tests/tex-outputs/prim_filemoddate.tex @@ -0,0 +1,5 @@ +% Git doesn't preserve file modification times, but the test case manually +% updates the modification time of this file before running the engine. +X\filemoddate{nosuchfile}% +Y\filemoddate{prim_filemoddate.tex}% +Z\bye diff --git a/tests/tex-outputs/prim_filemoddate.xdv b/tests/tex-outputs/prim_filemoddate.xdv new file mode 100644 index 0000000000000000000000000000000000000000..bc7a17bce2051abe33e2fef27d6ba9e88e5dba3b GIT binary patch literal 212 zcmey)&e%NZfQ&T*5HP>sC`nB&$b>8nr(cG@#;Z$1||kZtcLsq>X^ZP9|!<1t~{~; literal 0 HcmV?d00001 From cf840eaa20eac37db06f208154256be7ebc18b21 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Tue, 27 Oct 2020 18:22:54 -0400 Subject: [PATCH 22/24] dist/azure-ci-cd.yml: disable the Windows/vcpkg build for now It looks like it is going to take a while for vcpkg to get its act together. Tracking issue created: https://github.com/tectonic-typesetting/tectonic/issues/668 --- dist/azure-ci-cd.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/dist/azure-ci-cd.yml b/dist/azure-ci-cd.yml index 8fd386405b..5523154f99 100644 --- a/dist/azure-ci-cd.yml +++ b/dist/azure-ci-cd.yml @@ -80,12 +80,15 @@ parameters: TARGET: x86_64-apple-darwin TOOLCHAIN: stable - - name: windows - vmImage: windows-2019 - params: {} - vars: - TARGET: x86_64-pc-windows-msvc - TOOLCHAIN: stable-x86_64-pc-windows-msvc + # Temporarily disabled due to vcpkg brokenness that looks like it + # will take a little while to resolve. Tracking issue: + # https://github.com/tectonic-typesetting/tectonic/issues/668 + # - name: windows + # vmImage: windows-2019 + # params: {} + # vars: + # TARGET: x86_64-pc-windows-msvc + # TOOLCHAIN: stable-x86_64-pc-windows-msvc - name: crossBuilds type: object From 0cb9e0bb6ab5a19b45e62834d89213371f29032f Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Tue, 27 Oct 2020 18:39:46 -0400 Subject: [PATCH 23/24] reference_sources: we are now caught up to TeXLive 2020.0 (r54631) --- reference_sources | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference_sources b/reference_sources index 3b4ae66327..1d798f0f22 160000 --- a/reference_sources +++ b/reference_sources @@ -1 +1 @@ -Subproject commit 3b4ae66327b096970333eacde19118e07322bf66 +Subproject commit 1d798f0f2253cfdb6ea908e0ba4d721b5ec7d860 From d8dddeb3b7ba831d84caf9ae10247e4c077be37f Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Tue, 27 Oct 2020 20:44:56 -0400 Subject: [PATCH 24/24] tectonic/dpx-pkfont.c: warn if we try to kpse_find_glyph Discovered in the course of tracking down issue #478. XeLaTeX works because it generates a "PK" font file on the fly. We can't do that. More research needed to understand if we should even try. --- tectonic/dpx-pkfont.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/tectonic/dpx-pkfont.c b/tectonic/dpx-pkfont.c index 11b30afb16..5cd79f1bd1 100644 --- a/tectonic/dpx-pkfont.c +++ b/tectonic/dpx-pkfont.c @@ -84,17 +84,10 @@ truedpi (const char *ident, double point_size, unsigned int bdpi) static FILE * dpx_open_pk_font_at (const char *ident, unsigned int dpi) { - FILE *fp; - char *fqpn; /*kpse_glyph_file_type kpse_file_info;*/ - - fqpn = NULL; /*kpse_find_glyph(ident, dpi, kpse_pk_format, &kpse_file_info);*/ - if (!fqpn) - return NULL; - fp = fopen(fqpn, FOPEN_RBIN_MODE); - free(fqpn); - - return fp; + /*char * fqpn = kpse_find_glyph(ident, dpi, kpse_pk_format, &kpse_file_info);*/ + dpx_warning("Tectonic unable to generate PK font \"%s\" (dpi %u) on-the-fly", ident, dpi); + return NULL; }