diff options
Diffstat (limited to 'Build/source/texk/web2c/mfluadir/otfcc/lib/support/ttinstr/ttinstr.c')
-rw-r--r-- | Build/source/texk/web2c/mfluadir/otfcc/lib/support/ttinstr/ttinstr.c | 701 |
1 files changed, 701 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/lib/support/ttinstr/ttinstr.c b/Build/source/texk/web2c/mfluadir/otfcc/lib/support/ttinstr/ttinstr.c new file mode 100644 index 00000000000..3fc3e043b56 --- /dev/null +++ b/Build/source/texk/web2c/mfluadir/otfcc/lib/support/ttinstr/ttinstr.c @@ -0,0 +1,701 @@ +/* Copyright (C) 2001-2012 by George Williams */ +/* Copyright (C) 2016 by Belleve Invis */ + +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ttinstr.h" +#include <ctype.h> + +enum ttf_instructions { + ttf_npushb = 0x40, + ttf_npushw = 0x41, + ttf_pushb = 0xb0, + ttf_pushw = 0xb8, + ttf_aa = 0x7f, + ttf_abs = 0x64, + ttf_add = 0x60, + ttf_alignpts = 0x27, + ttf_alignrp = 0x3c, + ttf_and = 0x5a, + ttf_call = 0x2b, + ttf_ceiling = 0x67, + ttf_cindex = 0x25, + ttf_clear = 0x22, + ttf_debug = 0x4f, + ttf_deltac1 = 0x73, + ttf_deltac2 = 0x74, + ttf_deltac3 = 0x75, + ttf_deltap1 = 0x5d, + ttf_deltap2 = 0x71, + ttf_deltap3 = 0x72, + ttf_depth = 0x24, + ttf_div = 0x62, + ttf_dup = 0x20, + ttf_eif = 0x59, + ttf_else = 0x1b, + ttf_endf = 0x2d, + ttf_eq = 0x54, + ttf_even = 0x57, + ttf_fdef = 0x2c, + ttf_flipoff = 0x4e, + ttf_flipon = 0x4d, + ttf_flippt = 0x80, + ttf_fliprgoff = 0x82, + ttf_fliprgon = 0x81, + ttf_floor = 0x66, + ttf_gc = 0x46, + ttf_getinfo = 0x88, + ttf_gfv = 0x0d, + ttf_gpv = 0x0c, + ttf_gt = 0x52, + ttf_gteq = 0x53, + ttf_idef = 0x89, + ttf_if = 0x58, + ttf_instctrl = 0x8e, + ttf_ip = 0x39, + ttf_isect = 0x0f, + ttf_iup = 0x30, + ttf_jmpr = 0x1c, + ttf_jrof = 0x79, + ttf_jrot = 0x78, + ttf_loopcall = 0x2a, + ttf_lt = 0x50, + ttf_lteq = 0x51, + ttf_max = 0x8b, + ttf_md = 0x49, + ttf_mdap = 0x2e, + ttf_mdrp = 0xc0, + ttf_miap = 0x3e, + ttf_min = 0x8c, + ttf_mindex = 0x26, + ttf_mirp = 0xe0, + ttf_mppem = 0x4b, + ttf_mps = 0x4c, + ttf_msirp = 0x3a, + ttf_mul = 0x63, + ttf_neg = 0x65, + ttf_neq = 0x55, + ttf_not = 0x5c, + ttf_nround = 0x6c, + ttf_odd = 0x56, + ttf_or = 0x5b, + ttf_pop = 0x21, + ttf_rcvt = 0x45, + ttf_rdtg = 0x7d, + ttf_roff = 0x7a, + ttf_roll = 0x8a, + ttf_round = 0x68, + ttf_rs = 0x43, + ttf_rtdg = 0x3d, + ttf_rtg = 0x18, + ttf_rthg = 0x19, + ttf_rutg = 0x7c, + ttf_s45round = 0x77, + ttf_sangw = 0x7e, + ttf_scanctrl = 0x85, + ttf_scantype = 0x8d, + ttf_scfs = 0x48, + ttf_scvtci = 0x1d, + ttf_sdb = 0x5e, + ttf_sdpvtl = 0x86, + ttf_sds = 0x5f, + ttf_sfvfs = 0x0b, + ttf_sfvtca = 0x04, + ttf_sfvtl = 0x08, + ttf_sfvtpv = 0x0e, + ttf_shc = 0x34, + ttf_shp = 0x32, + ttf_shpix = 0x38, + ttf_shz = 0x36, + ttf_sloop = 0x17, + ttf_smd = 0x1a, + ttf_spvfs = 0x0a, + ttf_spvtca = 0x02, + ttf_spvtl = 0x06, + ttf_sround = 0x76, + ttf_srp0 = 0x10, + ttf_srp1 = 0x11, + ttf_srp2 = 0x12, + ttf_ssw = 0x1f, + ttf_sswci = 0x1e, + ttf_sub = 0x61, + ttf_svtca = 0x00, + ttf_swap = 0x23, + ttf_szp0 = 0x13, + ttf_szp1 = 0x14, + ttf_szp2 = 0x15, + ttf_szps = 0x16, + ttf_utp = 0x29, + ttf_wcvtf = 0x70, + ttf_wcvtp = 0x44, + ttf_ws = 0x42, + ttf_getvariation = 0x91 +}; +enum byte_types { bt_instr, bt_cnt, bt_byte, bt_wordhi, bt_wordlo, bt_impliedreturn }; + +struct instrdata { + uint8_t *instrs; + uint32_t instr_cnt; + uint8_t *bts; +}; + +const char *ff_ttf_instrnames[] = {"SVTCA[y-axis]", + "SVTCA[x-axis]", + "SPVTCA[y-axis]", + "SPVTCA[x-axis]", + "SFVTCA[y-axis]", + "SFVTCA[x-axis]", + "SPVTL[parallel]", + "SPVTL[orthog]", + "SFVTL[parallel]", + "SFVTL[orthog]", + "SPVFS", + "SFVFS", + "GPV", + "GFV", + "SFVTPV", + "ISECT", + "SRP0", + "SRP1", + "SRP2", + "SZP0", + "SZP1", + "SZP2", + "SZPS", + "SLOOP", + "RTG", + "RTHG", + "SMD", + "ELSE", + "JMPR", + "SCVTCI", + "SSWCI", + "SSW", + "DUP", + "POP", + "CLEAR", + "SWAP", + "DEPTH", + "CINDEX", + "MINDEX", + "ALIGNPTS", + "Unknown28", + "UTP", + "LOOPCALL", + "CALL", + "FDEF", + "ENDF", + "MDAP[no-rnd]", + "MDAP[rnd]", + "IUP[y]", + "IUP[x]", + "SHP[rp2]", + "SHP[rp1]", + "SHC[rp2]", + "SHC[rp1]", + "SHZ[rp2]", + "SHZ[rp1]", + "SHPIX", + "IP", + "MSIRP[no-rp0]", + "MSIRP[rp0]", + "ALIGNRP", + "RTDG", + "MIAP[no-rnd]", + "MIAP[rnd]", + "NPUSHB", + "NPUSHW", + "WS", + "RS", + "WCVTP", + "RCVT", + "GC[cur]", + "GC[orig]", + "SCFS", + "MD[grid]", + "MD[orig]", + "MPPEM", + "MPS", + "FLIPON", + "FLIPOFF", + "DEBUG", + "LT", + "LTEQ", + "GT", + "GTEQ", + "EQ", + "NEQ", + "ODD", + "EVEN", + "IF", + "EIF", + "AND", + "OR", + "NOT", + "DELTAP1", + "SDB", + "SDS", + "ADD", + "SUB", + "DIV", + "MUL", + "ABS", + "NEG", + "FLOOR", + "CEILING", + "ROUND[Grey]", + "ROUND[Black]", + "ROUND[White]", + "ROUND[Undef4]", + "NROUND[Grey]", + "NROUND[Black]", + "NROUND[White]", + "NROUND[Undef4]", + "WCVTF", + "DELTAP2", + "DELTAP3", + "DELTAC1", + "DELTAC2", + "DELTAC3", + "SROUND", + "S45ROUND", + "JROT", + "JROF", + "ROFF", + "Unknown7B", + "RUTG", + "RDTG", + "SANGW", + "AA", + "FLIPPT", + "FLIPRGON", + "FLIPRGOFF", + "Unknown83", + "Unknown84", + "SCANCTRL", + "SDPVTL[parallel]", + "SDPVTL[orthog]", + "GETINFO", + "IDEF", + "ROLL", + "MAX", + "MIN", + "SCANTYPE", + "INSTCTRL", + "Unknown8F", + "Unknown90", + "GETVARIATION", + "Unknown92", + "Unknown93", + "Unknown94", + "Unknown95", + "Unknown96", + "Unknown97", + "Unknown98", + "Unknown99", + "Unknown9A", + "Unknown9B", + "Unknown9C", + "Unknown9D", + "Unknown9E", + "Unknown9F", + "UnknownA0", + "UnknownA1", + "UnknownA2", + "UnknownA3", + "UnknownA4", + "UnknownA5", + "UnknownA6", + "UnknownA7", + "UnknownA8", + "UnknownA9", + "UnknownAA", + "UnknownAB", + "UnknownAC", + "UnknownAD", + "UnknownAE", + "UnknownAF", + "PUSHB_1", + "PUSHB_2", + "PUSHB_3", + "PUSHB_4", + "PUSHB_5", + "PUSHB_6", + "PUSHB_7", + "PUSHB_8", + "PUSHW_1", + "PUSHW_2", + "PUSHW_3", + "PUSHW_4", + "PUSHW_5", + "PUSHW_6", + "PUSHW_7", + "PUSHW_8", + "MDRP[grey]", + "MDRP[black]", + "MDRP[white]", + "MDRP03", + "MDRP[rnd,grey]", + "MDRP[rnd,black]", + "MDRP[rnd,white]", + "MDRP07", + "MDRP[min,grey]", + "MDRP[min,black]", + "MDRP[min,white]", + "MDRP0b", + "MDRP[min,rnd,grey]", + "MDRP[min,rnd,black]", + "MDRP[min,rnd,white]", + "MDRP0f", + "MDRP[rp0,grey]", + "MDRP[rp0,black]", + "MDRP[rp0,white]", + "MDRP13", + "MDRP[rp0,rnd,grey]", + "MDRP[rp0,rnd,black]", + "MDRP[rp0,rnd,white]", + "MDRP17", + "MDRP[rp0,min,grey]", + "MDRP[rp0,min,black]", + "MDRP[rp0,min,white]", + "MDRP1b", + "MDRP[rp0,min,rnd,grey]", + "MDRP[rp0,min,rnd,black]", + "MDRP[rp0,min,rnd,white]", + "MDRP1f", + "MIRP[grey]", + "MIRP[black]", + "MIRP[white]", + "MIRP03", + "MIRP[rnd,grey]", + "MIRP[rnd,black]", + "MIRP[rnd,white]", + "MIRP07", + "MIRP[min,grey]", + "MIRP[min,black]", + "MIRP[min,white]", + "MIRP0b", + "MIRP[min,rnd,grey]", + "MIRP[min,rnd,black]", + "MIRP[min,rnd,white]", + "MIRP0f", + "MIRP[rp0,grey]", + "MIRP[rp0,black]", + "MIRP[rp0,white]", + "MIRP13", + "MIRP[rp0,rnd,grey]", + "MIRP[rp0,rnd,black]", + "MIRP[rp0,rnd,white]", + "MIRP17", + "MIRP[rp0,min,grey]", + "MIRP[rp0,min,black]", + "MIRP[rp0,min,white]", + "MIRP1b", + "MIRP[rp0,min,rnd,grey]", + "MIRP[rp0,min,rnd,black]", + "MIRP[rp0,min,rnd,white]", + "MIRP1f"}; + +static int strnmatch(const char *str1, const char *str2, int n) { + int ch1, ch2; + for (; n-- > 0;) { + ch1 = *str1++; + ch2 = *str2++; + ch1 = tolower(ch1); + ch2 = tolower(ch2); + if (ch1 != ch2 || ch1 == '\0') return (ch1 - ch2); + } + return (0); +} + +static uint8_t *parse_instrs(char *text, int *len, void *context, + void (*IVError)(void *context, const char *, int)) { + short numberstack[256]; + int npos = 0, nread, i; + int push_left = 0, push_size = 0; + char *pt; + char *end, *bend, *brack; + int icnt = 0, imax = (int)(strlen(text)), val; + uint8_t *instrs; + NEW(instrs, imax); + + for (pt = text; *pt; ++pt) { + npos = 0; + while (npos < 256) { + while (*pt == ' ' || *pt == '\t') + ++pt; + if (isdigit(*pt) || *pt == '-') { + val = strtol(pt, &end, 0); + if (val > 32767 || val < -32768) { + IVError(context, "A value must be between [-32768,32767]", (int)(pt - text)); + return (NULL); + } + pt = end; + numberstack[npos++] = val; + } else + break; + } + while (*pt == ' ' || *pt == '\t') + ++pt; + if (npos == 0 && (*pt == '\r' || *pt == '\n' || *pt == '\0')) continue; + nread = 0; + if (push_left == -1) { + /* we need a push count */ + if (npos == 0) + IVError(context, "Expected a number for a push count", (int)(pt - text)); + else if (numberstack[0] > 255 || numberstack[0] <= 0) { + IVError(context, "The push count must be a number between 0 and 255", + (int)(pt - text)); + return (NULL); + } else { + nread = 1; + instrs[icnt++] = numberstack[0]; + push_left = numberstack[0]; + } + } + if (push_left != 0 && push_left < npos - nread && + (*pt == '\r' || *pt == '\n' || *pt == '\0')) { + IVError(context, "More pushes specified than needed", (int)(pt - text)); + return (NULL); + } + while (push_left > 0 && nread < npos) { + if (push_size == 2) { + instrs[icnt++] = numberstack[nread] >> 8; + instrs[icnt++] = numberstack[nread++] & 0xff; + } else if (numberstack[0] > 255 || numberstack[0] < 0) { + IVError(context, "A value to be pushed by a byte push must be between 0 and 255", + (int)(pt - text)); + return (NULL); + } else + instrs[icnt++] = numberstack[nread++]; + --push_left; + } + if (nread < npos && push_left == 0 && (*pt == '\r' || *pt == '\n' || *pt == '\0')) { + IVError(context, "Unexpected number", (int)(pt - text)); + return (NULL); + } + if (*pt == '\r' || *pt == '\n' || *pt == '\0') continue; + if (push_left > 0) { + IVError(context, "Missing pushes", (int)(pt - text)); + return (NULL); + } + while (nread < npos) { + i = nread; + if (numberstack[nread] >= 0 && numberstack[nread] <= 255) { + while (i < npos && numberstack[i] >= 0 && numberstack[i] <= 255) + ++i; + if (i - nread <= 8) + instrs[icnt++] = ttf_pushb + (i - nread) - 1; + else { + instrs[icnt++] = ttf_npushb; + instrs[icnt++] = i - nread; + } + while (nread < i) + instrs[icnt++] = numberstack[nread++]; + } else { + while (i < npos && (numberstack[i] < 0 || numberstack[i] > 255)) + ++i; + if (i - nread <= 8) + instrs[icnt++] = ttf_pushw + (i - nread) - 1; + else { + instrs[icnt++] = ttf_npushw; + instrs[icnt++] = i - nread; + } + while (nread < i) { + instrs[icnt++] = numberstack[nread] >> 8; + instrs[icnt++] = numberstack[nread++] & 0xff; + } + } + } + brack = NULL; + for (end = pt; *end != '\r' && *end != '\n' && *end != ' ' && *end != '\0'; ++end) + if (*end == '[' || *end == '_') brack = end; + for (i = 0; i < 256; ++i) + if (strnmatch(pt, ff_ttf_instrnames[i], (int)(end - pt)) == 0 && + sizeof(char) * (end - pt) == strlen(ff_ttf_instrnames[i])) + break; + if (i == 256 && brack != NULL) { + for (i = 0; i < 256; ++i) + if (strnmatch(pt, ff_ttf_instrnames[i], (int)(brack - pt + 1)) == 0) break; + val = strtol(brack + 1, &bend, 2); /* Stuff in brackets should be in binary */ + while (*bend == ' ' || *bend == '\t') + ++bend; + if (*bend != ']') { + IVError(context, + "Missing right bracket in command (or bad binary value in bracket)", + (int)(pt - text)); + return (NULL); + } + if (val >= 32) { + IVError(context, "Bracketted value is too large", (int)(pt - text)); + return (NULL); + } + i += val; + } + pt = end; + instrs[icnt++] = i; + if (i == ttf_npushb || i == ttf_npushw || (i >= ttf_pushb && i <= ttf_pushw + 7)) { + push_size = (i == ttf_npushb || (i >= ttf_pushb && i <= ttf_pushb + 7)) ? 1 : 2; + if (i == ttf_npushb || i == ttf_npushw) + push_left = -1; + else if (i >= ttf_pushb && i <= ttf_pushb + 7) + push_left = i - ttf_pushb + 1; + else + push_left = i - ttf_pushw + 1; + } + if (*pt == '\0') break; + } + *len = icnt; + RESIZE(instrs, icnt == 0 ? 1 : icnt); + return instrs; /* some versions of realloc abort on 0 */ +} + +static int instr_typify(struct instrdata *id) { + int i, len = id->instr_cnt, cnt, j, lh; + uint8_t *instrs = id->instrs; + uint8_t *bts; + + if (id->bts == NULL) NEW(id->bts, len + 1); + bts = id->bts; + for (i = lh = 0; i < len; ++i) { + bts[i] = bt_instr; + ++lh; + if (instrs[i] == ttf_npushb) { + /* NPUSHB */ + bts[++i] = bt_cnt; + cnt = instrs[i]; + for (j = 0; j < cnt; ++j) + bts[++i] = bt_byte; + lh += 1 + cnt; + } else if (instrs[i] == ttf_npushw) { + /* NPUSHW */ + bts[++i] = bt_cnt; + ++lh; + cnt = instrs[i]; + for (j = 0; j < cnt; ++j) { + bts[++i] = bt_wordhi; + bts[++i] = bt_wordlo; + } + lh += 1 + cnt; + } else if ((instrs[i] & 0xf8) == 0xb0) { + /* PUSHB[n] */ + cnt = (instrs[i] & 7) + 1; + for (j = 0; j < cnt; ++j) + bts[++i] = bt_byte; + lh += cnt; + } else if ((instrs[i] & 0xf8) == 0xb8) { + /* PUSHW[n] */ + cnt = (instrs[i] & 7) + 1; + for (j = 0; j < cnt; ++j) { + bts[++i] = bt_wordhi; + bts[++i] = bt_wordlo; + } + lh += cnt; + } + } + bts[i] = bt_impliedreturn; + return (lh); +} + +json_value *dump_ttinstr(uint8_t *instructions, uint32_t length, const otfcc_Options *options) { + if (options->instr_as_bytes) { + size_t len = 0; + uint8_t *buf = base64_encode(instructions, length, &len); + return json_string_new_length((uint32_t)len, (char *)buf); + FREE(buf); + } else { + struct instrdata id; + + memset(&id, 0, sizeof(id)); + id.instr_cnt = length; + id.instrs = instructions; + instr_typify(&id); + json_value *ret = json_array_new(id.instr_cnt); + for (uint32_t i = 0; i < id.instr_cnt; ++i) { + if (id.bts[i] == bt_wordhi) { + json_array_push( + ret, json_integer_new((int16_t)((id.instrs[i] << 8) | id.instrs[i + 1]))); + ++i; + } else if (id.bts[i] == bt_cnt || id.bts[i] == bt_byte) { + json_array_push(ret, json_integer_new(id.instrs[i])); + } else { + json_array_push(ret, json_string_new(ff_ttf_instrnames[id.instrs[i]])); + } + } + FREE(id.bts); + return preserialize(ret); + } +} + +void parse_ttinstr(json_value *col, void *context, void (*Make)(void *, uint8_t *, uint32_t), + void (*Wrong)(void *, const char *, int)) { + if (!col) { + Make(context, NULL, 0); + } else if (col->type == json_string) { + size_t instrlen; + uint8_t *instructions = + base64_decode((uint8_t *)col->u.string.ptr, col->u.string.length, &instrlen); + Make(context, instructions, (uint32_t)instrlen); + } else if (col->type == json_array) { + size_t istrlen = 0; + for (uint32_t j = 0; j < col->u.array.length; j++) { + json_value *record = col->u.array.values[j]; + if (record->type == json_string) { + istrlen += record->u.string.length + 1; + } else if (record->type == json_integer) { + istrlen += 1 + 20; + } else { + Make(context, NULL, 0); + return; + } + } + sds instrString = sdsnewlen(NULL, istrlen + 1); + char *head = instrString; + for (uint32_t j = 0; j < col->u.array.length; j++) { + json_value *record = col->u.array.values[j]; + if (record->type == json_string) { + memcpy(head, record->u.string.ptr, sizeof(char) * record->u.string.length); + head += record->u.string.length; + } else if (record->type == json_integer) { + int n = snprintf(head, 20, "%d", (int)record->u.integer); + head += n; + } + *head = '\n'; + head++; + } + int instrLength = 0; + uint8_t *instructions = parse_instrs(instrString, &instrLength, context, Wrong); + sdsfree(instrString); + if (instructions && instrLength) { + Make(context, instructions, instrLength); + } else { + Make(context, NULL, 0); + } + } else { + Make(context, NULL, 0); + } +} |