diff options
Diffstat (limited to 'Build/source/texk/dvipdfm-x/spc_pdfm.c')
-rw-r--r-- | Build/source/texk/dvipdfm-x/spc_pdfm.c | 2435 |
1 files changed, 0 insertions, 2435 deletions
diff --git a/Build/source/texk/dvipdfm-x/spc_pdfm.c b/Build/source/texk/dvipdfm-x/spc_pdfm.c deleted file mode 100644 index d45e09330f2..00000000000 --- a/Build/source/texk/dvipdfm-x/spc_pdfm.c +++ /dev/null @@ -1,2435 +0,0 @@ -/* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. - - Copyright (C) 2002-2020 by Jin-Hwan Cho and Shunsaku Hirata, - the dvipdfmx project team. - - Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu> - - 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 <config.h> -#endif - -#include <ctype.h> - -#include "system.h" -#include "mem.h" -#include "error.h" -#include "mfileio.h" - -#include "numbers.h" - -#include "fontmap.h" -#include "dpxfile.h" -#include "dpxutil.h" -#include "dpxconf.h" - -#include "unicode.h" - -#include "pdfobj.h" -#include "pdfparse.h" - -#include "pdfdoc.h" - -#include "pdfximage.h" -#include "pdfdraw.h" -#include "pdfcolor.h" -#include "pdfdev.h" - -#include "specials.h" - -#include "spc_util.h" -#include "spc_pdfm.h" - -#include "dvipdfmx.h" - -#define SPC_PDFM_SUPPORT_ANNOT_TRANS 1 - -struct tounicode { - int cmap_id; - int unescape_backslash; - pdf_obj *taintkeys; /* An array of PDF names. */ -}; - -struct spc_pdf_ -{ - pdf_obj *annot_dict; /* pending annotation dict */ - int lowest_level; /* current min level of outlines */ - 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, - { -1, 0, NULL }, - NULL -}; - -static pdf_obj * -parse_pdf_reference (const char **start, const char *end, void *user_data) -{ - pdf_obj *result = NULL; - char *name; - - skip_white(start, end); - name = parse_opt_ident(start, end); - if (name) { - result = spc_lookup_reference(name); - if (!result) { - WARN("Could not find the named reference (@%s).", name); - } - RELEASE(name); - } else { - WARN("Could not find a reference name."); - result = NULL; - } - - return result; -} - -static int -spc_handler_pdfm__init (void *dp) -{ - struct spc_pdf_ *sd = dp; - /* The folllowing dictionary entry keys are considered as keys for - * text strings. Be sure that string object is NOT always a text string. - */ - static const char *default_taintkeys[] = { - "Title", "Author", "Subject", "Keywords", - "Creator", "Producer", "Contents", "Subj", - "TU", "T", "TM", NULL /* EOD */ - }; - int i; - - sd->annot_dict = NULL; - sd->lowest_level = 255; - sd->cd.taintkeys = pdf_new_array(); - for (i = 0; default_taintkeys[i] != NULL; i++) { - pdf_add_array(sd->cd.taintkeys, - pdf_new_name(default_taintkeys[i])); - } - sd->pageresources = NULL; - - return 0; -} - -static int -spc_handler_pdfm__clean (void *dp) -{ - struct spc_pdf_ *sd = dp; - - if (sd->annot_dict) { - WARN("Unbalanced bann and eann found."); - pdf_release_obj(sd->annot_dict); - } - sd->lowest_level = 255; - sd->annot_dict = NULL; - if (sd->cd.taintkeys) - pdf_release_obj(sd->cd.taintkeys); - sd->cd.taintkeys = NULL; - if (sd->pageresources) - pdf_release_obj(sd->pageresources); - sd->pageresources = NULL; - - return 0; -} - - -int -spc_pdfm_at_begin_document (void) -{ - struct spc_pdf_ *sd = &_pdf_stat; - return spc_handler_pdfm__init(sd); -} - -int -spc_pdfm_at_end_document (void) -{ - struct spc_pdf_ *sd = &_pdf_stat; - return spc_handler_pdfm__clean(sd); -} - -/* Why should we have this kind of things? */ -static int -safeputresdent (pdf_obj *kp, pdf_obj *vp, void *dp) -{ - char *key; - - ASSERT(kp && vp && dp); - - key = pdf_name_value(kp); - if (pdf_lookup_dict(dp, key)) - WARN("Object \"%s\" already defined in dict! (ignored)", key); - else { - pdf_add_dict(dp, - pdf_link_obj(kp), pdf_link_obj(vp)); - } - return 0; -} - -static int -safeputresdict (pdf_obj *kp, pdf_obj *vp, void *dp) -{ - char *key; - pdf_obj *dict; - - ASSERT(kp && vp && dp); - - key = pdf_name_value(kp); - dict = pdf_lookup_dict(dp, key); - - /* Not sure what is the best way to handle this situation */ - if (PDF_OBJ_INDIRECTTYPE(dict)) { - if (PDF_OBJ_INDIRECTTYPE(vp)) { - /* If two indirect objects are pointing the same object, do nothing. */ - if (!pdf_compare_reference(dict, vp)) { - return 0; - } else { - /* otherwise merge the content of old one (see below) */ - dict = pdf_deref_obj(dict); - pdf_release_obj(dict); /* decrement link count */ - } - } - } - - if (pdf_obj_typeof(vp) == PDF_INDIRECT) { - /* Copy the content of old resource category dict (if exists) */ - if (dict) { - pdf_obj *dst = pdf_deref_obj(vp); - if (dst) { - if (pdf_obj_typeof(dst) == PDF_DICT) { - pdf_foreach_dict(dict, safeputresdent, dst); - pdf_release_obj(dst); - } else { - WARN("Invalid type (not DICT) for page/form resource dict entry: key=\"%s\"", key); - pdf_release_obj(dst); - return -1; - } - } - } - pdf_add_dict(dp, pdf_new_name(key), pdf_link_obj(vp)); - } else if (pdf_obj_typeof(vp) == PDF_DICT) { - if (dict) - pdf_foreach_dict(vp, safeputresdent, dict); - else { - pdf_add_dict(dp, pdf_new_name(key), pdf_link_obj(vp)); - } - } else { - WARN("Invalid type (not DICT) for page/form resource dict entry: key=\"%s\"", key); - return -1; - } - - 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) { - WARN("Can't deref object for page resource: %s", category); - r = -1; - } else if (pdf_obj_typeof(obj) != PDF_DICT) { - WARN("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 0 - /* 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: - WARN("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; -} - -/* Dvipdfm specials */ -static int -spc_handler_pdfm_bop (struct spc_env *spe, struct spc_arg *args) -{ - if (args->curptr < args->endptr) { - pdf_doc_set_bop_content(args->curptr, - (int) (args->endptr - args->curptr)); - } - - args->curptr = args->endptr; - - return 0; -} - -static int -spc_handler_pdfm_eop (struct spc_env *spe, struct spc_arg *args) -{ - if (args->curptr < args->endptr) { - pdf_doc_set_eop_content(args->curptr, - (int) (args->endptr - args->curptr)); - } - - args->curptr = args->endptr; - - return 0; -} - -#define streamfiltered(o) \ - (pdf_lookup_dict(pdf_stream_dict((o)), "Filter") ? 1 : 0) - -/* Think what happens if you do - * - * pdf:put @resources << /Font << >> >> - * - */ -static int -spc_handler_pdfm_put (struct spc_env *spe, struct spc_arg *ap) -{ - pdf_obj *obj1, *obj2; /* put obj2 into obj1 */ - char *ident; - int error = 0; - - skip_white(&ap->curptr, ap->endptr); - - ident = parse_opt_ident(&ap->curptr, ap->endptr); - if (!ident) { - spc_warn(spe, "Missing object identifier."); - return -1; - } - obj1 = spc_lookup_object(ident); - if (!obj1) { - spc_warn(spe, "Specified object not exist: %s", ident); - RELEASE(ident); - return -1; - } - skip_white(&ap->curptr, ap->endptr); - - obj2 = parse_pdf_object_extended(&ap->curptr, ap->endptr, NULL, parse_pdf_reference, spe); - if (!obj2) { - spc_warn(spe, "Missing (an) object(s) to put into \"%s\"!", ident); - RELEASE(ident); - return -1; - } - - switch (pdf_obj_typeof(obj1)) { - case PDF_DICT: - if (pdf_obj_typeof(obj2) != PDF_DICT) { - spc_warn(spe, "Inconsistent object type for \"put\" (expecting DICT): %s", ident); - error = -1; - } else { - if (!strcmp(ident, "resources")) - error = pdf_foreach_dict(obj2, safeputresdict, obj1); - else { - pdf_merge_dict(obj1, obj2); - } - } - break; - - case PDF_STREAM: - if (pdf_obj_typeof(obj2) == PDF_DICT) - pdf_merge_dict(pdf_stream_dict(obj1), obj2); - else if (pdf_obj_typeof(obj2) == PDF_STREAM) -#if 0 - { - pdf_merge_dict(pdf_stream_dict(obj1), pdf_stream_dict(obj2)); - pdf_add_stream(obj1, pdf_stream_dataptr(obj2), pdf_stream_length(obj2)); - } -#else - { - spc_warn(spe, "\"put\" operation not supported for STREAM <- STREAM: %s", ident); - error = -1; - } -#endif - else { - spc_warn(spe, "Invalid type: expecting a DICT or STREAM: %s", ident); - error = -1; - } - break; - - case PDF_ARRAY: - /* dvipdfm */ - pdf_add_array(obj1, pdf_link_obj(obj2)); - while (ap->curptr < ap->endptr) { - pdf_obj *obj3 = parse_pdf_object_extended(&ap->curptr, ap->endptr, NULL, parse_pdf_reference, spe); - if (!obj3) - break; - pdf_add_array(obj1, obj3); - skip_white(&ap->curptr, ap->endptr); - } - break; - - default: - spc_warn(spe, "Can't \"put\" object into non-DICT/STREAM/ARRAY type object: %s", ident); - error = -1; - break; - } - pdf_release_obj(obj2); - RELEASE(ident); - - return error; -} - - -/* For pdf:tounicode support - * This feature is provided for convenience. TeX can't do - * input encoding conversion. - */ -#include "cmap.h" - -static size_t -calculate_size_utf16 (const unsigned char *p, const unsigned char *endptr) -{ - size_t len = 0; - - while (p < endptr) { - unsigned char c = *p; - if (c < 0x80) { - len += 2; - p += 1; - } else if (c < 0xE0) { - len += 2; - p += 2; - } else if (c < 0xF0) { - len += 2; - p += 3; - } else if (c < 0xF8) { - len += 4; /* Surrogate */ - p += 4; - } else if (c < 0xFC) { - len += 4; /* Surrogate */ - p += 5; - } else if (c < 0xFE) { - len += 4; /* Surrogate */ - p += 6; - } - } - - return len; -} - -static int -reencode_string_from_utf8_to_utf16be (pdf_obj *instring) -{ - int error = 0; - unsigned char *strptr; - size_t length; - int non_ascii; - const unsigned char *p, *endptr; - - ASSERT(instring); - ASSERT(PDF_OBJ_STRINGTYPE(instring)); - - strptr = pdf_string_value(instring); - length = pdf_string_length(instring); - - /* check if the input string is strictly ASCII */ - p = strptr; - endptr = strptr + length; - non_ascii = 0; - for ( ; p < endptr; p++) { - if (*p > 127) - non_ascii++; - } - if (non_ascii == 0) - return 0; /* no need to reencode ASCII strings */ - - if (!UC_UTF8_is_valid_string(strptr, endptr)) { - error = -1; - } else { - unsigned char *q, *buf, *limptr; - size_t len; - - p = strptr; - /* Rough estimate of output length. */ - len = calculate_size_utf16(p, endptr) + 2; - buf = NEW(len, unsigned char); - q = buf; - limptr = buf + len; - q[0] = 0xfe; q[1] = 0xff; - q += 2; - while (p < endptr && q < limptr && !error) { - int32_t ucv; - size_t count; - - ucv = UC_UTF8_decode_char(&p, endptr); - if (!UC_is_valid(ucv)) { - error = -1; - } else { - count = UC_UTF16BE_encode_char(ucv, &q, limptr); - if (count == 0) { - error = -1; - } - } - } - if (!error) - pdf_set_string(instring, buf, q - buf); - RELEASE(buf); - } - - return error; -} - -static int -reencode_string (CMap *cmap, pdf_obj *instring) -{ - int error = 0; - - if (!instring || !PDF_OBJ_STRINGTYPE(instring)) - return -1; - - if (cmap) { - unsigned char *obuf; - unsigned char *obufcur; - const unsigned char *inbufcur; - int inbufleft, obufleft, obufsize; - - inbufleft = pdf_string_length(instring); - inbufcur = pdf_string_value (instring); - - obufsize = inbufleft * 4 + 2; - obuf = NEW(obufsize, unsigned char); - obuf[0] = 0xfe; - obuf[1] = 0xff; - obufcur = obuf + 2; - obufleft = obufsize - 2; - - CMap_decode(cmap, &inbufcur, &inbufleft, &obufcur, &obufleft); - - if (inbufleft > 0) - error = -1; - if (!error) - pdf_set_string(instring, obuf, obufsize - obufleft); - RELEASE(obuf); - } - - return error; -} - -/* The purpose of this routine is to check if given string object is - * surely an object for *text* strings. It does not do a complete check - * but does a quick check. Please add entries for taintkeys if you have found - * additional dictionary entries which is considered as a text string. - */ -static int -need_reencode (pdf_obj *kp, pdf_obj *vp, struct tounicode *cd) -{ - int r = 0, i; - pdf_obj *tk; - - ASSERT( cd && cd->taintkeys ); - ASSERT( pdf_obj_typeof(kp) == PDF_NAME ); - ASSERT( pdf_obj_typeof(vp) == PDF_STRING ); - - for (i = 0; i < pdf_array_length(cd->taintkeys); i++) { - tk = pdf_get_array(cd->taintkeys, i); - ASSERT( tk && pdf_obj_typeof(tk) == PDF_NAME ); - if (!strcmp(pdf_name_value(kp), pdf_name_value(tk))) { - r = 1; - break; - } - } - if (r) { - /* Check UTF-16BE BOM. */ - if (pdf_string_length(vp) >= 2 && - !memcmp(pdf_string_value(vp), "\xfe\xff", 2)) - r = 0; - } - - return r; -} - -static int -modify_strings (pdf_obj *kp, pdf_obj *vp, void *dp) -{ - int r = 0; /* continue */ - struct tounicode *cd = dp; - - ASSERT( pdf_obj_typeof(kp) == PDF_NAME ); - - switch (pdf_obj_typeof(vp)) { - case PDF_STRING: - if (cd && cd->cmap_id >= 0 && cd->taintkeys) { - CMap *cmap = CMap_cache_get(cd->cmap_id); - if (need_reencode(kp, vp, cd)) - r = reencode_string(cmap, vp); - } else if ((dpx_conf.compat_mode == dpx_mode_xdv_mode) && cd && cd->taintkeys) { - if (need_reencode(kp, vp, cd)) - r = reencode_string_from_utf8_to_utf16be(vp); - } - if (r < 0) /* error occured... */ - WARN("Input string conversion (to UTF16BE) failed for %s...", pdf_name_value(kp)); - break; - /* Array elements are also checked. */ - case PDF_ARRAY: - { - int i; - for (i = 0; i < pdf_array_length(vp); i++) { - pdf_obj *obj; - obj = pdf_get_array(vp, i); - r = modify_strings(kp, obj, dp); - if (r < 0) - break; - } - } - break; - case PDF_DICT: - r = pdf_foreach_dict(vp, modify_strings, dp); - break; - case PDF_STREAM: - r = pdf_foreach_dict(pdf_stream_dict(vp), modify_strings, dp); - break; - } - - return r; -} - -static pdf_obj * -parse_pdf_dict_with_tounicode (const char **pp, const char *endptr, struct tounicode *cd) -{ - pdf_obj *dict; - - /* disable this test for XDV files, as we do UTF8 reencoding with no cmap */ - if ((dpx_conf.compat_mode != dpx_mode_xdv_mode) && cd->cmap_id < 0) { - dict = parse_pdf_object_extended(pp, endptr, NULL, parse_pdf_reference, NULL); - if (dict && !PDF_OBJ_DICTTYPE(dict)) { - WARN("Dictionary type object expected but non-dictionary type found."); - pdf_release_obj(dict); - dict = NULL; - } - } else { - /* :( */ - if (cd && cd->unescape_backslash) { - dict = parse_pdf_tainted_dict(pp, endptr, parse_pdf_reference, NULL); - } else { - dict = parse_pdf_object_extended(pp, endptr, NULL, parse_pdf_reference, NULL); - } - if (dict) { - if (!PDF_OBJ_DICTTYPE(dict)) { - WARN("Dictionary type object expected but non-dictionary type found."); - pdf_release_obj(dict); - dict = NULL; - } else { - pdf_foreach_dict(dict, modify_strings, cd); - } - } - } - - return dict; -} - -static void -set_rect_for_annot (struct spc_env *spe, pdf_rect *rect, transform_info ti) -{ - pdf_coord cp, cp1, cp2, cp3, cp4; - - spc_get_current_point(spe, &cp); - - if (ti.flags & INFO_HAS_USER_BBOX) { - cp1.x = cp.x + ti.bbox.llx; - cp1.y = cp.y + ti.bbox.lly; - cp2.x = cp.x + ti.bbox.urx; - cp2.y = cp.y + ti.bbox.lly; - cp3.x = cp.x + ti.bbox.urx; - cp3.y = cp.y + ti.bbox.ury; - cp4.x = cp.x + ti.bbox.llx; - cp4.y = cp.y + ti.bbox.ury; - } else { - cp1.x = cp.x; - cp1.y = cp.y - spe->mag * ti.depth; - cp2.x = cp.x + spe->mag * ti.width; - cp2.y = cp.y - spe->mag * ti.depth; - cp3.x = cp.x + spe->mag * ti.width; - cp3.y = cp.y + spe->mag * ti.height; - cp4.x = cp.x; - cp4.y = cp.y + 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 = min4(cp1.x, cp2.x, cp3.x, cp4.x); - rect->lly = min4(cp1.y, cp2.y, cp3.y, cp4.y); - rect->urx = max4(cp1.x, cp2.x, cp3.x, cp4.x); - rect->ury = max4(cp1.y, cp2.y, cp3.y, cp4.y); -} - -static int -spc_handler_pdfm_annot (struct spc_env *spe, struct spc_arg *args) -{ - struct spc_pdf_ *sd = &_pdf_stat; - pdf_obj *annot_dict; - pdf_rect rect; - char *ident = NULL; - transform_info ti; - - skip_white(&args->curptr, args->endptr); - if (args->curptr[0] == '@') { - ident = parse_opt_ident(&args->curptr, args->endptr); - skip_white(&args->curptr, args->endptr); - } - - transform_info_clear(&ti); - if (spc_util_read_dimtrns(spe, &ti, args, 0) < 0) { - if (ident) - RELEASE(ident); - return -1; - } - - if ((ti.flags & INFO_HAS_USER_BBOX) && - ((ti.flags & INFO_HAS_WIDTH) || (ti.flags & INFO_HAS_HEIGHT))) { - spc_warn(spe, "You can't specify both bbox and width/height."); - if (ident) - RELEASE(ident); - return -1; - } - - annot_dict = parse_pdf_dict_with_tounicode(&args->curptr, args->endptr, &sd->cd); - if (!annot_dict) { - spc_warn(spe, "Could not find dictionary object."); - if (ident) - RELEASE(ident); - return -1; - } else if (!PDF_OBJ_DICTTYPE(annot_dict)) { - spc_warn(spe, "Invalid type: not dictionary object."); - if (ident) - RELEASE(ident); - pdf_release_obj(annot_dict); - return -1; - } - - set_rect_for_annot(spe, &rect, ti); - - /* Order is important... */ - if (ident) - spc_push_object(spe, ident, pdf_link_obj(annot_dict)); - /* Add this reference. */ - pdf_doc_add_annot(pdf_doc_current_page_number(), &rect, annot_dict, 1); - - if (ident) { - RELEASE(ident); - } - pdf_release_obj(annot_dict); - - return 0; -} - -/* NOTE: This can't have ident. See "Dvipdfm User's Manual". - * 1 Jul. 2020: ident allowed (upon request) - * Only first annotation can be accessed in line break cases. - */ -static int -spc_handler_pdfm_bann (struct spc_env *spe, struct spc_arg *args) -{ - struct spc_pdf_ *sd = &_pdf_stat; - char *ident = NULL; - int error = 0; - - if (sd->annot_dict) { - spc_warn(spe, "Can't begin an annotation when one is pending."); - return -1; - } - - skip_white(&args->curptr, args->endptr); - if (args->curptr[0] == '@') { - ident = parse_opt_ident(&args->curptr, args->endptr); - skip_white(&args->curptr, args->endptr); - } - - sd->annot_dict = parse_pdf_dict_with_tounicode(&args->curptr, args->endptr, &sd->cd); - if (!sd->annot_dict) { - spc_warn(spe, "Ignoring annotation with invalid dictionary."); - if (ident) - RELEASE(ident); - return -1; - } else if (!PDF_OBJ_DICTTYPE(sd->annot_dict)) { - spc_warn(spe, "Invalid type: not a dictionary object."); - pdf_release_obj(sd->annot_dict); - sd->annot_dict = NULL; - if (ident) - RELEASE(ident); - return -1; - } - - error = spc_begin_annot(spe, pdf_link_obj(sd->annot_dict)); - if (ident) { - spc_push_object(spe, ident, pdf_link_obj(sd->annot_dict)); - RELEASE(ident); - } - - return error; -} - -static int -spc_handler_pdfm_eann (struct spc_env *spe, struct spc_arg *args) -{ - struct spc_pdf_ *sd = &_pdf_stat; - int error = 0; - - if (!sd->annot_dict) { - spc_warn(spe, "Tried to end an annotation without starting one!"); - return -1; - } - - error = spc_end_annot(spe); - - pdf_release_obj(sd->annot_dict); - sd->annot_dict = NULL; - - return error; -} - -/* For supporting \phantom within bann-eann. - * - * \special{pdf:xann width 50pt height 8pt depth 1pt} - * - * tells dvipdfmx to extend the current annotation rectangle - * by the amount specified (witdh 50pt, height 8pt, depth 1pt) - * This was introduced since in the following situation - * - * \special{pdf:bann ...}\phantom{Some texts}\special{pdf:eann} - * - * annotation is not created since there is no annotation - * rectangle calculated due to no object being put. - */ -static int -spc_handler_pdfm_xann (struct spc_env *spe, struct spc_arg *args) -{ - pdf_rect rect; - transform_info ti; - - if (!spc_is_tracking_boxes(spe)) { - /* Silently ignore */ - args->curptr = args->endptr; - return 0; - } - - skip_white(&args->curptr, args->endptr); - - transform_info_clear(&ti); - if (spc_util_read_dimtrns(spe, &ti, args, 0) < 0) { - return -1; - } - - if ((ti.flags & INFO_HAS_USER_BBOX) && - ((ti.flags & INFO_HAS_WIDTH) || (ti.flags & INFO_HAS_HEIGHT))) { - spc_warn(spe, "You can't specify both bbox and width/height."); - return -1; - } - - set_rect_for_annot(spe, &rect, ti); - pdf_doc_expand_box(&rect); - - return 0; -} - -/* Color:.... */ -static int -spc_handler_pdfm_bcolor (struct spc_env *spe, struct spc_arg *ap) -{ - int error = 0; - pdf_color fc, sc; - pdf_color *pfc, *psc; - - skip_white(&ap->curptr, ap->endptr); - - pdf_color_get_current(&psc, &pfc); - if (ap->curptr < ap->endptr && - (ap->curptr[0] == 'f' || ap->curptr[0] == 's')) { - pdf_color_copycolor(&sc, psc); - pdf_color_copycolor(&fc, pfc); - while (!error && ap->curptr < ap->endptr) { - if (ap->curptr <= ap->endptr + strlen("fill") && - !memcmp(ap->curptr, "fill", strlen("fill"))) { - ap->curptr += strlen("fill"); - skip_white(&ap->curptr, ap->endptr); - error = spc_util_read_pdfcolor(spe, &fc, ap, pfc); - } else if (ap->curptr <= ap->endptr + strlen("stroke") && - !memcmp(ap->curptr, "stroke", strlen("stroke"))) { - ap->curptr += strlen("stroke"); - skip_white(&ap->curptr, ap->endptr); - error = spc_util_read_pdfcolor(spe, &sc, ap, psc); - } - skip_white(&ap->curptr, ap->endptr); - } - } else { - error = spc_util_read_pdfcolor(spe, &fc, ap, pfc); - if (!error) { - if (ap->curptr < ap->endptr) { - error = spc_util_read_pdfcolor(spe, &sc, ap, psc); - } else { - pdf_color_copycolor(&sc, &fc); - } - } - } - - if (error) { - spc_warn(spe, "Invalid color specification?"); - } else { - skip_white(&ap->curptr, ap->endptr); - pdf_color_push(&sc, &fc); /* save currentcolor */ - } - - return error; -} - -/* - * This special changes the current color without clearing the color stack. - * It therefore differs from "color rgb 1 0 0". - */ -static int -spc_handler_pdfm_scolor (struct spc_env *spe, struct spc_arg *ap) -{ - int error = 0; - pdf_color fc, sc; - pdf_color *pfc, *psc; - - skip_white(&ap->curptr, ap->endptr); - - pdf_color_get_current(&psc, &pfc); - if (ap->curptr < ap->endptr && - (ap->curptr[0] == 'f' || ap->curptr[0] == 's')) { - pdf_color_copycolor(&sc, psc); - pdf_color_copycolor(&fc, pfc); - while (!error && ap->curptr < ap->endptr) { - if (ap->curptr <= ap->endptr + strlen("fill") && - !memcmp(ap->curptr, "fill", strlen("fill"))) { - ap->curptr += strlen("fill"); - skip_white(&ap->curptr, ap->endptr); - error = spc_util_read_pdfcolor(spe, &fc, ap, pfc); - } else if (ap->curptr <= ap->endptr + strlen("stroke") && - !memcmp(ap->curptr, "stroke", strlen("stroke"))) { - ap->curptr += strlen("stroke"); - skip_white(&ap->curptr, ap->endptr); - error = spc_util_read_pdfcolor(spe, &sc, ap, psc); - } - skip_white(&ap->curptr, ap->endptr); - } - } else { - error = spc_util_read_pdfcolor(spe, &fc, ap, pfc); - if (!error) { - if (ap->curptr < ap->endptr) { - error = spc_util_read_pdfcolor(spe, &sc, ap, psc); - } else { - pdf_color_copycolor(&sc, &fc); - } - } - } - - if (error) { - spc_warn(spe, "Invalid color specification?"); - } else { - pdf_color_set(&sc, &fc); - } - - return error; -} - -static int -spc_handler_pdfm_ecolor (struct spc_env *spe, struct spc_arg *args) -{ - pdf_color_pop(); - return 0; -} - - -static int -spc_handler_pdfm_btrans (struct spc_env *spe, struct spc_arg *args) -{ - pdf_tmatrix M; - pdf_coord cp; - transform_info ti; - - transform_info_clear(&ti); - if (spc_util_read_dimtrns(spe, &ti, args, 0) < 0) { - return -1; - } - - /* btrans inside bcontent-econtent bug fix. - * I don't know if this is the only place needs to be fixed... - */ - spc_get_current_point(spe, &cp); - /* Create transformation matrix */ - pdf_copymatrix(&M, &(ti.matrix)); - M.e += ((1.0 - M.a) * cp.x - M.c * cp.y); - M.f += ((1.0 - M.d) * cp.y - M.b * cp.x); - - pdf_dev_gsave(); - pdf_dev_concat(&M); - - return 0; -} - -static int -spc_handler_pdfm_etrans (struct spc_env *spe, struct spc_arg *args) -{ - pdf_dev_grestore(); - - /* - * Unfortunately, the following line is necessary in case - * of a color change inside of the save/restore pair. - * (Font changes are automatically corrected by pdf_dev_grestore().) - * Anything that was done there must be redone, so in effect, - * we make no assumptions about what fonts. We act like we are - * starting a new page. - */ - pdf_dev_reset_color(0); - pdf_dev_reset_xgstate(0); - - return 0; -} - -static int -spc_handler_pdfm_outline (struct spc_env *spe, struct spc_arg *args) -{ - struct spc_pdf_ *sd = &_pdf_stat; - pdf_obj *item_dict, *tmp; - int level, is_open = -1; - int current_depth; - - skip_white(&args->curptr, args->endptr); - - /* - * pdf:outline is extended to support open/close feature - * - * pdf:outline 1 ... (as DVIPDFM) - * pdf:outline [] 1 ... (open bookmark) - * pdf:outline [-] 1 ... (closed bookmark) - */ - if (args->curptr+3 < args->endptr && *args->curptr == '[') { - args->curptr++; - if (*args->curptr == '-') { - args->curptr++; - } else { - is_open = 1; - } - args->curptr++; - } - skip_white(&args->curptr, args->endptr); - - tmp = parse_pdf_object(&args->curptr, args->endptr, NULL); - if (!tmp) { - spc_warn(spe, "Missing number for outline item depth."); - return -1; - } else if (!PDF_OBJ_NUMBERTYPE(tmp)) { - pdf_release_obj(tmp); - spc_warn(spe, "Expecting number for outline item depth."); - return -1; - } - - item_dict = NULL; - - level = (int) pdf_number_value(tmp); - pdf_release_obj(tmp); - - /* What is this? Starting at level 3 and can go down to level 1? - * - * Here is the original comment: - * Make sure we know where the starting level is - * - * NOTE: added - * We need this for converting pages from 3rd to... :( - */ - sd->lowest_level = MIN(sd->lowest_level, level); - - level += 1 - sd->lowest_level; - - item_dict = parse_pdf_dict_with_tounicode(&args->curptr, args->endptr, &sd->cd); - if (!item_dict) { - spc_warn(spe, "Ignoring invalid dictionary."); - return -1; - } - current_depth = pdf_doc_bookmarks_depth(); - if (current_depth > level) { - while (current_depth-- > level) - pdf_doc_bookmarks_up(); - } else if (current_depth < level) { - while (current_depth++ < level) - pdf_doc_bookmarks_down(); - } - - pdf_doc_bookmarks_add(item_dict, is_open); - - return 0; -} - -static int -spc_handler_pdfm_article (struct spc_env *spe, struct spc_arg *args) -{ - struct spc_pdf_ *sd = &_pdf_stat; - char *ident; - pdf_obj *info_dict; - - skip_white (&args->curptr, args->endptr); - - ident = parse_opt_ident(&args->curptr, args->endptr); - if (!ident) { - spc_warn(spe, "Article name expected but not found."); - return -1; - } - - info_dict = parse_pdf_dict_with_tounicode(&args->curptr, args->endptr, &sd->cd); - if (!info_dict) { - spc_warn(spe, "Ignoring article with invalid info dictionary."); - RELEASE(ident); - return -1; - } - - pdf_doc_begin_article(ident, pdf_link_obj(info_dict)); - spc_push_object(spe, ident, info_dict); - RELEASE(ident); - - return 0; -} - -static int -spc_handler_pdfm_bead (struct spc_env *spe, struct spc_arg *args) -{ - struct spc_pdf_ *sd = &_pdf_stat; - pdf_obj *article; - pdf_obj *article_info; - char *article_name; - pdf_rect rect; - int page_no; - transform_info ti; - - skip_white(&args->curptr, args->endptr); - - if (args->curptr[0] != '@') { - spc_warn(spe, "Article identifier expected but not found."); - return -1; - } - - article_name = parse_opt_ident(&args->curptr, args->endptr); - if (!article_name) { - spc_warn(spe, "Article reference expected but not found."); - return -1; - } - - /* If okay so far, try to get a bounding box */ - transform_info_clear(&ti); - if (spc_util_read_dimtrns(spe, &ti, args, 0) < 0) { - RELEASE(article_name); - return -1; - } - - if ((ti.flags & INFO_HAS_USER_BBOX) && - ((ti.flags & INFO_HAS_WIDTH) || (ti.flags & INFO_HAS_HEIGHT))) { - spc_warn(spe, "You can't specify both bbox and width/height."); - RELEASE(article_name); - return -1; - } - - skip_white(&args->curptr, args->endptr); - if (args->curptr[0] != '<') { - article_info = pdf_new_dict(); - } else { - article_info = parse_pdf_dict_with_tounicode(&args->curptr, args->endptr, &sd->cd); - if (!article_info) { - spc_warn(spe, "Error in reading dictionary."); - RELEASE(article_name); - return -1; - } - } - - /* Does this article exist yet */ - article = spc_lookup_object(article_name); - if (article) { - pdf_merge_dict (article, article_info); - pdf_release_obj(article_info); - } else { - pdf_doc_begin_article(article_name, pdf_link_obj(article_info)); - spc_push_object(spe, article_name, article_info); - } - page_no = pdf_doc_current_page_number(); - set_rect_for_annot(spe, &rect, ti); - pdf_doc_add_bead(article_name, NULL, page_no, &rect); - - RELEASE(article_name); - return 0; -} - -static int -spc_handler_pdfm_image (struct spc_env *spe, struct spc_arg *args) -{ - int xobj_id; - char *ident = NULL; - pdf_obj *fspec; - transform_info ti; - load_options options = {1, 0, NULL}; - - skip_white(&args->curptr, args->endptr); - if (args->curptr[0] == '@') { - ident = parse_opt_ident(&args->curptr, args->endptr); - skip_white(&args->curptr, args->endptr); - } - - /* 2015/12/29 - * There should not be "page" and "pagebox" in read_dimtrns(). - * It is for reading "dimensions" and "transformations" and "page" is - * completely unrelated. - */ - transform_info_clear(&ti); - if (spc_util_read_blahblah(spe, &ti, - &options.page_no, &options.bbox_type, args) < 0) { - spc_warn(spe, "Reading option field in pdf:image failed."); - if (ident) - RELEASE(ident); - return -1; - } - - skip_white(&args->curptr, args->endptr); - fspec = parse_pdf_object(&args->curptr, args->endptr, NULL); - if (!fspec) { - spc_warn(spe, "Missing filename string for pdf:image."); - if (ident) - RELEASE(ident); - return -1; - } else if (!PDF_OBJ_STRINGTYPE(fspec)) { - spc_warn(spe, "Missing filename string for pdf:image."); - pdf_release_obj(fspec); - if (ident) - RELEASE(ident); - return -1; - } - - skip_white(&args->curptr, args->endptr); - if (args->curptr < args->endptr) { - options.dict = parse_pdf_object_extended(&args->curptr, args->endptr, NULL, parse_pdf_reference, spe); - } - - xobj_id = pdf_ximage_load_image(ident, pdf_string_value(fspec), options); - - if (xobj_id < 0) { - spc_warn(spe, "Could not find image resource..."); - pdf_release_obj(fspec); - if (ident) - RELEASE(ident); - return -1; - } - - if (!(ti.flags & INFO_DO_HIDE)) { - spc_put_image(spe, xobj_id, &ti, spe->x_user, spe->y_user); - } - - if (ident) { - if ((dpx_conf.compat_mode == dpx_mode_compat_mode) && - pdf_ximage_get_subtype(xobj_id) == PDF_XOBJECT_TYPE_IMAGE) - pdf_ximage_set_attr(xobj_id, 1, 1, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0); - RELEASE(ident); - } - - pdf_release_obj(fspec); - - return 0; -} - -/* Use do_names instead. */ -static int -spc_handler_pdfm_dest (struct spc_env *spe, struct spc_arg *args) -{ - pdf_obj *name, *array; - - skip_white(&args->curptr, args->endptr); - - name = parse_pdf_object(&args->curptr, args->endptr, NULL); - if (!name) { - spc_warn(spe, "PDF string expected for destination name but not found."); - return -1; - } else if (!PDF_OBJ_STRINGTYPE(name)) { - spc_warn(spe, "PDF string expected for destination name but invalid type."); - pdf_release_obj(name); - return -1; - } - -#if 0 - if ((dpx_conf.compat_mode == dpx_mode_xdv_mode) && maybe_reencode_utf8(name) < 0) - WARN("Failed to convert input string to UTF16..."); -#endif - - array = parse_pdf_object_extended(&args->curptr, args->endptr, NULL, parse_pdf_reference, spe); - if (!array) { - spc_warn(spe, "No destination specified for pdf:dest."); - pdf_release_obj(name); - return -1; - } else if (!PDF_OBJ_ARRAYTYPE(array)) { - spc_warn(spe, "Destination not specified as an array object!"); - pdf_release_obj(name); - pdf_release_obj(array); - return -1; - } - - pdf_doc_add_names("Dests", - pdf_string_value (name), - pdf_string_length(name), - array); - pdf_release_obj(name); - - return 0; -} - -static int -spc_handler_pdfm_names (struct spc_env *spe, struct spc_arg *args) -{ - pdf_obj *category, *key, *value, *tmp; - int i, size; - - category = parse_pdf_object(&args->curptr, args->endptr, NULL); - if (!category) { - spc_warn(spe, "PDF name expected but not found."); - return -1; - } else if (!PDF_OBJ_NAMETYPE(category)) { - spc_warn(spe, "PDF name expected but not found."); - pdf_release_obj(category); - return -1; - } - - tmp = parse_pdf_object_extended(&args->curptr, args->endptr, NULL, parse_pdf_reference, spe); - if (!tmp) { - spc_warn(spe, "PDF object expected but not found."); - pdf_release_obj(category); - return -1; - } else if (PDF_OBJ_ARRAYTYPE(tmp)) { - size = pdf_array_length(tmp); - if (size % 2 != 0) { - spc_warn(spe, "Array size not multiple of 2 for pdf:names."); - pdf_release_obj(category); - pdf_release_obj(tmp); - return -1; - } - - for (i = 0; i < size / 2; i++) { - key = pdf_get_array(tmp, 2 * i); - value = pdf_get_array(tmp, 2 * i + 1); - if (!PDF_OBJ_STRINGTYPE(key)) { - spc_warn(spe, "Name tree key must be string."); - pdf_release_obj(category); - pdf_release_obj(tmp); - return -1; - } else if (pdf_doc_add_names(pdf_name_value(category), - pdf_string_value (key), - pdf_string_length(key), - pdf_link_obj(value)) < 0) { - spc_warn(spe, "Failed to add Name tree entry..."); - pdf_release_obj(category); - pdf_release_obj(tmp); - return -1; - } - } - pdf_release_obj(tmp); - } else if (PDF_OBJ_STRINGTYPE(tmp)) { - key = tmp; - value = parse_pdf_object_extended(&args->curptr, args->endptr, NULL, parse_pdf_reference, spe); - if (!value) { - pdf_release_obj(category); - pdf_release_obj(key); - spc_warn(spe, "PDF object expected but not found."); - return -1; - } - if (pdf_doc_add_names(pdf_name_value(category), - pdf_string_value (key), - pdf_string_length(key), - value) < 0) { - spc_warn(spe, "Failed to add Name tree entry..."); - pdf_release_obj(category); - pdf_release_obj(key); - return -1; - } - pdf_release_obj(key); - } else { - pdf_release_obj(tmp); - pdf_release_obj(category); - spc_warn(spe, "Invalid object type for pdf:names."); - return -1; - } - pdf_release_obj(category); - - return 0; -} - -static int -spc_handler_pdfm_docinfo (struct spc_env *spe, struct spc_arg *args) -{ - struct spc_pdf_ *sd = &_pdf_stat; - pdf_obj *docinfo, *dict; - - dict = parse_pdf_dict_with_tounicode(&args->curptr, args->endptr, &sd->cd); - if (!dict) { - spc_warn(spe, "Dictionary object expected but not found."); - return -1; - } - - docinfo = pdf_doc_docinfo(); - pdf_merge_dict(docinfo, dict); - pdf_release_obj(dict); - - return 0; -} - -static int -spc_handler_pdfm_docview (struct spc_env *spe, struct spc_arg *args) -{ - struct spc_pdf_ *sd = &_pdf_stat; - pdf_obj *catalog, *dict; - pdf_obj *pref_old, *pref_add; - - dict = parse_pdf_dict_with_tounicode(&args->curptr, args->endptr, &sd->cd); - if (!dict) { - spc_warn(spe, "Dictionary object expected but not found."); - return -1; - } - - catalog = pdf_doc_catalog(); - /* Avoid overriding whole ViewerPreferences */ - pref_old = pdf_lookup_dict(catalog, "ViewerPreferences"); - pref_add = pdf_lookup_dict(dict, "ViewerPreferences"); - if (pref_old && pref_add) { - pdf_merge_dict (pref_old, pref_add); - pdf_remove_dict(dict, "ViewerPreferences"); - } - pdf_merge_dict (catalog, dict); - pdf_release_obj(dict); - - return 0; -} - -static int -spc_handler_pdfm_close (struct spc_env *spe, struct spc_arg *args) -{ - char *ident; - - skip_white(&args->curptr, args->endptr); - ident = parse_opt_ident(&args->curptr, args->endptr); - if (ident) { - spc_flush_object(spe, ident); - RELEASE(ident); - } else { /* Close all? */ - spc_warn(spe, "pdf:close without an argument no longer supported!"); - spc_clear_objects(spe); - } - - return 0; -} - -static int -spc_handler_pdfm_object (struct spc_env *spe, struct spc_arg *args) -{ - char *ident; - pdf_obj *object; - - skip_white(&args->curptr, args->endptr); - ident = parse_opt_ident(&args->curptr, args->endptr); - if (!ident) { - spc_warn(spe, "Could not find a object identifier."); - return -1; - } - - object = parse_pdf_object_extended(&args->curptr, args->endptr, NULL, parse_pdf_reference, spe); - if (!object) { - spc_warn(spe, "Could not find an object definition for \"%s\".", ident); - RELEASE(ident); - return -1; - } else { - spc_push_object(spe, ident, object); - } - RELEASE(ident); - - return 0; -} - -static int -spc_handler_pdfm_content (struct spc_env *spe, struct spc_arg *args) -{ - int len = 0; - - skip_white(&args->curptr, args->endptr); - if (args->curptr < args->endptr) { - pdf_tmatrix M; - pdf_coord cp; - - spc_get_current_point(spe, &cp); - pdf_setmatrix(&M, 1.0, 0.0, 0.0, 1.0, cp.x, cp.y); - work_buffer[len++] = ' '; - work_buffer[len++] = 'q'; - work_buffer[len++] = ' '; - len += pdf_sprint_matrix(work_buffer + len, &M); - work_buffer[len++] = ' '; - work_buffer[len++] = 'c'; - work_buffer[len++] = 'm'; - work_buffer[len++] = ' '; - - pdf_doc_add_page_content(work_buffer, len); /* op: q cm */ - len = (int) (args->endptr - args->curptr); - pdf_doc_add_page_content(args->curptr, len); /* op: ANY */ - pdf_doc_add_page_content(" Q", 2); /* op: Q */ - } - args->curptr = args->endptr; - - return 0; -} - -static int -spc_handler_pdfm_literal (struct spc_env *spe, struct spc_arg *args) -{ - int direct = 0; - - skip_white(&args->curptr, args->endptr); - while (args->curptr < args->endptr) { - if (args->curptr + 7 <= args->endptr && - !strncmp(args->curptr, "reverse", 7)) { - args->curptr += 7; - WARN("The special \"pdf:literal reverse ...\" is no longer supported.\nIgnore the \"reverse\" option."); - } else if (args->curptr + 6 <= args->endptr && - !strncmp(args->curptr, "direct", 6)) { - direct = 1; - args->curptr += 6; - } else { - break; - } - skip_white(&args->curptr, args->endptr); - } - - if (args->curptr < args->endptr) { - pdf_tmatrix M; - pdf_coord cp; - - spc_get_current_point(spe, &cp); - 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); /* op: */ - pdf_doc_add_page_content(args->curptr, (int) (args->endptr - args->curptr)); /* op: ANY */ - if (!direct) { - M.e = -cp.x; M.f = -cp.y; - pdf_dev_concat(&M); - } - } - - args->curptr = args->endptr; - - return 0; -} - -static int -spc_handler_pdfm_bcontent (struct spc_env *spe, struct spc_arg *args) -{ - pdf_tmatrix M; - double xpos, ypos; - - pdf_dev_gsave(); - spc_get_coord(spe, &xpos, &ypos); - pdf_setmatrix(&M, 1.0, 0.0, 0.0, 1.0, spe->x_user - xpos, spe->y_user - ypos); - pdf_dev_concat(&M); - spc_push_coord(spe, spe->x_user, spe->y_user); - - return 0; -} - -static int -spc_handler_pdfm_econtent (struct spc_env *spe, struct spc_arg *args) -{ - spc_pop_coord(spe); - pdf_dev_grestore(); - pdf_dev_reset_color(0); - pdf_dev_reset_xgstate(0); - - return 0; -} - -static int -spc_handler_pdfm_code (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 int -spc_handler_pdfm_do_nothing (struct spc_env *spe, struct spc_arg *args) -{ - args->curptr = args->endptr; - return 0; -} - -#define STRING_STREAM 0 -#define FILE_STREAM 1 - -static int -spc_handler_pdfm_stream_with_type (struct spc_env *spe, struct spc_arg *args, int type) -{ - pdf_obj *fstream; - int nb_read; - char *ident, *instring, *fullname; - pdf_obj *tmp; - FILE *fp; - - skip_white(&args->curptr, args->endptr); - - ident = parse_opt_ident(&args->curptr, args->endptr); - if (!ident) { - spc_warn(spe, "Missing objname for pdf:(f)stream."); - return -1; - } - - skip_white(&args->curptr, args->endptr); - - tmp = parse_pdf_object(&args->curptr, args->endptr, NULL); - if (!tmp) { - spc_warn(spe, "Missing input string for pdf:(f)stream."); - RELEASE(ident); - return -1; - } else if (!PDF_OBJ_STRINGTYPE(tmp)) { - spc_warn(spe, "Invalid type of input string for pdf:(f)stream."); - pdf_release_obj(tmp); - RELEASE(ident); - return -1; - } - - instring = pdf_string_value(tmp); - - switch (type) { - case FILE_STREAM: - if (!instring) { - spc_warn(spe, "Missing filename for pdf:fstream."); - pdf_release_obj(tmp); - RELEASE(ident); - return -1; - } - fullname = kpse_find_pict(instring); - if (!fullname) { - spc_warn(spe, "File \"%s\" not found.", instring); - pdf_release_obj(tmp); - RELEASE(ident); - return -1; - } - fp = DPXFOPEN(fullname, DPX_RES_TYPE_BINARY); - if (!fp) { - spc_warn(spe, "Could not open file: %s", instring); - pdf_release_obj(tmp); - RELEASE(ident); - RELEASE(fullname); - return -1; - } - fstream = pdf_new_stream(STREAM_COMPRESS); - while ((nb_read = - fread(work_buffer, sizeof(char), WORK_BUFFER_SIZE, fp)) > 0) - pdf_add_stream(fstream, work_buffer, nb_read); - MFCLOSE(fp); - RELEASE(fullname); - break; - case STRING_STREAM: - fstream = pdf_new_stream(STREAM_COMPRESS); - pdf_add_stream(fstream, pdf_string_value(tmp), pdf_string_length(tmp)); - break; - default: - pdf_release_obj(tmp); - RELEASE(ident); - return -1; - } - pdf_release_obj(tmp); - - /* - * Optional dict. - * - * TODO: check Length, Filter... - */ - skip_white(&args->curptr, args->endptr); - - if (args->curptr[0] == '<') { - pdf_obj *stream_dict; - - stream_dict = pdf_stream_dict(fstream); - - tmp = parse_pdf_object_extended(&args->curptr, args->endptr, NULL, parse_pdf_reference, spe); - if (!tmp) { - spc_warn(spe, "Parsing dictionary failed."); - pdf_release_obj(fstream); - RELEASE(ident); - return -1; - } else if (!PDF_OBJ_DICTTYPE(tmp)) { - spc_warn(spe, "Expecting dictionary type object but non-dictionary type found."); - pdf_release_obj(fstream); - pdf_release_obj(tmp); - RELEASE(ident); - return -1; - } - if (pdf_lookup_dict(tmp, "Length")) { - pdf_remove_dict(tmp, "Length"); - } else if (pdf_lookup_dict(tmp, "Filter")) { - pdf_remove_dict(tmp, "Filter"); - } - pdf_merge_dict(stream_dict, tmp); - pdf_release_obj(tmp); - } - - /* Users should explicitly close this. */ - spc_push_object(spe, ident, fstream); - RELEASE(ident); - - return 0; -} - -/* - * STREAM: Create a PDF stream object from an input string. - * - * pdf: stream @objname (input_string) [PDF_DICT] - */ -static int -spc_handler_pdfm_stream (struct spc_env *spe, struct spc_arg *args) -{ - return spc_handler_pdfm_stream_with_type (spe, args, STRING_STREAM); -} - -/* - * FSTREAM: Create a PDF stream object from an existing file. - * - * pdf: fstream @objname (filename) [PDF_DICT] - */ -static int -spc_handler_pdfm_fstream (struct spc_env *spe, struct spc_arg *args) -{ - return spc_handler_pdfm_stream_with_type (spe, args, FILE_STREAM); -} - -/* Grab page content as follows: - * - * Reference point = (x_user, y_user) - * - * Case 1. \special{pdf:bxobj @obj width WD height HT depth DP} - * - * Grab the box with the lower-left corner (x_user, y_user-DP) - * and the upper right corner (x_user+WD, y_user+HT). - * - * Case 2. \special{pdf:bxobj @obj bbox LLX LLY URX, URY} - * - * Grab the box with the lower-left corner (x_user+LLX, y_user+LLY) - * and the upper right corner (x_user+URX, y_user+URY). - * - * Note that scale, xscale, yscale, xoffset, yoffset options are ignored. - */ -static int -spc_handler_pdfm_bform (struct spc_env *spe, struct spc_arg *args) -{ - int error; - char *ident; - pdf_rect cropbox; - pdf_coord cp; - transform_info ti; - - skip_white(&args->curptr, args->endptr); - - ident = parse_opt_ident(&args->curptr, args->endptr); - if (!ident) { - spc_warn(spe, "A form XObject must have name."); - return -1; - } - - transform_info_clear(&ti); - if (spc_util_read_dimtrns(spe, &ti, args, 0) < 0) { - RELEASE(ident); - return -1; - } - - /* A XForm with zero dimension results in a non-invertible transformation - * matrix. And it may result in unpredictable behaviour. It might be an - * error in Acrobat. Bounding box with zero dimension may cause division - * by zero. - */ - if (ti.flags & INFO_HAS_USER_BBOX) { - if (ti.bbox.urx - ti.bbox.llx == 0.0 || - ti.bbox.ury - ti.bbox.lly == 0.0) { - spc_warn(spe, "Bounding box has a zero dimension."); - RELEASE(ident); - return -1; - } - cropbox.llx = ti.bbox.llx; - cropbox.lly = ti.bbox.lly; - cropbox.urx = ti.bbox.urx; - cropbox.ury = ti.bbox.ury; - } else { - if (ti.width == 0.0 || - ti.depth + ti.height == 0.0) { - spc_warn(spe, "Bounding box has a zero dimension."); - RELEASE(ident); - return -1; - } - cropbox.llx = 0.0; - cropbox.lly = -ti.depth; - cropbox.urx = ti.width; - cropbox.ury = ti.height; - } - - spc_get_current_point(spe, &cp); - error = spc_begin_form(spe, ident, cp, &cropbox); - - if (error) - spc_warn(spe, "Couldn't start form object."); - - RELEASE(ident); - - return error; -} - -/* An extra dictionary after exobj must be merged to the form dictionary, - * not resource dictionary. - * Please use pdf:put @resources (before pdf:exobj) instead. - */ -static int -spc_handler_pdfm_eform (struct spc_env *spe, struct spc_arg *args) -{ - int error; - pdf_obj *attrib = NULL; - struct spc_pdf_ *sd = &_pdf_stat; - - skip_white(&args->curptr, args->endptr); - - if (args->curptr < args->endptr) { - attrib = parse_pdf_object_extended(&args->curptr, args->endptr, NULL, parse_pdf_reference, spe); - if (attrib && !PDF_OBJ_DICTTYPE(attrib)) { - pdf_release_obj(attrib); - attrib = NULL; - } - } - /* pageresources here too */ - if (sd->pageresources) { - pdf_foreach_dict(sd->pageresources, forallresourcecategory, NULL); - } - error = spc_end_form(spe, attrib); - - return error; -} - -/* Saved XObjects can be used as follows: - * - * Reference point = (x_user, y_user) - * - * Case 1. \special{pdf:uxobj @obj width WD height HT depth DP} - * - * Scale the XObject to fit in the box - * [x_user, y_user-DP, x_user+WD, y_user+HT]. - * - * Case 2. \special{pdf:uxobj @obj xscale XS yscale YS} - * - * Scale the XObject with XS and YS. Note that width and xscale - * or height and yscale cannot be used together. - * - * Case 3. \special{pdf:bxobj @obj bbox LLX LLY URX, URY} - * - * Scale the XObject to fit in the box - * [x_user+LLX, y_user+LLY, x_user+URX, y_user+URY]. - * - * Note that xoffset and yoffset moves the reference point where the - * lower-left corner of the XObject will be put. - */ -static int -spc_handler_pdfm_uxobj (struct spc_env *spe, struct spc_arg *args) -{ - int xobj_id; - char *ident; - transform_info ti; - - skip_white(&args->curptr, args->endptr); - - ident = parse_opt_ident(&args->curptr, args->endptr); - if (!ident) { - spc_warn(spe, "No object identifier given."); - return -1; - } - - transform_info_clear(&ti); - if (args->curptr < args->endptr) { - if (spc_util_read_dimtrns(spe, &ti, args, 0) < 0) { - RELEASE(ident); - return -1; - } - } - - xobj_id = pdf_ximage_findresource(ident); - if (xobj_id < 0) { - xobj_id = pdf_ximage_reserve(ident); - } - - spc_put_image(spe, xobj_id, &ti, spe->x_user, spe->y_user); - RELEASE(ident); - - return 0; -} - -static int -spc_handler_pdfm_link (struct spc_env *spe, struct spc_arg *args) -{ - return spc_resume_annot(spe); -} - -static int -spc_handler_pdfm_nolink (struct spc_env *spe, struct spc_arg *args) -{ - return spc_suspend_annot(spe); -} - - - -/* Handled at BOP */ -static int -spc_handler_pdfm_pagesize (struct spc_env *spe, struct spc_arg *args) -{ - args->curptr = args->endptr; - - return 0; -} - -/* Please remove this. - * This should be handled before processing pages! - */ -static int -spc_handler_pdfm_bgcolor (struct spc_env *spe, struct spc_arg *args) -{ - int error; - pdf_color colorspec; - - error = spc_util_read_pdfcolor(spe, &colorspec, args, NULL); - if (error) - spc_warn(spe, "No valid color specified?"); - else { - pdf_doc_set_bgcolor(&colorspec); - } - - 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[THEBUFFLENGTH]; - const char *p; - char *q; - int count; - - skip_white(&ap->curptr, ap->endptr); - if (ap->curptr >= ap->endptr) { - spc_warn(spe, "Empty mapline special?"); - return -1; - } - - opchr = ap->curptr[0]; - if (opchr == '-' || opchr == '+') - ap->curptr++; - - skip_white(&ap->curptr, ap->endptr); - - switch (opchr) { - case '-': - map_name = parse_ident(&ap->curptr, ap->endptr); - if (map_name) { - pdf_remove_fontmap_record(map_name); - RELEASE(map_name); - } else { - spc_warn(spe, "Invalid fontmap line: Missing TFM name."); - error = -1; - } - break; - default: - p = ap->curptr; - q = buffer; - 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); - error = pdf_read_fontmap_line(mrec, buffer, (int) (ap->endptr - ap->curptr), is_pdfm_mapline(buffer)); - if (error) - spc_warn(spe, "Invalid fontmap line."); - else if (opchr == '+') - pdf_append_fontmap_record(mrec->map_name, mrec); - else - pdf_insert_fontmap_record(mrec->map_name, mrec); - pdf_clear_fontmap_record(mrec); - RELEASE(mrec); - break; - } - if (!error) - ap->curptr = ap->endptr; - - return 0; -} - -static int -spc_handler_pdfm_mapfile (struct spc_env *spe, struct spc_arg *args) -{ - char *mapfile; - int mode, error = 0; - - skip_white(&args->curptr, args->endptr); - if (args->curptr >= args->endptr) - return 0; - - switch (args->curptr[0]) { - case '-': - mode = FONTMAP_RMODE_REMOVE; - args->curptr++; - break; - case '+': - mode = FONTMAP_RMODE_APPEND; - args->curptr++; - break; - default: - mode = FONTMAP_RMODE_REPLACE; - break; - } - - mapfile = parse_val_ident(&args->curptr, args->endptr); - if (!mapfile) { - spc_warn(spe, "No fontmap file specified."); - return -1; - } else { - error = pdf_load_fontmap_file(mapfile, mode); - } - RELEASE(mapfile); - - return error; -} - - -static int -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; - sd->cd.unescape_backslash = 0; - - skip_white(&args->curptr, args->endptr); - if (args->curptr >= args->endptr) { - spc_warn(spe, "Missing CMap name for pdf:tounicode."); - return -1; - } - - /* _FIXME_ - * Any valid char allowed for PDF name object should be allowed here. - * The argument to this special should be a PDF name obejct. - * But it's too late to change this special. - */ - cmap_name = parse_ident(&args->curptr, args->endptr); - if (!cmap_name) { - spc_warn(spe, "Missing ToUnicode mapping name..."); - return -1; - } - - sd->cd.cmap_id = CMap_cache_find(cmap_name); - if (sd->cd.cmap_id < 0) { - spc_warn(spe, "Failed to load ToUnicode mapping: %s", cmap_name); - RELEASE(cmap_name); - return -1; - } - - /* Shift-JIS like encoding may contain backslash in 2nd byte. - * WARNING: This will add nasty extension to PDF parser. - */ - if (sd->cd.cmap_id >= 0) { - if (strstr(cmap_name, "RKSJ") || - strstr(cmap_name, "B5") || - strstr(cmap_name, "GBK") || - strstr(cmap_name, "KSC")) - sd->cd.unescape_backslash = 1; - } - RELEASE(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_extended(&args->curptr, args->endptr, NULL, parse_pdf_reference, spe); - 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_pdfm_bxgstate (struct spc_env *spe, struct spc_arg *args) -{ - pdf_obj *obj; - - skip_white(&args->curptr, args->endptr); - obj = parse_pdf_object_extended(&args->curptr, args->endptr, NULL, parse_pdf_reference, spe); - if (!obj) { - spc_warn(spe, "Could not find an object definition."); - return -1; - } else if (!PDF_OBJ_DICTTYPE(obj)) { - spc_warn(spe, "Parsed object for ExtGState not a dictionary object!"); - pdf_release_obj(obj); - return -1; - } - pdf_dev_xgstate_push(obj); - - skip_white(&args->curptr, args->endptr); - - return 0; -} - -static int -spc_handler_pdfm_exgstate (struct spc_env *spe, struct spc_arg *args) -{ - pdf_dev_xgstate_pop(); - skip_white(&args->curptr, args->endptr); - 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}, - {"annotate", spc_handler_pdfm_annot}, - {"annot", spc_handler_pdfm_annot}, - {"ann", spc_handler_pdfm_annot}, - - {"outline", spc_handler_pdfm_outline}, - {"out", spc_handler_pdfm_outline}, - - {"article", spc_handler_pdfm_article}, - {"art", spc_handler_pdfm_article}, - - {"bead", spc_handler_pdfm_bead}, - {"thread", spc_handler_pdfm_bead}, - - {"destination", spc_handler_pdfm_dest}, - {"dest", spc_handler_pdfm_dest}, - - - {"object", spc_handler_pdfm_object}, - {"obj", spc_handler_pdfm_object}, - - - {"docinfo", spc_handler_pdfm_docinfo}, - {"docview", spc_handler_pdfm_docview}, - - {"content", spc_handler_pdfm_content}, - {"put", spc_handler_pdfm_put}, - {"close", spc_handler_pdfm_close}, - {"bop", spc_handler_pdfm_bop}, - {"eop", spc_handler_pdfm_eop}, - - {"image", spc_handler_pdfm_image}, - {"img", spc_handler_pdfm_image}, - {"epdf", spc_handler_pdfm_image}, - - {"link", spc_handler_pdfm_link}, - {"nolink", spc_handler_pdfm_nolink}, - - {"begincolor", spc_handler_pdfm_bcolor}, - {"bcolor", spc_handler_pdfm_bcolor}, - {"bc", spc_handler_pdfm_bcolor}, - - {"setcolor", spc_handler_pdfm_scolor}, - {"scolor", spc_handler_pdfm_scolor}, - {"sc", spc_handler_pdfm_scolor}, - - {"endcolor", spc_handler_pdfm_ecolor}, - {"ecolor", spc_handler_pdfm_ecolor}, - {"ec", spc_handler_pdfm_ecolor}, - - {"begingray", spc_handler_pdfm_bcolor}, - {"bgray", spc_handler_pdfm_bcolor}, - {"bg", spc_handler_pdfm_bcolor}, - - {"endgray", spc_handler_pdfm_ecolor}, - {"egray", spc_handler_pdfm_ecolor}, - {"eg", spc_handler_pdfm_ecolor}, - - {"bgcolor", spc_handler_pdfm_bgcolor}, - {"bgc", spc_handler_pdfm_bgcolor}, - {"bbc", spc_handler_pdfm_bgcolor}, - {"bbg", spc_handler_pdfm_bgcolor}, - - {"pagesize", spc_handler_pdfm_pagesize}, - - {"bannot", spc_handler_pdfm_bann}, - {"beginann", spc_handler_pdfm_bann}, - {"bann", spc_handler_pdfm_bann}, - - {"eannot", spc_handler_pdfm_eann}, - {"endann", spc_handler_pdfm_eann}, - {"eann", spc_handler_pdfm_eann}, - - {"btrans", spc_handler_pdfm_btrans}, - {"begintransform", spc_handler_pdfm_btrans}, - {"begintrans", spc_handler_pdfm_btrans}, - {"bt", spc_handler_pdfm_btrans}, - - {"etrans", spc_handler_pdfm_etrans}, - {"endtransform", spc_handler_pdfm_etrans}, - {"endtrans", spc_handler_pdfm_etrans}, - {"et", spc_handler_pdfm_etrans}, - - {"bform", spc_handler_pdfm_bform}, - {"beginxobj", spc_handler_pdfm_bform}, - {"bxobj", spc_handler_pdfm_bform}, - - {"eform", spc_handler_pdfm_eform}, - {"endxobj", spc_handler_pdfm_eform}, - {"exobj", spc_handler_pdfm_eform}, - - {"usexobj", spc_handler_pdfm_uxobj}, - {"uxobj", spc_handler_pdfm_uxobj}, - - {"tounicode", spc_handler_pdfm_tounicode}, - {"literal", spc_handler_pdfm_literal}, - {"stream", spc_handler_pdfm_stream}, - {"fstream", spc_handler_pdfm_fstream}, - {"names", spc_handler_pdfm_names}, - {"mapline", spc_handler_pdfm_mapline}, - {"mapfile", spc_handler_pdfm_mapfile}, - - {"bcontent", spc_handler_pdfm_bcontent}, - {"econtent", spc_handler_pdfm_econtent}, - {"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}, - - {"xannot", spc_handler_pdfm_xann}, - {"extendann", spc_handler_pdfm_xann}, - {"xann", spc_handler_pdfm_xann}, - - {"bxgstate", spc_handler_pdfm_bxgstate}, - {"exgstate", spc_handler_pdfm_exgstate}, -}; - -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}, -}; - -int -spc_pdfm_check_special (const char *buf, int len) -{ - int r = 0; - const char *p, *endptr; - - p = buf; - endptr = p + len; - - skip_white(&p, endptr); - if (p + strlen("pdf:") <= endptr && - !memcmp(p, "pdf:", strlen("pdf:"))) { - r = 1; - } - - return r; -} - -int -spc_pdfm_setup_handler (struct spc_handler *sph, - struct spc_env *spe, struct spc_arg *ap) -{ - int error = -1, i; - char *q; - - ASSERT(sph && spe && ap); - - skip_white(&ap->curptr, ap->endptr); - if (ap->curptr + strlen("pdf:") >= ap->endptr || - memcmp(ap->curptr, "pdf:", strlen("pdf:"))) { - spc_warn(spe, "Not pdf: special???"); - return -1; - } - ap->curptr += strlen("pdf:"); - - skip_white(&ap->curptr, ap->endptr); - q = parse_c_ident(&ap->curptr, ap->endptr); - if (q) { - 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; - } - } - } - RELEASE(q); - } - - return error; -} |