diff options
Diffstat (limited to 'Build/source/texk/dvipdfmx/dvipdfmx-20120420/src/cmap.c')
-rw-r--r-- | Build/source/texk/dvipdfmx/dvipdfmx-20120420/src/cmap.c | 997 |
1 files changed, 997 insertions, 0 deletions
diff --git a/Build/source/texk/dvipdfmx/dvipdfmx-20120420/src/cmap.c b/Build/source/texk/dvipdfmx/dvipdfmx-20120420/src/cmap.c new file mode 100644 index 00000000000..9ab66aece8a --- /dev/null +++ b/Build/source/texk/dvipdfmx/dvipdfmx-20120420/src/cmap.c @@ -0,0 +1,997 @@ +/* $Header: /home/cvsroot/dvipdfmx/src/cmap.c,v 1.30 2011/03/06 03:14:13 chofchof Exp $ + + This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. + + Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata, + the dvipdfmx project team <dvipdfmx@project.ktug.or.kr> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +*/ + +/* + * References: + * + * PostScript Language Reference Manual, 3rd. ed. (Adobe Systems Inc.) + * 5.11.4 CMap Dictionaries + * 5.11.5 FMapType 9 Composite Fonts + * Building CMap Files for CID-Keyed Fonts, Adobe Technical Note #5099 + * CID-Keyed Font Technology Overview, Adobe Technical Note #5092 + * Adobe CMap and CIDFont Files Specification, Adobe Technical Specification #5014 + * + * Undefined Character Handling: + * PLRM 3rd. ed., sec. 5.11.5., "Handling Undefined Characters" + * + * TODO: + * Only cid(range|char) allowed for CODE_TO_CID and bf(range|char) for CID_TO_CODE ? + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> + +#include "system.h" +#include "mem.h" +#include "error.h" +#include "dpxutil.h" + +#include "cmap_p.h" +#include "cmap.h" + +static int __verbose = 0; +static int __silent = 0; + +void +CMap_set_verbose (void) +{ + __verbose++; +} + +void +CMap_set_silent (int value) +{ + __silent = value ? 1 : 0; +} + +/* Private funcs. */ +static int bytes_consumed (CMap *cmap, const unsigned char *instr, long inbytes); +static void handle_undefined (CMap *cmap, + const unsigned char **inbuf, long *inbytesleft, + unsigned char **outbuf, long *outbytesleft); + +static int check_range (CMap *cmap, + const unsigned char *srclo, const unsigned char *srchi, int srcdim, + const unsigned char *dst, int dstdim); + +static unsigned char *get_mem (CMap *cmap, int size); +static mapDef *mapDef_new (void); +static void mapDef_release (mapDef *t); +static int locate_tbl (mapDef **cur, const unsigned char *code, int dim); + +CMap * +CMap_new (void) +{ + CMap *cmap; + + cmap = NEW(1, struct CMap); + cmap->name = NULL; + cmap->type = CMAP_TYPE_CODE_TO_CID; + cmap->wmode = 0; + cmap->useCMap = NULL; + cmap->CSI = NULL; + + cmap->profile.minBytesIn = 2; + cmap->profile.maxBytesIn = 2; + cmap->profile.minBytesOut = 2; + cmap->profile.maxBytesOut = 2; + + cmap->flags = 0; + + cmap->codespace.num = 0; + cmap->codespace.max = 10; + cmap->codespace.ranges = NEW(10, struct rangeDef); + + cmap->mapTbl = NULL; + + cmap->mapData = NEW(1, struct mapData); + cmap->mapData->prev = NULL; + cmap->mapData->pos = 0; + cmap->mapData->data = NEW(MEM_ALLOC_SIZE, unsigned char); + + return cmap; +} + +void +CMap_release (CMap *cmap) +{ + if (!cmap) + return; + + if (cmap->name) + RELEASE(cmap->name); + if (cmap->CSI) { + if (cmap->CSI->registry) RELEASE(cmap->CSI->registry); + if (cmap->CSI->ordering) RELEASE(cmap->CSI->ordering); + RELEASE(cmap->CSI); + } + if (cmap->codespace.ranges) + RELEASE(cmap->codespace.ranges); + if (cmap->mapTbl) + mapDef_release(cmap->mapTbl); + { + mapData *map = cmap->mapData; + while (map != NULL) { + mapData *prev = map->prev; + if (map->data != NULL) + RELEASE(map->data); + RELEASE(map); + map = prev; + } + } + + RELEASE(cmap); +} + +int +CMap_is_Identity (CMap *cmap) +{ + ASSERT(cmap); + if (!strcmp(cmap->name, "Identity-H") || !strcmp(cmap->name, "Identity-V")) + return 1; + else + return 0; +} + +#if 0 +/* NOT IMPLEMENTED YET */ +int +CMap_is_realy_Identity(CMap *cmap) +{ + return 0; +} +#endif + +int +CMap_is_valid (CMap *cmap) +{ + /* Quick check */ + if (!cmap || !(cmap->name) || cmap->type < CMAP_TYPE_IDENTITY || + cmap->type > CMAP_TYPE_CID_TO_CODE || cmap->codespace.num < 1 || + (cmap->type != CMAP_TYPE_IDENTITY && !cmap->mapTbl)) + return 0; + + if (cmap->useCMap) { + CIDSysInfo *csi1, *csi2; + csi1 = CMap_get_CIDSysInfo(cmap); + csi2 = CMap_get_CIDSysInfo(cmap->useCMap); + if (strcmp(csi1->registry, csi2->registry) || + strcmp(csi1->ordering, csi2->ordering)) { + WARN("CIDSystemInfo mismatched %s <--> %s", + CMap_get_name(cmap), CMap_get_name(cmap->useCMap)); + return 0; + } + } + + return 1; +} + +int +CMap_get_profile (CMap *cmap, int type) +{ + int value = 0; + + ASSERT(cmap); + switch (type) { + case CMAP_PROF_TYPE_INBYTES_MIN: + value = cmap->profile.minBytesIn; + break; + case CMAP_PROF_TYPE_INBYTES_MAX: + value = cmap->profile.maxBytesIn; + break; + case CMAP_PROF_TYPE_OUTBYTES_MIN: + value = cmap->profile.maxBytesOut; + break; + case CMAP_PROF_TYPE_OUTBYTES_MAX: + value = cmap->profile.maxBytesOut; + break; + default: + ERROR("%s: Unrecognized profile type %d.", CMAP_DEBUG_STR, type); + } + + return value; +} + +/* + * Put notdef chars for codes not declared in notdef(range|char) + */ +static void +handle_undefined (CMap *cmap, + const unsigned char **inbuf, long *inbytesleft, + unsigned char **outbuf, long *outbytesleft) +{ + long len = 0; + + if (*outbytesleft < 2) + ERROR("%s: Buffer overflow.", CMAP_DEBUG_STR); + + switch (cmap->type) { + case CMAP_TYPE_CODE_TO_CID: + memcpy(*outbuf, CID_NOTDEF_CHAR, 2); + break; + case CMAP_TYPE_TO_UNICODE: + memcpy(*outbuf, UCS_NOTDEF_CHAR, 2); + break; + default: + WARN("Cannot handle undefined mapping for this type of CMap mapping: %d", cmap->type); + WARN("<0000> is used for .notdef char."); + memset(*outbuf, 0, 2); + } + *outbuf += 2; + *outbytesleft -= 2; + + len = bytes_consumed(cmap, *inbuf, *inbytesleft); + + *inbuf += len; + *inbytesleft -= len; +} + +void +CMap_decode_char (CMap *cmap, + const unsigned char **inbuf, long *inbytesleft, + unsigned char **outbuf, long *outbytesleft) +{ + mapDef *t; + const unsigned char *p, *save; + unsigned char c = 0; + long count = 0; + + p = save = *inbuf; + /* + * First handle some special cases: + */ + if (cmap->type == CMAP_TYPE_IDENTITY) { + if ((*inbytesleft) % 2) + ERROR("%s: Invalid/truncated input string.", CMAP_DEBUG_STR); + if (*outbytesleft < 2) + ERROR("%s: Buffer overflow.", CMAP_DEBUG_STR); + memcpy(*outbuf, *inbuf, 2); + *inbuf += 2; + *outbuf += 2; + *outbytesleft -= 2; + *inbytesleft -= 2; + return; + } else if (!cmap->mapTbl) { + if (cmap->useCMap) { + CMap_decode_char(cmap->useCMap, inbuf, inbytesleft, outbuf, outbytesleft); + return; + } else { + /* no mapping available in this CMap */ + WARN("No mapping available for this character."); + handle_undefined(cmap, inbuf, inbytesleft, outbuf, outbytesleft); + return; + } + } + + ASSERT(cmap->mapTbl); + t = cmap->mapTbl; + while (count < *inbytesleft) { + c = *p++; + count++; + if (LOOKUP_END(t[c].flag)) + break; + t = t[c].next; + } + if (LOOKUP_CONTINUE(t[c].flag)) /* need more bytes */ + ERROR("%s: Premature end of input string.", CMAP_DEBUG_STR); + else if (!MAP_DEFINED(t[c].flag)) { + if (cmap->useCMap) { + CMap_decode_char(cmap->useCMap, inbuf, inbytesleft, outbuf, outbytesleft); + return; + } else { + /* no mapping available in this CMap */ + WARN("No character mapping available."); + MESG(" CMap name: %s\n", CMap_get_name(cmap)); + MESG(" input str: "); + MESG("<"); + while (save < p) { + MESG("%02x", *save); + save++; + } + MESG(">\n"); + /* + * We know partial match found up to `count' bytes, + * but we will not use this information for the sake of simplicity. + */ + handle_undefined(cmap, inbuf, inbytesleft, outbuf, outbytesleft); + return; + } + } else { + switch (MAP_TYPE(t[c].flag)) { + case MAP_IS_NOTDEF: + WARN("Character mapped to .notdef found."); + /* continue */ + case MAP_IS_CID: case MAP_IS_CODE: + if (*outbytesleft >= t[c].len) + memcpy(*outbuf, t[c].code, t[c].len); + else + ERROR("%s: Buffer overflow.", CMAP_DEBUG_STR); + *outbuf += t[c].len; + *outbytesleft -= t[c].len; + break; + case MAP_IS_NAME: + ERROR("%s: CharName mapping not supported.", CMAP_DEBUG_STR); + break; + default: + ERROR("%s: Unknown mapping type.", CMAP_DEBUG_STR); + } + if (inbytesleft) + *inbytesleft -= count; + *inbuf = p; + } +} + +/* + * For convenience, it does not do decoding to CIDs. + */ +long +CMap_decode (CMap *cmap, + const unsigned char **inbuf, long *inbytesleft, + unsigned char **outbuf, long *outbytesleft) +{ + int count; + + ASSERT(cmap && inbuf && outbuf); + ASSERT(inbytesleft && outbytesleft); + for (count = 0;*inbytesleft > 0 && *outbytesleft > 0; count++) + CMap_decode_char(cmap, inbuf, inbytesleft, outbuf, outbytesleft); + + return count; +} + +char * +CMap_get_name (CMap *cmap) +{ + ASSERT(cmap); + return cmap->name; +} + +int +CMap_get_type (CMap *cmap) +{ + ASSERT(cmap); + return cmap->type; +} + +int +CMap_get_wmode (CMap *cmap) +{ + ASSERT(cmap); + return cmap->wmode; +} + +CIDSysInfo * +CMap_get_CIDSysInfo (CMap *cmap) +{ + ASSERT(cmap); + return cmap->CSI; +} + +void +CMap_set_name (CMap *cmap, const char *name) +{ + ASSERT(cmap); + if (cmap->name) + RELEASE(cmap->name); + cmap->name = NEW(strlen(name)+1, char); + strcpy(cmap->name, name); +} + +void +CMap_set_type (CMap *cmap, int type) +{ + ASSERT(cmap); + cmap->type = type; +} + +void +CMap_set_wmode (CMap *cmap, int wmode) +{ + ASSERT(cmap); + cmap->wmode = wmode; +} + +void +CMap_set_CIDSysInfo (CMap *cmap, const CIDSysInfo *csi) +{ + ASSERT(cmap); + + if (cmap->CSI) { + if (cmap->CSI->registry) + RELEASE(cmap->CSI->registry); + if (cmap->CSI->ordering) + RELEASE(cmap->CSI->ordering); + RELEASE(cmap->CSI); + } + + if (csi && csi->registry && csi->ordering) { + cmap->CSI = NEW(1, CIDSysInfo); + cmap->CSI->registry = NEW(strlen(csi->registry)+1, char); + strcpy(cmap->CSI->registry, csi->registry); + cmap->CSI->ordering = NEW(strlen(csi->ordering)+1, char); + strcpy(cmap->CSI->ordering, csi->ordering); + cmap->CSI->supplement = csi->supplement; + } else { + WARN("Invalid CIDSystemInfo."); + cmap->CSI = NULL; + } +} + +/* + * Can have muliple entry ? + */ +void +CMap_set_usecmap (CMap *cmap, CMap *ucmap) +{ + int i; + + ASSERT(cmap); + ASSERT(ucmap); /* Maybe if (!ucmap) ERROR() is better for this. */ + + if (cmap == ucmap) + ERROR("%s: Identical CMap object cannot be used for usecmap CMap: 0x%p=0x%p", + CMAP_DEBUG_STR, cmap, ucmap); + + /* Check if ucmap have neccesary information. */ + if (!CMap_is_valid(ucmap)) + ERROR("%s: Invalid CMap.", CMAP_DEBUG_STR); + + /* + * CMapName of cmap can be undefined when usecmap is executed in CMap parsing. + * And it is also possible CSI is not defined at that time. + */ + if (cmap->name && strcmp(cmap->name, ucmap->name) == 0) + ERROR("%s: CMap refering itself not allowed: CMap %s --> %s", + CMAP_DEBUG_STR, cmap->name, ucmap->name); + + if (cmap->CSI && cmap->CSI->registry && cmap->CSI->ordering) { + if (strcmp(cmap->CSI->registry, ucmap->CSI->registry) || + strcmp(cmap->CSI->ordering, ucmap->CSI->ordering)) + ERROR("%s: CMap %s required by %s have different CSI.", + CMAP_DEBUG_STR, CMap_get_name(cmap), CMap_get_name(ucmap)); + } + + /* We must copy codespaceranges. */ + for (i = 0; i < ucmap->codespace.num; i++) { + rangeDef *csr = ucmap->codespace.ranges + i; + CMap_add_codespacerange(cmap, csr->codeLo, csr->codeHi, csr->dim); + } + + cmap->useCMap = ucmap; +} + +/* Test the validity of character c. */ +int +CMap_match_codespace (CMap *cmap, const unsigned char *c, int dim) +{ + int i, pos; + + ASSERT(cmap); + for (i = 0; i < cmap->codespace.num; i++) { + rangeDef *csr = cmap->codespace.ranges + i; + if (csr->dim != dim) + continue; + for (pos = 0; pos < dim; pos++) { + if (c[pos] > csr->codeHi[pos] || c[pos] < csr->codeLo[pos]) + break; + } + if (pos == dim) + return 0; /* Valid */ + } + + return -1; /* Invalid */ +} + +/* + * No overlapping codespace ranges are allowed, otherwise mapping is ambiguous. + */ +int +CMap_add_codespacerange (CMap *cmap, + const unsigned char *codelo, const unsigned char *codehi, int dim) +{ + rangeDef *csr = NULL; + int i; + + ASSERT(cmap && dim > 0); + + for (i = 0; i < cmap->codespace.num; i++) { + int j, overlap = 1; + csr = cmap->codespace.ranges + i; + for (j = 0; j < MIN(csr->dim, dim) && overlap; j++) { + if ((codelo[j] >= csr->codeLo[j] && codelo[j] <= csr->codeHi[j]) || + (codehi[j] >= csr->codeLo[j] && codehi[j] <= csr->codeHi[j])) + overlap = 1; + else + overlap = 0; + } + if (overlap) { + WARN("Overlapping codespace found. (ingored)"); + return -1; + } + } + + if (dim < cmap->profile.minBytesIn) + cmap->profile.minBytesIn = dim; + if (dim > cmap->profile.maxBytesIn) + cmap->profile.maxBytesIn = dim; + + if (cmap->codespace.num + 1 > cmap->codespace.max) { + cmap->codespace.max += 10; + cmap->codespace.ranges = RENEW(cmap->codespace.ranges, cmap->codespace.max, struct rangeDef); + } + + csr = cmap->codespace.ranges + cmap->codespace.num; + csr->dim = dim; + csr->codeHi = get_mem(cmap, dim); + csr->codeLo = get_mem(cmap, dim); + memcpy(csr->codeHi, codehi, dim); + memcpy(csr->codeLo, codelo, dim); + + (cmap->codespace.num)++; + + return 0; +} + +int +CMap_add_notdefchar (CMap *cmap, const unsigned char *src, int srcdim, CID dst) +{ + return CMap_add_notdefrange(cmap, src, src, srcdim, dst); +} + +int +CMap_add_notdefrange (CMap *cmap, + const unsigned char *srclo, const unsigned char *srchi, int srcdim, CID dst) +{ + int c; + mapDef *cur; + + ASSERT(cmap); + /* dst not used here */ + /* FIXME */ + if (check_range(cmap, srclo, srchi, srcdim, (const unsigned char *)&dst, 2) < 0) + return -1; + + if (cmap->mapTbl == NULL ) + cmap->mapTbl = mapDef_new(); + + cur = cmap->mapTbl; + if (locate_tbl(&cur, srclo, srcdim) < 0) + return -1; + + for (c = srclo[srcdim-1]; c <= srchi[srcdim-1]; c++) { + if (MAP_DEFINED(cur[c].flag)) { + if (!__silent) + WARN("Trying to redefine already defined code mapping. (ignored)"); + } else { + cur[c].flag = (MAP_LOOKUP_END|MAP_IS_NOTDEF); + cur[c].code = get_mem(cmap, 2); + cur[c].len = 2; + cur[c].code[0] = dst >> 8; + cur[c].code[1] = dst & 0xff; + } + /* Do not do dst++ for notdefrange */ + } + + return 0; +} + +int +CMap_add_bfchar (CMap *cmap, + const unsigned char *src, int srcdim, + const unsigned char *dst, int dstdim) +{ + return CMap_add_bfrange(cmap, src, src, srcdim, dst, dstdim); +} + +int +CMap_add_bfrange (CMap *cmap, + const unsigned char *srclo, const unsigned char *srchi, int srcdim, + const unsigned char *base, int dstdim) +{ + int c, last_byte, i; + mapDef *cur; + + ASSERT(cmap); + if (check_range(cmap, srclo, srchi, srcdim, base, dstdim) < 0) + return -1; + + if (cmap->mapTbl == NULL) + cmap->mapTbl = mapDef_new(); + + cur = cmap->mapTbl; + if (locate_tbl(&cur, srclo, srcdim) < 0) + return -1; + + for (c = srclo[srcdim-1]; c <= srchi[srcdim-1]; c++) { + /* According to 5014.CIDFont_Spec.pdf (p.52), + * Code mappings (unlike codespace ranges) may overlap, + * but succeeding maps superceded preceding maps. + * (reported and patched by Luo Jie on 2007/12/2) + */ + if (!MAP_DEFINED(cur[c].flag) || cur[c].len < dstdim) { + cur[c].flag = (MAP_LOOKUP_END|MAP_IS_CODE); + cur[c].code = get_mem(cmap, dstdim); + } + /* + * We assume restriction to code ranges also applied here. + * Addition <00FF> + 1 is undefined. + * + * Changed on 2004-03-20: + * + * Should be treated as <0100> in Acrobat's "ToUnicode" CMap. + */ + cur[c].len = dstdim; + memcpy(cur[c].code, base, dstdim); + + last_byte = c - srclo[srcdim-1] + base[dstdim-1]; + cur[c].code[dstdim-1] = (last_byte & 0xFF); + for (i = dstdim - 2; i >= 0 && last_byte > 255; i--) { + last_byte = cur[c].code[i] + 1; + cur[c].code[i] = (last_byte & 0xFF); + } + } + + return 0; +} + +int +CMap_add_cidchar (CMap *cmap, const unsigned char *src, int srcdim, CID dst) +{ + return CMap_add_cidrange(cmap, src, src, srcdim, dst); +} + +int +CMap_add_cidrange (CMap *cmap, + const unsigned char *srclo, const unsigned char *srchi, int srcdim, CID base) +{ + int c; + mapDef *cur; + + ASSERT(cmap); + /* base not used here */ + if (check_range(cmap, srclo, srchi, srcdim, (const unsigned char *)&base, 2) < 0) /* FIXME */ + return -1; + + if (cmap->mapTbl == NULL ) + cmap->mapTbl = mapDef_new(); + + cur = cmap->mapTbl; + if (locate_tbl(&cur, srclo, srcdim) < 0) + return -1; + + for (c = srclo[srcdim-1]; c <= srchi[srcdim-1]; c++) { + if (cur[c].flag != 0) { + if (!__silent) + WARN("Trying to redefine already defined CID mapping. (ignored)"); + } else { + cur[c].flag = (MAP_LOOKUP_END|MAP_IS_CID); + cur[c].len = 2; + cur[c].code = get_mem(cmap, 2); + cur[c].code[0] = base >> 8; + cur[c].code[1] = base & 0xff; + } + if (base >= CID_MAX) + WARN("CID number too large."); + base++; + } + + return 0; +} + +static void +mapDef_release (mapDef *t) +{ + int c; + + ASSERT(t); + for (c = 0; c < 256; c++) { + if (LOOKUP_CONTINUE(t[c].flag)) + mapDef_release(t[c].next); + } + RELEASE(t); +} + +static mapDef * +mapDef_new (void) +{ + mapDef *t; + int c; + + t = NEW(256, mapDef); + for (c=0; c<256; c++) { + t[c].flag = (MAP_LOOKUP_END|MAP_IS_UNDEF); + t[c].code = NULL; + t[c].next = NULL; + } + + return t; +} + +static unsigned char * +get_mem (CMap *cmap, int size) +{ + mapData *map; + unsigned char *p; + + ASSERT(cmap && cmap->mapData && size >= 0); + map = cmap->mapData; + if (map->pos + size >= MEM_ALLOC_SIZE) { + mapData *prev = map; + map = NEW(1, struct mapData); + map->data = NEW(MEM_ALLOC_SIZE, unsigned char); + map->prev = prev; + map->pos = 0; + cmap->mapData = map; + } + p = map->data + map->pos; + map->pos += size; + + return p; +} + +static int +locate_tbl (mapDef **cur, const unsigned char *code, int dim) +{ + int i, c; + + ASSERT(cur && *cur); + for (i = 0; i < dim-1; i++) { + c = code[i]; + if (MAP_DEFINED((*cur)[c].flag)) { + WARN("Ambiguous CMap entry."); + return -1; + } + if ((*cur)[c].next == NULL) /* create new node */ + (*cur)[c].next = mapDef_new(); + (*cur)[c].flag |= MAP_LOOKUP_CONTINUE; + *cur = (*cur)[c].next; + } + + return 0; +} + +/* + * Guess how many bytes consumed as a `single' character: + * Substring of length bytesconsumed bytes of input string is interpreted as + * a `single' character by CMap_decode(). + */ +static int +bytes_consumed (CMap *cmap, const unsigned char *instr, long inbytes) +{ + int i, pos, longest = 0, bytesconsumed; + + ASSERT(cmap); + for (i = 0; i < cmap->codespace.num; i++) { + rangeDef *csr = cmap->codespace.ranges + i; + for (pos = 0; pos < MIN(csr->dim, inbytes); pos++) { + if (instr[pos] > csr->codeHi[pos] || instr[pos] < csr->codeLo[pos]) + break; + } + if (pos == csr->dim) /* part of instr is totally valid in this codespace. */ + return csr->dim; + if (pos > longest) + longest = pos; + } + + if (i == cmap->codespace.num) /* No matching at all */ + bytesconsumed = cmap->profile.minBytesIn; + else { + bytesconsumed = cmap->profile.maxBytesIn; + for (i = 0; i< cmap->codespace.num; i++) { + rangeDef *csr = cmap->codespace.ranges + i; + if (csr->dim > longest && csr->dim < bytesconsumed) + bytesconsumed = csr->dim; + } + } + + return bytesconsumed; +} + +static int +check_range (CMap *cmap, + const unsigned char *srclo, const unsigned char *srchi, int srcdim, + const unsigned char *dst, int dstdim) +{ + if ((srcdim < 1 || dstdim < 1) || + (!srclo || !srchi || !dst) || + memcmp(srclo, srchi, srcdim - 1) || + srclo[srcdim-1] > srchi[srcdim-1]) { + WARN("Invalid CMap mapping entry. (ignored)"); + return -1; + } + + if (CMap_match_codespace(cmap, srclo, srcdim) < 0 || + CMap_match_codespace(cmap, srchi, srcdim) < 0) { + WARN("Invalid CMap mapping entry. (ignored)"); + return -1; + } + + if (srcdim < cmap->profile.minBytesIn) + cmap->profile.minBytesIn = srcdim; + if (srcdim > cmap->profile.maxBytesIn) + cmap->profile.maxBytesIn = srcdim; + if (dstdim < cmap->profile.minBytesOut) + cmap->profile.minBytesOut = dstdim; + if (dstdim > cmap->profile.maxBytesOut) + cmap->profile.maxBytesOut = dstdim; + + return 0; +} + +/************************** CMAP_CACHE **************************/ +#include "cmap_read.h" + +#define CMAP_CACHE_ALLOC_SIZE 16u + +struct CMap_cache { + int num; + int max; + CMap **cmaps; +}; + +static struct CMap_cache *__cache = NULL; + +#define CHECK_ID(n) do {\ + if (! __cache)\ + ERROR("%s: CMap cache not initialized.", CMAP_DEBUG_STR);\ + if ((n) < 0 || (n) >= __cache->num)\ + ERROR("Invalid CMap ID %d", (n));\ + } while (0) + +#include "dpxfile.h" + +void +CMap_cache_init (void) +{ + static unsigned char range_min[2] = {0x00, 0x00}; + static unsigned char range_max[2] = {0xff, 0xff}; + + if (__cache) + ERROR("%s: Already initialized.", CMAP_DEBUG_STR); + + __cache = NEW(1, struct CMap_cache); + + __cache->max = CMAP_CACHE_ALLOC_SIZE; + __cache->cmaps = NEW(__cache->max, CMap *); + __cache->num = 0; + + /* Create Identity mapping */ + __cache->cmaps[0] = CMap_new(); + CMap_set_name (__cache->cmaps[0], "Identity-H"); + CMap_set_type (__cache->cmaps[0], CMAP_TYPE_IDENTITY); + CMap_set_wmode(__cache->cmaps[0], 0); + CMap_set_CIDSysInfo(__cache->cmaps[0], &CSI_IDENTITY); + CMap_add_codespacerange(__cache->cmaps[0], range_min, range_max, 2); + + __cache->cmaps[1] = CMap_new(); + CMap_set_name (__cache->cmaps[1], "Identity-V"); + CMap_set_type (__cache->cmaps[1], CMAP_TYPE_IDENTITY); + CMap_set_wmode(__cache->cmaps[1], 1); + CMap_set_CIDSysInfo(__cache->cmaps[1], &CSI_IDENTITY); + CMap_add_codespacerange(__cache->cmaps[1], range_min, range_max, 2); + + __cache->num += 2; +} + +CMap * +CMap_cache_get (int id) +{ + CHECK_ID(id); + return __cache->cmaps[id]; +} + +int +CMap_cache_find (const char *cmap_name) +{ + int id = 0; + FILE *fp = NULL; + + if (!__cache) + CMap_cache_init(); + ASSERT(__cache); + + for (id = 0; id < __cache->num; id++) { + char *name = NULL; + /* CMapName may be undefined when processing usecmap. */ + name = CMap_get_name(__cache->cmaps[id]); + if (name && strcmp(cmap_name, name) == 0) { + return id; + } + } + + fp = DPXFOPEN(cmap_name, DPX_RES_TYPE_CMAP); + if (!fp) + return -1; + + if (CMap_parse_check_sig(fp) < 0) { + DPXFCLOSE(fp); + return -1; + } + + if (__verbose) + MESG("(CMap:%s", cmap_name); + + if (__cache->num >= __cache->max) { + __cache->max += CMAP_CACHE_ALLOC_SIZE; + __cache->cmaps = RENEW(__cache->cmaps, __cache->max, CMap *); + } + id = __cache->num; + (__cache->num)++; + __cache->cmaps[id] = CMap_new(); + + if (CMap_parse(__cache->cmaps[id], fp) < 0) + ERROR("%s: Parsing CMap file failed.", CMAP_DEBUG_STR); + + DPXFCLOSE(fp); + + if (__verbose) + MESG(")"); + + return id; +} + +int +CMap_cache_add (CMap *cmap) +{ + int id; + char *cmap_name0, *cmap_name1; + + if (!CMap_is_valid(cmap)) + ERROR("%s: Invalid CMap.", CMAP_DEBUG_STR); + + for (id = 0; id < __cache->num; id++) { + cmap_name0 = CMap_get_name(cmap); + cmap_name1 = CMap_get_name(__cache->cmaps[id]); + if (!strcmp(cmap_name0, cmap_name1)) { + ERROR("%s: CMap \"%s\" already defined.", + CMAP_DEBUG_STR, cmap_name0); + return -1; + } + } + + if (__cache->num >= __cache->max) { + __cache->max += CMAP_CACHE_ALLOC_SIZE; + __cache->cmaps = RENEW(__cache->cmaps, __cache->max, CMap *); + } + id = __cache->num; + (__cache->num)++; + __cache->cmaps[id] = cmap; + + return id; +} + +void +CMap_cache_close (void) +{ + if (__cache) { + int id; + for (id = 0; id < __cache->num; id++) { + CMap_release(__cache->cmaps[id]); + } + RELEASE(__cache->cmaps); + RELEASE(__cache); + __cache = NULL; + } +} |