Back to index

texmacs  1.0.7.15
cff.c
Go to the documentation of this file.
00001 /*  $Header: /home/cvsroot/dvipdfmx/src/cff.c,v 1.17 2009/03/24 07:55:52 chofchof Exp $
00002     
00003     This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
00004 
00005     Copyright (C) 2002 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 #include <stdio.h>
00024 #include <string.h>
00025 
00026 #include "system.h"
00027 #include "mem.h"
00028 #include "error.h"
00029 #include "mfileio.h"
00030 
00031 #include "cff_limits.h"
00032 #include "cff_types.h"
00033 #include "cff_stdstr.h"
00034 #include "cff_dict.h"
00035 
00036 #include "cff.h"
00037 
00038 #define CFF_DEBUG     5
00039 #define CFF_DEBUG_STR "CFF"
00040 
00041 static unsigned long get_unsigned (FILE *stream, int n)
00042 {
00043   unsigned long v = 0;
00044 
00045   while (n-- > 0)
00046     v = v*0x100u + get_unsigned_byte(stream);
00047 
00048   return v;
00049 }
00050 
00051 #define get_offset(s, n) get_unsigned((s), (n))
00052 #define get_card8(s)     get_unsigned_byte((s))
00053 #define get_card16(s)    get_unsigned_pair((s))
00054 
00055 /*
00056  * Read Header, Name INDEX, Top DICT INDEX, and String INDEX.
00057  */
00058 cff_font *cff_open(FILE *stream, long offset, int n)
00059 {
00060   cff_font  *cff;
00061   cff_index *idx;
00062 
00063   cff = NEW(1, cff_font);
00064 
00065   cff->fontname = NULL;
00066   cff->index    = n;
00067   cff->stream   = stream;
00068   cff->offset   = offset;
00069   cff->filter   = 0;      /* not used */
00070   cff->flag     = 0;
00071 
00072   cff->name     = NULL;
00073   cff->gsubr    = NULL;
00074   cff->encoding = NULL;
00075   cff->charsets = NULL;
00076   cff->fdselect = NULL;
00077   cff->cstrings = NULL;
00078   cff->fdarray  = NULL;
00079   cff->private  = NULL;
00080   cff->subrs    = NULL;
00081 
00082   cff->num_glyphs = 0;
00083   cff->num_fds    = 0;
00084   cff->_string    = NULL;
00085 
00086   cff_seek_set(cff, 0);
00087   cff->header.major    = get_card8(cff->stream);
00088   cff->header.minor    = get_card8(cff->stream);
00089   cff->header.hdr_size = get_card8(cff->stream);
00090   cff->header.offsize  = get_card8(cff->stream);
00091   if (cff->header.offsize < 1 ||
00092       cff->header.offsize > 4)
00093     ERROR("invalid offsize data");
00094 
00095   if (cff->header.major > 1 ||
00096       cff->header.minor > 0) {
00097     WARN("%s: CFF version %u.%u not supported.",
00098         CFF_DEBUG_STR, cff->header.major, cff->header.minor);
00099     cff_close(cff);
00100     return NULL;
00101   }
00102 
00103   cff_seek_set(cff, (cff->header).hdr_size);
00104 
00105   /* Name INDEX */
00106   idx = cff_get_index(cff);
00107   if (n > idx->count - 1) {
00108     WARN("%s: Invalid CFF fontset index number.", CFF_DEBUG_STR);
00109     cff_close(cff);
00110     return NULL;
00111   }
00112 
00113   cff->name = idx;
00114 
00115   cff->fontname = cff_get_name(cff);
00116 
00117   /* Top DICT INDEX */
00118   idx = cff_get_index(cff);
00119   if (n > idx->count - 1)
00120     ERROR("CFF Top DICT not exist...");
00121   cff->topdict = cff_dict_unpack(idx->data + idx->offset[n] - 1,
00122                              idx->data + idx->offset[n + 1] - 1);
00123   if (!cff->topdict)
00124     ERROR("Parsing CFF Top DICT data failed...");
00125   cff_release_index(idx);
00126 
00127   if (cff_dict_known(cff->topdict, "CharstringType") &&
00128       cff_dict_get(cff->topdict, "CharstringType", 0) != 2) {
00129     WARN("Only Type 2 Charstrings supported...");
00130     cff_close(cff);
00131     return NULL;
00132   }
00133 
00134   if (cff_dict_known(cff->topdict, "SyntheticBase")) {
00135     WARN("CFF Synthetic font not supported.");
00136     cff_close(cff);
00137     return NULL;
00138   }
00139 
00140   /* String INDEX */
00141   cff->string = cff_get_index(cff);
00142 
00143   /* offset to GSubr */
00144   cff->gsubr_offset = tell_position(cff->stream) - offset;
00145 
00146   /* Number of glyphs */
00147   offset = (long) cff_dict_get(cff->topdict, "CharStrings", 0);
00148   cff_seek_set(cff, offset);
00149   cff->num_glyphs = get_card16(cff->stream);
00150 
00151   /* Check for font type */
00152   if (cff_dict_known(cff->topdict, "ROS")) {
00153     cff->flag |= FONTTYPE_CIDFONT;
00154   } else {
00155     cff->flag |= FONTTYPE_FONT;
00156   }
00157 
00158   /* Check for encoding */
00159   if (cff_dict_known(cff->topdict, "Encoding")) {
00160     offset = (long) cff_dict_get(cff->topdict, "Encoding", 0);
00161     if (offset == 0) { /* predefined */
00162       cff->flag |= ENCODING_STANDARD;
00163     } else if (offset == 1) {
00164       cff->flag |= ENCODING_EXPERT;
00165     }
00166   } else {
00167     cff->flag |= ENCODING_STANDARD;
00168   }
00169 
00170   /* Check for charset */
00171   if (cff_dict_known(cff->topdict, "charset")) {
00172     offset = (long) cff_dict_get(cff->topdict, "charset", 0);
00173     if (offset == 0) { /* predefined */
00174       cff->flag |= CHARSETS_ISOADOBE;
00175     } else if (offset == 1) {
00176       cff->flag |= CHARSETS_EXPERT;
00177     } else if (offset == 2) {
00178       cff->flag |= CHARSETS_EXPSUB;
00179     }
00180   } else {
00181     cff->flag |= CHARSETS_ISOADOBE;
00182   }
00183 
00184   cff_seek_set(cff, cff->gsubr_offset); /* seek back to GSubr */
00185 
00186   return cff;
00187 }
00188 
00189 void
00190 cff_close (cff_font *cff)
00191 {
00192   card16 i;
00193 
00194   if (cff) {
00195     if (cff->fontname) RELEASE(cff->fontname);
00196     if (cff->name) cff_release_index(cff->name);
00197     if (cff->topdict) cff_release_dict(cff->topdict);
00198     if (cff->string) cff_release_index(cff->string);
00199     if (cff->gsubr) cff_release_index(cff->gsubr);
00200     if (cff->encoding) cff_release_encoding(cff->encoding);
00201     if (cff->charsets) cff_release_charsets(cff->charsets);
00202     if (cff->fdselect) cff_release_fdselect(cff->fdselect);
00203     if (cff->cstrings) cff_release_index(cff->cstrings);
00204     if (cff->fdarray) {
00205       for (i=0;i<cff->num_fds;i++) {
00206        if (cff->fdarray[i]) cff_release_dict(cff->fdarray[i]);
00207       }
00208       RELEASE(cff->fdarray);
00209     }
00210     if (cff->private) {
00211       for (i=0;i<cff->num_fds;i++) {
00212        if (cff->private[i]) cff_release_dict(cff->private[i]);
00213       }
00214       RELEASE(cff->private);
00215     }
00216     if (cff->subrs) {
00217       for (i=0;i<cff->num_fds;i++) {
00218        if (cff->subrs[i]) cff_release_index(cff->subrs[i]);
00219       }
00220       RELEASE(cff->subrs);
00221     }
00222     if (cff->_string)
00223       cff_release_index(cff->_string);
00224     RELEASE(cff);
00225   }
00226 
00227   return;
00228 }
00229 
00230 char *
00231 cff_get_name (cff_font *cff)
00232 {
00233   char      *fontname;
00234   l_offset   len;
00235   cff_index *idx;
00236 
00237   idx = cff->name;
00238   len = idx->offset[cff->index + 1] - idx->offset[cff->index];
00239   fontname = NEW(len + 1, char);
00240   memcpy(fontname, idx->data + idx->offset[cff->index] - 1, len);
00241   fontname[len] = '\0';
00242 
00243   return fontname;
00244 }
00245 
00246 long
00247 cff_set_name (cff_font *cff, char *name)
00248 {
00249   cff_index *idx;
00250 
00251   if (strlen(name) > 127)
00252     ERROR("FontName string length too large...");
00253 
00254   if (cff->name)
00255     cff_release_index(cff->name);
00256 
00257   cff->name = idx = NEW(1, cff_index);
00258   idx->count   = 1;
00259   idx->offsize = 1;
00260   idx->offset  = NEW(2, l_offset);
00261   (idx->offset)[0] = 1;
00262   (idx->offset)[1] = strlen(name) + 1;
00263   idx->data = NEW(strlen(name), card8);
00264   memmove(idx->data, name, strlen(name)); /* no trailing '\0' */
00265 
00266   return 5 + strlen(name);
00267 }
00268 
00269 long
00270 cff_put_header (cff_font *cff, card8 *dest, long destlen)
00271 {
00272   if (destlen < 4)
00273     ERROR("Not enough space available...");
00274 
00275   *(dest++) = cff->header.major;
00276   *(dest++) = cff->header.minor;
00277   *(dest++) = 4; /* Additional data in between header and
00278                 * Name INDEX ignored.
00279                 */
00280   /* We will set all offset (0) to four-byte integer. */
00281   *(dest++) = 4;
00282   cff->header.offsize = 4;
00283 
00284   return 4;
00285 }
00286 
00287 /* Only read header part but not body */
00288 cff_index *
00289 cff_get_index_header (cff_font *cff)
00290 {
00291   cff_index *idx;
00292   card16     i, count;
00293 
00294   idx = NEW(1, cff_index);
00295 
00296   idx->count = count = get_card16(cff->stream);
00297   if (count > 0) {
00298     idx->offsize = get_card8(cff->stream);
00299     if (idx->offsize < 1 || idx->offsize > 4)
00300       ERROR("invalid offsize data");
00301 
00302     idx->offset = NEW(count+1, l_offset);
00303     for (i=0;i<count+1;i++) {
00304       (idx->offset)[i] = get_offset(cff->stream, idx->offsize);
00305     }
00306 
00307     if (idx->offset[0] != 1)
00308       ERROR("cff_get_index(): invalid index data");
00309 
00310     idx->data = NULL;
00311   } else {
00312     idx->offsize = 0;
00313     idx->offset = NULL;
00314     idx->data = NULL;
00315   }
00316 
00317   return idx;
00318 }
00319 
00320 cff_index *
00321 cff_get_index (cff_font *cff)
00322 {
00323   cff_index *idx;
00324   card16     i, count;
00325   long       length, nb_read, offset;
00326 
00327   idx = NEW(1, cff_index);
00328 
00329   idx->count = count = get_card16(cff->stream);
00330   if (count > 0) {
00331     idx->offsize = get_card8(cff->stream);
00332     if (idx->offsize < 1 || idx->offsize > 4)
00333       ERROR("invalid offsize data");
00334 
00335     idx->offset = NEW(count + 1, l_offset);
00336     for (i = 0 ; i < count + 1; i++) {
00337       idx->offset[i] = get_offset(cff->stream, idx->offsize);
00338     }
00339 
00340     if (idx->offset[0] != 1)
00341       ERROR("Invalid CFF Index offset data");
00342 
00343     length = idx->offset[count] - idx->offset[0];
00344 
00345     idx->data = NEW(length, card8);
00346     offset    = 0;
00347     while (length > 0) {
00348       nb_read = fread(idx->data + offset, 1, length, cff->stream);
00349       offset += nb_read;
00350       length -= nb_read;
00351     }
00352   } else {
00353     idx->offsize = 0;
00354     idx->offset  = NULL;
00355     idx->data    = NULL;
00356   }
00357 
00358   return idx;
00359 }
00360 
00361 long
00362 cff_pack_index (cff_index *idx, card8 *dest, long destlen)
00363 {
00364   long    len = 0;
00365   long    datalen;
00366   card16  i;
00367 
00368   if (idx->count < 1) {
00369     if (destlen < 2)
00370       ERROR("Not enough space available...");
00371     memset(dest, 0, 2);
00372     return 2;
00373   }
00374 
00375   len     = cff_index_size(idx);
00376   datalen = idx->offset[idx->count] - 1;
00377 
00378   if (destlen < len)
00379     ERROR("Not enough space available...");
00380 
00381   *(dest++) = (idx->count >> 8) & 0xff;
00382   *(dest++) = idx->count & 0xff;
00383 
00384   if (datalen < 0xffUL) {
00385     idx->offsize = 1;
00386     *(dest++)    = 1;
00387     for (i = 0; i <= idx->count; i++) {
00388       *(dest++) = (card8) (idx->offset[i] & 0xff);
00389     }
00390   } else if (datalen < 0xffffUL) {
00391     idx->offsize = 2;
00392     *(dest++)    = 2;
00393     for (i = 0; i <= idx->count; i++) {
00394       *(dest++) = (card8) ((idx->offset[i] >> 8) & 0xff);
00395       *(dest++) = (card8) ( idx->offset[i] & 0xff);
00396     }
00397   } else if (datalen < 0xffffffUL) {
00398     idx->offsize = 3;
00399     *(dest++)    = 3;
00400     for (i = 0; i <= idx->count; i++) {
00401       *(dest++) = (card8)((idx->offset[i] >> 16) & 0xff);
00402       *(dest++) = (card8)((idx->offset[i] >> 8) & 0xff);
00403       *(dest++) = (card8)(idx->offset[i] & 0xff);
00404     }
00405   } else {
00406     idx->offsize = 4;
00407     *(dest++)    = 4;
00408     for (i = 0; i <= idx->count; i++) {
00409       *(dest++) = (card8)((idx->offset[i] >> 24) & 0xff);
00410       *(dest++) = (card8)((idx->offset[i] >> 16) & 0xff);
00411       *(dest++) = (card8)((idx->offset[i] >> 8) & 0xff);
00412       *(dest++) = (card8)(idx->offset[i] & 0xff);
00413     }
00414   }
00415 
00416   memmove(dest, idx->data, idx->offset[idx->count] - 1);
00417 
00418   return len;
00419 }
00420 
00421 long
00422 cff_index_size (cff_index *idx)
00423 {
00424   if (idx->count > 0) {
00425     l_offset datalen;
00426 
00427     datalen = idx->offset[idx->count] - 1;
00428     if (datalen < 0xffUL) {
00429       idx->offsize = 1;
00430     } else if (datalen < 0xffffUL) {
00431       idx->offsize = 2;
00432     } else if (datalen < 0xffffffUL) {
00433       idx->offsize = 3;
00434     } else {
00435       idx->offsize = 4;
00436     }
00437     return (3 + (idx->offsize)*(idx->count + 1) + datalen);
00438   } else {
00439     return 2;
00440   }
00441 }
00442 
00443 
00444 cff_index *cff_new_index (card16 count)
00445 {
00446   cff_index *idx;
00447 
00448   idx = NEW(1, cff_index);
00449   idx->count = count;
00450   idx->offsize = 0;
00451 
00452   if (count > 0) {
00453     idx->offset = NEW(count + 1, l_offset);
00454     (idx->offset)[0] = 1;
00455   } else {
00456     idx->offset = NULL;
00457   }
00458   idx->data = NULL;
00459 
00460   return idx;
00461 }
00462 
00463 void cff_release_index (cff_index *idx)
00464 {
00465   if (idx) {
00466     if (idx->data) {
00467       RELEASE(idx->data);
00468     }
00469     if (idx->offset) {
00470       RELEASE(idx->offset);
00471     }
00472     RELEASE(idx);
00473   }
00474 }
00475 
00476 /* Strings */
00477 char *cff_get_string (cff_font *cff, s_SID id)
00478 {
00479   char *result = NULL;
00480   long len;
00481 
00482   if (id < CFF_STDSTR_MAX) {
00483     len = strlen(cff_stdstr[id]);
00484     result = NEW(len+1, char);
00485     memcpy(result, cff_stdstr[id], len);
00486     result[len] = '\0';
00487   } else if (cff && cff->string) {
00488     cff_index *strings = cff->string;
00489     id -= CFF_STDSTR_MAX;
00490     if (id < strings->count) {
00491       len = (strings->offset)[id+1] - (strings->offset)[id];
00492       result = NEW(len + 1, char);
00493       memmove(result, strings->data + (strings->offset)[id] - 1, len);
00494       result[len] = '\0';
00495     }
00496   }
00497 
00498   return result;
00499 }
00500 
00501 long cff_get_sid (cff_font *cff, char *str)
00502 {
00503   card16 i;
00504 
00505   if (!cff || !str)
00506     return -1;
00507 
00508   /* I search String INDEX first. */
00509   if (cff && cff->string) {
00510     cff_index *idx = cff->string;
00511     for (i = 0; i < idx->count; i++) {
00512       if (strlen(str) == (idx->offset)[i+1] - (idx->offset)[i] &&
00513          !memcmp(str, (idx->data)+(idx->offset)[i]-1, strlen(str)))
00514        return (i + CFF_STDSTR_MAX);
00515     }
00516   }
00517 
00518   for (i = 0; i < CFF_STDSTR_MAX; i++) {
00519     if (!strcmp(str, cff_stdstr[i]))
00520       return i;
00521   }
00522 
00523   return -1;
00524 }
00525 
00526 int cff_match_string (cff_font *cff, const char *str, s_SID sid)
00527 {
00528   card16 i;
00529 
00530   if (sid < CFF_STDSTR_MAX) {
00531     return ((!strcmp(str, cff_stdstr[sid])) ? 1 : 0);
00532   } else {
00533     i = sid - CFF_STDSTR_MAX;
00534     if (cff == NULL || cff->string == NULL || i >= cff->string->count)
00535       ERROR("Invalid SID");
00536     if (strlen(str) == (cff->string->offset)[i+1] - (cff->string->offset)[i])
00537       return (!memcmp(str,
00538                     (cff->string->data)+(cff->string->offset)[i]-1,
00539                     strlen(str))) ? 1 : 0;
00540   }
00541 
00542   return 0;
00543 }
00544 
00545 void cff_update_string (cff_font *cff)
00546 {
00547   if (cff == NULL)
00548     ERROR("CFF font not opened.");
00549   
00550   if (cff->string)
00551     cff_release_index(cff->string);
00552   cff->string  = cff->_string;
00553   cff->_string = NULL;
00554 }
00555 
00556 s_SID cff_add_string (cff_font *cff, const char *str, int unique)
00557 /* Setting unique == 1 eliminates redundant or predefined strings. */
00558 {
00559   card16 idx;
00560   cff_index *strings;
00561   l_offset offset, size;
00562   long len = strlen(str);
00563 
00564   if (cff == NULL)
00565     ERROR("CFF font not opened.");
00566 
00567   if (cff->_string == NULL)
00568     cff->_string = cff_new_index(0);
00569   strings = cff->_string;
00570 
00571   if (unique) {
00572     /* TODO: do binary search to speed things up */
00573     for (idx = 0; idx < CFF_STDSTR_MAX; idx++) {
00574       if (cff_stdstr[idx] && !strcmp(cff_stdstr[idx], str))
00575        return idx;
00576     }
00577     for (idx = 0; idx < strings->count; idx++) {
00578       size   = strings->offset[idx+1] - strings->offset[idx];
00579       offset = strings->offset[idx];
00580       if (size == len && !memcmp(strings->data+offset-1, str, len))
00581        return (idx + CFF_STDSTR_MAX);
00582     }
00583   }
00584 
00585   offset = (strings->count > 0) ? strings->offset[strings->count] : 1;
00586   strings->offset = RENEW(strings->offset, strings->count+2, l_offset);
00587   if (strings->count == 0)
00588     strings->offset[0] = 1;
00589   idx = strings->count;
00590   strings->count += 1;
00591   strings->offset[strings->count] = offset + len;
00592   strings->data = RENEW(strings->data, offset+len-1, card8);
00593   memcpy(strings->data+offset-1, str, len);
00594 
00595   return (idx + CFF_STDSTR_MAX);
00596 }
00597 
00598 /*
00599  * Encoding and Charset
00600  *
00601  *  Encoding and Charset arrays always begin with GID = 1.
00602  */
00603 long cff_read_encoding (cff_font *cff)
00604 {
00605   cff_encoding *encoding;
00606   long offset, length;
00607   card8 i;
00608 
00609   if (cff->topdict == NULL) {
00610     ERROR("Top DICT data not found");
00611   }
00612 
00613   if (!cff_dict_known(cff->topdict, "Encoding")) {
00614     cff->flag |= ENCODING_STANDARD;
00615     cff->encoding = NULL;
00616     return 0;
00617   }
00618 
00619   offset = (long) cff_dict_get(cff->topdict, "Encoding", 0);
00620   if (offset == 0) { /* predefined */
00621     cff->flag |= ENCODING_STANDARD;
00622     cff->encoding = NULL;
00623     return 0;
00624   } else if (offset == 1) {
00625     cff->flag |= ENCODING_EXPERT;
00626     cff->encoding = NULL;
00627     return 0;
00628   }
00629 
00630   cff_seek_set(cff, offset);
00631   cff->encoding = encoding = NEW(1, cff_encoding);
00632   encoding->format = get_card8(cff->stream);
00633   length = 1;
00634 
00635   switch (encoding->format & (~0x80)) {
00636   case 0:
00637     encoding->num_entries = get_card8(cff->stream);
00638     (encoding->data).codes = NEW(encoding->num_entries, card8);
00639     for (i=0;i<(encoding->num_entries);i++) {
00640       (encoding->data).codes[i] = get_card8(cff->stream);
00641     }
00642     length += encoding->num_entries + 1;
00643     break;
00644   case 1:
00645     {
00646       cff_range1 *ranges;
00647       encoding->num_entries = get_card8(cff->stream);
00648       encoding->data.range1 = ranges
00649        = NEW(encoding->num_entries, cff_range1);
00650       for (i=0;i<(encoding->num_entries);i++) {
00651        ranges[i].first = get_card8(cff->stream);
00652        ranges[i].n_left = get_card8(cff->stream);
00653       }
00654       length += (encoding->num_entries) * 2 + 1;
00655     }
00656     break;
00657   default:
00658     RELEASE(encoding);
00659     ERROR("Unknown Encoding format");
00660     break;
00661   }
00662 
00663   /* Supplementary data */
00664   if ((encoding->format) & 0x80) {
00665     cff_map *map;
00666     encoding->num_supps = get_card8(cff->stream);
00667     encoding->supp = map = NEW(encoding->num_supps, cff_map);
00668     for (i=0;i<(encoding->num_supps);i++) {
00669       map[i].code = get_card8(cff->stream);
00670       map[i].glyph = get_card16(cff->stream); /* SID */
00671     }
00672     length += (encoding->num_supps) * 3 + 1;
00673   } else {
00674     encoding->num_supps = 0;
00675     encoding->supp = NULL;
00676   }
00677 
00678   return length;
00679 }
00680 
00681 long cff_pack_encoding (cff_font *cff, card8 *dest, long destlen)
00682 {
00683   long len = 0;
00684   cff_encoding *encoding;
00685   card16 i;
00686 
00687   if (cff->flag & HAVE_STANDARD_ENCODING || cff->encoding == NULL)
00688     return 0;
00689 
00690   if (destlen < 2)
00691     ERROR("in cff_pack_encoding(): Buffer overflow");
00692 
00693   encoding = cff->encoding;
00694 
00695   dest[len++] = encoding->format;
00696   dest[len++] = encoding->num_entries;
00697   switch (encoding->format & (~0x80)) {
00698   case 0:
00699     if (destlen < len + encoding->num_entries)
00700       ERROR("in cff_pack_encoding(): Buffer overflow");
00701     for (i=0;i<(encoding->num_entries);i++) {
00702       dest[len++] = (encoding->data).codes[i];
00703     }
00704     break;
00705   case 1:
00706     {
00707       if (destlen < len + (encoding->num_entries)*2)
00708        ERROR("in cff_pack_encoding(): Buffer overflow");
00709       for (i=0;i<(encoding->num_entries);i++) {
00710        dest[len++] = (encoding->data).range1[i].first & 0xff;
00711        dest[len++] = (encoding->data).range1[i].n_left;
00712       }
00713     }
00714     break;
00715   default:
00716     ERROR("Unknown Encoding format");
00717     break;
00718   }
00719 
00720   if ((encoding->format) & 0x80) {
00721     if (destlen < len + (encoding->num_supps)*3 + 1)
00722       ERROR("in cff_pack_encoding(): Buffer overflow");
00723     dest[len++] = encoding->num_supps;
00724     for (i=0;i<(encoding->num_supps);i++) {
00725       dest[len++] = (encoding->supp)[i].code;
00726       dest[len++] = ((encoding->supp)[i].glyph >> 8) & 0xff;
00727       dest[len++] = (encoding->supp)[i].glyph & 0xff;
00728     }
00729   }
00730 
00731   return len;
00732 }
00733 
00734 /* input: code, output: glyph index */
00735 card16 cff_encoding_lookup (cff_font *cff, card8 code)
00736 {
00737   card16 gid = 0;
00738   cff_encoding *encoding;
00739   card16 i;
00740 
00741   if (cff->flag & (ENCODING_STANDARD|ENCODING_EXPERT)) {
00742     ERROR("Predefined CFF encoding not supported yet");
00743   } else if (cff->encoding == NULL) {
00744     ERROR("Encoding data not available");
00745   }
00746 
00747   encoding = cff->encoding;
00748 
00749   gid = 0;
00750   switch (encoding->format & (~0x80)) {
00751   case 0:
00752     for (i = 0; i < encoding->num_entries; i++) {
00753       if (code == (encoding->data).codes[i]) {
00754        gid = i + 1;
00755        break;
00756       }
00757     }
00758     break;
00759   case 1:
00760     for (i = 0; i < encoding->num_entries; i++) {
00761       if (code >= (encoding->data).range1[i].first &&
00762          code <= (encoding->data).range1[i].first + (encoding->data).range1[i].n_left) {
00763         gid += code - (encoding->data).range1[i].first + 1;
00764         break;
00765       }
00766       gid += (encoding->data).range1[i].n_left + 1;
00767     }
00768     if (i == encoding->num_entries)
00769       gid = 0;
00770     break;
00771   default:
00772     ERROR("Unknown Encoding format.");
00773   }
00774 
00775   /* Supplementary data */
00776   if (gid == 0 && ((encoding->format) & 0x80)) {
00777     cff_map *map;
00778     if (!encoding->supp)
00779       ERROR("No CFF supplementary encoding data read.");
00780     map = encoding->supp;
00781     for (i=0;i<(encoding->num_supps);i++) {
00782       if (code == map[i].code) {
00783        gid = cff_charsets_lookup(cff, map[i].glyph);
00784        break;
00785       }
00786     }
00787   }
00788 
00789   return gid;
00790 }
00791 
00792 void cff_release_encoding (cff_encoding *encoding)
00793 {
00794   if (encoding) {
00795     switch (encoding->format & (~0x80)) {
00796     case 0:
00797       if (encoding->data.codes)
00798        RELEASE(encoding->data.codes);
00799       break;
00800     case 1:
00801       if (encoding->data.range1)
00802        RELEASE(encoding->data.range1);
00803       break;
00804     default:
00805       ERROR("Unknown Encoding format.");
00806     }
00807     if (encoding->format & 0x80) {
00808       if (encoding->supp)
00809        RELEASE(encoding->supp);
00810     }
00811     RELEASE(encoding);
00812   }
00813 }
00814 
00815 long cff_read_charsets (cff_font *cff)
00816 {
00817   cff_charsets *charset;
00818   long offset, length;
00819   card16 count, i;
00820 
00821   if (cff->topdict == NULL)
00822     ERROR("Top DICT not available");
00823 
00824   if (!cff_dict_known(cff->topdict, "charset")) {
00825     cff->flag |= CHARSETS_ISOADOBE;
00826     cff->charsets = NULL;
00827     return 0;
00828   }
00829 
00830   offset = (long) cff_dict_get(cff->topdict, "charset", 0);
00831 
00832   if (offset == 0) { /* predefined */
00833     cff->flag |= CHARSETS_ISOADOBE;
00834     cff->charsets = NULL;
00835     return 0;
00836   } else if (offset == 1) {
00837     cff->flag |= CHARSETS_EXPERT;
00838     cff->charsets = NULL;
00839     return 0;
00840   } else if (offset == 2) {
00841     cff->flag |= CHARSETS_EXPSUB;
00842     cff->charsets = NULL;
00843     return 0;
00844   }
00845 
00846   cff_seek_set(cff, offset);
00847   cff->charsets = charset = NEW(1, cff_charsets);
00848   charset->format = get_card8(cff->stream);
00849   charset->num_entries = 0;
00850 
00851   count = cff->num_glyphs - 1;
00852   length = 1;
00853 
00854   /* Not sure. Not well documented. */
00855   switch (charset->format) {
00856   case 0:
00857     charset->num_entries = cff->num_glyphs - 1; /* no .notdef */
00858     charset->data.glyphs = NEW(charset->num_entries, s_SID);
00859     length += (charset->num_entries) * 2;
00860     for (i=0;i<(charset->num_entries);i++) {
00861       charset->data.glyphs[i] = get_card16(cff->stream);
00862     }
00863     count = 0;
00864     break;
00865   case 1:
00866     {
00867       cff_range1 *ranges = NULL;
00868       while (count > 0 && charset->num_entries < cff->num_glyphs) {
00869        ranges = RENEW(ranges, charset->num_entries + 1, cff_range1);
00870        ranges[charset->num_entries].first = get_card16(cff->stream);
00871        ranges[charset->num_entries].n_left = get_card8(cff->stream);
00872        count -= ranges[charset->num_entries].n_left + 1; /* no-overrap */
00873        charset->num_entries += 1;
00874        charset->data.range1 = ranges;
00875       }
00876       length += (charset->num_entries) * 3;
00877     }
00878     break;
00879   case 2:
00880     {
00881       cff_range2 *ranges = NULL;
00882       while (count > 0 && charset->num_entries < cff->num_glyphs) {
00883        ranges = RENEW(ranges, charset->num_entries + 1, cff_range2);
00884        ranges[charset->num_entries].first = get_card16(cff->stream);
00885        ranges[charset->num_entries].n_left = get_card16(cff->stream);
00886        count -= ranges[charset->num_entries].n_left + 1; /* non-overrapping */
00887        charset->num_entries += 1;
00888       }
00889       charset->data.range2 = ranges;
00890       length += (charset->num_entries) * 4;
00891     }
00892     break;
00893   default:
00894     RELEASE(charset);
00895     ERROR("Unknown Charset format");
00896     break;
00897   }
00898 
00899   if (count > 0)
00900     ERROR("Charset data possibly broken");
00901 
00902   return length;
00903 }
00904 
00905 long cff_pack_charsets (cff_font *cff, card8 *dest, long destlen)
00906 {
00907   long len = 0;
00908   card16 i;
00909   cff_charsets *charset;
00910 
00911   if (cff->flag & HAVE_STANDARD_CHARSETS || cff->charsets == NULL)
00912     return 0;
00913 
00914   if (destlen < 1)
00915     ERROR("in cff_pack_charsets(): Buffer overflow");
00916 
00917   charset = cff->charsets;
00918 
00919   dest[len++] = charset->format;
00920   switch (charset->format) {
00921   case 0:
00922     if (destlen < len + (charset->num_entries)*2)
00923       ERROR("in cff_pack_charsets(): Buffer overflow");
00924     for (i=0;i<(charset->num_entries);i++) {
00925       s_SID sid = (charset->data).glyphs[i]; /* or CID */
00926       dest[len++] = (sid >> 8) & 0xff;
00927       dest[len++] = sid & 0xff;
00928     }
00929     break;
00930   case 1:
00931     {
00932       if (destlen < len + (charset->num_entries)*3)
00933        ERROR("in cff_pack_charsets(): Buffer overflow");
00934       for (i=0;i<(charset->num_entries);i++) {
00935        dest[len++] = ((charset->data).range1[i].first >> 8) & 0xff;
00936        dest[len++] = (charset->data).range1[i].first & 0xff;
00937        dest[len++] = (charset->data).range1[i].n_left;
00938       }
00939     }
00940     break;
00941   case 2:
00942     {
00943       if (destlen < len + (charset->num_entries)*4)
00944        ERROR("in cff_pack_charsets(): Buffer overflow");
00945       for (i=0;i<(charset->num_entries);i++) {
00946        dest[len++] = ((charset->data).range2[i].first >> 8) & 0xff;
00947        dest[len++] = (charset->data).range2[i].first & 0xff;
00948        dest[len++] = ((charset->data).range2[i].n_left >> 8) & 0xff;
00949        dest[len++] = (charset->data).range2[i].n_left & 0xff;
00950       }
00951     }
00952     break;
00953   default:
00954     ERROR("Unknown Charset format");
00955     break;
00956   }
00957 
00958   return len;
00959 }
00960 
00961 card16 cff_glyph_lookup (cff_font *cff, const char *glyph)
00962 {
00963   card16        gid;
00964   cff_charsets *charset;
00965   card16        i, n;
00966 
00967   if (cff->flag & (CHARSETS_ISOADOBE|CHARSETS_EXPERT|CHARSETS_EXPSUB)) {
00968     ERROR("Predefined CFF charsets not supported yet");
00969   } else if (cff->charsets == NULL) {
00970     ERROR("Charsets data not available");
00971   }
00972 
00973   /* .notdef always have glyph index 0 */
00974   if (!glyph || !strcmp(glyph, ".notdef")) {
00975     return 0;
00976   }
00977 
00978   charset = cff->charsets;
00979 
00980   gid = 0;
00981   switch (charset->format) {
00982   case 0:
00983     for (i = 0; i < charset->num_entries; i++) {
00984       gid++;
00985       if (cff_match_string(cff, glyph, charset->data.glyphs[i])) {
00986        return gid;
00987       }
00988     }
00989     break;
00990   case 1:
00991     for (i = 0; i < charset->num_entries; i++) {
00992       for (n = 0;
00993           n <= charset->data.range1[i].n_left; n++) {
00994        gid++;
00995        if (cff_match_string(cff, glyph,
00996                           (s_SID)(charset->data.range1[i].first + n))) {
00997          return gid;
00998        }
00999       }
01000     }
01001     break;
01002   case 2:
01003     for (i = 0; i <charset->num_entries; i++) {
01004       for (n = 0;
01005           n <= charset->data.range2[i].n_left; n++) {
01006        gid++;
01007        if (cff_match_string(cff, glyph,
01008                           (s_SID)(charset->data.range2[i].first + n))) {
01009          return gid;
01010        }
01011       }
01012     }
01013     break;
01014   default:
01015     ERROR("Unknown Charset format");
01016   }
01017 
01018   return 0; /* not found, returns .notdef */
01019 }
01020 
01021 /* Input : SID or CID (16-bit unsigned int)
01022  * Output: glyph index
01023  */
01024 card16
01025 cff_charsets_lookup (cff_font *cff, card16 cid)
01026 {
01027   card16        gid = 0;
01028   cff_charsets *charset;
01029   card16        i;
01030 
01031   if (cff->flag & (CHARSETS_ISOADOBE|CHARSETS_EXPERT|CHARSETS_EXPSUB)) {
01032     ERROR("Predefined CFF charsets not supported yet");
01033   } else if (cff->charsets == NULL) {
01034     ERROR("Charsets data not available");
01035   }
01036 
01037   if (cid == 0) {
01038     return 0; /* GID 0 (.notdef) */
01039   }
01040 
01041   charset = cff->charsets;
01042 
01043   gid = 0;
01044   switch (charset->format) {
01045   case 0:
01046     for (i = 0; i <charset->num_entries; i++) {
01047       if (cid == charset->data.glyphs[i]) {
01048        gid = i + 1;
01049        return gid;
01050       }
01051     }
01052     break;
01053   case 1:
01054     for (i = 0; i < charset->num_entries; i++) {
01055       if (cid >= charset->data.range1[i].first &&
01056          cid <= charset->data.range1[i].first + charset->data.range1[i].n_left) {
01057         gid += cid - charset->data.range1[i].first + 1;
01058        return gid;
01059       }
01060       gid += charset->data.range1[i].n_left + 1;
01061     }
01062     break;
01063   case 2:
01064     for (i = 0; i < charset->num_entries; i++) {
01065       if (cid >= charset->data.range2[i].first &&
01066          cid <= charset->data.range2[i].first + charset->data.range2[i].n_left) {
01067         gid += cid - charset->data.range2[i].first + 1;
01068        return gid;
01069       }
01070       gid += charset->data.range2[i].n_left + 1;
01071     }
01072     break;
01073   default:
01074     ERROR("Unknown Charset format");
01075   }
01076 
01077   return 0; /* not found */
01078 }
01079 
01080 /* Input : GID
01081  * Output: SID/CID (card16)
01082  */
01083 card16
01084 cff_charsets_lookup_inverse (cff_font *cff, card16 gid)
01085 {
01086   card16        sid = 0;
01087   cff_charsets *charset;
01088   card16        i;
01089 
01090   if (cff->flag & (CHARSETS_ISOADOBE|CHARSETS_EXPERT|CHARSETS_EXPSUB)) {
01091     ERROR("Predefined CFF charsets not supported yet");
01092   } else if (cff->charsets == NULL) {
01093     ERROR("Charsets data not available");
01094   }
01095 
01096   if (gid == 0) {
01097     return 0;  /* .notdef */
01098   }
01099 
01100   charset = cff->charsets;
01101 
01102   sid = 0;
01103   switch (charset->format) {
01104   case 0:
01105     if (gid - 1 >= charset->num_entries)
01106       ERROR("Invalid GID.");
01107     sid = charset->data.glyphs[gid - 1];
01108     break;
01109   case 1:
01110     for (i = 0; i < charset->num_entries; i++) {
01111       if (gid <= charset->data.range1[i].n_left + 1) {
01112        sid = gid + charset->data.range1[i].first - 1;
01113         break;
01114       }
01115       gid -= charset->data.range1[i].n_left + 1;
01116     }
01117     if (i == charset->num_entries)
01118       ERROR("Invalid GID");
01119     break;
01120   case 2:
01121     for (i = 0; i < charset->num_entries; i++) {
01122       if (gid <= charset->data.range2[i].n_left + 1) {
01123        sid = gid + charset->data.range2[i].first - 1;
01124         break;
01125       }
01126       gid -= charset->data.range2[i].n_left + 1;
01127     }
01128     if (i == charset->num_entries)
01129       ERROR("Invalid GID");
01130     break;
01131   default:
01132     ERROR("Unknown Charset format");
01133   }
01134 
01135   return sid;
01136 }
01137 
01138 void
01139 cff_release_charsets (cff_charsets *charset)
01140 {
01141   if (charset) {
01142     switch (charset->format) {
01143     case 0:
01144       if (charset->data.glyphs)
01145        RELEASE(charset->data.glyphs);
01146       break;
01147     case 1:
01148       if (charset->data.range1)
01149        RELEASE(charset->data.range1);
01150       break;
01151     case 2:
01152       if (charset->data.range2)
01153        RELEASE(charset->data.range2);
01154       break;
01155     default:
01156       break;
01157     }
01158     RELEASE(charset);
01159   }
01160 }
01161 
01162 /* CID-Keyed font specific */
01163 long cff_read_fdselect (cff_font *cff)
01164 {
01165   cff_fdselect *fdsel;
01166   long offset, length;
01167   card16 i;
01168 
01169   if (cff->topdict == NULL)
01170     ERROR("Top DICT not available");
01171 
01172   if (!(cff->flag & FONTTYPE_CIDFONT))
01173     return 0;
01174 
01175   offset = (long) cff_dict_get(cff->topdict, "FDSelect", 0);
01176   cff_seek_set(cff, offset);
01177   cff->fdselect = fdsel = NEW(1, cff_fdselect);
01178   fdsel->format = get_card8(cff->stream);
01179 
01180   length = 1;
01181 
01182   switch (fdsel->format) {
01183   case 0:
01184     fdsel->num_entries = cff->num_glyphs;
01185     (fdsel->data).fds = NEW(fdsel->num_entries, card8);
01186     for (i=0;i<(fdsel->num_entries);i++) {
01187       (fdsel->data).fds[i] = get_card8(cff->stream);
01188     }
01189     length += fdsel->num_entries;
01190     break;
01191   case 3:
01192     {
01193       cff_range3 *ranges;
01194       fdsel->num_entries = get_card16(cff->stream);
01195       fdsel->data.ranges = ranges = NEW(fdsel->num_entries, cff_range3);
01196       for (i=0;i<(fdsel->num_entries);i++) {
01197        ranges[i].first = get_card16(cff->stream);
01198        ranges[i].fd = get_card8(cff->stream);
01199       }
01200       if (ranges[0].first != 0)
01201        ERROR("Range not starting with 0.");
01202       if (cff->num_glyphs != get_card16(cff->stream))
01203        ERROR("Sentinel value mismatched with number of glyphs.");
01204       length += (fdsel->num_entries) * 3 + 4;
01205     }
01206     break;
01207   default:
01208     RELEASE(fdsel);
01209     ERROR("Unknown FDSelect format.");
01210     break;
01211   }
01212 
01213   return length;
01214 }
01215 
01216 long cff_pack_fdselect (cff_font *cff, card8 *dest, long destlen)
01217 {
01218   cff_fdselect *fdsel;
01219   long len = 0;
01220   card16 i;
01221 
01222   if (cff->fdselect == NULL)
01223     return 0;
01224 
01225   if (destlen < 1)
01226     ERROR("in cff_pack_fdselect(): Buffur overflow");
01227 
01228   fdsel = cff->fdselect;
01229 
01230   dest[len++] = fdsel->format;
01231   switch (fdsel->format) {
01232   case 0:
01233     if (fdsel->num_entries != cff->num_glyphs)
01234       ERROR("in cff_pack_fdselect(): Invalid data");
01235     if (destlen < len + fdsel->num_entries)
01236       ERROR("in cff_pack_fdselect(): Buffer overflow");
01237     for (i=0;i<fdsel->num_entries;i++) {
01238       dest[len++] = (fdsel->data).fds[i];
01239     }
01240     break;
01241   case 3:
01242     {
01243       if (destlen < len + 2)
01244        ERROR("in cff_pack_fdselect(): Buffer overflow");
01245       len += 2;
01246       for (i=0;i<(fdsel->num_entries);i++) {
01247        if (destlen < len + 3)
01248          ERROR("in cff_pack_fdselect(): Buffer overflow");
01249        dest[len++] = ((fdsel->data).ranges[i].first >> 8) & 0xff;
01250        dest[len++] = (fdsel->data).ranges[i].first & 0xff;
01251        dest[len++] = (fdsel->data).ranges[i].fd;
01252       }
01253       if (destlen < len + 2)
01254        ERROR("in cff_pack_fdselect(): Buffer overflow");
01255       dest[len++]  = (cff->num_glyphs >> 8) & 0xff;
01256       dest[len++]  = cff->num_glyphs & 0xff;
01257       dest[1] = ((len/3 - 1) >> 8) & 0xff;
01258       dest[2] = (len/3 - 1) & 0xff;
01259     }
01260     break;
01261   default:
01262     ERROR("Unknown FDSelect format.");
01263     break;
01264   }
01265 
01266   return len;
01267 }
01268 
01269 void cff_release_fdselect (cff_fdselect *fdselect)
01270 {
01271   if (fdselect) {
01272     if (fdselect->format == 0) {
01273       if (fdselect->data.fds) RELEASE(fdselect->data.fds);
01274     } else if (fdselect->format == 3) {
01275       if (fdselect->data.ranges) RELEASE(fdselect->data.ranges);
01276     }
01277     RELEASE(fdselect);
01278   }
01279 }
01280 
01281 card8 cff_fdselect_lookup (cff_font *cff, card16 gid)
01282 {
01283   card8 fd = 0xff;
01284   cff_fdselect *fdsel;
01285 
01286   if (cff->fdselect == NULL)
01287     ERROR("in cff_fdselect_lookup(): FDSelect not available");
01288 
01289   fdsel = cff->fdselect;
01290 
01291   if (gid >= cff->num_glyphs)
01292     ERROR("in cff_fdselect_lookup(): Invalid glyph index");
01293 
01294   switch (fdsel->format) {
01295   case 0:
01296     fd = fdsel->data.fds[gid];
01297     break;
01298   case 3:
01299     {
01300       if (gid == 0) {
01301        fd = (fdsel->data).ranges[0].fd;
01302       } else {
01303        card16 i;
01304        for (i=1;i<(fdsel->num_entries);i++) {
01305          if (gid < (fdsel->data).ranges[i].first)
01306            break;
01307        }
01308        fd = (fdsel->data).ranges[i-1].fd;
01309       }
01310     }
01311     break;
01312   default:
01313     ERROR("in cff_fdselect_lookup(): Invalid FDSelect format");
01314     break;
01315   }
01316 
01317   if (fd >= cff->num_fds)
01318     ERROR("in cff_fdselect_lookup(): Invalid Font DICT index");
01319 
01320   return fd;
01321 }
01322 
01323 long cff_read_subrs (cff_font *cff)
01324 {
01325   long len = 0;
01326   long offset;
01327   int i;
01328 
01329   if ((cff->flag & FONTTYPE_CIDFONT) && cff->fdarray == NULL) {
01330     cff_read_fdarray(cff);
01331   }
01332 
01333   if (cff->private == NULL)
01334     cff_read_private(cff);
01335 
01336   if (cff->gsubr == NULL) {
01337     cff_seek_set(cff, cff->gsubr_offset);
01338     cff->gsubr = cff_get_index(cff);
01339   }
01340     
01341   cff->subrs = NEW(cff->num_fds, cff_index *);
01342   if (cff->flag & FONTTYPE_CIDFONT) {
01343     for (i=0;i<cff->num_fds;i++) {
01344       if (cff->private[i] == NULL ||
01345          !cff_dict_known(cff->private[i], "Subrs")) {
01346        (cff->subrs)[i] = NULL;
01347       } else {
01348        offset = (long) cff_dict_get(cff->fdarray[i], "Private", 1);
01349        offset += (long) cff_dict_get(cff->private[i], "Subrs", 0);
01350        cff_seek_set(cff, offset);
01351        (cff->subrs)[i] = cff_get_index(cff);
01352        len += cff_index_size((cff->subrs)[i]);
01353       }
01354     }
01355   } else {
01356     if (cff->private[0] == NULL ||
01357        !cff_dict_known(cff->private[0], "Subrs")) {
01358       (cff->subrs)[0] = NULL;
01359     } else {
01360       offset = (long) cff_dict_get(cff->topdict, "Private", 1);
01361       offset += (long) cff_dict_get(cff->private[0], "Subrs", 0);
01362       cff_seek_set(cff, offset);
01363       (cff->subrs)[0] = cff_get_index(cff);
01364       len += cff_index_size((cff->subrs)[0]);
01365     }
01366   }
01367 
01368   return len;
01369 }
01370 
01371 long cff_read_fdarray (cff_font *cff)
01372 {
01373   long len = 0;
01374   cff_index *idx;
01375   long offset, size;
01376   card16 i;
01377 
01378   if (cff->topdict == NULL)
01379     ERROR("in cff_read_fdarray(): Top DICT not found");
01380 
01381   if (!(cff->flag & FONTTYPE_CIDFONT))
01382     return 0;
01383 
01384   /* must exist */
01385   offset = (long) cff_dict_get(cff->topdict, "FDArray", 0);
01386   cff_seek_set(cff, offset);
01387   idx = cff_get_index(cff);
01388   cff->num_fds = (card8)idx->count;
01389   cff->fdarray = NEW(idx->count, cff_dict *);
01390   for (i=0;i<idx->count;i++) {
01391     card8 *data = idx->data + (idx->offset)[i] - 1;
01392     size = (idx->offset)[i+1] - (idx->offset)[i];
01393     if (size > 0) {
01394       (cff->fdarray)[i] = cff_dict_unpack(data, data+size);
01395     } else {
01396       (cff->fdarray)[i] = NULL;
01397     }
01398   }
01399   len = cff_index_size(idx);
01400   cff_release_index(idx);
01401 
01402   return len;
01403 }
01404 
01405 long cff_read_private (cff_font *cff)
01406 {
01407   long len = 0;
01408   card8 *data;
01409   long offset, size;
01410 
01411   if (cff->flag & FONTTYPE_CIDFONT) {
01412     int i;
01413 
01414     if (cff->fdarray == NULL)
01415       cff_read_fdarray(cff);
01416 
01417     cff->private = NEW(cff->num_fds, cff_dict *);
01418     for (i=0;i<cff->num_fds;i++) {
01419       if (cff->fdarray[i] != NULL &&
01420          cff_dict_known(cff->fdarray[i], "Private") &&
01421          (size = (long) cff_dict_get(cff->fdarray[i], "Private", 0))
01422          > 0) {
01423        offset = (long) cff_dict_get(cff->fdarray[i], "Private", 1);
01424        cff_seek_set(cff, offset);
01425        data = NEW(size, card8);
01426        if (fread(data, 1, size, cff->stream) != size)
01427          ERROR("reading file failed");
01428        (cff->private)[i] = cff_dict_unpack(data, data+size);
01429        RELEASE(data);
01430        len += size;
01431       } else {
01432        (cff->private)[i] = NULL;
01433       }
01434     }
01435   } else {
01436     cff->num_fds = 1;
01437     cff->private = NEW(1, cff_dict *);
01438     if (cff_dict_known(cff->topdict, "Private") &&
01439        (size = (long) cff_dict_get(cff->topdict, "Private", 0)) > 0) {
01440       offset = (long) cff_dict_get(cff->topdict, "Private", 1);
01441       cff_seek_set(cff, offset);
01442       data = NEW(size, card8);
01443       if (fread(data, 1, size, cff->stream) != size)
01444        ERROR("reading file failed");
01445       cff->private[0] = cff_dict_unpack(data, data+size);
01446       RELEASE(data);
01447       len += size;
01448     } else {
01449       (cff->private)[0] = NULL;
01450       len = 0;
01451     }
01452   }
01453 
01454   return len;
01455 }