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