/* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. Copyright (C) 2007-2019 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifdef HAVE_CONFIG_H #include #endif #ifdef _MSC_VER #include #endif #if defined(MIKTEX_WINDOWS) #include #endif #include #include "system.h" #include "error.h" #include "mem.h" #include "dpxconf.h" #include "dpxutil.h" #include "mfileio.h" #include "dpxfile.h" #include "dpxcrypt.h" #define MAX_KEY_LEN 16 #include #include #ifdef WIN32 #include #include #include #else #if HAVE_SYS_WAIT_H #include #endif #ifndef WEXITSTATUS #define WEXITSTATUS(val) ((unsigned)(val) >> 8) #endif #ifndef WIFEXITED #define WIFEXITED(val) (((val) & 255) == 0) #endif #endif #if defined(MIKTEX) || defined(TESTCOMPILE) #if defined(__APPLE__) # include #endif #if !defined(PATH_MAX) # define PATH_MAX 256 #endif #endif /* MIKTEX || TESTCOMPILE */ /* Kpathsea library does not check file type. */ static int qcheck_filetype (const char *fqpn, dpx_res_type type); /* For testing MIKTEX enabled compilation */ #if defined(TESTCOMPILE) && !defined(MIKTEX) # define MIKTEX 1 # define PATH_SEP_CHR '/' static int miktex_get_acrobat_font_dir (char *buf) { strcpy(buf, "/usr/share/ghostscript/Resource/Font/"); return 1; } static int miktex_find_file (const char *filename, const char *dirlist, char *buf) { int r = 0; char *fqpn; fqpn = kpse_path_search(dirlist, filename, 0); if (!fqpn) return 0; if (strlen(fqpn) > PATH_MAX) r = 0; else { strcpy(buf, fqpn); r = 1; } RELEASE(fqpn); return r; } static int miktex_find_app_input_file (const char *progname, const char *filename, char *buf) { int r = 0; char *fqpn; kpse_reset_program_name(progname); fqpn = kpse_find_file (filename, kpse_program_text_format, false); kpse_reset_program_name("dvipdfmx"); if (!fqpn) return 0; if (strlen(fqpn) > PATH_MAX) r = 0; else { strcpy(buf, fqpn); r = 1; } RELEASE(fqpn); return r; } static int miktex_find_psheader_file (const char *filename, char *buf) { int r; char *fqpn; fqpn = kpse_find_file(filename, kpse_tex_ps_header_format, 0); if (!fqpn) return 0; if (strlen(fqpn) > PATH_MAX) r = 0; else { strcpy(buf, fqpn); r = 1; } RELEASE(fqpn); return r; } #endif /* TESTCOMPILE */ #ifdef MIKTEX_NO_KPATHSEA #ifndef PATH_SEP_CHR # define PATH_SEP_CHR '\\' #endif static char _tmpbuf[PATH_MAX+1]; #endif /* MIKTEX */ #if defined(WIN32) extern int utf8name_failed; #endif /* WIN32 */ #define CMDBUFSIZ 1024 static int exec_spawn (char *cmd) { char **cmdv, **qv; char *p, *pp; char buf[CMDBUFSIZ]; int charcnt; int i, ret = -1; #ifdef WIN32 wchar_t **cmdvw, **qvw; #endif if (!cmd) return -1; while (*cmd == ' ' || *cmd == '\t') cmd++; if (*cmd == '\0') return -1; i = 0; p = cmd; while (*p) { if (*p == ' ' || *p == '\t') i++; p++; } cmdv = xcalloc (i + 4, sizeof (char *)); p = cmd; qv = cmdv; while (*p) { pp = buf; charcnt = 0; if (*p == '"') { p++; while (*p != '"') { if (*p == '\0') { goto done; } *pp++ = *p++; charcnt++; if (charcnt > CMDBUFSIZ - 1) { ERROR("Too long a command line."); } } p++; } else if (*p == '\'') { p++; while (*p != '\'') { if (*p == '\0') { goto done; } *pp++ = *p++; charcnt++; if (charcnt > CMDBUFSIZ - 1) { ERROR("Too long a command line."); } } p++; } else { while (*p != ' ' && *p != '\t' && *p) { if (*p == '\'') { p++; while (*p != '\'') { if (*p == '\0') { goto done; } *pp++ = *p++; charcnt++; if (charcnt > CMDBUFSIZ - 1) { ERROR("Too long a command line."); } } p++; } else { *pp++ = *p++; charcnt++; if (charcnt > CMDBUFSIZ - 1) { ERROR("Too long a command line."); } } } } *pp = '\0'; #ifdef WIN32 if (strchr (buf, ' ') || strchr (buf, '\t')) *qv = concat3 ("\"", buf, "\""); else #endif *qv = xstrdup (buf); /* fprintf(stderr,"\n%s", *qv); */ while (*p == ' ' || *p == '\t') p++; qv++; } *qv = NULL; #ifdef WIN32 #if defined(MIKTEX) ret = _spawnvp(_P_WAIT, *cmdv, (const char* const*)cmdv); #else cmdvw = xcalloc (i + 4, sizeof (wchar_t *)); if (utf8name_failed == 0) { qv = cmdv; qvw = cmdvw; while (*qv) { *qvw = get_wstring_from_fsyscp(*qv, *qvw=NULL); qv++; qvw++; } *qvw = NULL; ret = _wspawnvp (_P_WAIT, *cmdvw, (const wchar_t* const*) cmdvw); } else { int tmpcp; tmpcp = file_system_codepage; file_system_codepage = win32_codepage; qv = cmdv; qvw = cmdvw; while (*qv) { *qvw = get_wstring_from_fsyscp(*qv, *qvw=NULL); qv++; qvw++; } *qvw = NULL; file_system_codepage = tmpcp; utf8name_failed = 0; ret = _wspawnvp (_P_WAIT, *cmdvw, (const wchar_t* const*) cmdvw); } if (cmdvw) { qvw = cmdvw; while (*qvw) { free (*qvw); qvw++; } free (cmdvw); } #endif #else i = fork (); if (i < 0) ret = -1; else if (i == 0) { if (execvp (*cmdv, cmdv)) _exit (-1); } else { if (wait (&ret) == i) { ret = (WIFEXITED (ret) ? WEXITSTATUS (ret) : -1); } else { ret = -1; } } #endif done: qv = cmdv; while (*qv) { free (*qv); qv++; } free (cmdv); return ret; } /* ensuresuffix() returns a copy of basename if sfx is "". */ static char * ensuresuffix (const char *basename, const char *sfx) { char *q, *p; p = NEW(strlen(basename) + strlen(sfx) + 1, char); strcpy(p, basename); q = strrchr(p, '.'); if (!q && sfx[0]) strcat(p, sfx); return p; } #ifdef MIKTEX_NO_KPATHSEA static char * dpx_find__app__xyz (const char *filename, const char *suffix, int is_text) { char *fqpn = NULL; int r; char *q; q = ensuresuffix(filename, suffix); r = miktex_find_app_input_file("dvipdfmx", q, _tmpbuf); if (!r && strcmp(q, filename)) r = miktex_find_app_input_file("dvipdfmx", filename, _tmpbuf); if (r) { fqpn = NEW(strlen(_tmpbuf) + 1, char); strcpy(fqpn, _tmpbuf); } RELEASE(q); return fqpn; } static char * dpx_foolsearch (const char *foolname, const char *filename, int is_text) { char *fqpn = NULL; int r; r = miktex_find_app_input_file(foolname, filename, _tmpbuf); if (r) { fqpn = NEW(strlen(_tmpbuf) + 1, char); strcpy(fqpn, _tmpbuf); } return fqpn; } #else /* !MIKTEX */ # define TDS11DOC "http://www.tug.org/ftp/tex/tds-1.1/tds.html#Fonts" static void insistupdate (const char *filename, const char *fqpn, const char *foolname, kpse_file_format_type foolformat, kpse_file_format_type realformat) { #if defined(MIKTEX) /* users are not fools */ #else kpse_format_info_type *fif; kpse_format_info_type *fir; if (dpx_conf.verbose_level < 1) return; fif = &kpse_format_info[foolformat]; fir = &kpse_format_info[realformat]; WARN("File name=\"%s\" format=\"%s\" might be found in different location than I expected:", filename, fir->type); WARN(">> %s", fqpn); WARN(">> Please adjust your TEXMF as conformant with:"); WARN(">> " TDS11DOC); WARN(">> I searched it with fooling kpathsea as progname=\"%s\" format=\"%s\".", foolname, fif->type); WARN(">> Default search path for this format file is:"); WARN(">> %s", fir->default_path); WARN(">> Please read \"README\" file."); #endif } static char * dpx_find__app__xyz (const char *filename, const char *suffix, int is_text) { char *fqpn = NULL; char *q; q = ensuresuffix(filename, suffix); fqpn = kpse_find_file(q, (is_text ? kpse_program_text_format : kpse_program_binary_format), 0); if (!fqpn && strcmp(q, filename)) fqpn = kpse_find_file(filename, (is_text ? kpse_program_text_format : kpse_program_binary_format), 0); RELEASE(q); return fqpn; } static char * dpx_foolsearch (const char *foolname, const char *filename, int is_text) { char *fqpn = NULL; kpse_reset_program_name(foolname); fqpn = kpse_find_file (filename, (is_text ? kpse_program_text_format : kpse_program_binary_format), false); kpse_reset_program_name("dvipdfmx"); return fqpn; } #endif /* MIKTEX */ static char *dpx_find_fontmap_file (const char *filename); static char *dpx_find_agl_file (const char *filename); static char *dpx_find_sfd_file (const char *filename); static char *dpx_find_cmap_file (const char *filename); static char *dpx_find_enc_file (const char *filename); static char *dpx_find_iccp_file (const char *filename); FILE * dpx_open_file (const char *filename, dpx_res_type type) { FILE *fp = NULL; char *fqpn = NULL; switch (type) { case DPX_RES_TYPE_FONTMAP: fqpn = dpx_find_fontmap_file(filename); if (dpx_conf.verbose_level > 0) { if (fqpn != NULL) MESG(fqpn); } break; case DPX_RES_TYPE_T1FONT: fqpn = dpx_find_type1_file(filename); break; case DPX_RES_TYPE_TTFONT: fqpn = dpx_find_truetype_file(filename); break; case DPX_RES_TYPE_OTFONT: fqpn = dpx_find_opentype_file(filename); break; case DPX_RES_TYPE_PKFONT: break; case DPX_RES_TYPE_CMAP: fqpn = dpx_find_cmap_file(filename); break; case DPX_RES_TYPE_ENC: fqpn = dpx_find_enc_file(filename); break; case DPX_RES_TYPE_SFD: fqpn = dpx_find_sfd_file(filename); break; case DPX_RES_TYPE_AGL: fqpn = dpx_find_agl_file(filename); break; case DPX_RES_TYPE_ICCPROFILE: fqpn = dpx_find_iccp_file(filename); break; case DPX_RES_TYPE_DFONT: fqpn = dpx_find_dfont_file(filename); break; case DPX_RES_TYPE_BINARY: fqpn = dpx_find__app__xyz(filename, "", 0); break; case DPX_RES_TYPE_TEXT: fqpn = dpx_find__app__xyz(filename, "", 1); break; } if (fqpn) { fp = MFOPEN(fqpn, FOPEN_RBIN_MODE); RELEASE(fqpn); } return fp; } static char * dpx_find_iccp_file (const char *filename) { char *fqpn = NULL; fqpn = dpx_find__app__xyz(filename, "", 0); if (fqpn || strrchr(filename, '.')) return fqpn; fqpn = dpx_find__app__xyz(filename, ".icc", 0); if (fqpn) return fqpn; fqpn = dpx_find__app__xyz(filename, ".icm", 0); return fqpn; } static char * dpx_find_fontmap_file (const char *filename) { char *fqpn = NULL; char *q; q = ensuresuffix(filename, ".map"); #ifdef MIKTEX_NO_KPATHSEA fqpn = dpx_find__app__xyz(q, ".map", 1); #else /* !MIKTEX */ fqpn = kpse_find_file(q, kpse_fontmap_format, 0); if (!fqpn) { fqpn = dpx_find__app__xyz(q, ".map", 1); if (fqpn) insistupdate(q, fqpn, "dvipdfmx", kpse_program_text_format, kpse_fontmap_format); } #endif /* MIKETEX */ RELEASE(q); return fqpn; } static char * dpx_find_agl_file (const char *filename) { char *fqpn = NULL; char *q; q = ensuresuffix(filename, ".txt"); #ifdef MIKTEX_NO_KPATHSEA fqpn = dpx_find__app__xyz(q, ".txt", 1); #else /* !MIKTEX */ fqpn = kpse_find_file(q, kpse_fontmap_format, 0); if (!fqpn) { fqpn = dpx_find__app__xyz(q, ".txt", 1); if (fqpn) insistupdate(q, fqpn, "dvipdfmx", kpse_program_text_format, kpse_fontmap_format); } #endif /* MIKETEX */ RELEASE(q); return fqpn; } /* cmap.sty put files into tex/latex/cmap */ static char * dpx_find_cmap_file (const char *filename) { char *fqpn = NULL; static const char *fools[] = { "cmap", "tex", NULL }; int i; #if defined(MIKTEX_NO_KPATHSEA) /* Find in Acrobat's Resource/CMap dir */ { char _acrodir[PATH_MAX+1]; char *q; int r; memset(_acrodir, 0, PATH_MAX+1); r = miktex_get_acrobat_font_dir(_acrodir); if (r && strlen(_acrodir) > strlen("Font")) { /* ....\Font\ */ q = strrchr(_acrodir, PATH_SEP_CHR); if (q && q[1] == '\0') q[0] = '\0'; q = strrchr(_acrodir, PATH_SEP_CHR); if (q && !strcmp(q + 1, "Font")) { sprintf(q, "%cCMap%c", PATH_SEP_CHR, PATH_SEP_CHR); r = miktex_find_file(filename, _acrodir, _tmpbuf); if (r) { fqpn = NEW(strlen(_tmpbuf) + 1, char); strcpy(fqpn, _tmpbuf); } } } memset(_tmpbuf, 0, PATH_MAX+1); } #else fqpn = kpse_find_file(filename, kpse_cmap_format, 0); #endif /* Files found above are assumed to be CMap, * if it's not really CMap it will cause an error. */ for (i = 0; !fqpn && fools[i]; i++) { fqpn = dpx_foolsearch(fools[i], filename, 1); if (fqpn) { #ifndef MIKTEX_NO_KPATHSEA insistupdate(filename, fqpn, fools[i], kpse_program_text_format, kpse_cmap_format); #endif if (!qcheck_filetype(fqpn, DPX_RES_TYPE_CMAP)) { WARN("Found file \"%s\" for PostScript CMap but it doesn't look like a CMap...", fqpn); RELEASE(fqpn); fqpn = NULL; } } } return fqpn; } /* Search order: * SFDFONTS (TDS 1.1) * ttf2pk (text file) * ttf2tfm (text file) * dvipdfm (text file) */ static char * dpx_find_sfd_file (const char *filename) { char *fqpn = NULL; char *q; static const char *fools[] = { "ttf2pk", "ttf2tfm", NULL }; int i; q = ensuresuffix(filename, ".sfd"); #ifndef MIKTEX_NO_KPATHSEA fqpn = kpse_find_file(q, kpse_sfd_format, 0); #endif /* !MIKTEX */ for (i = 0; !fqpn && fools[i]; i++) { fqpn = dpx_foolsearch(fools[i], q, 1); #ifndef MIKTEX_NO_KPATHSEA if (fqpn) insistupdate(filename, fqpn, fools[i], kpse_program_text_format, kpse_sfd_format); #endif } RELEASE(q); return fqpn; } static char * dpx_find_enc_file (const char *filename) { char *fqpn = NULL; char *q; static const char *fools[] = { "dvips", NULL }; int i; q = ensuresuffix(filename, ".enc"); #ifdef MIKTEX_NO_KPATHSEA if (miktex_find_psheader_file(q, _tmpbuf)) { fqpn = NEW(strlen(_tmpbuf) + 1, char); strcpy(fqpn, _tmpbuf); } #else fqpn = kpse_find_file(q, kpse_enc_format, 0); #endif /* MIKTEX */ for (i = 0; !fqpn && fools[i]; i++) { fqpn = dpx_foolsearch(fools[i], q, 1); #ifndef MIKTEX_NO_KPATHSEA if (fqpn) insistupdate(filename, fqpn, fools[i], kpse_program_text_format, kpse_enc_format); #endif } RELEASE(q); return fqpn; } static int is_absolute_path(const char *filename) { #ifdef WIN32 if (isalpha(filename[0]) && filename[1] == ':') return 1; if (filename[0] == '\\' && filename[1] == '\\') return 1; if (filename[0] == '/' && filename[1] == '/') return 1; #else if (filename[0] == '/') return 1; #endif return 0; } char * dpx_find_type1_file (const char *filename) { char *fqpn = NULL; if (is_absolute_path(filename)) fqpn = xstrdup(filename); else fqpn = kpse_find_file(filename, kpse_type1_format, 0); if (fqpn && !qcheck_filetype(fqpn, DPX_RES_TYPE_T1FONT)) { RELEASE(fqpn); fqpn = NULL; } return fqpn; } char * dpx_find_truetype_file (const char *filename) { char *fqpn = NULL; if (is_absolute_path(filename)) fqpn = xstrdup(filename); else fqpn = kpse_find_file(filename, kpse_truetype_format, 0); if (fqpn && !qcheck_filetype(fqpn, DPX_RES_TYPE_TTFONT)) { RELEASE(fqpn); fqpn = NULL; } return fqpn; } char * dpx_find_opentype_file (const char *filename) { char *fqpn = NULL; char *q; q = ensuresuffix(filename, ".otf"); #ifndef MIKTEX_NO_KPATHSEA if (is_absolute_path(q)) fqpn = xstrdup(q); else fqpn = kpse_find_file(q, kpse_opentype_format, 0); if (!fqpn) { #endif fqpn = dpx_foolsearch("dvipdfmx", q, 0); #ifndef MIKTEX_NO_KPATHSEA if (fqpn) insistupdate(filename, fqpn, "dvipdfmx", kpse_program_binary_format, kpse_opentype_format); } #endif RELEASE(q); /* *We* use "opentype" for ".otf" (CFF). */ if (fqpn && !qcheck_filetype(fqpn, DPX_RES_TYPE_OTFONT)) { RELEASE(fqpn); fqpn = NULL; } return fqpn; } char * dpx_find_dfont_file (const char *filename) { char *fqpn = NULL; fqpn = kpse_find_file(filename, kpse_truetype_format, 0); if (fqpn) { int len = strlen(fqpn); if (len > 6 && strncmp(fqpn+len-6, ".dfont", 6)) { fqpn = RENEW(fqpn, len+6, char); strcat(fqpn, "/rsrc"); } } if (!qcheck_filetype(fqpn, DPX_RES_TYPE_DFONT)) { RELEASE(fqpn); fqpn = NULL; } return fqpn; } static char * dpx_get_tmpdir (void) { #ifdef WIN32 # define __TMPDIR "." #else /* WIN32 */ # define __TMPDIR "/tmp" #endif /* WIN32 */ size_t i; char *ret; const char *_tmpd; #ifdef HAVE_GETENV _tmpd = getenv("TMPDIR"); # ifdef WIN32 if (!_tmpd) _tmpd = getenv("TMP"); if (!_tmpd) _tmpd = getenv("TEMP"); # endif /* WIN32 */ if (!_tmpd) _tmpd = __TMPDIR; #else /* HAVE_GETENV */ _tmpd = __TMPDIR; #endif /* HAVE_GETENV */ ret = xstrdup(_tmpd); i = strlen(ret); while(i > 1 && IS_DIR_SEP(ret[i-1])) { ret[i-1] = '\0'; i--; } return ret; } #ifdef HAVE_MKSTEMP # include #endif char * dpx_create_temp_file (void) { char *tmp = NULL; #if defined(MIKTEX) { tmp = NEW(PATH_MAX + 1, char); miktex_create_temp_file_name(tmp); /* FIXME_FIXME */ #if defined(MIKTEX_WINDOWS) { char * lpsz; for (lpsz = tmp; *lpsz != 0; ++ lpsz) { if (*lpsz == '\\') { *lpsz = '/'; } } } #endif } #elif defined(HAVE_MKSTEMP) # define TEMPLATE "/dvipdfmx.XXXXXX" { char *_tmpd; int _fd = -1; _tmpd = dpx_get_tmpdir(); tmp = NEW(strlen(_tmpd) + strlen(TEMPLATE) + 1, char); strcpy(tmp, _tmpd); RELEASE(_tmpd); strcat(tmp, TEMPLATE); _fd = mkstemp(tmp); if (_fd != -1) { # ifdef WIN32 char *p; for (p = tmp; *p; p++) { if (IS_KANJI (p)) p++; else if (*p == '\\') *p = '/'; } _close(_fd); # else close(_fd); # endif /* WIN32 */ } else { RELEASE(tmp); tmp = NULL; } } #else /* use _tempnam or tmpnam */ { # ifdef WIN32 char *_tmpd; char *p; _tmpd = dpx_get_tmpdir(); tmp = _tempnam (_tmpd, "dvipdfmx."); RELEASE(_tmpd); for (p = tmp; *p; p++) { if (IS_KANJI(p)) p++; else if (*p == '\\') *p = '/'; } # else /* WIN32 */ char *_tmpa = NEW(L_tmpnam + 1, char); tmp = tmpnam(_tmpa); if (!tmp) RELEASE(_tmpa); # endif /* WIN32 */ } #endif /* MIKTEX */ return tmp; } char * dpx_create_fix_temp_file (const char *filename) { #define PREFIX "dvipdfm-x." static char *dir = NULL; static char *cwd = NULL; char *ret, *s; int i; MD5_CONTEXT state; unsigned char digest[MAX_KEY_LEN]; #ifdef WIN32 char *p; #endif if (!dir) { dir = dpx_get_tmpdir(); cwd = xgetcwd(); } MD5_init(&state); MD5_write(&state, (unsigned char *)cwd, strlen(cwd)); MD5_write(&state, (unsigned const char *)filename, strlen(filename)); MD5_final(digest, &state); ret = NEW(strlen(dir)+1+strlen(PREFIX)+MAX_KEY_LEN*2 + 1, char); sprintf(ret, "%s/%s", dir, PREFIX); s = ret + strlen(ret); for (i=0; id_name) != plen + MAX_KEY_LEN * 2) return 0; #ifdef WIN32 return strncasecmp(ent->d_name, PREFIX, plen) == 0; #else return strncmp(ent->d_name, PREFIX, plen) == 0; #endif } void dpx_delete_old_cache (int life) { char *dir; char *pathname; DIR *dp; struct dirent *de; time_t limit; if (life == -2) { dpx_conf.file.keep_cache = -1; return; } dir = dpx_get_tmpdir(); pathname = NEW(strlen(dir)+1+strlen(PREFIX)+MAX_KEY_LEN*2 + 1, char); limit = time(NULL) - life * 60 * 60; if (life >= 0) dpx_conf.file.keep_cache = 1; if ((dp = opendir(dir)) != NULL) { while((de = readdir(dp)) != NULL) { if (dpx_clear_cache_filter(de)) { struct stat sb; sprintf(pathname, "%s/%s", dir, de->d_name); stat(pathname, &sb); if (sb.st_mtime < limit) { remove(pathname); /* printf("remove: %s\n", pathname); */ } } } closedir(dp); } RELEASE(dir); RELEASE(pathname); } void dpx_delete_temp_file (char *tmp, int force) { if (!tmp) return; if (force || dpx_conf.file.keep_cache != 1) remove (tmp); RELEASE(tmp); return; } /* dpx_file_apply_filter() is used for converting unsupported graphics * format to one of the formats that dvipdfmx can natively handle. * 'input' is the filename of the original file and 'output' is actually * temporal files 'generated' by the above routine. * This should be system dependent. (MiKTeX may want something different) * Please modify as appropriate (see also pdfximage.c and dvipdfmx.c). */ int dpx_file_apply_filter (const char *cmdtmpl, const char *input, const char *output, int version) { char *cmd = NULL; const char *p, *q; size_t n, size; int error = 0; if (!cmdtmpl) return -1; else if (!input || !output) return -1; size = strlen(cmdtmpl) + strlen(input) + strlen(output) + 3; cmd = NEW(size, char); memset(cmd, 0, size); for (n = 0, p = cmdtmpl; *p != 0; p++) { #define need(s,l,m,n) \ if ((l) + (n) >= (m)) { \ (m) += (n) + 128; \ (s) = RENEW((s), (m), char); \ } if (p[0] == '%') { p++; switch (p[0]) { case 'o': /* Output file name */ need(cmd, n, size, strlen(output)); strcpy(cmd + n, output); n += strlen(output); break; case 'i': /* Input filename */ need(cmd, n, size, strlen(input)); strcpy(cmd + n, input); n += strlen(input); break; case 'b': need(cmd, n, size, strlen(input)); q = strrchr(input, '.'); /* wrong */ if (q) { memcpy(cmd + n, input, (int) (q - input)); n += (int) (q - input); } else { strcpy(cmd + n, input); n += strlen(input); } break; case 'v': /* Version number, e.g. 1.4 */ { char buf[256]; sprintf(buf, "%d.%d", version/10, version%10); need(cmd, n, size, strlen(buf)); strcpy(cmd + n, buf); n += strlen(buf); break; } case 0: break; case '%': need(cmd, n, size, 1); cmd[n] = '%'; n++; break; } } else { need(cmd, n, size, 1); cmd[n] = p[0]; n++; } } need(cmd, n, size, 1); cmd[n] = '\0'; if (strlen(cmd) == 0) { RELEASE(cmd); return -1; } error = exec_spawn(cmd); if (error) WARN("Filtering file via command -->%s<-- failed.", cmd); RELEASE(cmd); return error; } static char _sbuf[128]; /* * SFNT type sigs: * `true' (0x74727565): TrueType (Mac) * `typ1' (0x74797031) (Mac): PostScript font housed in a sfnt wrapper * 0x00010000: TrueType (Win)/OpenType * `OTTO': PostScript CFF font with OpenType wrapper * `ttcf': TrueType Collection */ static int istruetype (FILE *fp) { int n; rewind(fp); n = fread(_sbuf, 1, 4, fp); rewind(fp); if (n != 4) return 0; else if (!memcmp(_sbuf, "true", 4) || !memcmp(_sbuf, "\0\1\0\0", 4)) /* This doesn't help... */ return 1; else if (!memcmp(_sbuf, "ttcf", 4)) return 1; return 0; } /* "OpenType" is only for ".otf" here */ static int isopentype (FILE *fp) { int n; rewind(fp); n = fread(_sbuf, 1, 4, fp); rewind(fp); if (n != 4) return 0; else if (!memcmp(_sbuf, "OTTO", 4)) return 1; else return 0; } static int ist1binary (FILE *fp) { char *p; int n; rewind(fp); n = fread(_sbuf, 1, 21, fp); rewind(fp); p = _sbuf; if (n != 21) return 0; else if (p[0] != (char) 0x80 || p[1] < 0 || p[1] > 3) return 0; else if (!memcmp(p + 6, "%!PS-AdobeFont", 14) || !memcmp(p + 6, "%!FontType1", 11)) return 1; else if (!memcmp(p + 6, "%!PS", 4)) { #if 0 p[20] = '\0'; p += 6; WARN("Ambiguous PostScript resource type: %s", (char *) p); #endif return 1; } /* Otherwise ambiguious */ return 0; } /* %!PS-Adobe-x.y Resource-CMap */ static int ispscmap (FILE *fp) { char *p; p = mfgets(_sbuf, 128, fp); p[127] = '\0'; if (!p || strlen(p) < 4 || memcmp(p, "%!PS", 4)) return 0; for (p += 4; *p && !isspace((unsigned char)*p); p++); for ( ; *p && (*p == ' ' || *p == '\t'); p++); if (*p == '\0' || strlen(p) < strlen("Resource-CMap")) return 0; else if (!memcmp(p, "Resource-CMap", strlen("Resource-CMap"))) return 1; /* Otherwise ambiguious */ return 0; } static int isdfont (FILE *fp) { int i, n; uint32_t pos; rewind(fp); get_unsigned_quad(fp); seek_absolute(fp, (pos = get_unsigned_quad(fp)) + 0x18); seek_absolute(fp, pos + get_unsigned_pair(fp)); n = get_unsigned_pair(fp); for (i = 0; i <= n; i++) { if (get_unsigned_quad(fp) == 0x73666e74UL) /* "sfnt" */ return 1; get_unsigned_quad(fp); } return 0; } /* This actually opens files. */ static int qcheck_filetype (const char *fqpn, dpx_res_type type) { int r = 1; FILE *fp; struct stat sb; if (!fqpn) return 0; if (stat(fqpn, &sb) != 0) return 0; if (sb.st_size == 0) return 0; fp = MFOPEN(fqpn, FOPEN_RBIN_MODE); if (!fp) { WARN("File \"%s\" found but I could not open that...", fqpn); return 0; } switch (type) { case DPX_RES_TYPE_T1FONT: r = ist1binary(fp); break; case DPX_RES_TYPE_TTFONT: r = istruetype(fp); break; case DPX_RES_TYPE_OTFONT: r = isopentype(fp); break; case DPX_RES_TYPE_CMAP: r = ispscmap(fp); break; case DPX_RES_TYPE_DFONT: r = isdfont(fp); break; default: break; } MFCLOSE(fp); return r; } #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 */