/* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. Copyright (C) 2002-2021 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 #include #include "system.h" #include "mem.h" #include "error.h" #include "mfileio.h" #include "dpxutil.h" #include "pdfparse.h" #include "pdfobj.h" #include "pdfcolor.h" #include "pdfdraw.h" #include "pdfximage.h" #include "pdfdev.h" #include "mpost.h" #include "specials.h" #include "spc_util.h" #include "spc_misc.h" /* pdfcolorstack: * This special is provoded as a compatibility feature to pdftex. */ struct stack { int page; int direct; dpx_stack stack; }; #define PDFCOLORSTACK_MAX_STACK 256 struct spc_stack { struct stack stacks[PDFCOLORSTACK_MAX_STACK]; }; static struct spc_stack spc_stack; static int pdfcolorstack__get_id (struct spc_env *spe, int *id, struct spc_arg *args) { char *q; if (args->curptr >= args->endptr) { spc_warn(spe, "Stack ID number expected but not found."); return -1; } q = parse_number(&args->curptr, args->endptr); if (!q) { spc_warn(spe, "Stack ID number expected but not found."); return -1; } *id = atoi(q); RELEASE(q); skip_white(&args->curptr, args->endptr); return 0; } static int pdfcolorstack__init (void *dp) { struct spc_stack *sd = dp; int i; for (i = 0; i < PDFCOLORSTACK_MAX_STACK; i++) { sd->stacks[i].page = 0; sd->stacks[i].direct = 0; dpx_stack_init(&sd->stacks[i].stack); } return 0; } static int pdfcolorstack__clean (void *dp) { struct spc_stack *sd = dp; int i; for (i = 0; i < PDFCOLORSTACK_MAX_STACK; i++) { pdf_obj *litstr; dpx_stack *stk = &sd->stacks[i].stack; while ((litstr = dpx_stack_pop(stk)) != NULL) { pdf_release_obj(litstr); } } return 0; } static void pdfcolorstack__set_litstr (pdf_coord cp, pdf_obj *litstr, int direct) { pdf_tmatrix M; if (!litstr) return; if (!direct) { M.a = M.d = 1.0; M.b = M.c = 0.0; M.e = cp.x; M.f = cp.y; pdf_dev_concat(&M); } pdf_doc_add_page_content(" ", 1); pdf_doc_add_page_content(pdf_string_value(litstr), pdf_string_length(litstr)); if (!direct) { M.e = -cp.x; M.f = -cp.y; pdf_dev_concat(&M); } } static int spc_handler_pdfcolorstackinit (struct spc_env *spe, struct spc_arg *args) { int id = -1; struct stack *st; char *q; pdf_coord cp = {0.0, 0.0}; pdf_obj *litstr; skip_white(&args->curptr, args->endptr); if (args->curptr >= args->endptr) return -1; if (pdfcolorstack__get_id(spe, &id, args) < 0) return -1; if (id < 0 || id >= PDFCOLORSTACK_MAX_STACK) { spc_warn(spe, "Invalid stack number specified: %d", id); return -1; } skip_white(&args->curptr, args->endptr); st = &spc_stack.stacks[id]; if (dpx_stack_depth(&st->stack) > 0) { spc_warn(spe, "Stadk ID=%d already initialized?", id); return -1; } while ((q = parse_c_ident(&args->curptr, args->endptr)) != NULL) { if (!strcmp(q, "page")) { st->page = 1; } else if (!strcmp(q, "direct")) { st->direct = 1; } else { spc_warn(spe, "Ignoring unknown option for pdfcolorstack special (init): %s", q); } RELEASE(q); skip_white(&args->curptr, args->endptr); } if (args->curptr < args->endptr) { litstr = parse_pdf_string(&args->curptr, args->endptr); if (litstr) { dpx_stack_push(&st->stack, litstr); pdfcolorstack__set_litstr(cp, litstr, st->direct); } skip_white(&args->curptr, args->endptr); } else { spc_warn(spe, "No valid PDF literal specified."); return -1; } return 0; } static int pdfcolorstack__set (struct spc_env *spe, struct stack *st, pdf_coord cp, struct spc_arg *args) { pdf_obj *litstr; skip_white(&args->curptr, args->endptr); if (args->curptr >= args->endptr) return -1; litstr = dpx_stack_pop(&st->stack); if (!litstr) { spc_warn(spe, "Stack empty!"); return -1; } pdf_release_obj(litstr); litstr = parse_pdf_string(&args->curptr, args->endptr); if (litstr) { dpx_stack_push(&st->stack, litstr); pdfcolorstack__set_litstr(cp, litstr, st->direct); skip_white(&args->curptr, args->endptr); } return 0; } static int pdfcolorstack__push (struct spc_env *spe, struct stack *st, pdf_coord cp, struct spc_arg *args) { pdf_obj *litstr; skip_white(&args->curptr, args->endptr); if (args->curptr >= args->endptr) return -1; litstr = parse_pdf_string(&args->curptr, args->endptr); if (litstr) { dpx_stack_push(&st->stack, litstr); pdfcolorstack__set_litstr(cp, litstr, st->direct); skip_white(&args->curptr, args->endptr); } return 0; } static int pdfcolorstack__current (struct spc_env *spe, struct stack *st, pdf_coord cp, struct spc_arg *args) { pdf_obj *litstr; litstr = dpx_stack_top(&st->stack); if (litstr) { pdfcolorstack__set_litstr(cp, litstr, st->direct); skip_white(&args->curptr, args->endptr); } else { spc_warn(spe, "Stack empty!"); return -1; } return 0; } static int pdfcolorstack__pop (struct spc_env *spe, struct stack *st, pdf_coord cp, struct spc_arg *args) { int error = 0; pdf_obj *litstr; /* "default" at the bottom */ if (dpx_stack_depth(&st->stack) < 2) { spc_warn(spe, "Stack underflow"); return -1; } litstr = dpx_stack_pop(&st->stack); if (litstr) { pdf_release_obj(litstr); } litstr = dpx_stack_top(&st->stack); if (litstr) { pdfcolorstack__set_litstr(cp, litstr, st->direct); } return error; } static int spc_handler_pdfcolorstack (struct spc_env *spe, struct spc_arg *args) { int error = 0; int id; char *command; struct stack *st; pdf_coord cp; skip_white(&args->curptr, args->endptr); if (args->curptr >= args->endptr) return -1; if (pdfcolorstack__get_id(spe, &id, args) < 0) return -1; if (id < 0 || id >= PDFCOLORSTACK_MAX_STACK) { spc_warn(spe, "Invalid stack ID specified: %d", id); return -1; } skip_white(&args->curptr, args->endptr); st = &spc_stack.stacks[id]; if (dpx_stack_depth(&st->stack) < 1) { spc_warn(spe, "Stack ID=%d not properly initialized?", id); return -1; } command = parse_c_ident(&args->curptr, args->endptr); if (!command) return -1; spc_get_current_point(spe, &cp); if (!strcmp(command, "set")) { error = pdfcolorstack__set(spe, st, cp, args); } else if (!strcmp(command, "push")) { error = pdfcolorstack__push(spe, st, cp, args); } else if (!strcmp(command, "pop")) { error = pdfcolorstack__pop(spe, st, cp, args); } else if (!strcmp(command, "current")) { error = pdfcolorstack__current(spe, st, cp, args); } else { spc_warn(spe, "Unknown action: %s", command); } if (error) { spc_warn(spe, "Error occurred while processing pdfcolorstack: id=%d command=\"%s\"", id, command); } RELEASE(command); return error; } /* Duplicate from spc_pdfm */ static pdf_obj * parse_pdf_reference (const char **start, const char *end, void *user_data) { pdf_obj *result = NULL; char *name; skip_white(start, end); name = parse_opt_ident(start, end); if (name) { result = spc_lookup_reference(name); if (!result) { WARN("Could not find the named reference (@%s).", name); } RELEASE(name); } else { WARN("Could not find a reference name."); result = NULL; } return result; } /* pdffontattr */ #include "pdffont.h" struct fontattr { char *ident; double size; pdf_obj *attr; }; struct fontattr *fontattrs = NULL; int num_fontattrs = 0; int max_fontattrs = 0; static int process_fontattr (const char *ident, double size, pdf_obj *attr) { int font_id; pdf_obj *fontdict; ASSERT(ident && attr); font_id = pdf_font_findresource(ident, size); if (font_id < 0) { WARN("Could not find specified font resource: %s (%gpt)", ident, size); return -1; } fontdict = pdf_get_font_resource(font_id); if (!fontdict) { WARN("Specified object not exist: %s (%gpt)", ident, size); return -1; } pdf_merge_dict(fontdict, attr); return 0; } static int spc_handler_pdffontattr (struct spc_env *spe, struct spc_arg *ap) { struct fontattr *fontattr; char *ident = NULL; double size = 0.0; pdf_obj *attr = NULL; skip_white(&ap->curptr, ap->endptr); if (ap->curptr >= ap->endptr) return -1; ident = parse_ident(&ap->curptr, ap->endptr); if (!ident) { spc_warn(spe, "Missing a font name."); return -1; } skip_white(&ap->curptr, ap->endptr); if (ap->curptr < ap->endptr && ap->curptr[0] != '<') { int error = dpx_util_read_length(&size, 1.0, &ap->curptr, ap->endptr); if (error) { spc_warn(spe, "Font size expected but not found."); RELEASE(ident); return -1; } skip_white(&ap->curptr, ap->endptr); } attr = parse_pdf_object_extended(&ap->curptr, ap->endptr, NULL, parse_pdf_reference, spe); if (!attr) { spc_warn(spe, "Failed to parse a PDF dictionary object: %s", ident); RELEASE(ident); return -1; } else if (!PDF_OBJ_DICTTYPE(attr)) { spc_warn(spe, "PDF dict expected but non-dict object found: %s", ident); RELEASE(ident); pdf_release_obj(attr); return -1; } skip_white(&ap->curptr, ap->endptr); if (num_fontattrs >= max_fontattrs) { fontattrs = RENEW(fontattrs, max_fontattrs + 256, struct fontattr); max_fontattrs += 256; } fontattr = &fontattrs[num_fontattrs]; num_fontattrs += 1; fontattr->ident = ident; fontattr->size = size; fontattr->attr = attr; return 0; } int spc_misc_at_begin_document (void) { struct spc_stack *sd = &spc_stack; if (!fontattrs) { fontattrs = NEW(256, struct fontattr); num_fontattrs = 0; max_fontattrs = 256; } return pdfcolorstack__init(sd); } int spc_misc_at_end_document (void) { struct spc_stack *sd = &spc_stack; if (fontattrs) { int i; for (i = 0; i < num_fontattrs; i++) { process_fontattr(fontattrs[i].ident, fontattrs[i].size, fontattrs[i].attr); RELEASE(fontattrs[i].ident); pdf_release_obj(fontattrs[i].attr); } RELEASE(fontattrs); fontattrs = NULL; max_fontattrs = num_fontattrs = 0; } return pdfcolorstack__clean(sd); } int spc_misc_at_begin_page (void) { struct spc_stack *sd = &spc_stack; int i; for (i = 0; i < PDFCOLORSTACK_MAX_STACK; i++) { dpx_stack *stk = &sd->stacks[i].stack; if (sd->stacks[i].page) { pdf_obj *litstr = dpx_stack_top(stk); pdf_coord cp = {0.0, 0.0}; if (litstr) pdfcolorstack__set_litstr(cp, litstr, sd->stacks[i].direct); } } return 0; } int spc_misc_at_begin_form (void) { return spc_misc_at_begin_page(); } int spc_misc_at_end_form (void) { return spc_misc_at_begin_page(); } static int spc_handler_postscriptbox (struct spc_env *spe, struct spc_arg *ap) { int form_id, len; transform_info ti; load_options options = {1, 0, NULL}; char filename[256], *fullname; char buf[512]; FILE *fp; ASSERT(spe && ap); if (ap->curptr >= ap->endptr) { spc_warn(spe, "No width/height/filename given for postscriptbox special."); return -1; } /* input is not NULL terminated */ len = (int) (ap->endptr - ap->curptr); len = MIN(511, len); memcpy(buf, ap->curptr, len); buf[len] = '\0'; transform_info_clear(&ti); spc_warn(spe, buf); if (sscanf(buf, "{%lfpt}{%lfpt}{%255[^}]}", &ti.width, &ti.height, filename) != 3) { spc_warn(spe, "Syntax error in postscriptbox special?"); return -1; } ap->curptr = ap->endptr; ti.width *= 72.0 / 72.27; ti.height *= 72.0 / 72.27; fullname = kpse_find_pict(filename); if (!fullname) { spc_warn(spe, "Image file \"%s\" not found.", filename); return -1; } fp = MFOPEN(fullname, FOPEN_R_MODE); if (!fp) { spc_warn(spe, "Could not open image file: %s", fullname); RELEASE(fullname); return -1; } RELEASE(fullname); ti.flags |= (INFO_HAS_WIDTH|INFO_HAS_HEIGHT); for (;;) { const char *p = mfgets(buf, 512, fp); if (!p) break; if (mps_scan_bbox(&p, p + strlen(p), &ti.bbox) >= 0) { ti.flags |= INFO_HAS_USER_BBOX; break; } } MFCLOSE(fp); form_id = pdf_ximage_load_image(NULL, filename, options); if (form_id < 0) { spc_warn(spe, "Failed to load image file: %s", filename); return -1; } spc_put_image(spe, form_id, &ti, spe->x_user, spe->y_user); return 0; } static int spc_handler_null (struct spc_env *spe, struct spc_arg *args) { args->curptr = args->endptr; return 0; } static struct spc_handler misc_handlers[] = { {"postscriptbox", spc_handler_postscriptbox}, {"pdfcolorstackinit", spc_handler_pdfcolorstackinit}, {"pdfcolorstack", spc_handler_pdfcolorstack}, {"pdffontattr", spc_handler_pdffontattr}, {"landscape", spc_handler_null}, /* handled at bop */ {"papersize", spc_handler_null}, /* handled at bop */ {"src:", spc_handler_null}, /* simply ignore */ {"pos:", spc_handler_null}, /* simply ignore */ {"om:", spc_handler_null} /* simply ignore */ }; int spc_misc_check_special (const char *buffer, int size) { const char *p, *endptr; int i; p = buffer; endptr = p + size; skip_white(&p, endptr); size = (int) (endptr - p); for (i = 0; i < sizeof(misc_handlers)/sizeof(struct spc_handler); i++) { if (size >= strlen(misc_handlers[i].key) && !strncmp(p, misc_handlers[i].key, strlen(misc_handlers[i].key))) { return 1; } } return 0; } int spc_misc_setup_handler (struct spc_handler *handle, struct spc_env *spe, struct spc_arg *args) { const char *key; int i, keylen; ASSERT(handle && spe && args); skip_white(&args->curptr, args->endptr); key = args->curptr; while (args->curptr < args->endptr && isalpha((unsigned char)args->curptr[0])) { args->curptr++; } if (args->curptr < args->endptr && args->curptr[0] == ':') { args->curptr++; } keylen = (int) (args->curptr - key); if (keylen < 1) { return -1; } for (i = 0; i < sizeof(misc_handlers)/sizeof(struct spc_handler); i++) { if (keylen == strlen(misc_handlers[i].key) && !strncmp(key, misc_handlers[i].key, keylen)) { skip_white(&args->curptr, args->endptr); args->command = misc_handlers[i].key; handle->key = "???:"; handle->exec = misc_handlers[i].exec; return 0; } } return -1; }