Back to index

texmacs  1.0.7.15
cmap.c
Go to the documentation of this file.
00001 /*  $Header: /home/cvsroot/dvipdfmx/src/cmap.c,v 1.29 2007/12/03 03:10:43 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 /*
00024  * References:
00025  *
00026  *  PostScript Language Reference Manual, 3rd. ed. (Adobe Systems Inc.)
00027  *    5.11.4 CMap Dictionaries
00028  *    5.11.5 FMapType 9 Composite Fonts
00029  *  Building CMap Files for CID-Keyed Fonts, Adobe Technical Note #5099
00030  *  CID-Keyed Font Technology Overview, Adobe Technical Note #5092
00031  *  Adobe CMap and CIDFont Files Specification, Adobe Technical Specification #5014
00032  *
00033  *  Undefined Character Handling:
00034  *    PLRM 3rd. ed., sec. 5.11.5., "Handling Undefined Characters"
00035  *
00036  * TODO:
00037  *   Only cid(range|char) allowed for CODE_TO_CID and bf(range|char) for CID_TO_CODE ?
00038  */
00039 
00040 #if HAVE_CONFIG_H
00041 #include "config.h"
00042 #endif
00043 
00044 #include <string.h>
00045 
00046 #include "system.h"
00047 #include "mem.h"
00048 #include "error.h"
00049 #include "dpxutil.h"
00050 
00051 #include "cmap_p.h"
00052 #include "cmap.h"
00053 
00054 static int __verbose = 0;
00055 static int __silent  = 0;
00056 
00057 void
00058 CMap_set_verbose (void)
00059 {
00060   __verbose++;
00061 }
00062 
00063 void
00064 CMap_set_silent (int value)
00065 {
00066   __silent = value ? 1 : 0;
00067 }
00068 
00069 /* Private funcs. */
00070 static int  bytes_consumed   (CMap *cmap, const unsigned char *instr, long inbytes);
00071 static void handle_undefined (CMap *cmap,
00072                            const unsigned char **inbuf, long *inbytesleft,
00073                            unsigned char **outbuf, long *outbytesleft);
00074 
00075 static int  check_range      (CMap *cmap,
00076                            const unsigned char *srclo, const unsigned char *srchi, int srcdim,
00077                            const unsigned char *dst, int dstdim);
00078 
00079 static unsigned char *get_mem (CMap *cmap, int size);
00080 static mapDef *mapDef_new     (void);
00081 static void    mapDef_release (mapDef *t);
00082 static int     locate_tbl     (mapDef **cur, const unsigned char *code, int dim);
00083 
00084 CMap *
00085 CMap_new (void)
00086 {
00087   CMap *cmap;
00088 
00089   cmap = NEW(1, struct CMap);
00090   cmap->name     = NULL;
00091   cmap->type     = CMAP_TYPE_CODE_TO_CID;
00092   cmap->wmode    = 0;
00093   cmap->useCMap  = NULL;
00094   cmap->CSI      = NULL;
00095 
00096   cmap->profile.minBytesIn  = 2;
00097   cmap->profile.maxBytesIn  = 2;
00098   cmap->profile.minBytesOut = 2;
00099   cmap->profile.maxBytesOut = 2;
00100 
00101   cmap->flags = 0;
00102 
00103   cmap->codespace.num    = 0;
00104   cmap->codespace.max    = 10;
00105   cmap->codespace.ranges = NEW(10, struct rangeDef);
00106 
00107   cmap->mapTbl  = NULL;
00108 
00109   cmap->mapData = NEW(1, struct mapData);
00110   cmap->mapData->prev = NULL;
00111   cmap->mapData->pos  = 0;
00112   cmap->mapData->data = NEW(MEM_ALLOC_SIZE, unsigned char);
00113 
00114   return cmap;
00115 }
00116 
00117 void
00118 CMap_release (CMap *cmap)
00119 {
00120   if (!cmap)
00121     return;
00122 
00123   if (cmap->name)
00124     RELEASE(cmap->name);
00125   if (cmap->CSI) {
00126     if (cmap->CSI->registry) RELEASE(cmap->CSI->registry);
00127     if (cmap->CSI->ordering) RELEASE(cmap->CSI->ordering);
00128     RELEASE(cmap->CSI);
00129   }
00130   if (cmap->codespace.ranges)
00131     RELEASE(cmap->codespace.ranges);
00132   if (cmap->mapTbl)
00133     mapDef_release(cmap->mapTbl);
00134   {
00135     mapData *map = cmap->mapData;
00136     while (map != NULL) {
00137       mapData *prev = map->prev;
00138       if (map->data != NULL)
00139        RELEASE(map->data);
00140       RELEASE(map);
00141       map = prev;
00142     }
00143   }
00144 
00145   RELEASE(cmap);
00146 }
00147 
00148 int
00149 CMap_is_Identity (CMap *cmap)
00150 {
00151   ASSERT(cmap);
00152   if (!strcmp(cmap->name, "Identity-H") || !strcmp(cmap->name, "Identity-V"))
00153     return 1;
00154   else
00155     return 0;
00156 }
00157 
00158 #if 0
00159 /* NOT IMPLEMENTED YET */
00160 int
00161 CMap_is_realy_Identity(CMap *cmap)
00162 {
00163   return 0;
00164 }
00165 #endif
00166 
00167 int
00168 CMap_is_valid (CMap *cmap)
00169 {
00170   /* Quick check */
00171   if (!cmap || !(cmap->name) || cmap->type < CMAP_TYPE_IDENTITY ||
00172       cmap->type > CMAP_TYPE_CID_TO_CODE || cmap->codespace.num < 1 ||
00173       (cmap->type != CMAP_TYPE_IDENTITY && !cmap->mapTbl))
00174     return 0;
00175 
00176   if (cmap->useCMap) {
00177     CIDSysInfo *csi1, *csi2;
00178     csi1 = CMap_get_CIDSysInfo(cmap);
00179     csi2 = CMap_get_CIDSysInfo(cmap->useCMap);
00180     if (strcmp(csi1->registry, csi2->registry) ||
00181        strcmp(csi1->ordering, csi2->ordering)) {
00182       WARN("CIDSystemInfo mismatched %s <--> %s",
00183           CMap_get_name(cmap), CMap_get_name(cmap->useCMap));
00184       return 0;
00185     }
00186   }
00187 
00188   return 1;
00189 }
00190 
00191 int
00192 CMap_get_profile (CMap *cmap, int type)
00193 {
00194   int value = 0;
00195 
00196   ASSERT(cmap);
00197   switch (type) {
00198   case CMAP_PROF_TYPE_INBYTES_MIN:
00199     value = cmap->profile.minBytesIn;
00200     break;
00201   case CMAP_PROF_TYPE_INBYTES_MAX:
00202     value = cmap->profile.maxBytesIn;
00203     break;
00204   case CMAP_PROF_TYPE_OUTBYTES_MIN:
00205     value = cmap->profile.maxBytesOut;
00206     break;
00207   case CMAP_PROF_TYPE_OUTBYTES_MAX:
00208     value = cmap->profile.maxBytesOut;
00209     break;
00210   default:
00211     ERROR("%s: Unrecognized profile type %d.", CMAP_DEBUG_STR, type);
00212   }
00213 
00214   return value;
00215 }
00216 
00217 /*
00218  * Put notdef chars for codes not declared in notdef(range|char)
00219  */
00220 static void
00221 handle_undefined (CMap *cmap,
00222                 const unsigned char **inbuf,  long *inbytesleft,
00223                 unsigned char **outbuf, long *outbytesleft)
00224 {
00225   long len = 0;
00226 
00227   if (*outbytesleft < 2)
00228     ERROR("%s: Buffer overflow.", CMAP_DEBUG_STR);
00229 
00230   switch (cmap->type) {
00231   case CMAP_TYPE_CODE_TO_CID:
00232     memcpy(*outbuf, CID_NOTDEF_CHAR, 2);
00233     break;
00234   case CMAP_TYPE_TO_UNICODE:
00235     memcpy(*outbuf, UCS_NOTDEF_CHAR, 2);
00236     break;
00237   default:
00238     WARN("Cannot handle undefined mapping for this type of CMap mapping: %d", cmap->type);
00239     WARN("<0000> is used for .notdef char.");
00240     memset(*outbuf, 0, 2);
00241   }
00242   *outbuf += 2;
00243   *outbytesleft -= 2;
00244 
00245   len = bytes_consumed(cmap, *inbuf, *inbytesleft);
00246 
00247   *inbuf  += len;
00248   *inbytesleft  -= len;
00249 }
00250 
00251 void
00252 CMap_decode_char (CMap *cmap,
00253                 const unsigned char **inbuf, long *inbytesleft,
00254                 unsigned char **outbuf, long *outbytesleft)
00255 {
00256   mapDef *t;
00257   unsigned char *p, c = 0, *save;
00258   long    count = 0;
00259 
00260   p = save = (unsigned char *) *inbuf;
00261   /*
00262    * First handle some special cases:
00263    */
00264   if (cmap->type == CMAP_TYPE_IDENTITY) {
00265     if ((*inbytesleft) % 2)
00266       ERROR("%s: Invalid/truncated input string.", CMAP_DEBUG_STR);
00267     if (*outbytesleft < 2)
00268       ERROR("%s: Buffer overflow.", CMAP_DEBUG_STR);
00269     memcpy(*outbuf, *inbuf, 2);
00270     *inbuf  += 2;
00271     *outbuf += 2;
00272     *outbytesleft -= 2;
00273     *inbytesleft  -= 2;
00274     return;
00275   } else if (!cmap->mapTbl) {
00276     if (cmap->useCMap) {
00277       CMap_decode_char(cmap->useCMap, inbuf, inbytesleft, outbuf, outbytesleft);
00278       return;
00279     } else {
00280       /* no mapping available in this CMap */
00281       WARN("No mapping available for this character.");
00282       handle_undefined(cmap, inbuf, inbytesleft, outbuf, outbytesleft);
00283       return;
00284     }
00285   }
00286 
00287   ASSERT(cmap->mapTbl);
00288   t = cmap->mapTbl;
00289   while (count < *inbytesleft) {
00290     c = *p++;
00291     count++;
00292     if (LOOKUP_END(t[c].flag))
00293       break;
00294     t = t[c].next;
00295   }
00296   if (LOOKUP_CONTINUE(t[c].flag)) /* need more bytes */
00297     ERROR("%s: Premature end of input string.", CMAP_DEBUG_STR);
00298   else if (!MAP_DEFINED(t[c].flag)) {
00299     if (cmap->useCMap) {
00300       CMap_decode_char(cmap->useCMap, inbuf, inbytesleft, outbuf, outbytesleft);
00301       return;
00302     } else {
00303       /* no mapping available in this CMap */
00304       WARN("No character mapping available.");
00305       MESG(" CMap name: %s\n", CMap_get_name(cmap));
00306       MESG(" input str: ");
00307       MESG("<");
00308       while (save < p) {
00309         MESG("%02x", *save);
00310         save++;
00311       }
00312       MESG(">\n");
00313       /*
00314        * We know partial match found up to `count' bytes,
00315        * but we will not use this information for the sake of simplicity.
00316        */ 
00317       handle_undefined(cmap, inbuf, inbytesleft, outbuf, outbytesleft);
00318       return;
00319     }
00320   } else {
00321     switch (MAP_TYPE(t[c].flag)) {
00322     case MAP_IS_NOTDEF:
00323       WARN("Character mapped to .notdef found.");
00324       /* continue */
00325     case MAP_IS_CID: case MAP_IS_CODE:
00326       if (*outbytesleft >= t[c].len)
00327        memcpy(*outbuf, t[c].code, t[c].len);
00328       else
00329        ERROR("%s: Buffer overflow.", CMAP_DEBUG_STR);
00330       *outbuf       += t[c].len;
00331       *outbytesleft -= t[c].len;
00332       break;
00333     case MAP_IS_NAME:
00334       ERROR("%s: CharName mapping not supported.", CMAP_DEBUG_STR);
00335       break;
00336     default:
00337       ERROR("%s: Unknown mapping type.", CMAP_DEBUG_STR);
00338     }
00339     if (inbytesleft)
00340       *inbytesleft -= count;
00341     *inbuf = p;
00342   }
00343 }
00344 
00345 /*
00346  * For convenience, it does not do decoding to CIDs.
00347  */
00348 long
00349 CMap_decode (CMap *cmap,
00350             const unsigned char **inbuf,  long *inbytesleft,
00351             unsigned char **outbuf, long *outbytesleft)
00352 {
00353   int count;
00354 
00355   ASSERT(cmap && inbuf && outbuf);
00356   ASSERT(inbytesleft && outbytesleft);
00357   for (count = 0;*inbytesleft > 0 && *outbytesleft > 0; count++)
00358     CMap_decode_char(cmap, inbuf, inbytesleft, outbuf, outbytesleft);
00359 
00360   return count;
00361 }
00362 
00363 char *
00364 CMap_get_name (CMap *cmap)
00365 {
00366   ASSERT(cmap);
00367   return cmap->name;
00368 }
00369 
00370 int
00371 CMap_get_type (CMap *cmap)
00372 {
00373   ASSERT(cmap);
00374   return cmap->type;
00375 }
00376 
00377 int
00378 CMap_get_wmode (CMap *cmap)
00379 {
00380   ASSERT(cmap);
00381   return cmap->wmode;
00382 }
00383 
00384 CIDSysInfo *
00385 CMap_get_CIDSysInfo (CMap *cmap)
00386 {
00387   ASSERT(cmap);
00388   return cmap->CSI;
00389 }
00390 
00391 void
00392 CMap_set_name (CMap *cmap, const char *name)
00393 {
00394   ASSERT(cmap);
00395   if (cmap->name)
00396     RELEASE(cmap->name);
00397   cmap->name = NEW(strlen(name)+1, char);
00398   strcpy(cmap->name, name);
00399 }
00400 
00401 void
00402 CMap_set_type (CMap *cmap, int type)
00403 {
00404   ASSERT(cmap);
00405   cmap->type = type;
00406 }
00407 
00408 void
00409 CMap_set_wmode (CMap *cmap, int wmode)
00410 {
00411   ASSERT(cmap);
00412   cmap->wmode = wmode;
00413 }
00414 
00415 void
00416 CMap_set_CIDSysInfo (CMap *cmap, const CIDSysInfo *csi)
00417 {
00418   ASSERT(cmap);
00419 
00420   if (cmap->CSI) {
00421     if (cmap->CSI->registry)
00422       RELEASE(cmap->CSI->registry);
00423     if (cmap->CSI->ordering)
00424       RELEASE(cmap->CSI->ordering);
00425     RELEASE(cmap->CSI);
00426   }
00427 
00428   if (csi && csi->registry && csi->ordering) {
00429     cmap->CSI = NEW(1, CIDSysInfo);
00430     cmap->CSI->registry = NEW(strlen(csi->registry)+1, char);
00431     strcpy(cmap->CSI->registry, csi->registry);
00432     cmap->CSI->ordering = NEW(strlen(csi->ordering)+1, char);
00433     strcpy(cmap->CSI->ordering, csi->ordering);
00434     cmap->CSI->supplement = csi->supplement;
00435   } else {
00436     WARN("Invalid CIDSystemInfo.");
00437     cmap->CSI = NULL;
00438   }
00439 }
00440 
00441 /*
00442  * Can have muliple entry ?
00443  */
00444 void
00445 CMap_set_usecmap (CMap *cmap, CMap *ucmap)
00446 {
00447   int i;
00448 
00449   ASSERT(cmap);
00450   ASSERT(ucmap); /* Maybe if (!ucmap) ERROR() is better for this. */
00451 
00452   if (cmap == ucmap)
00453     ERROR("%s: Identical CMap object cannot be used for usecmap CMap: 0x%p=0x%p",
00454          CMAP_DEBUG_STR, cmap, ucmap);
00455 
00456   /* Check if ucmap have neccesary information. */
00457   if (!CMap_is_valid(ucmap))
00458     ERROR("%s: Invalid CMap.", CMAP_DEBUG_STR);
00459 
00460   /*
00461    *  CMapName of cmap can be undefined when usecmap is executed in CMap parsing.
00462    *  And it is also possible CSI is not defined at that time.
00463    */
00464   if (cmap->name && strcmp(cmap->name, ucmap->name) == 0)
00465     ERROR("%s: CMap refering itself not allowed: CMap %s --> %s",
00466          CMAP_DEBUG_STR, cmap->name, ucmap->name);
00467 
00468   if (cmap->CSI && cmap->CSI->registry && cmap->CSI->ordering) {
00469     if (strcmp(cmap->CSI->registry, ucmap->CSI->registry) ||
00470        strcmp(cmap->CSI->ordering, ucmap->CSI->ordering))
00471       ERROR("%s: CMap %s required by %s have different CSI.",
00472            CMAP_DEBUG_STR, CMap_get_name(cmap), CMap_get_name(ucmap));
00473   }
00474 
00475   /* We must copy codespaceranges. */
00476   for (i = 0; i < ucmap->codespace.num; i++) {
00477     rangeDef *csr = ucmap->codespace.ranges + i;
00478     CMap_add_codespacerange(cmap, csr->codeLo, csr->codeHi, csr->dim);
00479   }
00480 
00481   cmap->useCMap = ucmap;
00482 }
00483 
00484 /* Test the validity of character c. */
00485 int
00486 CMap_match_codespace (CMap *cmap, const unsigned char *c, int dim)
00487 {
00488   int i, pos;
00489 
00490   ASSERT(cmap);
00491   for (i = 0; i < cmap->codespace.num; i++) {
00492     rangeDef *csr = cmap->codespace.ranges + i;
00493     if (csr->dim != dim)
00494       continue;
00495     for (pos = 0; pos < dim; pos++) {
00496       if (c[pos] > csr->codeHi[pos] || c[pos] < csr->codeLo[pos])
00497        break;
00498     }
00499     if (pos == dim)
00500       return 0; /* Valid */
00501   }
00502 
00503   return -1; /* Invalid */
00504 }
00505 
00506 /*
00507  * No overlapping codespace ranges are allowed, otherwise mapping is ambiguous.
00508  */
00509 int
00510 CMap_add_codespacerange (CMap *cmap,
00511                       const unsigned char *codelo, const unsigned char *codehi, int dim)
00512 {
00513   rangeDef *csr = NULL;
00514   int       i;
00515 
00516   ASSERT(cmap && dim > 0);
00517 
00518   for (i = 0; i < cmap->codespace.num; i++) {
00519     int j, overlap = 1;
00520     csr = cmap->codespace.ranges + i;
00521     for (j = 0; j < MIN(csr->dim, dim) && overlap; j++) {
00522       if ((codelo[j] >= csr->codeLo[j] && codelo[j] <= csr->codeHi[j]) ||
00523          (codehi[j] >= csr->codeLo[j] && codehi[j] <= csr->codeHi[j]))
00524        overlap = 1;
00525       else
00526        overlap = 0;
00527     }
00528     if (overlap) {
00529       WARN("Overlapping codespace found. (ingored)");
00530       return -1;
00531     }
00532   }
00533 
00534   if (dim < cmap->profile.minBytesIn)
00535     cmap->profile.minBytesIn = dim;
00536   if (dim > cmap->profile.maxBytesIn)
00537     cmap->profile.maxBytesIn = dim;
00538 
00539   if (cmap->codespace.num + 1 > cmap->codespace.max) {
00540     cmap->codespace.max += 10;
00541     cmap->codespace.ranges = RENEW(cmap->codespace.ranges, cmap->codespace.max, struct rangeDef);
00542   }
00543 
00544   csr = cmap->codespace.ranges + cmap->codespace.num;
00545   csr->dim    = dim;
00546   csr->codeHi = get_mem(cmap, dim);
00547   csr->codeLo = get_mem(cmap, dim);
00548   memcpy(csr->codeHi, codehi, dim);
00549   memcpy(csr->codeLo, codelo, dim);
00550 
00551   (cmap->codespace.num)++;
00552 
00553   return 0;
00554 }
00555 
00556 int
00557 CMap_add_notdefchar (CMap *cmap, const unsigned char *src, int srcdim, CID dst)
00558 {
00559   return CMap_add_notdefrange(cmap, src, src, srcdim, dst);
00560 }
00561 
00562 int
00563 CMap_add_notdefrange (CMap *cmap,
00564                     const unsigned char *srclo, const unsigned char *srchi, int srcdim, CID dst)
00565 {
00566   int     c;
00567   mapDef *cur;
00568 
00569   ASSERT(cmap);
00570   /* dst not used here */
00571   /* FIXME */
00572   if (check_range(cmap, srclo, srchi, srcdim, (const unsigned char *)&dst, 2) < 0)
00573     return -1;
00574     
00575   if (cmap->mapTbl == NULL )
00576     cmap->mapTbl = mapDef_new();
00577 
00578   cur = cmap->mapTbl;
00579   if (locate_tbl(&cur, srclo, srcdim) < 0)
00580     return -1;
00581 
00582   for (c = srclo[srcdim-1]; c <= srchi[srcdim-1]; c++) {
00583     if (MAP_DEFINED(cur[c].flag)) {
00584       if (!__silent)
00585        WARN("Trying to redefine already defined code mapping. (ignored)");
00586     } else {
00587       cur[c].flag = (MAP_LOOKUP_END|MAP_IS_NOTDEF);
00588       cur[c].code = get_mem(cmap, 2);
00589       cur[c].len  = 2;
00590       cur[c].code[0] = dst >> 8;
00591       cur[c].code[1] = dst & 0xff;
00592     }
00593     /* Do not do dst++ for notdefrange  */
00594   }
00595 
00596   return 0;
00597 }
00598 
00599 int
00600 CMap_add_bfchar (CMap *cmap,
00601                const unsigned char *src, int srcdim,
00602                const unsigned char *dst, int dstdim)
00603 {
00604   return CMap_add_bfrange(cmap, src, src, srcdim, dst, dstdim);
00605 }
00606 
00607 int
00608 CMap_add_bfrange (CMap *cmap,
00609                 const unsigned char *srclo, const unsigned char *srchi, int srcdim,
00610                 const unsigned char *base, int dstdim)
00611 {
00612   int     c, last_byte, i;
00613   mapDef *cur;
00614 
00615   ASSERT(cmap);
00616   if (check_range(cmap, srclo, srchi, srcdim, base, dstdim) < 0)
00617     return -1;
00618 
00619   if (cmap->mapTbl == NULL)
00620     cmap->mapTbl = mapDef_new();
00621 
00622   cur = cmap->mapTbl;
00623   if (locate_tbl(&cur, srclo, srcdim) < 0)
00624     return -1;
00625 
00626   for (c = srclo[srcdim-1]; c <= srchi[srcdim-1]; c++) {
00627     /* According to 5014.CIDFont_Spec.pdf (p.52),
00628      * Code mappings (unlike codespace ranges) may overlap,
00629      * but succeeding maps superceded preceding maps.
00630      * (reported and patched by Luo Jie on 2007/12/2)
00631      */
00632     if (!MAP_DEFINED(cur[c].flag) || cur[c].len < dstdim) {
00633       cur[c].flag = (MAP_LOOKUP_END|MAP_IS_CODE);
00634       cur[c].code = get_mem(cmap, dstdim);
00635     }
00636     /*
00637      * We assume restriction to code ranges also applied here.
00638      * Addition <00FF> + 1 is undefined.
00639      *
00640      * Changed on 2004-03-20:
00641      *
00642      *  Should be treated as <0100> in Acrobat's "ToUnicode" CMap.
00643      */
00644     cur[c].len = dstdim;
00645     memcpy(cur[c].code, base, dstdim);
00646 
00647     last_byte = c - srclo[srcdim-1] + base[dstdim-1];
00648     cur[c].code[dstdim-1] = (last_byte & 0xFF);
00649     for (i = dstdim - 2; i >= 0 && last_byte > 255; i--) {
00650       last_byte = cur[c].code[i] + 1;
00651       cur[c].code[i] = (last_byte & 0xFF);
00652     }
00653   }
00654 
00655   return 0;
00656 }
00657 
00658 int
00659 CMap_add_cidchar (CMap *cmap, const unsigned char *src, int srcdim, CID dst)
00660 {
00661   return CMap_add_cidrange(cmap, src, src, srcdim, dst);
00662 }
00663 
00664 int
00665 CMap_add_cidrange (CMap *cmap,
00666                  const unsigned char *srclo, const unsigned char *srchi, int srcdim, CID base)
00667 {
00668   int     c;
00669   mapDef *cur;
00670 
00671   ASSERT(cmap);
00672   /* base not used here */
00673   if (check_range(cmap, srclo, srchi, srcdim, (const unsigned char *)&base, 2) < 0) /* FIXME */
00674     return -1;
00675 
00676   if (cmap->mapTbl == NULL )
00677     cmap->mapTbl = mapDef_new();
00678 
00679   cur = cmap->mapTbl;
00680   if (locate_tbl(&cur, srclo, srcdim) < 0)
00681     return -1;
00682 
00683   for (c = srclo[srcdim-1]; c <= srchi[srcdim-1]; c++) {
00684     if (cur[c].flag != 0) {
00685       if (!__silent)
00686        WARN("Trying to redefine already defined CID mapping. (ignored)");
00687     } else {
00688       cur[c].flag = (MAP_LOOKUP_END|MAP_IS_CID);
00689       cur[c].len  = 2;
00690       cur[c].code = get_mem(cmap, 2);
00691       cur[c].code[0] = base >> 8;
00692       cur[c].code[1] = base & 0xff;
00693     }
00694     if (base >= CID_MAX)
00695       WARN("CID number too large.");
00696     base++;
00697   }
00698 
00699   return 0;
00700 }
00701 
00702 static void
00703 mapDef_release (mapDef *t)
00704 {
00705   int c;
00706 
00707   ASSERT(t);
00708   for (c = 0; c < 256; c++) {
00709     if (LOOKUP_CONTINUE(t[c].flag))
00710       mapDef_release(t[c].next);
00711   }
00712   RELEASE(t);
00713 }
00714 
00715 static mapDef *
00716 mapDef_new (void)
00717 {
00718   mapDef *t;
00719   int     c;
00720 
00721   t = NEW(256, mapDef);
00722   for (c=0; c<256; c++) {
00723     t[c].flag = (MAP_LOOKUP_END|MAP_IS_UNDEF);
00724     t[c].code = NULL;
00725     t[c].next = NULL;
00726   }
00727 
00728   return t;
00729 }
00730 
00731 static unsigned char *
00732 get_mem (CMap *cmap, int size)
00733 {
00734   mapData *map;
00735   unsigned char  *p;
00736 
00737   ASSERT(cmap && cmap->mapData && size >= 0);
00738   map = cmap->mapData;
00739   if (map->pos + size >= MEM_ALLOC_SIZE) {
00740     mapData *prev = map;
00741     map = NEW(1, struct mapData); 
00742     map->data = NEW(MEM_ALLOC_SIZE, unsigned char);
00743     map->prev = prev;
00744     map->pos  = 0;
00745     cmap->mapData = map;
00746   }
00747   p = map->data + map->pos;
00748   map->pos += size;
00749 
00750   return p;
00751 }
00752 
00753 static int
00754 locate_tbl (mapDef **cur, const unsigned char *code, int dim)
00755 {
00756   int i, c;
00757 
00758   ASSERT(cur && *cur);
00759   for (i = 0; i < dim-1; i++) {
00760     c = code[i];
00761     if (MAP_DEFINED((*cur)[c].flag)) {
00762       WARN("Ambiguous CMap entry.");
00763       return -1;
00764     }
00765     if ((*cur)[c].next == NULL)  /* create new node */
00766       (*cur)[c].next = mapDef_new();
00767     (*cur)[c].flag  |= MAP_LOOKUP_CONTINUE;
00768     *cur = (*cur)[c].next;
00769   }
00770 
00771   return 0;
00772 }
00773 
00774 /*
00775  * Guess how many bytes consumed as a `single' character:
00776  * Substring of length bytesconsumed bytes of input string is interpreted as
00777  * a `single' character by CMap_decode().
00778  */
00779 static int
00780 bytes_consumed (CMap *cmap, const unsigned char *instr, long inbytes)
00781 {
00782   int i, pos, longest = 0, bytesconsumed;
00783 
00784   ASSERT(cmap);
00785   for (i = 0; i < cmap->codespace.num; i++) {
00786     rangeDef *csr = cmap->codespace.ranges + i;
00787     for (pos = 0; pos < MIN(csr->dim, inbytes); pos++) {
00788       if (instr[pos] > csr->codeHi[pos] || instr[pos] < csr->codeLo[pos])
00789        break;
00790     }
00791     if (pos == csr->dim) /* part of instr is totally valid in this codespace. */
00792       return csr->dim;
00793     if (pos > longest)
00794       longest = pos;
00795   }
00796 
00797   if (i == cmap->codespace.num) /* No matching at all */
00798     bytesconsumed = cmap->profile.minBytesIn;
00799   else {
00800     bytesconsumed = cmap->profile.maxBytesIn;
00801     for (i = 0; i< cmap->codespace.num; i++) {
00802       rangeDef *csr = cmap->codespace.ranges + i;
00803       if (csr->dim > longest && csr->dim < bytesconsumed)
00804        bytesconsumed = csr->dim;
00805     }
00806   }
00807 
00808   return bytesconsumed;
00809 }
00810 
00811 static int
00812 check_range (CMap *cmap,
00813             const unsigned char *srclo, const unsigned char *srchi, int srcdim,
00814             const unsigned char *dst, int dstdim)
00815 {
00816   if ((srcdim < 1 || dstdim < 1) ||
00817       (!srclo || !srchi || !dst) ||
00818       memcmp(srclo, srchi, srcdim - 1) ||
00819       srclo[srcdim-1] > srchi[srcdim-1]) {
00820     WARN("Invalid CMap mapping entry. (ignored)");
00821     return -1;
00822   }
00823 
00824   if (CMap_match_codespace(cmap, srclo, srcdim) < 0 ||
00825       CMap_match_codespace(cmap, srchi, srcdim) < 0) {
00826     WARN("Invalid CMap mapping entry. (ignored)");
00827     return -1;
00828   }
00829 
00830   if (srcdim < cmap->profile.minBytesIn)
00831     cmap->profile.minBytesIn  = srcdim;
00832   if (srcdim > cmap->profile.maxBytesIn)
00833     cmap->profile.maxBytesIn  = srcdim;
00834   if (dstdim < cmap->profile.minBytesOut)
00835     cmap->profile.minBytesOut = dstdim;
00836   if (dstdim > cmap->profile.maxBytesOut)
00837     cmap->profile.maxBytesOut = dstdim;
00838 
00839   return 0;
00840 }
00841 
00842 /************************** CMAP_CACHE **************************/
00843 #include "cmap_read.h"
00844 
00845 #define CMAP_CACHE_ALLOC_SIZE 16u
00846 
00847 struct CMap_cache {
00848   int    num;
00849   int    max;
00850   CMap **cmaps;
00851 };
00852 
00853 static struct CMap_cache *__cache = NULL;
00854 
00855 #define CHECK_ID(n) do {\
00856                         if (! __cache)\
00857                            ERROR("%s: CMap cache not initialized.", CMAP_DEBUG_STR);\
00858                         if ((n) < 0 || (n) >= __cache->num)\
00859                            ERROR("Invalid CMap ID %d", (n));\
00860                     } while (0)
00861 
00862 #include "dpxfile.h"
00863 
00864 void
00865 CMap_cache_init (void)
00866 {
00867   static unsigned char range_min[2] = {0x00, 0x00};
00868   static unsigned char range_max[2] = {0xff, 0xff};
00869 
00870   if (__cache)
00871     ERROR("%s: Already initialized.", CMAP_DEBUG_STR);
00872 
00873   __cache = NEW(1, struct CMap_cache);
00874 
00875   __cache->max   = CMAP_CACHE_ALLOC_SIZE;
00876   __cache->cmaps = NEW(__cache->max, CMap *);
00877   __cache->num   = 0;
00878 
00879   /* Create Identity mapping */
00880   __cache->cmaps[0] = CMap_new();
00881   CMap_set_name (__cache->cmaps[0], "Identity-H");
00882   CMap_set_type (__cache->cmaps[0], CMAP_TYPE_IDENTITY);
00883   CMap_set_wmode(__cache->cmaps[0], 0);
00884   CMap_set_CIDSysInfo(__cache->cmaps[0], &CSI_IDENTITY);
00885   CMap_add_codespacerange(__cache->cmaps[0], range_min, range_max, 2);
00886 
00887   __cache->cmaps[1] = CMap_new();
00888   CMap_set_name (__cache->cmaps[1], "Identity-V");
00889   CMap_set_type (__cache->cmaps[1], CMAP_TYPE_IDENTITY);
00890   CMap_set_wmode(__cache->cmaps[1], 1);
00891   CMap_set_CIDSysInfo(__cache->cmaps[1], &CSI_IDENTITY);
00892   CMap_add_codespacerange(__cache->cmaps[1], range_min, range_max, 2);
00893 
00894   __cache->num += 2;
00895 }
00896 
00897 CMap *
00898 CMap_cache_get (int id)
00899 {
00900   CHECK_ID(id);
00901   return __cache->cmaps[id];
00902 }
00903 
00904 int
00905 CMap_cache_find (const char *cmap_name)
00906 {
00907   int   id = 0;
00908   FILE *fp = NULL;
00909 
00910   if (!__cache)
00911     CMap_cache_init();
00912   ASSERT(__cache);
00913 
00914   for (id = 0; id < __cache->num; id++) {
00915     char *name = NULL;
00916     /* CMapName may be undefined when processing usecmap. */
00917     name = CMap_get_name(__cache->cmaps[id]);
00918     if (name && strcmp(cmap_name, name) == 0) {
00919       return id;
00920     }
00921   }
00922 
00923   fp = DPXFOPEN(cmap_name, DPX_RES_TYPE_CMAP);
00924   if (!fp)
00925     return -1;
00926 
00927   if (CMap_parse_check_sig(fp) < 0) {
00928     DPXFCLOSE(fp);
00929     return -1;
00930   }
00931      
00932   if (__verbose)
00933     MESG("(CMap:%s", cmap_name);
00934 
00935   if (__cache->num >= __cache->max) {
00936     __cache->max   += CMAP_CACHE_ALLOC_SIZE;
00937     __cache->cmaps = RENEW(__cache->cmaps, __cache->max, CMap *);
00938   }
00939   id = __cache->num;
00940   (__cache->num)++;
00941   __cache->cmaps[id] = CMap_new();
00942 
00943   if (CMap_parse(__cache->cmaps[id], fp) < 0)
00944     ERROR("%s: Parsing CMap file failed.", CMAP_DEBUG_STR);
00945 
00946   DPXFCLOSE(fp);
00947 
00948   if (__verbose)
00949     MESG(")");
00950 
00951   return id;
00952 }
00953 
00954 int
00955 CMap_cache_add (CMap *cmap)
00956 {
00957   int   id;
00958   char *cmap_name0, *cmap_name1;
00959 
00960   if (!CMap_is_valid(cmap))
00961     ERROR("%s: Invalid CMap.", CMAP_DEBUG_STR);
00962 
00963   for (id = 0; id < __cache->num; id++) {
00964     cmap_name0 = CMap_get_name(cmap);
00965     cmap_name1 = CMap_get_name(__cache->cmaps[id]);
00966     if (!strcmp(cmap_name0, cmap_name1)) {
00967       ERROR("%s: CMap \"%s\" already defined.",
00968            CMAP_DEBUG_STR, cmap_name0);
00969       return -1;
00970     }
00971   }
00972 
00973   if (__cache->num >= __cache->max) {
00974     __cache->max   += CMAP_CACHE_ALLOC_SIZE;
00975     __cache->cmaps = RENEW(__cache->cmaps, __cache->max, CMap *);
00976   }
00977   id = __cache->num;
00978   (__cache->num)++;
00979   __cache->cmaps[id] = cmap;
00980 
00981   return id;
00982 }
00983 
00984 void
00985 CMap_cache_close (void)
00986 {
00987   if (__cache) {
00988     int id;
00989     for (id = 0; id < __cache->num; id++) {
00990       CMap_release(__cache->cmaps[id]);
00991     }
00992     RELEASE(__cache->cmaps);
00993     RELEASE(__cache);
00994     __cache = NULL;
00995   }
00996 }