summaryrefslogtreecommitdiff
path: root/Build/source/texk/dvipdfm-x/cff_dict.c
diff options
context:
space:
mode:
authorPeter Breitenlohner <peb@mppmu.mpg.de>2013-07-22 09:10:19 +0000
committerPeter Breitenlohner <peb@mppmu.mpg.de>2013-07-22 09:10:19 +0000
commit9390cbb84a9dca0d3d20e02765cc92902b06ec14 (patch)
tree5688e78de0248b85cda933213a1aaa01e550b460 /Build/source/texk/dvipdfm-x/cff_dict.c
parentccb5ed485c606f3475f6412c5f41f9c6dbd4484a (diff)
dvipdfm-x: Continue merging dvipdfmx and xdvipdfmx
git-svn-id: svn://tug.org/texlive/trunk@31262 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/dvipdfm-x/cff_dict.c')
-rw-r--r--Build/source/texk/dvipdfm-x/cff_dict.c734
1 files changed, 734 insertions, 0 deletions
diff --git a/Build/source/texk/dvipdfm-x/cff_dict.c b/Build/source/texk/dvipdfm-x/cff_dict.c
new file mode 100644
index 00000000000..aa2f07d0786
--- /dev/null
+++ b/Build/source/texk/dvipdfm-x/cff_dict.c
@@ -0,0 +1,734 @@
+/*
+
+ This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
+
+ Copyright (C) 2002-2012 by Jin-Hwan Cho and Shunsaku Hirata,
+ the dvipdfmx project team.
+
+ 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.
+*/
+
+/*
+ * CFF Font Dictionary
+ *
+ * Adobe Technical Note #5176 "The Compact Font Format Specification"
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "error.h"
+#include "mem.h"
+
+#ifndef CFF_DEBUG_STR
+#define CFF_DEBUG_STR "CFF"
+#define CFF_DEBUG 5
+#endif
+
+/* work_buffer for get_real() */
+#include "mfileio.h"
+
+#include "cff_types.h"
+#include "cff_limits.h"
+
+/* #include "cff_string.h" */
+#include "cff_dict.h"
+/* cff_update_dict requires this. */
+#include "cff.h"
+
+#define CFF_PARSE_OK 0
+#define CFF_ERROR_PARSE_ERROR -1
+#define CFF_ERROR_STACK_OVERFLOW -2
+#define CFF_ERROR_STACK_UNDERFLOW -3
+#define CFF_ERROR_STACK_RANGECHECK -4
+
+#define DICT_ENTRY_MAX 16
+cff_dict *cff_new_dict (void)
+{
+ cff_dict *dict;
+
+ dict = NEW(1, cff_dict);
+ dict->max = DICT_ENTRY_MAX;
+ dict->count = 0;
+ dict->entries = NEW(dict->max, cff_dict_entry);
+
+ return dict;
+}
+
+void cff_release_dict (cff_dict *dict)
+{
+ if (dict) {
+ if (dict->entries) {
+ int i;
+ for (i=0;i<dict->count;i++) {
+ if ((dict->entries)[i].values)
+ RELEASE((dict->entries)[i].values);
+ }
+ RELEASE(dict->entries);
+ }
+ RELEASE(dict);
+ }
+}
+
+/*
+ * Operand stack:
+ * only numbers are stored (as double)
+ *
+ * Operand types:
+ *
+ * number : double (integer or real)
+ * boolean: stored as a number
+ * SID : stored as a number
+ * array : array of numbers
+ * delta : array of numbers
+ */
+
+#define CFF_DICT_STACK_LIMIT 64
+static int stack_top = 0;
+static double arg_stack[CFF_DICT_STACK_LIMIT];
+
+/*
+ * CFF DICT encoding:
+ * TODO: default values
+ */
+
+#define CFF_LAST_DICT_OP1 22
+#define CFF_LAST_DICT_OP2 39
+#define CFF_LAST_DICT_OP (CFF_LAST_DICT_OP1 + CFF_LAST_DICT_OP2)
+
+static struct {
+ const char *opname;
+ int argtype;
+} dict_operator[CFF_LAST_DICT_OP] = {
+ {"version", CFF_TYPE_SID},
+ {"Notice", CFF_TYPE_SID},
+ {"FullName", CFF_TYPE_SID},
+ {"FamilyName", CFF_TYPE_SID},
+ {"Weight", CFF_TYPE_SID},
+ {"FontBBox", CFF_TYPE_ARRAY},
+ {"BlueValues", CFF_TYPE_DELTA},
+ {"OtherBlues", CFF_TYPE_DELTA},
+ {"FamilyBlues", CFF_TYPE_DELTA},
+ {"FamilyOtherBlues", CFF_TYPE_DELTA},
+ {"StdHW", CFF_TYPE_NUMBER},
+ {"StdVW", CFF_TYPE_NUMBER},
+ {NULL, -1}, /* first byte of two-byte operator */
+ /* Top */
+ {"UniqueID", CFF_TYPE_NUMBER},
+ {"XUID", CFF_TYPE_ARRAY},
+ {"charset", CFF_TYPE_OFFSET},
+ {"Encoding", CFF_TYPE_OFFSET},
+ {"CharStrings", CFF_TYPE_OFFSET},
+ {"Private", CFF_TYPE_SZOFF}, /* two numbers (size and offset) */
+ /* Private */
+ {"Subrs", CFF_TYPE_OFFSET},
+ {"defaultWidthX", CFF_TYPE_NUMBER},
+ {"nominalWidthX", CFF_TYPE_NUMBER},
+ /* Operator 2 */
+ {"Copyright", CFF_TYPE_SID},
+ {"IsFixedPitch", CFF_TYPE_BOOLEAN},
+ {"ItalicAngle", CFF_TYPE_NUMBER},
+ {"UnderlinePosition", CFF_TYPE_NUMBER},
+ {"UnderlineThickness", CFF_TYPE_NUMBER},
+ {"PaintType", CFF_TYPE_NUMBER},
+ {"CharstringType", CFF_TYPE_NUMBER},
+ {"FontMatrix", CFF_TYPE_ARRAY},
+ {"StrokeWidth", CFF_TYPE_NUMBER},
+ {"BlueScale", CFF_TYPE_NUMBER},
+ {"BlueShift", CFF_TYPE_NUMBER},
+ {"BlueFuzz", CFF_TYPE_NUMBER},
+ {"StemSnapH", CFF_TYPE_DELTA},
+ {"StemSnapV", CFF_TYPE_DELTA},
+ {"ForceBold", CFF_TYPE_BOOLEAN},
+ {NULL, -1},
+ {NULL, -1},
+ {"LanguageGroup", CFF_TYPE_NUMBER},
+ {"ExpansionFactor", CFF_TYPE_NUMBER},
+ {"InitialRandomSeed", CFF_TYPE_NUMBER},
+ {"SyntheticBase", CFF_TYPE_NUMBER},
+ {"PostScript", CFF_TYPE_SID},
+ {"BaseFontName", CFF_TYPE_SID},
+ {"BaseFontBlend", CFF_TYPE_DELTA}, /* MMaster ? */
+ {NULL, -1},
+ {NULL, -1},
+ {NULL, -1},
+ {NULL, -1},
+ {NULL, -1},
+ {NULL, -1},
+ /* CID-Keyed font */
+ {"ROS", CFF_TYPE_ROS}, /* SID SID number */
+ {"CIDFontVersion", CFF_TYPE_NUMBER},
+ {"CIDFontRevision", CFF_TYPE_NUMBER},
+ {"CIDFontType", CFF_TYPE_NUMBER},
+ {"CIDCount", CFF_TYPE_NUMBER},
+ {"UIDBase", CFF_TYPE_NUMBER},
+ {"FDArray", CFF_TYPE_OFFSET},
+ {"FDSelect", CFF_TYPE_OFFSET},
+ {"FontName", CFF_TYPE_SID},
+};
+
+/* Parse DICT data */
+static double get_integer (card8 **data, card8 *endptr, int *status)
+{
+ long result = 0;
+ card8 b0, b1, b2;
+
+ b0 = *(*data)++;
+ if (b0 == 28 && *data < endptr - 2) { /* shortint */
+ b1 = *(*data)++;
+ b2 = *(*data)++;
+ result = b1*256+b2;
+ if (result > 0x7fffL)
+ result -= 0x10000L;
+ } else if (b0 == 29 && *data < endptr - 4) { /* longint */
+ int i;
+ result = *(*data)++;
+ if (result > 0x7f)
+ result -= 0x100;
+ for (i=0;i<3;i++) {
+ result = result*256+(**data);
+ *data += 1;
+ }
+ } else if (b0 >= 32 && b0 <= 246) { /* int (1) */
+ result = b0 - 139;
+ } else if (b0 >= 247 && b0 <= 250) { /* int (2) */
+ b1 = *(*data)++;
+ result = (b0-247)*256+b1+108;
+ } else if (b0 >= 251 && b0 <= 254) {
+ b1 = *(*data)++;
+ result = -(b0-251)*256-b1-108;
+ } else {
+ *status = CFF_ERROR_PARSE_ERROR;
+ }
+
+ return (double) result;
+}
+
+/* Simply uses strtod */
+static double get_real(card8 **data, card8 *endptr, int *status)
+{
+ double result = 0.0;
+ int nibble = 0, pos = 0;
+ int len = 0, fail = 0;
+
+ if (**data != 30 || *data >= endptr -1) {
+ *status = CFF_ERROR_PARSE_ERROR;
+ return 0.0;
+ }
+
+ *data += 1; /* skip first byte (30) */
+
+ pos = 0;
+ while ((! fail) && len < WORK_BUFFER_SIZE - 2 && *data < endptr) {
+ /* get nibble */
+ if (pos % 2) {
+ nibble = **data & 0x0f;
+ *data += 1;
+ } else {
+ nibble = (**data >> 4) & 0x0f;
+ }
+ if (nibble >= 0x00 && nibble <= 0x09) {
+ work_buffer[len++] = nibble + '0';
+ } else if (nibble == 0x0a) { /* . */
+ work_buffer[len++] = '.';
+ } else if (nibble == 0x0b || nibble == 0x0c) { /* E, E- */
+ work_buffer[len++] = 'e';
+ if (nibble == 0x0c)
+ work_buffer[len++] = '-';
+ } else if (nibble == 0x0e) { /* `-' */
+ work_buffer[len++] = '-';
+ } else if (nibble == 0x0d) { /* skip */
+ /* do nothing */
+ } else if (nibble == 0x0f) { /* end */
+ work_buffer[len++] = '\0';
+ if (((pos % 2) == 0) && (**data != 0xff)) {
+ fail = 1;
+ }
+ break;
+ } else { /* invalid */
+ fail = 1;
+ }
+ pos++;
+ }
+
+ /* returned values */
+ if (fail || nibble != 0x0f) {
+ *status = CFF_ERROR_PARSE_ERROR;
+ } else {
+ char *s;
+ result = strtod(work_buffer, &s);
+ if (*s != 0 || errno == ERANGE) {
+ *status = CFF_ERROR_PARSE_ERROR;
+ }
+ }
+
+ return result;
+}
+
+/* operators */
+static void add_dict (cff_dict *dict,
+ card8 **data, card8 *endptr, int *status)
+{
+ int id, argtype;
+
+ id = **data;
+ if (id == 0x0c) {
+ *data += 1;
+ if (*data >= endptr ||
+ (id = **data + CFF_LAST_DICT_OP1) >= CFF_LAST_DICT_OP) {
+ *status = CFF_ERROR_PARSE_ERROR;
+ return;
+ }
+ } else if (id >= CFF_LAST_DICT_OP1) {
+ *status = CFF_ERROR_PARSE_ERROR;
+ return;
+ }
+
+ argtype = dict_operator[id].argtype;
+ if (dict_operator[id].opname == NULL || argtype < 0) {
+ *status = CFF_ERROR_PARSE_ERROR;
+ return;
+#ifndef XETEX
+ } else if (stack_top < 1) {
+ *status = CFF_ERROR_STACK_UNDERFLOW;
+ return;
+#endif
+ }
+
+ if (dict->count >= dict->max) {
+ dict->max += DICT_ENTRY_MAX;
+ dict->entries = RENEW(dict->entries, dict->max, cff_dict_entry);
+ }
+
+ (dict->entries)[dict->count].id = id;
+ (dict->entries)[dict->count].key = dict_operator[id].opname;
+ if (argtype == CFF_TYPE_NUMBER ||
+ argtype == CFF_TYPE_BOOLEAN ||
+ argtype == CFF_TYPE_SID ||
+ argtype == CFF_TYPE_OFFSET) {
+#ifdef XETEX
+ /* check for underflow here, as exactly one operand is expected */
+ if (stack_top < 1) {
+ *status = CFF_ERROR_STACK_UNDERFLOW;
+ return;
+ }
+#endif
+ stack_top--;
+ (dict->entries)[dict->count].count = 1;
+ (dict->entries)[dict->count].values = NEW(1, double);
+ (dict->entries)[dict->count].values[0] = arg_stack[stack_top];
+ dict->count += 1;
+ } else {
+#ifdef XETEX
+ /* just ignore operator if there were no operands provided;
+ don't treat this as underflow (e.g. StemSnapV in TemporaLGCUni-Italic.otf) */
+ if (stack_top > 0)
+#endif
+ {
+ (dict->entries)[dict->count].count = stack_top;
+ (dict->entries)[dict->count].values = NEW(stack_top, double);
+ while (stack_top > 0) {
+ stack_top--;
+ (dict->entries)[dict->count].values[stack_top] = arg_stack[stack_top];
+ }
+ dict->count += 1;
+ }
+ }
+
+ *data += 1;
+
+ return;
+}
+
+/*
+ * All operands are treated as number or array of numbers.
+ * Private: two numbers, size and offset
+ * ROS : three numbers, SID, SID, and a number
+ */
+cff_dict *cff_dict_unpack (card8 *data, card8 *endptr)
+{
+ cff_dict *dict;
+ int status = CFF_PARSE_OK;
+
+ stack_top = 0;
+
+ dict = cff_new_dict();
+ while (data < endptr && status == CFF_PARSE_OK) {
+ if (*data < 22) { /* operator */
+ add_dict(dict, &data, endptr, &status);
+ } else if (*data == 30) { /* real - First byte of a sequence (variable) */
+ if (stack_top < CFF_DICT_STACK_LIMIT) {
+ arg_stack[stack_top] = get_real(&data, endptr, &status);
+ stack_top++;
+ } else {
+ status = CFF_ERROR_STACK_OVERFLOW;
+ }
+ } else if (*data == 255 || (*data >= 22 && *data <= 27)) { /* reserved */
+ data++;
+ } else { /* everything else are integer */
+ if (stack_top < CFF_DICT_STACK_LIMIT) {
+ arg_stack[stack_top] = get_integer(&data, endptr, &status);
+ stack_top++;
+ } else {
+ status = CFF_ERROR_STACK_OVERFLOW;
+ }
+ }
+ }
+
+ if (status != CFF_PARSE_OK) {
+ ERROR("%s: Parsing CFF DICT failed. (error=%d)", CFF_DEBUG_STR, status);
+ } else if (stack_top != 0) {
+ WARN("%s: Garbage in CFF DICT data.", CFF_DEBUG_STR);
+ stack_top = 0;
+ }
+
+ return dict;
+}
+
+/* Pack DICT data */
+static long pack_integer (card8 *dest, long destlen, long value)
+{
+ long len = 0;
+
+ if (value >= -107 && value <= 107) {
+ if (destlen < 1)
+ ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
+ dest[0] = (value + 139) & 0xff;
+ len = 1;
+ } else if (value >= 108 && value <= 1131) {
+ if (destlen < 2)
+ ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
+ value = 0xf700u + value - 108;
+ dest[0] = (value >> 8) & 0xff;
+ dest[1] = value & 0xff;
+ len = 2;
+ } else if (value >= -1131 && value <= -108) {
+ if (destlen < 2)
+ ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
+ value = 0xfb00u - value - 108;
+ dest[0] = (value >> 8) & 0xff;
+ dest[1] = value & 0xff;
+ len = 2;
+ } else if (value >= -32768 && value <= 32767) { /* shortint */
+ if (destlen < 3)
+ ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
+ dest[0] = 28;
+ dest[1] = (value >> 8) & 0xff;
+ dest[2] = value & 0xff;
+ len = 3;
+ } else { /* longint */
+ if (destlen < 5)
+ ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
+ dest[0] = 29;
+ dest[1] = (value >> 24) & 0xff;
+ dest[2] = (value >> 16) & 0xff;
+ dest[3] = (value >> 8) & 0xff;
+ dest[4] = value & 0xff;
+ len = 5;
+ }
+
+ return len;
+}
+
+static long pack_real (card8 *dest, long destlen, double value)
+{
+ int i = 0, pos = 2;
+ char buffer[32];
+
+ if (destlen < 2)
+ ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
+
+ dest[0] = 30;
+
+ if (value == 0.0) {
+ dest[1] = 0x0f;
+ return 2;
+ }
+
+ if (value < 0.0) {
+ dest[1] = 0xe0;
+ value *= -1.0;
+ pos++;
+ }
+
+ /* To avoid the problem with Mac OS X 10.4 Quartz,
+ * change the presion of the real numbers
+ * on June 27, 2007 for musix20.pfb */
+ sprintf(buffer, "%.13g", value);
+
+ for (i = 0; buffer[i] != '\0'; i++) {
+ unsigned char ch = 0;
+ if (buffer[i] == '.') {
+ ch = 0x0a;
+ } else if (buffer[i] >= '0' && buffer[i] <= '9') {
+ ch = buffer[i] - '0';
+ } else if (buffer[i] == 'e') {
+ ch = (buffer[++i] == '-' ? 0x0c : 0x0b);
+ } else {
+ ERROR("%s: Invalid character.", CFF_DEBUG_STR);
+ }
+
+ if (destlen < pos/2 + 1)
+ ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
+
+ if (pos % 2) {
+ dest[pos/2] += ch;
+ } else {
+ dest[pos/2] = (ch << 4);
+ }
+ pos++;
+ }
+
+ if (pos % 2) {
+ dest[pos/2] += 0x0f;
+ pos++;
+ } else {
+ if (destlen < pos/2 + 1)
+ ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
+ dest[pos/2] = 0xff;
+ pos += 2;
+ }
+
+ return pos/2;
+}
+
+static long cff_dict_put_number (double value,
+ card8 *dest, long destlen,
+ int type)
+{
+ long len = 0;
+ double nearint;
+
+ nearint = floor(value+0.5);
+ /* set offset to longint */
+ if (type == CFF_TYPE_OFFSET) {
+ long lvalue;
+
+ lvalue = (long) value;
+ if (destlen < 5)
+ ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
+ dest[0] = 29;
+ dest[1] = (lvalue >> 24) & 0xff;
+ dest[2] = (lvalue >> 16) & 0xff;
+ dest[3] = (lvalue >> 8) & 0xff;
+ dest[4] = lvalue & 0xff;
+ len = 5;
+ } else if (value > CFF_INT_MAX || value < CFF_INT_MIN ||
+ (fabs(value - nearint) > 1.0e-5)) { /* real */
+ len = pack_real(dest, destlen, value);
+ } else { /* integer */
+ len = pack_integer(dest, destlen, (long) nearint);
+ }
+
+ return len;
+}
+
+static long
+put_dict_entry (cff_dict_entry *de,
+ card8 *dest, long destlen)
+{
+ long len = 0;
+ int i, type, id;
+
+ if (de->count > 0) {
+ id = de->id;
+ if (dict_operator[id].argtype == CFF_TYPE_OFFSET ||
+ dict_operator[id].argtype == CFF_TYPE_SZOFF) {
+ type = CFF_TYPE_OFFSET;
+ } else {
+ type = CFF_TYPE_NUMBER;
+ }
+ for (i = 0; i < de->count; i++) {
+ len += cff_dict_put_number(de->values[i],
+ dest+len,
+ destlen-len, type);
+ }
+ if (id >= 0 && id < CFF_LAST_DICT_OP1) {
+ if (len + 1 > destlen)
+ ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
+ dest[len++] = id;
+ } else if (id >= 0 && id < CFF_LAST_DICT_OP) {
+ if (len + 2 > destlen)
+ ERROR("in cff_dict_pack(): Buffer overflow");
+ dest[len++] = 12;
+ dest[len++] = id - CFF_LAST_DICT_OP1;
+ } else {
+ ERROR("%s: Invalid CFF DICT operator ID.", CFF_DEBUG_STR);
+ }
+ }
+
+ return len;
+}
+
+long cff_dict_pack (cff_dict *dict, card8 *dest, long destlen)
+{
+ long len = 0;
+ int i;
+
+ for (i = 0; i < dict->count; i++) {
+ if (!strcmp(dict->entries[i].key, "ROS")) {
+ len += put_dict_entry(&dict->entries[i], dest, destlen);
+ break;
+ }
+ }
+ for (i = 0; i < dict->count; i++) {
+ if (strcmp(dict->entries[i].key, "ROS")) {
+ len += put_dict_entry(&dict->entries[i], dest+len, destlen-len);
+ }
+ }
+
+ return len;
+}
+
+void cff_dict_add (cff_dict *dict, const char *key, int count)
+{
+ int id, i;
+
+ for (id=0;id<CFF_LAST_DICT_OP;id++) {
+ if (key && dict_operator[id].opname &&
+ strcmp(dict_operator[id].opname, key) == 0)
+ break;
+ }
+
+ if (id == CFF_LAST_DICT_OP)
+ ERROR("%s: Unknown CFF DICT operator.", CFF_DEBUG_STR);
+
+ for (i=0;i<dict->count;i++) {
+ if ((dict->entries)[i].id == id) {
+ if ((dict->entries)[i].count != count)
+ ERROR("%s: Inconsistent DICT argument number.", CFF_DEBUG_STR);
+ return;
+ }
+ }
+
+ if (dict->count + 1 >= dict->max) {
+ dict->max += 8;
+ dict->entries = RENEW(dict->entries, dict->max, cff_dict_entry);
+ }
+
+ (dict->entries)[dict->count].id = id;
+ (dict->entries)[dict->count].key = dict_operator[id].opname;
+ (dict->entries)[dict->count].count = count;
+ if (count > 0) {
+ (dict->entries)[dict->count].values = NEW(count, double);
+ memset((dict->entries)[dict->count].values,
+ 0, sizeof(double)*count);
+ } else {
+ (dict->entries)[dict->count].values = NULL;
+ }
+ dict->count += 1;
+
+ return;
+}
+
+void cff_dict_remove (cff_dict *dict, const char *key)
+{
+ int i;
+ for (i = 0; i < dict->count; i++) {
+ if (key && strcmp(key, (dict->entries)[i].key) == 0) {
+ (dict->entries)[i].count = 0;
+ if ((dict->entries)[i].values)
+ RELEASE((dict->entries)[i].values);
+ (dict->entries)[i].values = NULL;
+ }
+ }
+}
+
+int cff_dict_known (cff_dict *dict, const char *key)
+{
+ int i;
+
+ for (i = 0; i < dict->count; i++) {
+ if (key && strcmp(key, (dict->entries)[i].key) == 0
+ && (dict->entries)[i].count > 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+double cff_dict_get (cff_dict *dict, const char *key, int idx)
+{
+ double value = 0.0;
+ int i;
+
+ ASSERT(key && dict);
+
+ for (i = 0; i < dict->count; i++) {
+ if (strcmp(key, (dict->entries)[i].key) == 0) {
+ if ((dict->entries)[i].count > idx)
+ value = (dict->entries)[i].values[idx];
+ else
+ ERROR("%s: Invalid index number.", CFF_DEBUG_STR);
+ break;
+ }
+ }
+
+ if (i == dict->count)
+ ERROR("%s: DICT entry \"%s\" not found.", CFF_DEBUG_STR, key);
+
+ return value;
+}
+
+void cff_dict_set (cff_dict *dict, const char *key, int idx, double value)
+{
+ int i;
+
+ ASSERT(dict && key);
+
+ for (i = 0 ; i < dict->count; i++) {
+ if (strcmp(key, (dict->entries)[i].key) == 0) {
+ if ((dict->entries)[i].count > idx)
+ (dict->entries)[i].values[idx] = value;
+ else
+ ERROR("%s: Invalid index number.", CFF_DEBUG_STR);
+ break;
+ }
+ }
+
+ if (i == dict->count)
+ ERROR("%s: DICT entry \"%s\" not found.", CFF_DEBUG_STR, key);
+}
+
+void cff_dict_update (cff_dict *dict, cff_font *cff)
+{
+ int i;
+
+ for (i = 0;i < dict->count; i++) {
+ if ((dict->entries)[i].count > 0) {
+ char *str;
+ int id;
+
+ id = (dict->entries)[i].id;
+ if (dict_operator[id].argtype == CFF_TYPE_SID) {
+ str = cff_get_string(cff, (dict->entries)[i].values[0]);
+ (dict->entries)[i].values[0] = cff_add_string(cff, str, 1);
+ RELEASE(str);
+ } else if (dict_operator[id].argtype == CFF_TYPE_ROS) {
+ str = cff_get_string(cff, (dict->entries)[i].values[0]);
+ (dict->entries)[i].values[0] = cff_add_string(cff, str, 1);
+ RELEASE(str);
+ str = cff_get_string(cff, (dict->entries)[i].values[1]);
+ (dict->entries)[i].values[1] = cff_add_string(cff, str, 1);
+ RELEASE(str);
+ }
+ }
+ }
+}