Back to index

texmacs  1.0.7.15
cff_dict.c
Go to the documentation of this file.
00001 /*  $Header: /home/cvsroot/dvipdfmx/src/cff_dict.c,v 1.17 2008/10/13 19:42:48 matthias Exp $
00002     
00003     This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
00004 
00005     Copyright (C) 2007 by Jin-Hwan Cho and Shunsaku Hirata,
00006     the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
00007     
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012     
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017     
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00021 */
00022 
00023 /*
00024  * CFF Font Dictionary
00025  *
00026  *  Adobe Technical Note #5176 "The Compact Font Format Specification"
00027  */
00028 
00029 #include <math.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <errno.h>
00033 
00034 #include "error.h"
00035 #include "mem.h"
00036 
00037 #ifndef CFF_DEBUG_STR
00038 #define CFF_DEBUG_STR "CFF"
00039 #define CFF_DEBUG     5
00040 #endif
00041 
00042 /* work_buffer for get_real() */
00043 #include "mfileio.h"
00044 
00045 #include "cff_types.h"
00046 #include "cff_limits.h"
00047 
00048 /* #include "cff_string.h" */
00049 #include "cff_dict.h"
00050 /* cff_update_dict requires this. */
00051 #include "cff.h"
00052 
00053 #define CFF_PARSE_OK                0
00054 #define CFF_ERROR_PARSE_ERROR      -1
00055 #define CFF_ERROR_STACK_OVERFLOW   -2
00056 #define CFF_ERROR_STACK_UNDERFLOW  -3
00057 #define CFF_ERROR_STACK_RANGECHECK -4
00058 
00059 #define DICT_ENTRY_MAX 16
00060 cff_dict *cff_new_dict (void)
00061 {
00062   cff_dict *dict;
00063 
00064   dict = NEW(1, cff_dict);
00065   dict->max     = DICT_ENTRY_MAX;
00066   dict->count   = 0;
00067   dict->entries = NEW(dict->max, cff_dict_entry);
00068 
00069   return dict;
00070 }
00071 
00072 void cff_release_dict (cff_dict *dict)
00073 {
00074   if (dict) {
00075     if (dict->entries) {
00076       int i;
00077       for (i=0;i<dict->count;i++) {
00078        if ((dict->entries)[i].values)
00079          RELEASE((dict->entries)[i].values);
00080       }
00081       RELEASE(dict->entries);
00082     }
00083   RELEASE(dict);
00084   }
00085 }
00086 
00087 /*
00088  * Operand stack:
00089  *  only numbers are stored (as double)
00090  *
00091  * Operand types:
00092  *
00093  * number : double (integer or real)
00094  * boolean: stored as a number
00095  * SID    : stored as a number
00096  * array  : array of numbers
00097  * delta  : array of numbers
00098  */
00099 
00100 #define CFF_DICT_STACK_LIMIT 64
00101 static int    stack_top = 0;
00102 static double arg_stack[CFF_DICT_STACK_LIMIT];
00103 
00104 /*
00105  * CFF DICT encoding:
00106  * TODO: default values
00107  */
00108 
00109 #define CFF_LAST_DICT_OP1 22
00110 #define CFF_LAST_DICT_OP2 39
00111 #define CFF_LAST_DICT_OP (CFF_LAST_DICT_OP1 + CFF_LAST_DICT_OP2)
00112 
00113 static struct {
00114   const char *opname;
00115   int   argtype;
00116 } dict_operator[CFF_LAST_DICT_OP] = {
00117   {"version",     CFF_TYPE_SID},
00118   {"Notice",      CFF_TYPE_SID},
00119   {"FullName",    CFF_TYPE_SID},
00120   {"FamilyName",  CFF_TYPE_SID},
00121   {"Weight",      CFF_TYPE_SID},
00122   {"FontBBox",    CFF_TYPE_ARRAY},
00123   {"BlueValues",       CFF_TYPE_DELTA},
00124   {"OtherBlues",       CFF_TYPE_DELTA},
00125   {"FamilyBlues",      CFF_TYPE_DELTA},
00126   {"FamilyOtherBlues", CFF_TYPE_DELTA},
00127   {"StdHW",            CFF_TYPE_NUMBER},
00128   {"StdVW",            CFF_TYPE_NUMBER},
00129   {NULL, -1},  /* first byte of two-byte operator */
00130   /* Top */
00131   {"UniqueID",    CFF_TYPE_NUMBER},
00132   {"XUID",        CFF_TYPE_ARRAY},
00133   {"charset",     CFF_TYPE_OFFSET},
00134   {"Encoding",    CFF_TYPE_OFFSET},
00135   {"CharStrings", CFF_TYPE_OFFSET},
00136   {"Private",     CFF_TYPE_SZOFF}, /* two numbers (size and offset) */
00137   /* Private */
00138   {"Subrs",         CFF_TYPE_OFFSET},
00139   {"defaultWidthX", CFF_TYPE_NUMBER},
00140   {"nominalWidthX", CFF_TYPE_NUMBER},
00141   /* Operator 2 */
00142   {"Copyright",          CFF_TYPE_SID},
00143   {"IsFixedPitch",       CFF_TYPE_BOOLEAN},
00144   {"ItalicAngle",        CFF_TYPE_NUMBER},
00145   {"UnderlinePosition",  CFF_TYPE_NUMBER},
00146   {"UnderlineThickness", CFF_TYPE_NUMBER},
00147   {"PaintType",      CFF_TYPE_NUMBER},
00148   {"CharstringType", CFF_TYPE_NUMBER},
00149   {"FontMatrix",     CFF_TYPE_ARRAY},
00150   {"StrokeWidth",    CFF_TYPE_NUMBER},
00151   {"BlueScale", CFF_TYPE_NUMBER},
00152   {"BlueShift", CFF_TYPE_NUMBER},
00153   {"BlueFuzz",  CFF_TYPE_NUMBER},
00154   {"StemSnapH", CFF_TYPE_DELTA},
00155   {"StemSnapV", CFF_TYPE_DELTA},
00156   {"ForceBold", CFF_TYPE_BOOLEAN},
00157   {NULL, -1},
00158   {NULL, -1},
00159   {"LanguageGroup",     CFF_TYPE_NUMBER},
00160   {"ExpansionFactor",   CFF_TYPE_NUMBER},
00161   {"InitialRandomSeed", CFF_TYPE_NUMBER},
00162   {"SyntheticBase", CFF_TYPE_NUMBER},
00163   {"PostScript",    CFF_TYPE_SID},
00164   {"BaseFontName",  CFF_TYPE_SID},
00165   {"BaseFontBlend", CFF_TYPE_DELTA}, /* MMaster ? */
00166   {NULL, -1},
00167   {NULL, -1},
00168   {NULL, -1},
00169   {NULL, -1},
00170   {NULL, -1},
00171   {NULL, -1},
00172   /* CID-Keyed font */
00173   {"ROS",             CFF_TYPE_ROS}, /* SID SID number */
00174   {"CIDFontVersion",  CFF_TYPE_NUMBER},
00175   {"CIDFontRevision", CFF_TYPE_NUMBER},
00176   {"CIDFontType",     CFF_TYPE_NUMBER},
00177   {"CIDCount",        CFF_TYPE_NUMBER},
00178   {"UIDBase",         CFF_TYPE_NUMBER},
00179   {"FDArray",         CFF_TYPE_OFFSET},
00180   {"FDSelect",        CFF_TYPE_OFFSET},
00181   {"FontName",        CFF_TYPE_SID},
00182 };
00183 
00184 /* Parse DICT data */
00185 static double get_integer (card8 **data, card8 *endptr, int *status)
00186 {
00187   long result = 0;
00188   card8 b0, b1, b2;
00189 
00190   b0 = *(*data)++;
00191   if (b0 == 28 && *data < endptr - 2) { /* shortint */
00192     b1 = *(*data)++;
00193     b2 = *(*data)++;
00194     result = b1*256+b2;
00195     if (result > 0x7fffL)
00196       result -= 0x10000L;
00197   } else if (b0 == 29 && *data < endptr - 4) { /* longint */
00198     int i;
00199     result = *(*data)++;
00200     if (result > 0x7f)
00201       result -= 0x100;
00202     for (i=0;i<3;i++) {
00203       result = result*256+(**data);
00204       *data += 1;
00205     }
00206   } else if (b0 >= 32 && b0 <= 246) { /* int (1) */
00207     result = b0 - 139;
00208   } else if (b0 >= 247 && b0 <= 250) { /* int (2) */
00209     b1 = *(*data)++;
00210     result = (b0-247)*256+b1+108;
00211   } else if (b0 >= 251 && b0 <= 254) {
00212     b1 = *(*data)++;
00213     result = -(b0-251)*256-b1-108;
00214   } else {
00215     *status = CFF_ERROR_PARSE_ERROR;
00216   }
00217 
00218   return (double) result;
00219 }
00220 
00221 /* Simply uses strtod */
00222 static double get_real(card8 **data, card8 *endptr, int *status)
00223 {
00224   double result = 0.0;
00225   int nibble = 0, pos = 0;
00226   int len = 0, fail = 0;
00227 
00228   if (**data != 30 || *data >= endptr -1) {
00229     *status = CFF_ERROR_PARSE_ERROR;
00230     return 0.0;
00231   }
00232 
00233   *data += 1; /* skip first byte (30) */
00234 
00235   pos = 0;
00236   while ((! fail) && len < WORK_BUFFER_SIZE - 2 && *data < endptr) {
00237     /* get nibble */
00238     if (pos % 2) {
00239       nibble = **data & 0x0f;
00240       *data += 1;
00241     } else {
00242       nibble = (**data >> 4) & 0x0f;
00243     }
00244     if (nibble >= 0x00 && nibble <= 0x09) {
00245       work_buffer[len++] = nibble + '0';
00246     } else if (nibble == 0x0a) { /* . */
00247       work_buffer[len++] = '.';
00248     } else if (nibble == 0x0b || nibble == 0x0c) { /* E, E- */
00249       work_buffer[len++] = 'e';
00250       if (nibble == 0x0c)
00251        work_buffer[len++] = '-';
00252     } else if (nibble == 0x0e) { /* `-' */
00253       work_buffer[len++] = '-';
00254     } else if (nibble == 0x0d) { /* skip */
00255       /* do nothing */
00256     } else if (nibble == 0x0f) { /* end */
00257       work_buffer[len++] = '\0';
00258       if (((pos % 2) == 0) && (**data != 0xff)) {
00259        fail = 1;
00260       }
00261       break;
00262     } else { /* invalid */
00263       fail = 1;
00264     }
00265     pos++;
00266   }
00267 
00268   /* returned values */
00269   if (fail || nibble != 0x0f) {
00270     *status = CFF_ERROR_PARSE_ERROR;
00271   } else {
00272     char *s;
00273     result = strtod(work_buffer, &s);
00274     if (*s != 0 || errno == ERANGE) {
00275       *status = CFF_ERROR_PARSE_ERROR;
00276     }
00277   }
00278 
00279   return result;
00280 }
00281 
00282 /* operators */
00283 static void add_dict (cff_dict *dict,
00284                     card8 **data, card8 *endptr, int *status)
00285 {
00286   int id, argtype;
00287 
00288   id = **data;
00289   if (id == 0x0c) {
00290     *data += 1;
00291     if (*data >= endptr ||
00292        (id = **data + CFF_LAST_DICT_OP1) >= CFF_LAST_DICT_OP) {
00293       *status = CFF_ERROR_PARSE_ERROR;
00294       return;
00295     }
00296   } else if (id >= CFF_LAST_DICT_OP1) {
00297     *status = CFF_ERROR_PARSE_ERROR;
00298     return;
00299   }
00300 
00301   argtype = dict_operator[id].argtype;
00302   if (dict_operator[id].opname == NULL || argtype < 0) {
00303     *status = CFF_ERROR_PARSE_ERROR;
00304     return;
00305   } else if (stack_top < 1) {
00306     *status = CFF_ERROR_STACK_UNDERFLOW;
00307     return;
00308   }
00309 
00310   if (dict->count >= dict->max) {
00311     dict->max += DICT_ENTRY_MAX;
00312     dict->entries = RENEW(dict->entries, dict->max, cff_dict_entry);
00313   }
00314 
00315   (dict->entries)[dict->count].id = id;
00316   (dict->entries)[dict->count].key = (char *) dict_operator[id].opname;
00317   if (argtype == CFF_TYPE_NUMBER ||
00318       argtype == CFF_TYPE_BOOLEAN ||
00319       argtype == CFF_TYPE_SID ||
00320       argtype == CFF_TYPE_OFFSET) {
00321     stack_top--;
00322     (dict->entries)[dict->count].count  = 1;
00323     (dict->entries)[dict->count].values = NEW(1, double);
00324     (dict->entries)[dict->count].values[0] = arg_stack[stack_top];
00325   } else {
00326     (dict->entries)[dict->count].count  = stack_top;
00327     (dict->entries)[dict->count].values = NEW(stack_top, double);
00328     while (stack_top > 0) {
00329       stack_top--;
00330       (dict->entries)[dict->count].values[stack_top] = arg_stack[stack_top];
00331     }
00332   }
00333 
00334   dict->count += 1;
00335   *data += 1;
00336 
00337   return;
00338 }
00339 
00340 /*
00341  * All operands are treated as number or array of numbers.
00342  *  Private: two numbers, size and offset
00343  *  ROS    : three numbers, SID, SID, and a number
00344  */
00345 cff_dict *cff_dict_unpack (card8 *data, card8 *endptr)
00346 {
00347   cff_dict *dict;
00348   int status = CFF_PARSE_OK;
00349 
00350   stack_top = 0;
00351 
00352   dict = cff_new_dict();
00353   while (data < endptr && status == CFF_PARSE_OK) {
00354     if (*data < 22) { /* operator */
00355       add_dict(dict, &data, endptr, &status);
00356     } else if (*data == 30) { /* real - First byte of a sequence (variable) */
00357       if (stack_top < CFF_DICT_STACK_LIMIT) {
00358        arg_stack[stack_top] = get_real(&data, endptr, &status);
00359        stack_top++;
00360       } else {
00361        status = CFF_ERROR_STACK_OVERFLOW;
00362       }
00363     } else if (*data == 255 || (*data >= 22 && *data <= 27)) { /* reserved */
00364       data++;
00365     } else { /* everything else are integer */
00366       if (stack_top < CFF_DICT_STACK_LIMIT) {
00367        arg_stack[stack_top] = get_integer(&data, endptr, &status);
00368        stack_top++;
00369       } else {
00370        status = CFF_ERROR_STACK_OVERFLOW;
00371       }
00372     }
00373   }
00374 
00375   if (status != CFF_PARSE_OK) {
00376     ERROR("%s: Parsing CFF DICT failed. (error=%d)", CFF_DEBUG_STR, status);
00377   } else if (stack_top != 0) {
00378     WARN("%s: Garbage in CFF DICT data.", CFF_DEBUG_STR);
00379     stack_top = 0;
00380   }
00381 
00382   return dict;
00383 }
00384 
00385 /* Pack DICT data */
00386 static long pack_integer (card8 *dest, long destlen, long value)
00387 {
00388   long len = 0;
00389 
00390   if (value >= -107 && value <= 107) {
00391     if (destlen < 1)
00392       ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
00393     dest[0] = (value + 139) & 0xff;
00394     len = 1;
00395   } else if (value >= 108 && value <= 1131) {
00396     if (destlen < 2)
00397       ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
00398     value = 0xf700u + value - 108;
00399     dest[0] = (value >> 8) & 0xff;
00400     dest[1] = value & 0xff;
00401     len = 2;
00402   } else if (value >= -1131 && value <= -108) {
00403     if (destlen < 2)
00404       ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
00405     value = 0xfb00u - value - 108;
00406     dest[0] = (value >> 8) & 0xff;
00407     dest[1] = value & 0xff;
00408     len = 2;
00409   } else if (value >= -32768 && value <= 32767) { /* shortint */
00410     if (destlen < 3)
00411       ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
00412     dest[0] = 28;
00413     dest[1] = (value >> 8) & 0xff;
00414     dest[2] = value & 0xff;
00415     len = 3;
00416   } else { /* longint */
00417     if (destlen < 5)
00418       ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
00419     dest[0] = 29;
00420     dest[1] = (value >> 24) & 0xff;
00421     dest[2] = (value >> 16) & 0xff;
00422     dest[3] = (value >> 8) & 0xff;
00423     dest[4] = value & 0xff;
00424     len = 5;
00425   }
00426 
00427   return len;
00428 }
00429 
00430 static long pack_real (card8 *dest, long destlen, double value)
00431 {
00432   int i = 0, pos = 2;
00433   char buffer[32];
00434 
00435   if (destlen < 2)
00436     ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
00437 
00438   dest[0] = 30;
00439 
00440   if (value == 0.0) {
00441     dest[1] = 0x0f;
00442     return 2;
00443   }
00444 
00445   if (value < 0.0) {
00446     dest[1] = 0xe0;
00447     value *= -1.0;
00448     pos++;
00449   }
00450 
00451   /* To avoid the problem with Mac OS X 10.4 Quartz,
00452    * change the presion of the real numbers
00453    * on June 27, 2007 for musix20.pfb */
00454   sprintf(buffer, "%.13g", value);
00455 
00456   for (i = 0; buffer[i] != '\0'; i++) {
00457     unsigned char ch = 0;
00458     if (buffer[i] == '.') {
00459       ch = 0x0a;
00460     } else if (buffer[i] >= '0' && buffer[i] <= '9') {
00461       ch = buffer[i] - '0';
00462     } else if (buffer[i] == 'e') {
00463       ch = (buffer[++i] == '-' ? 0x0c : 0x0b);
00464     } else {
00465       ERROR("%s: Invalid character.", CFF_DEBUG_STR);
00466     }
00467 
00468     if (destlen < pos/2 + 1)
00469       ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
00470 
00471     if (pos % 2) {
00472       dest[pos/2] += ch;
00473     } else {
00474       dest[pos/2] = (ch << 4);
00475     }
00476     pos++;
00477   }
00478 
00479   if (pos % 2) {
00480     dest[pos/2] += 0x0f;
00481     pos++;
00482   } else {
00483     if (destlen < pos/2 + 1)
00484       ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
00485     dest[pos/2] = 0xff;
00486     pos += 2;
00487   }
00488 
00489   return pos/2;
00490 }
00491 
00492 static long cff_dict_put_number (double value,
00493                              card8 *dest, long destlen,
00494                              int type)
00495 {
00496   long   len = 0;
00497   double nearint;
00498 
00499   nearint = floor(value+0.5);
00500   /* set offset to longint */
00501   if (type == CFF_TYPE_OFFSET) {
00502     long lvalue;
00503 
00504     lvalue = (long) value;
00505     if (destlen < 5)
00506       ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
00507     dest[0] = 29;
00508     dest[1] = (lvalue >> 24) & 0xff;
00509     dest[2] = (lvalue >> 16) & 0xff;
00510     dest[3] = (lvalue >>  8) & 0xff;
00511     dest[4] = lvalue         & 0xff;
00512     len = 5;
00513   } else if (value > CFF_INT_MAX || value < CFF_INT_MIN ||
00514             (fabs(value - nearint) > 1.0e-5)) { /* real */
00515     len = pack_real(dest, destlen, value);
00516   } else { /* integer */
00517     len = pack_integer(dest, destlen, (long) nearint);
00518   }
00519 
00520   return len;
00521 }
00522 
00523 static long
00524 put_dict_entry (cff_dict_entry *de,
00525               card8 *dest, long destlen)
00526 {
00527   long len = 0;
00528   int  i, type, id;
00529 
00530   if (de->count > 0) {
00531     id = de->id;
00532     if (dict_operator[id].argtype == CFF_TYPE_OFFSET ||
00533        dict_operator[id].argtype == CFF_TYPE_SZOFF) {
00534       type = CFF_TYPE_OFFSET;
00535     } else {
00536       type = CFF_TYPE_NUMBER;
00537     }
00538     for (i = 0; i < de->count; i++) {
00539       len += cff_dict_put_number(de->values[i],
00540                              dest+len,
00541                              destlen-len, type);
00542     }
00543     if (id >= 0 && id < CFF_LAST_DICT_OP1) {
00544       if (len + 1 > destlen)
00545        ERROR("%s: Buffer overflow.", CFF_DEBUG_STR);
00546       dest[len++] = id;
00547     } else if (id >= 0 && id < CFF_LAST_DICT_OP) {
00548       if (len + 2 > destlen)
00549        ERROR("in cff_dict_pack(): Buffer overflow");
00550       dest[len++] = 12;
00551       dest[len++] = id - CFF_LAST_DICT_OP1;
00552     } else {
00553       ERROR("%s: Invalid CFF DICT operator ID.", CFF_DEBUG_STR);
00554     }
00555   }
00556 
00557   return len;
00558 }
00559 
00560 long cff_dict_pack (cff_dict *dict, card8 *dest, long destlen)
00561 {
00562   long len = 0;
00563   int  i;
00564 
00565   for (i = 0; i < dict->count; i++) {
00566     if (!strcmp(dict->entries[i].key, "ROS")) {
00567       len += put_dict_entry(&dict->entries[i], dest, destlen);
00568       break;
00569     }
00570   }
00571   for (i = 0; i < dict->count; i++) {
00572     if (strcmp(dict->entries[i].key, "ROS")) {
00573       len += put_dict_entry(&dict->entries[i], dest+len, destlen-len);
00574     }
00575   }
00576 
00577   return len;
00578 }
00579 
00580 void cff_dict_add (cff_dict *dict, const char *key, int count)
00581 {
00582   int id, i;
00583 
00584   for (id=0;id<CFF_LAST_DICT_OP;id++) {
00585     if (key && dict_operator[id].opname &&
00586        strcmp(dict_operator[id].opname, key) == 0)
00587       break;
00588   }
00589 
00590   if (id == CFF_LAST_DICT_OP)
00591     ERROR("%s: Unknown CFF DICT operator.", CFF_DEBUG_STR);
00592 
00593   for (i=0;i<dict->count;i++) {
00594     if ((dict->entries)[i].id == id) {
00595       if ((dict->entries)[i].count != count)
00596        ERROR("%s: Inconsistent DICT argument number.", CFF_DEBUG_STR);
00597       return;
00598     }
00599   }
00600 
00601   if (dict->count + 1 >= dict->max) {
00602     dict->max += 8;
00603     dict->entries = RENEW(dict->entries, dict->max, cff_dict_entry);
00604   }
00605 
00606   (dict->entries)[dict->count].id    = id;
00607   (dict->entries)[dict->count].key   = (char *) dict_operator[id].opname;
00608   (dict->entries)[dict->count].count = count;
00609   if (count > 0) {
00610     (dict->entries)[dict->count].values = NEW(count, double);
00611     memset((dict->entries)[dict->count].values,
00612           0, sizeof(double)*count);
00613   } else {
00614     (dict->entries)[dict->count].values = NULL;
00615   }
00616   dict->count += 1;
00617 
00618   return;
00619 }
00620 
00621 void cff_dict_remove (cff_dict *dict, const char *key)
00622 {
00623   int i;
00624   for (i = 0; i < dict->count; i++) {
00625     if (key && strcmp(key, (dict->entries)[i].key) == 0) {
00626       (dict->entries)[i].count = 0;
00627       if ((dict->entries)[i].values)
00628        RELEASE((dict->entries)[i].values);
00629       (dict->entries)[i].values = NULL;
00630     }
00631   }
00632 }
00633 
00634 int cff_dict_known (cff_dict *dict, const char *key)
00635 {
00636   int i;
00637 
00638   for (i = 0; i < dict->count; i++) {
00639     if (key && strcmp(key, (dict->entries)[i].key) == 0
00640        && (dict->entries)[i].count > 0)
00641       return 1;
00642   }
00643 
00644   return 0;
00645 }
00646 
00647 double cff_dict_get (cff_dict *dict, const char *key, int idx)
00648 {
00649   double value = 0.0;
00650   int    i;
00651 
00652   ASSERT(key && dict);
00653 
00654   for (i = 0; i < dict->count; i++) {
00655     if (strcmp(key, (dict->entries)[i].key) == 0) {
00656       if ((dict->entries)[i].count > idx)
00657        value = (dict->entries)[i].values[idx];
00658       else
00659        ERROR("%s: Invalid index number.", CFF_DEBUG_STR);
00660       break;
00661     }
00662   }
00663 
00664   if (i == dict->count)
00665     ERROR("%s: DICT entry \"%s\" not found.", CFF_DEBUG_STR, key);
00666 
00667   return value;
00668 }
00669 
00670 void cff_dict_set (cff_dict *dict, const char *key, int idx, double value)
00671 {
00672   int i;
00673 
00674   ASSERT(dict && key);
00675 
00676   for (i = 0 ; i < dict->count; i++) {
00677     if (strcmp(key, (dict->entries)[i].key) == 0) {
00678       if ((dict->entries)[i].count > idx)
00679        (dict->entries)[i].values[idx] = value;
00680       else
00681        ERROR("%s: Invalid index number.", CFF_DEBUG_STR);
00682       break;
00683     }
00684   }
00685 
00686   if (i == dict->count)
00687     ERROR("%s: DICT entry \"%s\" not found.", CFF_DEBUG_STR, key);
00688 }
00689 
00690 void cff_dict_update (cff_dict *dict, cff_font *cff)
00691 {
00692   int i;
00693 
00694   for (i = 0;i < dict->count; i++) {
00695     if ((dict->entries)[i].count > 0) {
00696       char *str;
00697       int   id;
00698 
00699       id = (dict->entries)[i].id;
00700       if (dict_operator[id].argtype == CFF_TYPE_SID) {
00701        str = cff_get_string(cff, (dict->entries)[i].values[0]);
00702        (dict->entries)[i].values[0] = cff_add_string(cff, str, 1);
00703        RELEASE(str);
00704       } else if (dict_operator[id].argtype == CFF_TYPE_ROS) {
00705        str = cff_get_string(cff, (dict->entries)[i].values[0]);
00706        (dict->entries)[i].values[0] = cff_add_string(cff, str, 1);
00707        RELEASE(str);
00708        str = cff_get_string(cff, (dict->entries)[i].values[1]);
00709        (dict->entries)[i].values[1] = cff_add_string(cff, str, 1);
00710        RELEASE(str);
00711       }
00712     }
00713   }
00714 }