1 /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
2 
3     Copyright (C) 2002-2014 by Jin-Hwan Cho and Shunsaku Hirata,
4     the dvipdfmx project team.
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 */
20 
21 /*
22  * References:
23  *
24  *  PostScript Language Reference Manual, 3rd. ed. (Adobe Systems Inc.)
25  *    5.11.4 CMap Dictionaries
26  *    5.11.5 FMapType 9 Composite Fonts
27  *  Building CMap Files for CID-Keyed Fonts, Adobe Technical Note #5099
28  *  CID-Keyed Font Technology Overview, Adobe Technical Note #5092
29  *  Adobe CMap and CIDFont Files Specification, Adobe Technical Specification #5014
30  *
31  *  Undefined Character Handling:
32  *    PLRM 3rd. ed., sec. 5.11.5., "Handling Undefined Characters"
33  *
34  * TODO:
35  *   Only cid(range|char) allowed for CODE_TO_CID and bf(range|char) for CID_TO_CODE ?
36  */
37 
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41 
42 #include <string.h>
43 
44 #include "system.h"
45 #include "mem.h"
46 #include "error.h"
47 #include "dpxutil.h"
48 
49 #include "cmap_p.h"
50 #include "cmap.h"
51 
52 static int __verbose = 0;
53 static int __silent  = 0;
54 
55 void
CMap_set_verbose(void)56 CMap_set_verbose (void)
57 {
58   __verbose++;
59 }
60 
61 void
CMap_set_silent(int value)62 CMap_set_silent (int value)
63 {
64   __silent = value ? 1 : 0;
65 }
66 
67 /* Private funcs. */
68 static int  bytes_consumed   (CMap *cmap, const unsigned char *instr, long inbytes);
69 static void handle_undefined (CMap *cmap,
70 			      const unsigned char **inbuf, long *inbytesleft,
71 			      unsigned char **outbuf, long *outbytesleft);
72 
73 static int  check_range      (CMap *cmap,
74 			      const unsigned char *srclo, const unsigned char *srchi, int srcdim,
75 			      const unsigned char *dst, int dstdim);
76 
77 static unsigned char *get_mem (CMap *cmap, int size);
78 static mapDef *mapDef_new     (void);
79 static void    mapDef_release (mapDef *t);
80 static int     locate_tbl     (mapDef **cur, const unsigned char *code, int dim);
81 
82 CMap *
CMap_new(void)83 CMap_new (void)
84 {
85   CMap *cmap;
86 
87   cmap = NEW(1, struct CMap);
88   cmap->name     = NULL;
89   cmap->type     = CMAP_TYPE_CODE_TO_CID;
90   cmap->wmode    = 0;
91   cmap->useCMap  = NULL;
92   cmap->CSI      = NULL;
93 
94   cmap->profile.minBytesIn  = 2;
95   cmap->profile.maxBytesIn  = 2;
96   cmap->profile.minBytesOut = 2;
97   cmap->profile.maxBytesOut = 2;
98 
99   cmap->flags = 0;
100 
101   cmap->codespace.num    = 0;
102   cmap->codespace.max    = 10;
103   cmap->codespace.ranges = NEW(10, struct rangeDef);
104 
105   cmap->mapTbl  = NULL;
106 
107   cmap->mapData = NEW(1, struct mapData);
108   cmap->mapData->prev = NULL;
109   cmap->mapData->pos  = 0;
110   cmap->mapData->data = NEW(MEM_ALLOC_SIZE, unsigned char);
111 
112   cmap->reverseMap = NEW(65536, int);
113   memset(cmap->reverseMap, 0, 65536 * sizeof(int));
114 
115   return cmap;
116 }
117 
118 void
CMap_release(CMap * cmap)119 CMap_release (CMap *cmap)
120 {
121   if (!cmap)
122     return;
123 
124   if (cmap->name)
125     RELEASE(cmap->name);
126   if (cmap->CSI) {
127     if (cmap->CSI->registry) RELEASE(cmap->CSI->registry);
128     if (cmap->CSI->ordering) RELEASE(cmap->CSI->ordering);
129     RELEASE(cmap->CSI);
130   }
131   if (cmap->codespace.ranges)
132     RELEASE(cmap->codespace.ranges);
133   if (cmap->mapTbl)
134     mapDef_release(cmap->mapTbl);
135   {
136     mapData *map = cmap->mapData;
137     while (map != NULL) {
138       mapData *prev = map->prev;
139       if (map->data != NULL)
140 	RELEASE(map->data);
141       RELEASE(map);
142       map = prev;
143     }
144   }
145 
146   if (cmap->reverseMap)
147     RELEASE(cmap->reverseMap);
148 
149   RELEASE(cmap);
150 }
151 
152 int
CMap_is_Identity(CMap * cmap)153 CMap_is_Identity (CMap *cmap)
154 {
155   ASSERT(cmap);
156   if (!strcmp(cmap->name, "Identity-H") || !strcmp(cmap->name, "Identity-V"))
157     return 1;
158   else
159     return 0;
160 }
161 
162 #if 0
163 /* NOT IMPLEMENTED YET */
164 int
165 CMap_is_realy_Identity(CMap *cmap)
166 {
167   return 0;
168 }
169 #endif
170 
171 int
CMap_is_valid(CMap * cmap)172 CMap_is_valid (CMap *cmap)
173 {
174   /* Quick check */
175   if (!cmap || !(cmap->name) || cmap->type < CMAP_TYPE_IDENTITY ||
176       cmap->type > CMAP_TYPE_CID_TO_CODE || cmap->codespace.num < 1 ||
177       (cmap->type != CMAP_TYPE_IDENTITY && !cmap->mapTbl))
178     return 0;
179 
180   if (cmap->useCMap) {
181     CIDSysInfo *csi1, *csi2;
182     csi1 = CMap_get_CIDSysInfo(cmap);
183     csi2 = CMap_get_CIDSysInfo(cmap->useCMap);
184     if (strcmp(csi1->registry, csi2->registry) ||
185 	strcmp(csi1->ordering, csi2->ordering)) {
186       WARN("CIDSystemInfo mismatched %s <--> %s",
187 	   CMap_get_name(cmap), CMap_get_name(cmap->useCMap));
188       return 0;
189     }
190   }
191 
192   return 1;
193 }
194 
195 int
CMap_get_profile(CMap * cmap,int type)196 CMap_get_profile (CMap *cmap, int type)
197 {
198   int value = 0;
199 
200   ASSERT(cmap);
201   switch (type) {
202   case CMAP_PROF_TYPE_INBYTES_MIN:
203     value = cmap->profile.minBytesIn;
204     break;
205   case CMAP_PROF_TYPE_INBYTES_MAX:
206     value = cmap->profile.maxBytesIn;
207     break;
208   case CMAP_PROF_TYPE_OUTBYTES_MIN:
209     value = cmap->profile.maxBytesOut;
210     break;
211   case CMAP_PROF_TYPE_OUTBYTES_MAX:
212     value = cmap->profile.maxBytesOut;
213     break;
214   default:
215     ERROR("%s: Unrecognized profile type %d.", CMAP_DEBUG_STR, type);
216   }
217 
218   return value;
219 }
220 
221 /*
222  * Put notdef chars for codes not declared in notdef(range|char)
223  */
224 static void
handle_undefined(CMap * cmap,const unsigned char ** inbuf,long * inbytesleft,unsigned char ** outbuf,long * outbytesleft)225 handle_undefined (CMap *cmap,
226 		  const unsigned char **inbuf,  long *inbytesleft,
227 		  unsigned char **outbuf, long *outbytesleft)
228 {
229   long len = 0;
230 
231   if (*outbytesleft < 2)
232     ERROR("%s: Buffer overflow.", CMAP_DEBUG_STR);
233 
234   switch (cmap->type) {
235   case CMAP_TYPE_CODE_TO_CID:
236     memcpy(*outbuf, CID_NOTDEF_CHAR, 2);
237     break;
238   case CMAP_TYPE_TO_UNICODE:
239     memcpy(*outbuf, UCS_NOTDEF_CHAR, 2);
240     break;
241   default:
242     WARN("Cannot handle undefined mapping for this type of CMap mapping: %d", cmap->type);
243     WARN("<0000> is used for .notdef char.");
244     memset(*outbuf, 0, 2);
245   }
246   *outbuf += 2;
247   *outbytesleft -= 2;
248 
249   len = bytes_consumed(cmap, *inbuf, *inbytesleft);
250 
251   *inbuf  += len;
252   *inbytesleft  -= len;
253 }
254 
255 void
CMap_decode_char(CMap * cmap,const unsigned char ** inbuf,long * inbytesleft,unsigned char ** outbuf,long * outbytesleft)256 CMap_decode_char (CMap *cmap,
257 		  const unsigned char **inbuf, long *inbytesleft,
258 		  unsigned char **outbuf, long *outbytesleft)
259 {
260   mapDef *t;
261   const unsigned char *p, *save;
262   unsigned char c = 0;
263   long    count = 0;
264 
265   p = save = *inbuf;
266   /*
267    * First handle some special cases:
268    */
269   if (cmap->type == CMAP_TYPE_IDENTITY) {
270     if ((*inbytesleft) % 2)
271       ERROR("%s: Invalid/truncated input string.", CMAP_DEBUG_STR);
272     if (*outbytesleft < 2)
273       ERROR("%s: Buffer overflow.", CMAP_DEBUG_STR);
274     memcpy(*outbuf, *inbuf, 2);
275     *inbuf  += 2;
276     *outbuf += 2;
277     *outbytesleft -= 2;
278     *inbytesleft  -= 2;
279     return;
280   } else if (!cmap->mapTbl) {
281     if (cmap->useCMap) {
282       CMap_decode_char(cmap->useCMap, inbuf, inbytesleft, outbuf, outbytesleft);
283       return;
284     } else {
285       /* no mapping available in this CMap */
286       WARN("No mapping available for this character.");
287       handle_undefined(cmap, inbuf, inbytesleft, outbuf, outbytesleft);
288       return;
289     }
290   }
291 
292   ASSERT(cmap->mapTbl);
293   t = cmap->mapTbl;
294   while (count < *inbytesleft) {
295     c = *p++;
296     count++;
297     if (LOOKUP_END(t[c].flag))
298       break;
299     t = t[c].next;
300   }
301   if (LOOKUP_CONTINUE(t[c].flag)) /* need more bytes */
302     ERROR("%s: Premature end of input string.", CMAP_DEBUG_STR);
303   else if (!MAP_DEFINED(t[c].flag)) {
304     if (cmap->useCMap) {
305       CMap_decode_char(cmap->useCMap, inbuf, inbytesleft, outbuf, outbytesleft);
306       return;
307     } else {
308       /* no mapping available in this CMap */
309       WARN("No character mapping available.");
310       MESG(" CMap name: %s\n", CMap_get_name(cmap));
311       MESG(" input str: ");
312       MESG("<");
313       while (save < p) {
314         MESG("%02x", *save);
315         save++;
316       }
317       MESG(">\n");
318       /*
319        * We know partial match found up to `count' bytes,
320        * but we will not use this information for the sake of simplicity.
321        */
322       handle_undefined(cmap, inbuf, inbytesleft, outbuf, outbytesleft);
323       return;
324     }
325   } else {
326     switch (MAP_TYPE(t[c].flag)) {
327     case MAP_IS_NOTDEF:
328       WARN("Character mapped to .notdef found.");
329       /* continue */
330     case MAP_IS_CID: case MAP_IS_CODE:
331       if (*outbytesleft >= t[c].len)
332 	memcpy(*outbuf, t[c].code, t[c].len);
333       else
334 	ERROR("%s: Buffer overflow.", CMAP_DEBUG_STR);
335       *outbuf       += t[c].len;
336       *outbytesleft -= t[c].len;
337       break;
338     case MAP_IS_NAME:
339       ERROR("%s: CharName mapping not supported.", CMAP_DEBUG_STR);
340       break;
341     default:
342       ERROR("%s: Unknown mapping type.", CMAP_DEBUG_STR);
343     }
344     if (inbytesleft)
345       *inbytesleft -= count;
346     *inbuf = p;
347   }
348 }
349 
350 /*
351  * For convenience, it does not do decoding to CIDs.
352  */
353 long
CMap_decode(CMap * cmap,const unsigned char ** inbuf,long * inbytesleft,unsigned char ** outbuf,long * outbytesleft)354 CMap_decode (CMap *cmap,
355 	     const unsigned char **inbuf,  long *inbytesleft,
356 	     unsigned char **outbuf, long *outbytesleft)
357 {
358   int count;
359 
360   ASSERT(cmap && inbuf && outbuf);
361   ASSERT(inbytesleft && outbytesleft);
362   for (count = 0;*inbytesleft > 0 && *outbytesleft > 0; count++)
363     CMap_decode_char(cmap, inbuf, inbytesleft, outbuf, outbytesleft);
364 
365   return count;
366 }
367 
368 int
CMap_reverse_decode(CMap * cmap,CID cid)369 CMap_reverse_decode(CMap *cmap, CID cid) {
370   int ch = cmap->reverseMap ? cmap->reverseMap[cid] : -1;
371   if (ch == 0 && cmap->useCMap)
372     return CMap_reverse_decode(cmap->useCMap, cid);
373   return ch;
374 }
375 
376 char *
CMap_get_name(CMap * cmap)377 CMap_get_name (CMap *cmap)
378 {
379   ASSERT(cmap);
380   return cmap->name;
381 }
382 
383 int
CMap_get_type(CMap * cmap)384 CMap_get_type (CMap *cmap)
385 {
386   ASSERT(cmap);
387   return cmap->type;
388 }
389 
390 int
CMap_get_wmode(CMap * cmap)391 CMap_get_wmode (CMap *cmap)
392 {
393   ASSERT(cmap);
394   return cmap->wmode;
395 }
396 
397 CIDSysInfo *
CMap_get_CIDSysInfo(CMap * cmap)398 CMap_get_CIDSysInfo (CMap *cmap)
399 {
400   ASSERT(cmap);
401   return cmap->CSI;
402 }
403 
404 void
CMap_set_name(CMap * cmap,const char * name)405 CMap_set_name (CMap *cmap, const char *name)
406 {
407   ASSERT(cmap);
408   if (cmap->name)
409     RELEASE(cmap->name);
410   cmap->name = NEW(strlen(name)+1, char);
411   strcpy(cmap->name, name);
412 }
413 
414 void
CMap_set_type(CMap * cmap,int type)415 CMap_set_type (CMap *cmap, int type)
416 {
417   ASSERT(cmap);
418   cmap->type = type;
419 }
420 
421 void
CMap_set_wmode(CMap * cmap,int wmode)422 CMap_set_wmode (CMap *cmap, int wmode)
423 {
424   ASSERT(cmap);
425   cmap->wmode = wmode;
426 }
427 
428 void
CMap_set_CIDSysInfo(CMap * cmap,const CIDSysInfo * csi)429 CMap_set_CIDSysInfo (CMap *cmap, const CIDSysInfo *csi)
430 {
431   ASSERT(cmap);
432 
433   if (cmap->CSI) {
434     if (cmap->CSI->registry)
435       RELEASE(cmap->CSI->registry);
436     if (cmap->CSI->ordering)
437       RELEASE(cmap->CSI->ordering);
438     RELEASE(cmap->CSI);
439   }
440 
441   if (csi && csi->registry && csi->ordering) {
442     cmap->CSI = NEW(1, CIDSysInfo);
443     cmap->CSI->registry = NEW(strlen(csi->registry)+1, char);
444     strcpy(cmap->CSI->registry, csi->registry);
445     cmap->CSI->ordering = NEW(strlen(csi->ordering)+1, char);
446     strcpy(cmap->CSI->ordering, csi->ordering);
447     cmap->CSI->supplement = csi->supplement;
448   } else {
449     WARN("Invalid CIDSystemInfo.");
450     cmap->CSI = NULL;
451   }
452 }
453 
454 /*
455  * Can have muliple entry ?
456  */
457 void
CMap_set_usecmap(CMap * cmap,CMap * ucmap)458 CMap_set_usecmap (CMap *cmap, CMap *ucmap)
459 {
460   int i;
461 
462   ASSERT(cmap);
463   ASSERT(ucmap); /* Maybe if (!ucmap) ERROR() is better for this. */
464 
465   if (cmap == ucmap)
466     ERROR("%s: Identical CMap object cannot be used for usecmap CMap: 0x%p=0x%p",
467 	  CMAP_DEBUG_STR, cmap, ucmap);
468 
469   /* Check if ucmap have neccesary information. */
470   if (!CMap_is_valid(ucmap))
471     ERROR("%s: Invalid CMap.", CMAP_DEBUG_STR);
472 
473   /*
474    *  CMapName of cmap can be undefined when usecmap is executed in CMap parsing.
475    *  And it is also possible CSI is not defined at that time.
476    */
477   if (cmap->name && strcmp(cmap->name, ucmap->name) == 0)
478     ERROR("%s: CMap refering itself not allowed: CMap %s --> %s",
479 	  CMAP_DEBUG_STR, cmap->name, ucmap->name);
480 
481   if (cmap->CSI && cmap->CSI->registry && cmap->CSI->ordering) {
482     if (strcmp(cmap->CSI->registry, ucmap->CSI->registry) ||
483 	strcmp(cmap->CSI->ordering, ucmap->CSI->ordering))
484       ERROR("%s: CMap %s required by %s have different CSI.",
485 	    CMAP_DEBUG_STR, CMap_get_name(cmap), CMap_get_name(ucmap));
486   }
487 
488   /* We must copy codespaceranges. */
489   for (i = 0; i < ucmap->codespace.num; i++) {
490     rangeDef *csr = ucmap->codespace.ranges + i;
491     CMap_add_codespacerange(cmap, csr->codeLo, csr->codeHi, csr->dim);
492   }
493 
494   cmap->useCMap = ucmap;
495 }
496 
497 /* Test the validity of character c. */
498 int
CMap_match_codespace(CMap * cmap,const unsigned char * c,int dim)499 CMap_match_codespace (CMap *cmap, const unsigned char *c, int dim)
500 {
501   int i, pos;
502 
503   ASSERT(cmap);
504   for (i = 0; i < cmap->codespace.num; i++) {
505     rangeDef *csr = cmap->codespace.ranges + i;
506     if (csr->dim != dim)
507       continue;
508     for (pos = 0; pos < dim; pos++) {
509       if (c[pos] > csr->codeHi[pos] || c[pos] < csr->codeLo[pos])
510 	break;
511     }
512     if (pos == dim)
513       return 0; /* Valid */
514   }
515 
516   return -1; /* Invalid */
517 }
518 
519 /*
520  * No overlapping codespace ranges are allowed, otherwise mapping is ambiguous.
521  */
522 int
CMap_add_codespacerange(CMap * cmap,const unsigned char * codelo,const unsigned char * codehi,int dim)523 CMap_add_codespacerange (CMap *cmap,
524 			 const unsigned char *codelo, const unsigned char *codehi, int dim)
525 {
526   rangeDef *csr = NULL;
527   int       i;
528 
529   ASSERT(cmap && dim > 0);
530 
531   for (i = 0; i < cmap->codespace.num; i++) {
532     int j, overlap = 1;
533     csr = cmap->codespace.ranges + i;
534     for (j = 0; j < MIN(csr->dim, dim) && overlap; j++) {
535       if ((codelo[j] >= csr->codeLo[j] && codelo[j] <= csr->codeHi[j]) ||
536 	  (codehi[j] >= csr->codeLo[j] && codehi[j] <= csr->codeHi[j]))
537 	overlap = 1;
538       else
539 	overlap = 0;
540     }
541     if (overlap) {
542       WARN("Overlapping codespace found. (ingored)");
543       return -1;
544     }
545   }
546 
547   if (dim < cmap->profile.minBytesIn)
548     cmap->profile.minBytesIn = dim;
549   if (dim > cmap->profile.maxBytesIn)
550     cmap->profile.maxBytesIn = dim;
551 
552   if (cmap->codespace.num + 1 > cmap->codespace.max) {
553     cmap->codespace.max += 10;
554     cmap->codespace.ranges = RENEW(cmap->codespace.ranges, cmap->codespace.max, struct rangeDef);
555   }
556 
557   csr = cmap->codespace.ranges + cmap->codespace.num;
558   csr->dim    = dim;
559   csr->codeHi = get_mem(cmap, dim);
560   csr->codeLo = get_mem(cmap, dim);
561   memcpy(csr->codeHi, codehi, dim);
562   memcpy(csr->codeLo, codelo, dim);
563 
564   (cmap->codespace.num)++;
565 
566   return 0;
567 }
568 
569 int
CMap_add_notdefchar(CMap * cmap,const unsigned char * src,int srcdim,CID dst)570 CMap_add_notdefchar (CMap *cmap, const unsigned char *src, int srcdim, CID dst)
571 {
572   return CMap_add_notdefrange(cmap, src, src, srcdim, dst);
573 }
574 
575 int
CMap_add_notdefrange(CMap * cmap,const unsigned char * srclo,const unsigned char * srchi,int srcdim,CID dst)576 CMap_add_notdefrange (CMap *cmap,
577 		      const unsigned char *srclo, const unsigned char *srchi, int srcdim, CID dst)
578 {
579   int     c;
580   mapDef *cur;
581 
582   ASSERT(cmap);
583   /* dst not used here */
584   /* FIXME */
585   if (check_range(cmap, srclo, srchi, srcdim, (const unsigned char *)&dst, 2) < 0)
586     return -1;
587 
588   if (cmap->mapTbl == NULL )
589     cmap->mapTbl = mapDef_new();
590 
591   cur = cmap->mapTbl;
592   if (locate_tbl(&cur, srclo, srcdim) < 0)
593     return -1;
594 
595   for (c = srclo[srcdim-1]; c <= srchi[srcdim-1]; c++) {
596     if (MAP_DEFINED(cur[c].flag)) {
597       if (!__silent)
598 	WARN("Trying to redefine already defined code mapping. (ignored)");
599     } else {
600       cur[c].flag = (MAP_LOOKUP_END|MAP_IS_NOTDEF);
601       cur[c].code = get_mem(cmap, 2);
602       cur[c].len  = 2;
603       cur[c].code[0] = dst >> 8;
604       cur[c].code[1] = dst & 0xff;
605     }
606     /* Do not do dst++ for notdefrange  */
607   }
608 
609   return 0;
610 }
611 
612 int
CMap_add_bfchar(CMap * cmap,const unsigned char * src,int srcdim,const unsigned char * dst,int dstdim)613 CMap_add_bfchar (CMap *cmap,
614 		 const unsigned char *src, int srcdim,
615 		 const unsigned char *dst, int dstdim)
616 {
617   return CMap_add_bfrange(cmap, src, src, srcdim, dst, dstdim);
618 }
619 
620 int
CMap_add_bfrange(CMap * cmap,const unsigned char * srclo,const unsigned char * srchi,int srcdim,const unsigned char * base,int dstdim)621 CMap_add_bfrange (CMap *cmap,
622 		  const unsigned char *srclo, const unsigned char *srchi, int srcdim,
623 		  const unsigned char *base, int dstdim)
624 {
625   int     c, last_byte, i;
626   mapDef *cur;
627 
628   ASSERT(cmap);
629   if (check_range(cmap, srclo, srchi, srcdim, base, dstdim) < 0)
630     return -1;
631 
632   if (cmap->mapTbl == NULL)
633     cmap->mapTbl = mapDef_new();
634 
635   cur = cmap->mapTbl;
636   if (locate_tbl(&cur, srclo, srcdim) < 0)
637     return -1;
638 
639   for (c = srclo[srcdim-1]; c <= srchi[srcdim-1]; c++) {
640     /* According to 5014.CIDFont_Spec.pdf (p.52),
641      * Code mappings (unlike codespace ranges) may overlap,
642      * but succeeding maps superceded preceding maps.
643      * (reported and patched by Luo Jie on 2007/12/2)
644      */
645     if (!MAP_DEFINED(cur[c].flag) || cur[c].len < dstdim) {
646       cur[c].flag = (MAP_LOOKUP_END|MAP_IS_CODE);
647       cur[c].code = get_mem(cmap, dstdim);
648     }
649     /*
650      * We assume restriction to code ranges also applied here.
651      * Addition <00FF> + 1 is undefined.
652      *
653      * Changed on 2004-03-20:
654      *
655      *  Should be treated as <0100> in Acrobat's "ToUnicode" CMap.
656      */
657     cur[c].len = dstdim;
658     memcpy(cur[c].code, base, dstdim);
659 
660     last_byte = c - srclo[srcdim-1] + base[dstdim-1];
661     cur[c].code[dstdim-1] = (last_byte & 0xFF);
662     for (i = dstdim - 2; i >= 0 && last_byte > 255; i--) {
663       last_byte = cur[c].code[i] + 1;
664       cur[c].code[i] = (last_byte & 0xFF);
665     }
666   }
667 
668   return 0;
669 }
670 
671 int
CMap_add_cidchar(CMap * cmap,const unsigned char * src,int srcdim,CID dst)672 CMap_add_cidchar (CMap *cmap, const unsigned char *src, int srcdim, CID dst)
673 {
674   return CMap_add_cidrange(cmap, src, src, srcdim, dst);
675 }
676 
677 int
CMap_add_cidrange(CMap * cmap,const unsigned char * srclo,const unsigned char * srchi,int srcdim,CID base)678 CMap_add_cidrange (CMap *cmap,
679 		   const unsigned char *srclo, const unsigned char *srchi, int srcdim, CID base)
680 {
681   int    i, c, v;
682   mapDef *cur;
683 
684   ASSERT(cmap);
685   /* base not used here */
686   if (check_range(cmap, srclo, srchi, srcdim, (const unsigned char *)&base, 2) < 0) /* FIXME */
687     return -1;
688 
689   if (cmap->mapTbl == NULL )
690     cmap->mapTbl = mapDef_new();
691 
692   cur = cmap->mapTbl;
693   if (locate_tbl(&cur, srclo, srcdim) < 0)
694     return -1;
695 
696   for (v = 0, i = 0; i < srcdim - 1; i++)
697     v = (v << 8) + srclo[i];
698 
699   cmap->reverseMap[base] = v;
700 
701   for (c = srclo[srcdim-1]; c <= srchi[srcdim-1]; c++) {
702     if (cur[c].flag != 0) {
703       if (!__silent)
704 	WARN("Trying to redefine already defined CID mapping. (ignored)");
705     } else {
706       cur[c].flag = (MAP_LOOKUP_END|MAP_IS_CID);
707       cur[c].len  = 2;
708       cur[c].code = get_mem(cmap, 2);
709       cur[c].code[0] = base >> 8;
710       cur[c].code[1] = base & 0xff;
711 
712       cmap->reverseMap[base] = (v << 8) + c;
713     }
714     if (base >= CID_MAX)
715       WARN("CID number too large.");
716     base++;
717   }
718 
719   return 0;
720 }
721 
722 static void
mapDef_release(mapDef * t)723 mapDef_release (mapDef *t)
724 {
725   int c;
726 
727   ASSERT(t);
728   for (c = 0; c < 256; c++) {
729     if (LOOKUP_CONTINUE(t[c].flag))
730       mapDef_release(t[c].next);
731   }
732   RELEASE(t);
733 }
734 
735 static mapDef *
mapDef_new(void)736 mapDef_new (void)
737 {
738   mapDef *t;
739   int     c;
740 
741   t = NEW(256, mapDef);
742   for (c=0; c<256; c++) {
743     t[c].flag = (MAP_LOOKUP_END|MAP_IS_UNDEF);
744     t[c].code = NULL;
745     t[c].next = NULL;
746   }
747 
748   return t;
749 }
750 
751 static unsigned char *
get_mem(CMap * cmap,int size)752 get_mem (CMap *cmap, int size)
753 {
754   mapData *map;
755   unsigned char  *p;
756 
757   ASSERT(cmap && cmap->mapData && size >= 0);
758   map = cmap->mapData;
759   if (map->pos + size >= MEM_ALLOC_SIZE) {
760     mapData *prev = map;
761     map = NEW(1, struct mapData);
762     map->data = NEW(MEM_ALLOC_SIZE, unsigned char);
763     map->prev = prev;
764     map->pos  = 0;
765     cmap->mapData = map;
766   }
767   p = map->data + map->pos;
768   map->pos += size;
769 
770   return p;
771 }
772 
773 static int
locate_tbl(mapDef ** cur,const unsigned char * code,int dim)774 locate_tbl (mapDef **cur, const unsigned char *code, int dim)
775 {
776   int i, c;
777 
778   ASSERT(cur && *cur);
779   for (i = 0; i < dim-1; i++) {
780     c = code[i];
781     if (MAP_DEFINED((*cur)[c].flag)) {
782       WARN("Ambiguous CMap entry.");
783       return -1;
784     }
785     if ((*cur)[c].next == NULL)  /* create new node */
786       (*cur)[c].next = mapDef_new();
787     (*cur)[c].flag  |= MAP_LOOKUP_CONTINUE;
788     *cur = (*cur)[c].next;
789   }
790 
791   return 0;
792 }
793 
794 /*
795  * Guess how many bytes consumed as a `single' character:
796  * Substring of length bytesconsumed bytes of input string is interpreted as
797  * a `single' character by CMap_decode().
798  */
799 static int
bytes_consumed(CMap * cmap,const unsigned char * instr,long inbytes)800 bytes_consumed (CMap *cmap, const unsigned char *instr, long inbytes)
801 {
802   int i, pos, longest = 0, bytesconsumed;
803 
804   ASSERT(cmap);
805   for (i = 0; i < cmap->codespace.num; i++) {
806     rangeDef *csr = cmap->codespace.ranges + i;
807     for (pos = 0; pos < MIN(csr->dim, inbytes); pos++) {
808       if (instr[pos] > csr->codeHi[pos] || instr[pos] < csr->codeLo[pos])
809 	break;
810     }
811     if (pos == csr->dim) /* part of instr is totally valid in this codespace. */
812       return csr->dim;
813     if (pos > longest)
814       longest = pos;
815   }
816 
817   if (i == cmap->codespace.num) /* No matching at all */
818     bytesconsumed = cmap->profile.minBytesIn;
819   else {
820     bytesconsumed = cmap->profile.maxBytesIn;
821     for (i = 0; i< cmap->codespace.num; i++) {
822       rangeDef *csr = cmap->codespace.ranges + i;
823       if (csr->dim > longest && csr->dim < bytesconsumed)
824 	bytesconsumed = csr->dim;
825     }
826   }
827 
828   return bytesconsumed;
829 }
830 
831 static int
check_range(CMap * cmap,const unsigned char * srclo,const unsigned char * srchi,int srcdim,const unsigned char * dst,int dstdim)832 check_range (CMap *cmap,
833 	     const unsigned char *srclo, const unsigned char *srchi, int srcdim,
834 	     const unsigned char *dst, int dstdim)
835 {
836   if ((srcdim < 1 || dstdim < 1) ||
837       (!srclo || !srchi || !dst) ||
838       memcmp(srclo, srchi, srcdim - 1) ||
839       srclo[srcdim-1] > srchi[srcdim-1]) {
840     WARN("Invalid CMap mapping entry. (ignored)");
841     return -1;
842   }
843 
844   if (CMap_match_codespace(cmap, srclo, srcdim) < 0 ||
845       CMap_match_codespace(cmap, srchi, srcdim) < 0) {
846     WARN("Invalid CMap mapping entry. (ignored)");
847     return -1;
848   }
849 
850   if (srcdim < cmap->profile.minBytesIn)
851     cmap->profile.minBytesIn  = srcdim;
852   if (srcdim > cmap->profile.maxBytesIn)
853     cmap->profile.maxBytesIn  = srcdim;
854   if (dstdim < cmap->profile.minBytesOut)
855     cmap->profile.minBytesOut = dstdim;
856   if (dstdim > cmap->profile.maxBytesOut)
857     cmap->profile.maxBytesOut = dstdim;
858 
859   return 0;
860 }
861 
862 /************************** CMAP_CACHE **************************/
863 #include "cmap_read.h"
864 
865 #define CMAP_CACHE_ALLOC_SIZE 16u
866 
867 struct CMap_cache {
868   int    num;
869   int    max;
870   CMap **cmaps;
871 };
872 
873 static struct CMap_cache *__cache = NULL;
874 
875 #define CHECK_ID(n) do {\
876                         if (! __cache)\
877                            ERROR("%s: CMap cache not initialized.", CMAP_DEBUG_STR);\
878                         if ((n) < 0 || (n) >= __cache->num)\
879                            ERROR("Invalid CMap ID %d", (n));\
880                     } while (0)
881 
882 #include "dpxfile.h"
883 
884 void
CMap_cache_init(void)885 CMap_cache_init (void)
886 {
887   static unsigned char range_min[2] = {0x00, 0x00};
888   static unsigned char range_max[2] = {0xff, 0xff};
889 
890   if (__cache)
891     ERROR("%s: Already initialized.", CMAP_DEBUG_STR);
892 
893   __cache = NEW(1, struct CMap_cache);
894 
895   __cache->max   = CMAP_CACHE_ALLOC_SIZE;
896   __cache->cmaps = NEW(__cache->max, CMap *);
897   __cache->num   = 0;
898 
899   /* Create Identity mapping */
900   __cache->cmaps[0] = CMap_new();
901   CMap_set_name (__cache->cmaps[0], "Identity-H");
902   CMap_set_type (__cache->cmaps[0], CMAP_TYPE_IDENTITY);
903   CMap_set_wmode(__cache->cmaps[0], 0);
904   CMap_set_CIDSysInfo(__cache->cmaps[0], &CSI_IDENTITY);
905   CMap_add_codespacerange(__cache->cmaps[0], range_min, range_max, 2);
906 
907   __cache->cmaps[1] = CMap_new();
908   CMap_set_name (__cache->cmaps[1], "Identity-V");
909   CMap_set_type (__cache->cmaps[1], CMAP_TYPE_IDENTITY);
910   CMap_set_wmode(__cache->cmaps[1], 1);
911   CMap_set_CIDSysInfo(__cache->cmaps[1], &CSI_IDENTITY);
912   CMap_add_codespacerange(__cache->cmaps[1], range_min, range_max, 2);
913 
914   __cache->num += 2;
915 }
916 
917 CMap *
CMap_cache_get(int id)918 CMap_cache_get (int id)
919 {
920   CHECK_ID(id);
921   return __cache->cmaps[id];
922 }
923 
924 int
CMap_cache_find(const char * cmap_name)925 CMap_cache_find (const char *cmap_name)
926 {
927   int   id = 0;
928   FILE *fp = NULL;
929 
930   if (!__cache)
931     CMap_cache_init();
932   ASSERT(__cache);
933 
934   for (id = 0; id < __cache->num; id++) {
935     char *name = NULL;
936     /* CMapName may be undefined when processing usecmap. */
937     name = CMap_get_name(__cache->cmaps[id]);
938     if (name && strcmp(cmap_name, name) == 0) {
939       return id;
940     }
941   }
942 
943   fp = DPXFOPEN(cmap_name, DPX_RES_TYPE_CMAP);
944   if (!fp)
945     return -1;
946 
947   if (CMap_parse_check_sig(fp) < 0) {
948     DPXFCLOSE(fp);
949     return -1;
950   }
951 
952   if (__verbose)
953     MESG("(CMap:%s", cmap_name);
954 
955   if (__cache->num >= __cache->max) {
956     __cache->max   += CMAP_CACHE_ALLOC_SIZE;
957     __cache->cmaps = RENEW(__cache->cmaps, __cache->max, CMap *);
958   }
959   id = __cache->num;
960   (__cache->num)++;
961   __cache->cmaps[id] = CMap_new();
962 
963   if (CMap_parse(__cache->cmaps[id], fp) < 0)
964     ERROR("%s: Parsing CMap file failed.", CMAP_DEBUG_STR);
965 
966   DPXFCLOSE(fp);
967 
968   if (__verbose)
969     MESG(")");
970 
971   return id;
972 }
973 
974 int
CMap_cache_add(CMap * cmap)975 CMap_cache_add (CMap *cmap)
976 {
977   int   id;
978   char *cmap_name0, *cmap_name1;
979 
980   if (!CMap_is_valid(cmap))
981     ERROR("%s: Invalid CMap.", CMAP_DEBUG_STR);
982 
983   for (id = 0; id < __cache->num; id++) {
984     cmap_name0 = CMap_get_name(cmap);
985     cmap_name1 = CMap_get_name(__cache->cmaps[id]);
986     if (!strcmp(cmap_name0, cmap_name1)) {
987       ERROR("%s: CMap \"%s\" already defined.",
988 	    CMAP_DEBUG_STR, cmap_name0);
989       return -1;
990     }
991   }
992 
993   if (__cache->num >= __cache->max) {
994     __cache->max   += CMAP_CACHE_ALLOC_SIZE;
995     __cache->cmaps = RENEW(__cache->cmaps, __cache->max, CMap *);
996   }
997   id = __cache->num;
998   (__cache->num)++;
999   __cache->cmaps[id] = cmap;
1000 
1001   return id;
1002 }
1003 
1004 void
CMap_cache_close(void)1005 CMap_cache_close (void)
1006 {
1007   if (__cache) {
1008     int id;
1009     for (id = 0; id < __cache->num; id++) {
1010       CMap_release(__cache->cmaps[id]);
1011     }
1012     RELEASE(__cache->cmaps);
1013     RELEASE(__cache);
1014     __cache = NULL;
1015   }
1016 }
1017