diff options
author | Jonathan Kew <jfkthame@googlemail.com> | 2006-09-29 15:15:10 +0000 |
---|---|---|
committer | Jonathan Kew <jfkthame@googlemail.com> | 2006-09-29 15:15:10 +0000 |
commit | 387cf3625583fb046baf756f72f188924f35cfe2 (patch) | |
tree | 6e09f2e03b9c590a9f14689dfdb4d77ed66e773d /Build/source/texk/xdvipdfmx/src/t1_load.c | |
parent | fe77ff4cdab25604b424a273c726920830f63abc (diff) |
adding xdvipdfmx sources
git-svn-id: svn://tug.org/texlive/trunk@2220 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/xdvipdfmx/src/t1_load.c')
-rw-r--r-- | Build/source/texk/xdvipdfmx/src/t1_load.c | 1197 |
1 files changed, 1197 insertions, 0 deletions
diff --git a/Build/source/texk/xdvipdfmx/src/t1_load.c b/Build/source/texk/xdvipdfmx/src/t1_load.c new file mode 100644 index 00000000000..ccb09703351 --- /dev/null +++ b/Build/source/texk/xdvipdfmx/src/t1_load.c @@ -0,0 +1,1197 @@ +/* $Header: /home/cvsroot/dvipdfmx/src/t1_load.c,v 1.9 2005/07/17 09:53:38 hirata Exp $ + + This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. + + Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata, + the dvipdfmx project team <dvipdfmx@project.ktug.or.kr> + + 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. +*/ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include <math.h> + +#include "system.h" +#include "mfileio.h" +#include "mem.h" +#include "error.h" +#include "numbers.h" + +#include "pdfobj.h" +#include "pdffont.h" + +#include "pdfencoding.h" +#include "unicode.h" + +#include "dpxutil.h" + +#include "pst_obj.h" +#include "pst.h" + +#include "cff_limits.h" +#include "cff_types.h" +#include "cff_dict.h" +#include "cff.h" + +#include "t1_load.h" + +/* Migrated from t1crypt */ +#define T1_EEKEY 55665u +#define T1_CHARKEY 4330u + +#if 0 +/* We no longer need encryption. */ +static unsigned char t1_encrypt (unsigned char plain); +#endif /* 0 */ +static void t1_crypt_init (unsigned short key); +static unsigned char t1_decrypt (unsigned char cipher); +static unsigned short r = T1_EEKEY, c1 = 52845, c2 = 22719; + +#if 0 +static unsigned char t1_encrypt (unsigned char plain) +{ + unsigned char cipher; + cipher = (plain ^ (r >> 8)); + r = (cipher + r) * c1 + c2; + return cipher; +} +#endif /* 0 */ + +static void t1_crypt_init (unsigned short key) +{ + r = key; +} + +static unsigned char t1_decrypt (unsigned char cipher) +{ + unsigned char plain; + plain = (cipher ^ (r >> 8)); + r = (cipher + r) * c1 + c2; + return plain; +} +/* T1CRYPT */ + +#define MATCH_NAME(t,n) ((t) && PST_NAMETYPE((t)) && !strncmp(pst_data_ptr((t)),(n),strlen((n)))) +#define MATCH_OP(t,n) ((t) && PST_UNKNOWNTYPE((t)) && !strncmp(pst_data_ptr((t)),(n),strlen((n)))) + +#define RELEASE_TOK(t) if ((t) != NULL) {\ + pst_release_obj((t));\ + (t) = NULL;\ +} + +static char * +get_next_key (unsigned char **start, unsigned char *end) +{ + char *key = NULL; + pst_obj *tok; + + while (*start < end && + (tok = pst_get_token(start, end)) != NULL) { + if (PST_NAMETYPE(tok)) { + key = (char *) pst_getSV(tok); + RELEASE_TOK(tok); + break; + } + RELEASE_TOK(tok); + } + + return key; +} + +static int +seek_operator (unsigned char **start, unsigned char *end, const char *op) +{ + pst_obj *tok = NULL; + + while (*start < end && + (tok = pst_get_token(start, end)) != NULL) { + if (MATCH_OP(tok, op)) { + break; + } + RELEASE_TOK(tok); + } + + if (tok == NULL) + return -1; + RELEASE_TOK(tok); + + return 0; +} + + +static int +parse_svalue (unsigned char **start, unsigned char *end, char **value) +{ + pst_obj *tok; + + tok = pst_get_token(start, end); + if (tok == NULL) + return -1; + else if (PST_NAMETYPE(tok) || PST_STRINGTYPE(tok)) + *value = (char *) pst_getSV(tok); + else { + RELEASE_TOK(tok); + return -1; + } + RELEASE_TOK(tok); + + return 1; +} + +static int +parse_bvalue (unsigned char **start, unsigned char *end, double *value) +{ + pst_obj *tok; + + tok = pst_get_token(start, end); + if (tok == NULL) + return -1; + else if (PST_BOOLEANTYPE(tok)) + *value = (double) pst_getIV(tok); + else { + RELEASE_TOK(tok); + return -1; + } + RELEASE_TOK(tok); + + return 1; +} + +static int +parse_nvalue (unsigned char **start, unsigned char *end, double *value, int max) +{ + int argn = 0; + pst_obj *tok; + + tok = pst_get_token(start, end); + if (tok == NULL) + return -1; + /* + * All array elements must be numeric token. (ATM compatible) + */ + if (PST_NUMBERTYPE(tok) && max > 0) { + value[0] = (double) pst_getRV(tok); + argn = 1; + } else if (PST_MARKTYPE(tok)) { + /* It does not distinguish '[' and '{'... */ + RELEASE_TOK(tok); + while (*start < end && + (tok = pst_get_token(start, end)) != NULL && + PST_NUMBERTYPE(tok) && argn < max) { + value[argn++] = (double) pst_getRV(tok); + RELEASE_TOK(tok); + } + if (tok == NULL) + return -1; + if (!MATCH_OP(tok, "]") && !MATCH_OP(tok, "}")) { + argn = -1; + } + } + RELEASE_TOK(tok); + + return argn; +} + +static const char *const StandardEncoding[256] = { + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", "space", "exclam", "quotedbl", + "numbersign", "dollar", "percent", "ampersand", "quoteright", + "parenleft", "parenright", "asterisk", "plus", "comma", + "hyphen", "period", "slash", "zero", "one", + "two", "three", "four", "five", "six", + "seven", "eight", "nine", "colon", "semicolon", + "less", "equal", "greater", "question", "at", + "A", "B", "C", "D", "E", + "F", "G", "H", "I", "J", + "K", "L", "M", "N", "O", + "P", "Q", "R", "S", "T", + "U", "V", "W", "X", "Y", + "Z", "bracketleft", "backslash", "bracketright", "asciicircum", + "underscore", "quoteleft", "a", "b", "c", + "d", "e", "f", "g", "h", + "i", "j", "k", "l", "m", + "n", "o", "p", "q", "r", + "s", "t", "u", "v", "w", + "x", "y", "z", "braceleft", "bar", + "braceright", "asciitilde", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", "exclamdown", "cent", "sterling", "fraction", + "yen", "florin", "section", "currency", "quotesingle", + "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", + "fl", ".notdef", "endash", "dagger", "daggerdbl", + "periodcentered", ".notdef", "paragraph", "bullet", "quotesinglbase", + "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand", + ".notdef", "questiondown", ".notdef", "grave", "acute", + "circumflex", "tilde", "macron", "breve", "dotaccent", + "dieresis", ".notdef", "ring", "cedilla", ".notdef", + "hungarumlaut", "ogonek", "caron", "emdash", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + "AE", ".notdef", "ordfeminine", ".notdef", ".notdef", + ".notdef", ".notdef", "Lslash", "Oslash", "OE", + "ordmasculine", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", "ae", ".notdef", ".notdef", ".notdef", + "dotlessi", ".notdef", ".notdef", "lslash", "oslash", + "oe", "germandbls", ".notdef", ".notdef", ".notdef", + ".notdef" +}; + +static const char *const ISOLatin1Encoding[256] = { + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", "space", "exclam", "quotedbl", + "numbersign", "dollar", "percent", "ampersand", "quotesingle", + "parenleft", "parenright", "asterisk", "plus", "comma", + "hyphen", "period", "slash", "zero", "one", + "two", "three", "four", "five", "six", + "seven", "eight", "nine", "colon", "semicolon", + "less", "equal", "greater", "question", "at", + "A", "B", "C", "D", "E", + "F", "G", "H", "I", "J", + "K", "L", "M", "N", "O", + "P", "Q", "R", "S", "T", + "U", "V", "W", "X", "Y", + "Z", "bracketleft", "backslash", "bracketright", "asciicircum", + "underscore", "grave", "a", "b", "c", + "d", "e", "f", "g", "h", + "i", "j", "k", "l", "m", + "n", "o", "p", "q", "r", + "s", "t", "u", "v", "w", + "x", "y", "z", "braceleft", "bar", + "braceright", "asciitilde", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", + ".notdef", ".notdef", ".notdef", ".notdef", "dotlessi", + "quoteleft", "quoteright", "circumflex", "tilde", "macron", + "breve", "dotaccent", "dieresis", ".notdef", "ring", + "cedilla", ".notdef", "hungarumlaut", "ogonek", "caron", + "space", "exclamdown", "cent", "sterling", "currency", + "yen", "brokenbar", "section", "dieresis", "copyright", + "ordfeminine", "guillemotleft", "logicalnot", "hyphen", + "registered", + "macron", "degree", "plusminus", "twosuperior", "threesuperior", + "acute", "mu", "paragraph", "periodcentered", "cedilla", + "onesuperior", "ordmasculine", "guillemotright", "onequarter", + "onehalf", + "threequarters", "questiondown", "Agrave", "Aacute", "Acircumflex", + "Atilde", "Adieresis", "Aring", "AE", "Ccedilla", + "Egrave", "Eacute", "Ecircumflex", "Edieresis", "Igrave", + "Iacute", "Icircumflex", "Idieresis", "Eth", "Ntilde", + "Ograve", "Oacute", "Ocircumflex", "Otilde", "Odieresis", + "multiply", "Oslash", "Ugrave", "Uacute", "Ucircumflex", + "Udieresis", "Yacute", "Thorn", "germandbls", "agrave", + "aacute", "acircumflex", "atilde", "adieresis", "aring", + "ae", "ccedilla", "egrave", "eacute", "ecircumflex", + "edieresis", "igrave", "iacute", "icircumflex", "idieresis", + "eth", "ntilde", "ograve", "oacute", "ocircumflex", + "otilde", "odieresis", "divide", "oslash", "ugrave", + "uacute", "ucircumflex", "udieresis", "yacute", "thorn", + "ydieresis" +}; + +static int +parse_encoding (char **enc_vec, unsigned char **start, unsigned char *end, int mode) +{ + pst_obj *tok; + int code; + + /* + * StandardEncoding def + * or + * ISOLatin1Encoding def + * or + * 0 1 255 {1 index exch /.notdef put } for + * dup int name put + * ... + * [readonly] def + */ + tok = pst_get_token(start, end); + if (MATCH_OP(tok, "StandardEncoding")) { + RELEASE_TOK(tok); + if (enc_vec) { + for (code = 0; code < 256; code++) { + if (StandardEncoding[code] && + strcmp(StandardEncoding[code], ".notdef") != 0) { + enc_vec[code] = NEW(strlen(StandardEncoding[code])+1, char); + strcpy(enc_vec[code], StandardEncoding[code]); + } else { + enc_vec[code] = NULL; + } + } + } + } else if (MATCH_OP(tok, "ISOLatin1Encoding")) { + RELEASE_TOK(tok); + if (enc_vec) { + for (code = 0; code < 256; code++) { + if (ISOLatin1Encoding[code] && + strcmp(ISOLatin1Encoding[code], ".notdef") != 0) { + enc_vec[code] = NEW(strlen(ISOLatin1Encoding[code])+1, char); + strcpy(enc_vec[code], ISOLatin1Encoding[code]); + } else { + enc_vec[code] = NULL; + } + } + } + } else if (MATCH_OP(tok, "ExpertEncoding")) { + RELEASE_TOK(tok); + if (enc_vec) { + WARN("ExpertEncoding not supported."); + RELEASE_TOK(tok); + return -1; + } + /* + * Not supported yet. + */ + } else { + RELEASE_TOK(tok); + seek_operator(start, end, "array"); + /* + * Pick all seaquences that matches "dup n /Name put" until + * occurrence of "def" or "readonly". + */ + while (*start < end && + (tok = pst_get_token(start, end)) != NULL) { + if (MATCH_OP(tok, "def") || MATCH_OP(tok, "readonly")) { + RELEASE_TOK(tok); + break; + } else if (!MATCH_OP(tok, "dup")) { + RELEASE_TOK(tok); + continue; + } + RELEASE_TOK(tok); + + tok = pst_get_token(start, end); + if (!tok || !PST_INTEGERTYPE(tok) || + (code = pst_getIV(tok)) > 255 || code < 0) { + RELEASE_TOK(tok); + continue; + } + RELEASE_TOK(tok); + + tok = pst_get_token(start, end); + if (!tok || !PST_NAMETYPE(tok)) { + RELEASE_TOK(tok); + continue; + } + if (enc_vec) { + if (enc_vec[code]) + RELEASE(enc_vec[code]); + enc_vec[code] = (char *) pst_getSV(tok); + } + RELEASE_TOK(tok); + + tok = pst_get_token(start, end); + if (!MATCH_OP(tok, "put")) { + if (enc_vec[code]) { + RELEASE(enc_vec[code]); + enc_vec[code] = NULL; + } + RELEASE_TOK(tok); + continue; + } + RELEASE_TOK(tok); + } + } + + return 0; +} + +#ifndef CS_STR_LEN_MAX +#define CS_STR_LEN_MAX 65536UL +#endif +#ifndef CFF_GLYPH_MAX +#define CFF_GLYPH_MAX CFF_SID_MAX +#endif + +static int +parse_subrs (cff_font *font, + unsigned char **start, unsigned char *end, int lenIV, int mode) +{ + cff_index *subrs; + pst_obj *tok; + long i, count, offset, max_size; + long *offsets, *lengths; + card8 *data; + + tok = pst_get_token(start, end); + if (!PST_INTEGERTYPE(tok) || pst_getIV(tok) < 0) { + WARN("Parsing Subrs failed."); + RELEASE_TOK(tok); + return -1; + } + + count = pst_getIV(tok); + RELEASE_TOK(tok); + + if (count == 0) { + font->subrs[0] = NULL; + return 0; + } + + tok = pst_get_token(start, end); + if (!MATCH_OP(tok, "array")) { + RELEASE_TOK(tok); + return -1; + } + RELEASE_TOK(tok); + + if (mode != 1) { + max_size = CS_STR_LEN_MAX; + data = NEW(max_size, card8); + offsets = NEW(count, long); + lengths = NEW(count, long); + memset(offsets, 0, sizeof(long)*count); + memset(lengths, 0, sizeof(long)*count); + } else { + max_size = 0; + data = NULL; + offsets = NULL; + lengths = NULL; + } + + offset = 0; + /* dup subr# n-bytes RD n-binary-bytes NP */ + for (i = 0; i < count;) { + long idx, len; + + tok = pst_get_token(start, end); + if (!tok) { + if (data) RELEASE(data); + if (offsets) RELEASE(offsets); + if (lengths) RELEASE(lengths); + return -1; + } else if (MATCH_OP(tok, "ND") || + MATCH_OP(tok, "|-") || MATCH_OP(tok, "def")) { + RELEASE_TOK(tok); + break; + } else if (!MATCH_OP(tok, "dup")) { + RELEASE_TOK(tok); + continue; + } + RELEASE_TOK(tok); + + /* Found "dup" */ + tok = pst_get_token(start, end); + if (!PST_INTEGERTYPE(tok) || pst_getIV(tok) < 0 || + pst_getIV(tok) >= count) { + RELEASE_TOK(tok); + if (data) RELEASE(data); + if (offsets) RELEASE(offsets); + if (lengths) RELEASE(lengths); + return -1; + } + idx = pst_getIV(tok); + RELEASE_TOK(tok); + + tok = pst_get_token(start, end); + if (!PST_INTEGERTYPE(tok) || pst_getIV(tok) < 0 || + pst_getIV(tok) > CS_STR_LEN_MAX) { + RELEASE_TOK(tok); + return -1; + } + len = pst_getIV(tok); + RELEASE_TOK(tok); + + tok = pst_get_token(start, end); + if (!MATCH_OP(tok, "RD") && !MATCH_OP(tok, "-|") && + seek_operator(start, end, "readstring") < 0) { + RELEASE_TOK(tok); + if (data) RELEASE(data); + if (offsets) RELEASE(offsets); + if (lengths) RELEASE(lengths); + return -1; + } + RELEASE_TOK(tok); + + *start += 1; + if (*start + len >= end) { + if (data) RELEASE(data); + if (offsets) RELEASE(offsets); + if (lengths) RELEASE(lengths); + return -1; + } + if (mode != 1) { + if (offset + len >= max_size) { + max_size += CS_STR_LEN_MAX; + data = RENEW(data, max_size, card8); + } + if (lenIV >= 0) { + long j; + + offsets[idx] = offset; + lengths[idx] = len - lenIV; + t1_crypt_init(T1_CHARKEY); + for (j = 0; j < lenIV; j++) + t1_decrypt(*((*start)+j)); + for (j = lenIV; j < len ; j++) { + data[offset] = (card8) t1_decrypt(*((*start)+j)); + offset++; + } + } else if (len > 0) { + offsets[idx] = offset; + lengths[idx] = len; + memcpy(&data[offset], *start, len); + offset += len; + } + } + *start += len; + i++; + } + + if (mode != 1) { + subrs = font->subrs[0] = cff_new_index(count); + subrs->data = NEW(offset, card8); + offset = 0; + for (i = 0; i < count; i++) { + subrs->offset[i] = offset + 1; + if (lengths[i] > 0) { + memcpy(subrs->data + offset, data + offsets[i], lengths[i]); + offset += lengths[i]; + } + } + subrs->offset[count] = offset + 1; + + RELEASE(data); + RELEASE(offsets); + RELEASE(lengths); + } + + return 0; +} + +static int +parse_charstrings (cff_font *font, + unsigned char **start, unsigned char *end, int lenIV, int mode) +{ + cff_index *charstrings; + cff_charsets *charset; + pst_obj *tok; + long i, count, have_notdef; + long max_size, offset; + + /* /CharStrings n dict dup begin + * /GlyphName n-bytes RD -n-binary-bytes- ND + * ... + * end + * - stack - ... /CharStrings dict + */ + tok = pst_get_token(start, end); + if (!PST_INTEGERTYPE(tok) || + pst_getIV(tok) < 0 || pst_getIV(tok) > CFF_GLYPH_MAX) { + RELEASE_TOK(tok); + return -1; + } + count = pst_getIV(tok); + RELEASE_TOK(tok); + + if (mode != 1) { + charstrings = cff_new_index(count); + max_size = CS_STR_LEN_MAX; + charstrings->data = NEW(max_size, card8); + } else { + charstrings = NULL; + max_size = 0; + } + font->cstrings = charstrings; + + charset = font->charsets = NEW(1, cff_charsets); + charset->format = 0; + charset->num_entries = count-1; + charset->data.glyphs = NEW(count-1, s_SID); + memset(charset->data.glyphs, 0, sizeof(s_SID)*(count-1)); + +#ifdef XETEX + font->ft_to_gid = NEW(count, unsigned short); +#endif + + offset = 0; + have_notdef = 0; /* .notdef must be at gid = 0 in CFF */ + + seek_operator(start, end, "begin"); + for (i = 0; i < count; i++) { + char *glyph_name; + long len, gid, j; + + glyph_name = get_next_key(start, end); + if (!glyph_name) { + return -1; + } else if (!strcmp(glyph_name, ".notdef")) { + gid = 0; + have_notdef = 1; + } else if (have_notdef) { + gid = i; + } else if (i == count - 1) { + WARN("No .notdef glyph???"); + return -1; + } else { + gid = i+1; + } +#ifdef XETEX + font->ft_to_gid[i] = gid; +#endif + + if (gid > 0) + charset->data.glyphs[gid-1] = cff_add_string(font, glyph_name); + RELEASE(glyph_name); + + tok = pst_get_token(start, end); + if (!PST_INTEGERTYPE(tok) || + pst_getIV(tok) < 0 || pst_getIV(tok) > CS_STR_LEN_MAX) { + RELEASE_TOK(tok); + return -1; + } + len = pst_getIV(tok); + RELEASE_TOK(tok); + + tok = pst_get_token(start, end); + if (!MATCH_OP(tok, "RD") && + !MATCH_OP(tok, "-|") && + seek_operator(start, end, "readstring") < 0) { + RELEASE_TOK(tok); + return -1; + } + RELEASE_TOK(tok); + + if (*start + len + 1 >= end) { + return -1; + } + if (mode != 1) { + if (offset + len >= max_size) { + max_size += MAX(len, CS_STR_LEN_MAX); + charstrings->data = RENEW(charstrings->data, max_size, card8); + } + if (gid == 0) { + if (lenIV >= 0) { + memmove(charstrings->data + len - lenIV, charstrings->data, offset); + for (j = 1; j <= i; j++) { + charstrings->offset[j] += len - lenIV; + } + } else { + memmove(charstrings->data + len, charstrings->data, offset); + for (j = 1; j <= i; j++) { + charstrings->offset[j] += len; + } + } + } + } + + *start += 1; + if (mode != 1) { + if (lenIV >= 0) { + t1_crypt_init(T1_CHARKEY); + for (j = 0; j < lenIV; j++) + t1_decrypt(*((*start)+j)); + if (gid == 0) { + charstrings->offset[gid] = 1; /* start at 1 */ + for (j = lenIV; j < len; j++) { + charstrings->data[j-lenIV] = t1_decrypt(*((*start)+j)); + } + } else { + charstrings->offset[gid] = offset + 1; /* start at 1 */ + for (j = lenIV; j < len; j++) { + charstrings->data[offset+j-lenIV] = t1_decrypt(*((*start)+j)); + } + } + offset += len - lenIV; + } else { + if (gid == 0) { + charstrings->offset[gid] = 1; + memcpy(&charstrings->data[0], *start, len); + } else { + charstrings->offset[gid] = offset + 1; + memcpy(&charstrings->data[offset], *start, len); + } + offset += len; + } + } + *start += len; + } + if (mode != 1) + charstrings->offset[count] = offset + 1; + font->num_glyphs = count; + + return 0; +} + +#define CHECK_ARGN_EQ(n) if (argn != (n)) {\ + WARN("%d values expected but only %d read.", (n), argn);\ + RELEASE(key);\ + return -1;\ +} +#define CHECK_ARGN_GE(n) if (argn < (n)) {\ + WARN("%d values expected but only %d read.", (n), argn);\ + RELEASE(key);\ + return -1;\ +} + +#define MAX_ARGS 127 +static int +parse_part2 (cff_font *font, unsigned char **start, unsigned char *end, int mode) +{ + char *key; + double argv[MAX_ARGS]; + int argn, lenIV = 4; + + while (*start < end && + (key = get_next_key(start, end)) != NULL) { + if (!strcmp(key, "Subrs")) { + /* levIV must appear before Subrs */ + if (parse_subrs(font, start, end, lenIV, mode) < 0) { + RELEASE(key); + return -1; + } + } else if (!strcmp(key, "CharStrings")) { + if (parse_charstrings(font, start, end, lenIV, mode) < 0) { + RELEASE(key); + return -1; + } + } else if (!strcmp(key, "lenIV")) { + argn = parse_nvalue(start, end, argv, 1); + CHECK_ARGN_EQ(1); + lenIV = (int) argv[0]; + } else if (!strcmp(key, "BlueValues") || + !strcmp(key, "OtherBlues") || + !strcmp(key, "FamilyBlues") || + !strcmp(key, "FamilyOtherBlues") || + !strcmp(key, "StemSnapH") || + !strcmp(key, "StemSnapV")) { + /* + * Operand values are delta in CFF font dictionary encoding. + */ + argn = parse_nvalue(start, end, argv, MAX_ARGS); + CHECK_ARGN_GE(0); + cff_dict_add(font->private[0], key, argn); + while (argn-- > 0) { + cff_dict_set(font->private[0], key, argn, + (argn == 0) ? argv[argn] : argv[argn] - argv[argn-1]); + } + } else if (!strcmp(key, "StdHW") || + !strcmp(key, "StdVW") || + !strcmp(key, "BlueScale") || + !strcmp(key, "BlueShift") || + !strcmp(key, "BlueFuzz") || + !strcmp(key, "LanguageGroup") || + !strcmp(key, "ExpansionFactor")) { + /* + * Value of StdHW and StdVW is described as an array in the + * Type 1 Font Specification but is a number in CFF format. + */ + argn = parse_nvalue(start, end, argv, 1); + CHECK_ARGN_EQ(1); + cff_dict_add(font->private[0], key, 1); + cff_dict_set(font->private[0], key, 0, argv[0]); + } else if (!strcmp(key, "ForceBold")) { + argn = parse_bvalue(start, end, &(argv[0])); + CHECK_ARGN_EQ(1); + if (argv[0] != 0) { + cff_dict_add(font->private[0], key, 1); + cff_dict_set(font->private[0], key, 0, 1); + } + } + /* + * MinFeature, RndStemUp, UniqueID, Password ignored. + */ + RELEASE(key); + } + + return 0; +} + +#ifndef TYPE1_NAME_LEN_MAX +#define TYPE1_NAME_LEN_MAX 127 +#endif + +static long +parse_part1 (cff_font *font, char **enc_vec, + unsigned char **start, unsigned char *end, int mode) +{ + char *key, *strval; + double argv[MAX_ARGS]; + int argn; /* Macro CHECK_ARGN_XX assume 'argn' is used. */ + + /* + * We skip PostScript code inserted before the beginning of + * font dictionary so that parser will not be confused with + * it. See LMRoman10-Regular (lmr10.pfb) for example. + */ + if (seek_operator(start, end, "begin") < 0) + return -1; + + while (*start < end && + (key = get_next_key(start, end)) != NULL) { + if (!strcmp(key, "Encoding")) { + if (parse_encoding(enc_vec, start, end, mode) < 0) { + RELEASE(key); + return -1; + } + } else if (!strcmp(key, "FontName")) { + argn = parse_svalue(start, end, &strval); + CHECK_ARGN_EQ(1); + if (strlen(strval) > TYPE1_NAME_LEN_MAX) { + WARN("FontName too long: %s (%d bytes)", strval, strlen(strval)); + strval[TYPE1_NAME_LEN_MAX] = '\0'; + } + cff_set_name(font, strval); + RELEASE(strval); + } else if (!strcmp(key, "FontType")) { + argn = parse_nvalue(start, end, argv, 1); + CHECK_ARGN_EQ(1); + if (argv[0] != 1.0) { + WARN("FontType %d not supported.", (int) argv[0]); + RELEASE(key); + return -1; + } +#if 0 + /* DISABLED: + * + * Subsetted font shouldn't have UniqueID. + */ + } else if (!strcmp(key, "UniqueID")) { + argn = parse_nvalue(start, end, argv, 1); + CHECK_ARGN_EQ(1); + cff_dict_add(font->topdict, key, 1); + cff_dict_set(font->topdict, key, 0, argv[0]); +#endif + } else if (!strcmp(key, "ItalicAngle") || + !strcmp(key, "StrokeWidth") || + !strcmp(key, "PaintType")) { + argn = parse_nvalue(start, end, argv, 1); + CHECK_ARGN_EQ(1); + if (argv[0] != 0.0) { +#if 0 + /* + * Positive value in Bitstream CharterBT-Italic ??? + */ + if (!strcmp(key, "ItalicAngle") && argv[0] > 0) { + WARN("Positive ItalicAngle value: %g", argv[0]); + argv[0] *= -1; + } +#endif + cff_dict_add(font->topdict, key, 1); + cff_dict_set(font->topdict, key, 0, argv[0]); + } + } else if (!strcmp(key, "UnderLinePosition") || + !strcmp(key, "UnderLineThickness")) { + argn = parse_nvalue(start, end, argv, 1); + CHECK_ARGN_EQ(1); + cff_dict_add(font->topdict, key, 1); + cff_dict_set(font->topdict, key, 0, argv[0]); + } else if (!strcmp(key, "FontBBox")) { + argn = parse_nvalue(start, end, argv, 4); + CHECK_ARGN_EQ(4); + cff_dict_add(font->topdict, key, 4); + while (argn-- > 0) { + cff_dict_set(font->topdict, key, argn, argv[argn]); + } + } else if (!strcmp(key, "FontMatrix")) { + argn = parse_nvalue(start, end, argv, 6); + CHECK_ARGN_EQ(6); + if (argv[0] != 0.001 || argv[1] != 0.0 || argv[2] != 0.0 || + argv[3] != 0.001 || argv[4] != 0.0 || argv[5] != 0.0) { + cff_dict_add(font->topdict, key, 6); + while (argn-- > 0) { + cff_dict_set(font->topdict, key, argn, argv[argn]); + } + } + } else if (!strcmp(key, "version") || !strcmp(key, "Notice") || + !strcmp(key, "FullName") || !strcmp(key, "FamilyName") || + !strcmp(key, "Weight") || !strcmp(key, "Copyright")) { + /* + * FontInfo + */ + argn = parse_svalue(start, end, &strval); + CHECK_ARGN_EQ(1); + { + s_SID sid; + + cff_dict_add(font->topdict, key, 1); + if ((sid = cff_get_sid(font, strval)) == CFF_STRING_NOTDEF) + sid = cff_add_string(font, strval); /* FIXME */ + cff_dict_set(font->topdict, key, 0, sid); + } + RELEASE(strval); + } else if (!strcmp(key, "IsFixedPitch")) { + argn = parse_bvalue(start, end, &(argv[0])); + CHECK_ARGN_EQ(1); + if (argv[0] != 0.0) { + cff_dict_add(font->private[0], key, 1); + cff_dict_set(font->private[0], key, 0, 1); + } + } + RELEASE(key); + } + + return 0; +} + +int +is_pfb (FILE *fp) +{ + char sig[15]; + int i, ch; + + rewind(fp); + if ((ch = fgetc(fp)) != 128 || + (ch = fgetc (fp)) < 0 || ch > 3) { + return 0; + } + for (i = 0; i < 4; i++) { + if ((ch = fgetc(fp)) < 0) { + return 0; + } + } + for (i = 0; i < 14; i++) { + if ((ch = fgetc(fp)) < 0) { + return 0; + } + sig[i] = (char) ch; + } + if (!memcmp(sig, "%!PS-AdobeFont", 14) || + !memcmp(sig, "%!FontType1", 11)) { + return 1; + } else if (!memcmp(sig, "%!PS", 4)) { + sig[14] = '\0'; + WARN("Ambiguous PostScript resource type: %s", sig); + return 1; + } else { + WARN("Not a PFB font file?"); + return 0; + } + + return 0; +} + + +#define PFB_SEG_TYPE_ASCII 1 +#define PFB_SEG_TYPE_BINARY 2 + +static unsigned char * +get_pfb_segment (FILE *fp, int expected_type, long *length) +{ + unsigned char *buffer; + long bytesread; + + buffer = NULL; bytesread = 0; + for (;;) { + int ch; + + ch = fgetc(fp); + if (ch < 0) { + break; + } else if (ch != 128) { + ERROR("Not a pfb file?"); + } + ch = fgetc(fp); + if (ch < 0 || ch != expected_type) { + seek_relative(fp, -2); + break; + } + { + long slen, rlen; + int i; + + slen = 0; + for (i = 0; i < 4; i++) { + if ((ch = fgetc(fp)) < 0) { + if (buffer) + RELEASE(buffer); + return NULL; + } + slen = slen + (ch << (8*i)); + } + buffer = RENEW(buffer, bytesread + slen, unsigned char); + while (slen > 0) { + rlen = fread(buffer + bytesread, sizeof(unsigned char), slen, fp); + if (rlen < 0) { + if (buffer) + RELEASE(buffer); + return NULL; + } + slen -= rlen; + bytesread += rlen; + } + } + } + if (bytesread == 0) { + ERROR("PFB segment length zero?"); + } + + if (length) + *length = bytesread; + return buffer; +} + +char * +t1_get_standard_glyph (int code) +{ + if (!StandardEncoding[code]) + return NULL; + + return (char *) StandardEncoding[code]; +} + +int +t1_get_fontname (FILE *fp, char *fontname) +{ + unsigned char *buffer, *start, *end; + long length; + char *key; + int fn_found = 0; + + rewind(fp); + buffer = get_pfb_segment(fp, PFB_SEG_TYPE_ASCII, &length); + if (buffer == NULL || length == 0) + ERROR("Reading PFB (ASCII part) file failed."); + start = buffer; + end = buffer + length; + + if (seek_operator(&start, end, "begin") < 0) { + RELEASE(buffer); + return -1; + } + + while (!fn_found && start < end && + (key = get_next_key(&start, end)) != NULL) { + if (!strcmp(key, "FontName")) { + char *strval; + if (parse_svalue(&start, end, &strval) == 1) { + if (strlen(strval) > TYPE1_NAME_LEN_MAX) { + WARN("FontName \"%s\" too long. (%d bytes)", strval, strlen(strval)); + strval[TYPE1_NAME_LEN_MAX] = '\0'; + } + strcpy(fontname, strval); + RELEASE(strval); + fn_found = 1; + } + } + RELEASE(key); + } + RELEASE(buffer); + + return 0; +} + +static void +init_cff_font (cff_font *cff) +{ + cff->sfont = NULL; + cff->filter = 0; + cff->fontname = NULL; + cff->index = 0; + cff->flag = FONTTYPE_FONT; + + cff->header.major = 1; + cff->header.minor = 0; + cff->header.hdr_size = 4; + cff->header.offsize = 4; + cff->name = cff_new_index(1); + cff->topdict = cff_new_dict(); + cff->string = NULL; + cff->gsubr = cff_new_index(0); /* No Global Subr */ + cff->encoding = NULL; + cff->charsets = NULL; + cff->fdselect = NULL; + cff->cstrings = NULL; + cff->fdarray = NULL; + cff->private = NEW(1, cff_dict *); + cff->private[0] = cff_new_dict(); + cff->subrs = NEW(1, cff_index *); + cff->subrs[0] = NULL; + + cff->offset = 0; + cff->gsubr_offset = 0; + cff->num_glyphs = 0; + cff->num_fds = 1; + cff->_string = cff_new_index(0); +} + +cff_font * +t1_load_font (char **enc_vec, int mode, FILE *fp) +{ + long length; + cff_font *cff; + unsigned char *buffer, *start, *end; + + rewind(fp); + /* ASCII section */ + buffer = get_pfb_segment(fp, PFB_SEG_TYPE_ASCII, &length); + if (buffer == NULL || length == 0) { + ERROR("Reading PFB (ASCII part) file failed."); + return NULL; + } + + cff = NEW(1, cff_font); + init_cff_font(cff); + + start = buffer; end = buffer + length; + if (parse_part1(cff, enc_vec, &start, end, mode) < 0) { + cff_close(cff); + RELEASE(buffer); + ERROR("Reading PFB (ASCII part) file failed."); + return NULL; + } + RELEASE(buffer); + + /* Binary section */ + buffer = get_pfb_segment(fp, PFB_SEG_TYPE_BINARY, &length); + if (buffer == NULL || length == 0) { + cff_close(cff); + RELEASE(buffer); + ERROR("Reading PFB (BINARY part) file failed."); + return NULL; + } else { + long i; + + t1_crypt_init(T1_EEKEY); + for (i = 0; i < length; i++) { + buffer[i] = (unsigned char) t1_decrypt(buffer[i]); + } + } + start = buffer + 4; end = buffer + length; + if (parse_part2(cff, &start, end, mode) < 0) { + cff_close(cff); + RELEASE(buffer); + ERROR("Reading PFB (BINARY part) file failed."); + return NULL; + } + RELEASE(buffer); + + cff_update_string(cff); + + /* Remaining section ignored. */ + + return cff; +} |