OSDN Git Service

updated with TeX Live 2014.
[putex/putex.git] / src / dvipdfmx-pu / src / cmap_write.c
1 /*  
2
3     This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
4
5     Copyright (C) 2002-2012 by Jin-Hwan Cho and Shunsaku Hirata,
6     the dvipdfmx project team.
7
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 */
22
23 /*
24  * References:
25  *
26  *  PostScript Language Reference Manual, 3rd. ed. (Adobe Systems Inc.)
27  *    5.11.4 CMap Dictionaries
28  *    5.11.5 FMapType 9 Composite Fonts
29  *  Building CMap Files for CID-Keyed Fonts, Adobe Technical Note #5099
30  *  CID-Keyed Font Technology Overview, Adobe Technical Note #5092
31  *  Adobe CMap and CIDFont Files Specification, Adobe Technical Specification #5014
32  *
33  *  Undefined Character Handling:
34  *    PLRM 3rd. ed., sec. 5.11.5., "Handling Undefined Characters"
35  *
36  */
37
38 #if 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 "pdfobj.h"
50 #include "pdfresource.h"
51
52 #include "cmap_p.h"
53 #include "cmap.h"
54
55 #include "cmap_write.h"
56
57 struct sbuf {
58   char *buf;
59   char *curptr;
60   char *limptr;
61 };
62
63 static int write_map (mapDef *mtab, int count,
64                       unsigned char *codestr, int depth,
65                       struct sbuf *wbuf, pdf_obj *stream);
66 #if 0
67 /* Not completed yet */
68
69 /* used_slot...
70  * This is for collecting only used CIDs.
71  * add_inverse_map never supports code-to-code of
72  * cid-to-code mapping.
73  */
74 static int add_inverse_map (CMap *icmap, mapDef *mtab,
75                             unsigned char *codestr, int depth,
76                             unsigned char *used_slot);
77 static int add_map         (CMap *cmap,  mapDef *mtab,
78                             unsigned char *codestr, int depth);
79 static CMap *invert_cmap  (CMap *cmap, unsigned char *used_slot);
80 static CMap *flatten_cmap (CMap *cmap);
81 #endif /* 0 */
82
83 static int
84 block_count (mapDef *mtab, int c)
85 {
86   int count = 0, n;
87
88   n  = mtab[c].len - 1;
89   c += 1;
90   for (; c < 256; c++) {
91     if (LOOKUP_CONTINUE(mtab[c].flag) ||
92         !MAP_DEFINED(mtab[c].flag)     ||
93         (MAP_TYPE(mtab[c].flag) != MAP_IS_CID &&
94          MAP_TYPE(mtab[c].flag) != MAP_IS_CODE) ||
95         mtab[c-1].len != mtab[c].len)
96       break;
97     else if (!memcmp(mtab[c-1].code, mtab[c].code, n) &&
98              mtab[c-1].code[n] < 255 &&
99              mtab[c-1].code[n] + 1 == mtab[c].code[n])
100       count++;
101     else {
102       break;
103     }
104   }
105
106   return count;
107 }
108
109 static int
110 write_map (mapDef *mtab, int count,
111            unsigned char *codestr, int depth,
112            struct sbuf *wbuf, pdf_obj *stream)
113 {
114   int     c, i, block_length;
115   mapDef *mtab1;
116   /* Must be greater than 1 */
117 #define BLOCK_LEN_MIN 2
118   struct {
119     int start, count;
120   } blocks[256/BLOCK_LEN_MIN+1];
121   int num_blocks = 0;
122
123   for (c = 0; c < 256; c++) {
124     codestr[depth] = (unsigned char) (c & 0xff);
125     if (LOOKUP_CONTINUE(mtab[c].flag)) {
126       mtab1 = mtab[c].next;
127       count = write_map(mtab1, count,
128                         codestr, depth + 1, wbuf, stream);
129     } else {
130       if (MAP_DEFINED(mtab[c].flag)) {
131         switch (MAP_TYPE(mtab[c].flag)) {
132         case MAP_IS_CID: case MAP_IS_CODE:
133           block_length = block_count(mtab, c);
134           if (block_length >= BLOCK_LEN_MIN) {
135             blocks[num_blocks].start = c;
136             blocks[num_blocks].count = block_length;
137             num_blocks++;
138             c += block_length;
139           } else {
140             *(wbuf->curptr)++ = '<';
141             for (i = 0; i <= depth; i++)
142               sputx(codestr[i], &(wbuf->curptr), wbuf->limptr);
143             *(wbuf->curptr)++ = '>';
144             *(wbuf->curptr)++ = ' ';
145             *(wbuf->curptr)++ = '<';
146             for (i = 0; i < mtab[c].len; i++)
147               sputx(mtab[c].code[i], &(wbuf->curptr), wbuf->limptr);
148             *(wbuf->curptr)++ = '>';
149             *(wbuf->curptr)++ = '\n';
150             count++;
151           }
152           break;
153         case MAP_IS_NAME:
154           ERROR("%s: Unexpected error...", CMAP_DEBUG_STR);
155           break;
156         case MAP_IS_NOTDEF:
157           break;
158         default:
159           ERROR("%s: Unknown mapping type: %d",
160                 CMAP_DEBUG_STR, MAP_TYPE(mtab[c].flag));
161         }
162       }
163     }
164
165     /* Flush if necessary */
166     if (count >= 100 ||
167         wbuf->curptr >= wbuf->limptr ) {
168       char fmt_buf[32];
169       if (count > 100)
170         ERROR("Unexpected error....: %d", count);
171       sprintf(fmt_buf, "%d beginbfchar\n", count);
172       pdf_add_stream(stream, fmt_buf,  strlen(fmt_buf));
173       pdf_add_stream(stream,
174                      wbuf->buf, (long) (wbuf->curptr - wbuf->buf));
175       wbuf->curptr = wbuf->buf;
176       pdf_add_stream(stream,
177                      "endbfchar\n", strlen("endbfchar\n"));
178       count = 0;
179     }
180   }
181
182   if (num_blocks > 0) {
183     char fmt_buf[32];
184
185     if (count > 0) {
186       sprintf(fmt_buf, "%d beginbfchar\n", count);
187       pdf_add_stream(stream, fmt_buf,  strlen(fmt_buf));
188       pdf_add_stream(stream,
189                      wbuf->buf, (long) (wbuf->curptr - wbuf->buf));
190       wbuf->curptr = wbuf->buf;
191       pdf_add_stream(stream,
192                      "endbfchar\n", strlen("endbfchar\n"));
193       count = 0;
194     }
195     sprintf(fmt_buf, "%d beginbfrange\n", num_blocks);
196     pdf_add_stream(stream, fmt_buf, strlen(fmt_buf));
197     for (i = 0; i < num_blocks; i++) {
198       int j;
199
200       c = blocks[i].start;
201       *(wbuf->curptr)++ = '<';
202       for (j = 0; j < depth; j++)
203         sputx(codestr[j], &(wbuf->curptr), wbuf->limptr);
204       sputx((unsigned char)c, &(wbuf->curptr), wbuf->limptr);
205       *(wbuf->curptr)++ = '>';
206       *(wbuf->curptr)++ = ' ';
207       *(wbuf->curptr)++ = '<';
208       for (j = 0; j < depth; j++)
209         sputx(codestr[j], &(wbuf->curptr), wbuf->limptr);
210       sputx((unsigned char)(c + blocks[i].count), &(wbuf->curptr), wbuf->limptr);
211       *(wbuf->curptr)++ = '>';
212       *(wbuf->curptr)++ = ' ';
213       *(wbuf->curptr)++ = '<';
214       for (j = 0; j < mtab[c].len; j++)
215         sputx(mtab[c].code[j], &(wbuf->curptr), wbuf->limptr);
216       *(wbuf->curptr)++ = '>';
217       *(wbuf->curptr)++ = '\n';
218     }
219     pdf_add_stream(stream,
220                    wbuf->buf, (long) (wbuf->curptr - wbuf->buf));
221     wbuf->curptr = wbuf->buf;
222     pdf_add_stream(stream,
223                    "endbfrange\n", strlen("endbfrange\n"));
224   }
225
226   return count;
227 }
228
229 #define CMAP_BEGIN "\
230 /CIDInit /ProcSet findresource begin\n\
231 12 dict begin\n\
232 begincmap\n\
233 "
234
235 #define CMAP_END "\
236 endcmap\n\
237 CMapName currentdict /CMap defineresource pop\n\
238 end\n\
239 end\n\
240 "
241
242 pdf_obj *
243 CMap_create_stream (CMap *cmap, int flags) /* flags unused */
244 {
245   pdf_obj         *stream;
246   pdf_obj         *stream_dict;
247   CIDSysInfo      *csi;
248   struct sbuf      wbuf;
249   struct rangeDef *ranges;
250   unsigned char   *codestr;
251   int              i, j, count = 0;
252
253   if (!cmap || !CMap_is_valid(cmap)) {
254     WARN("Invalid CMap");
255     return NULL;
256   }
257
258   if (cmap->type == CMAP_TYPE_IDENTITY)
259     return NULL;
260
261   stream      = pdf_new_stream(STREAM_COMPRESS);
262   stream_dict = pdf_stream_dict(stream);
263
264   csi = CMap_get_CIDSysInfo(cmap);
265   if (!csi) {
266     csi = (cmap->type != CMAP_TYPE_TO_UNICODE) ?
267       &CSI_IDENTITY : &CSI_UNICODE;
268   }
269
270   if (cmap->type != CMAP_TYPE_TO_UNICODE) {
271     pdf_obj *csi_dict;
272
273     csi_dict = pdf_new_dict();
274     pdf_add_dict(csi_dict,
275                  pdf_new_name("Registry"),
276                  pdf_new_string(csi->registry, strlen(csi->registry)));
277     pdf_add_dict(csi_dict,
278                  pdf_new_name("Ordering"),
279                  pdf_new_string(csi->ordering, strlen(csi->ordering)));
280     pdf_add_dict(csi_dict,
281                  pdf_new_name("Supplement"),
282                  pdf_new_number(csi->supplement));
283
284     pdf_add_dict(stream_dict,
285                  pdf_new_name("Type"),
286                  pdf_new_name("CMap"));
287     pdf_add_dict(stream_dict,
288                  pdf_new_name("CMapName"),
289                  pdf_new_name(cmap->name));
290     pdf_add_dict(stream_dict,
291                  pdf_new_name("CIDSystemInfo"), csi_dict);
292     if (cmap->wmode != 0)
293       pdf_add_dict(stream_dict,
294                    pdf_new_name("WMode"),
295                    pdf_new_number(cmap->wmode));
296   }
297
298   /* TODO:
299    * Predefined CMaps need not to be embedded.
300    */
301   if (cmap->useCMap) {
302     ERROR("UseCMap found (not supported yet)...");
303     if (CMap_is_Identity(cmap->useCMap)) { /* not sure */
304       if (CMap_get_wmode(cmap) == 1) {
305         pdf_add_dict(stream_dict,
306                      pdf_new_name("UseCMap"),
307                      pdf_new_name("Identity-V"));
308       } else {
309         pdf_add_dict(stream_dict,
310                      pdf_new_name("UseCMap"),
311                      pdf_new_name("Identity-H"));
312       }
313     } else {
314       long     res_id;
315       pdf_obj *ucmap_ref;
316
317       res_id = pdf_findresource("CMap", CMap_get_name(cmap->useCMap));
318       if (res_id >= 0) {
319         ucmap_ref = pdf_get_resource_reference(res_id);
320       } else {
321         pdf_obj *ucmap_obj;
322
323         ucmap_obj = CMap_create_stream(cmap->useCMap, 0);
324         if (!ucmap_obj) {
325           ERROR("Uh ah. I cannot continue...");
326         }
327
328         res_id = pdf_defineresource("CMap",
329                                     CMap_get_name(cmap->useCMap),
330                                     ucmap_obj, PDF_RES_FLUSH_IMMEDIATE);
331         ucmap_ref = pdf_get_resource_reference(res_id);
332       }
333       pdf_add_dict(stream_dict, pdf_new_name("UseCMap"), ucmap_ref);
334     }
335   }
336
337 #define WBUF_SIZE 4096
338   wbuf.buf = NEW(WBUF_SIZE, char);
339   codestr  = NEW(cmap->profile.maxBytesIn, unsigned char);
340   memset(codestr, 0, cmap->profile.maxBytesIn);
341
342   wbuf.curptr = wbuf.buf;
343   wbuf.limptr = wbuf.buf + WBUF_SIZE -
344     2 * (cmap->profile.maxBytesIn + cmap->profile.maxBytesOut) + 16;
345
346   /* Start CMap */
347   pdf_add_stream(stream, (const void *) CMAP_BEGIN, strlen(CMAP_BEGIN));
348
349   wbuf.curptr += sprintf(wbuf.curptr, "/CMapName /%s def\n", cmap->name);
350   wbuf.curptr += sprintf(wbuf.curptr, "/CMapType %d def\n" , cmap->type);
351   if (cmap->wmode != 0 &&
352       cmap->type != CMAP_TYPE_TO_UNICODE)
353     wbuf.curptr += sprintf(wbuf.curptr, "/WMode %d def\n", cmap->wmode);
354
355 #define CMAP_CSI_FMT "/CIDSystemInfo <<\n\
356   /Registry (%s)\n\
357   /Ordering (%s)\n\
358   /Supplement %d\n\
359 >> def\n"
360   wbuf.curptr += sprintf(wbuf.curptr, CMAP_CSI_FMT,
361                          csi->registry, csi->ordering, csi->supplement);
362   pdf_add_stream(stream, wbuf.buf, (long)(wbuf.curptr - wbuf.buf));
363   wbuf.curptr = wbuf.buf;
364
365   /* codespacerange */
366   ranges = cmap->codespace.ranges;
367   wbuf.curptr += sprintf(wbuf.curptr,
368                          "%d begincodespacerange\n", cmap->codespace.num);
369   for (i = 0; i < cmap->codespace.num; i++) {
370     *(wbuf.curptr)++ = '<';
371     for (j = 0; j < ranges[i].dim; j++) {
372       sputx(ranges[i].codeLo[j], &(wbuf.curptr), wbuf.limptr);
373     }
374     *(wbuf.curptr)++ = '>';
375     *(wbuf.curptr)++ = ' ';
376     *(wbuf.curptr)++ = '<';
377     for (j = 0; j < ranges[i].dim; j++) {
378       sputx(ranges[i].codeHi[j], &(wbuf.curptr), wbuf.limptr);
379     }
380     *(wbuf.curptr)++ = '>';
381     *(wbuf.curptr)++ = '\n';
382   }
383   pdf_add_stream(stream, wbuf.buf, (long)(wbuf.curptr - wbuf.buf));
384   wbuf.curptr = wbuf.buf;
385   pdf_add_stream(stream,
386                  "endcodespacerange\n", strlen("endcodespacerange\n"));
387
388   /* CMap body */
389   if (cmap->mapTbl) {
390     count = write_map(cmap->mapTbl,
391                       0, codestr, 0, &wbuf, stream); /* Top node */
392     if (count > 0) { /* Flush */
393       char fmt_buf[32];
394       if (count > 100)
395         ERROR("Unexpected error....: %d", count);
396       sprintf(fmt_buf, "%d beginbfchar\n", count);
397       pdf_add_stream(stream, fmt_buf,  strlen(fmt_buf));
398       pdf_add_stream(stream,
399                      wbuf.buf, (long) (wbuf.curptr - wbuf.buf));
400       pdf_add_stream(stream,
401                      "endbfchar\n", strlen("endbfchar\n"));
402       count = 0;
403       wbuf.curptr = wbuf.buf;
404     }
405   }
406   /* End CMap */
407   pdf_add_stream(stream, CMAP_END, strlen(CMAP_END));
408
409   RELEASE(codestr);
410   RELEASE(wbuf.buf);
411
412   return stream;
413 }
414
415 #if 0
416 /* Not completed yet */
417
418 static int
419 add_inverse_map (CMap *icmap, mapDef *mtab,
420                  unsigned char *codestr, int depth,
421                  unsigned char *used_slot)
422 {
423   CID     cid;
424   int     c;
425   mapDef *mtab1;
426
427   for (c = 0; c < 256; c++) {
428     codestr[depth] = (unsigned char) (c & 0xff);
429     if (LOOKUP_CONTINUE(mtab[c].flag)) {
430       mtab1 = mtab[c].next;
431       add_inverse_map(icmap, mtab1, codestr, depth + 1, used_slot);
432     } else {
433       if (MAP_DEFINED(mtab[c].flag)) {
434         switch (MAP_TYPE(mtab[c].flag)) {
435           /* We should restrict it to to-CID mapping.
436            * However...
437            */
438         case MAP_IS_CID: case MAP_IS_CODE:
439           if (mtab[c].len == 2) {
440             cid = (mtab[c].code[0] << 8)|mtab[c].code[1];
441 #ifndef is_used_char2
442 #define is_used_char2(b,c) (((b)[(c)/8]) & (1 << (7-((c)%8))))
443 #endif
444             if (!used_slot ||
445                 is_used_char2(used_slot, cid)) {
446               CMap_add_bfchar(icmap,
447                               mtab[c].code, mtab[c].len,
448                               codestr, depth + 1);
449             }
450           }
451           break;
452         case MAP_IS_NAME:
453           ERROR("%s: Unexpected error...", CMAP_DEBUG_STR);
454           break;
455         case MAP_IS_NOTDEF:
456           break;
457         default:
458           ERROR("%s: Unknown mapping type: %d",
459                 CMAP_DEBUG_STR, MAP_TYPE(mtab[c].flag));
460         }
461       }
462     }
463   }
464
465   return 0;
466 }
467
468 static int
469 add_map (CMap *cmap, mapDef *mtab,
470          unsigned char *codestr, int depth)
471 {
472   int     c;
473   mapDef *mtab1;
474
475   for (c = 0; c < 256; c++) {
476     codestr[depth] = (unsigned char) (c & 0xff);
477     if (LOOKUP_CONTINUE(mtab[c].flag)) {
478       mtab1 = mtab[c].next;
479       add_map(cmap, mtab1, codestr, depth + 1);
480     } else {
481       if (MAP_DEFINED(mtab[c].flag)) {
482         switch (MAP_TYPE(mtab[c].flag)) {
483         case MAP_IS_CID: case MAP_IS_CODE:
484           CMap_add_bfchar(cmap,
485                           codestr, depth + 1,
486                           mtab[c].code, mtab[c].len);
487           break;
488         case MAP_IS_NAME:
489           ERROR("%s: Unexpected error...", CMAP_DEBUG_STR);
490           break;
491         case MAP_IS_NOTDEF:
492           break;
493         default:
494           ERROR("%s: Unknown mapping type: %d",
495                 CMAP_DEBUG_STR, MAP_TYPE(mtab[c].flag));
496         }
497       }
498     }
499   }
500
501   return 0;
502 }
503
504
505 static CMap *
506 invert_cmap (CMap *cmap, unsigned char *used_slot)
507 {
508   CMap *icmap;
509   unsigned char *codestr;
510   unsigned char  range_min[2] = {0x00, 0x00}; /* CID */
511   unsigned char  range_max[2] = {0xff, 0xfe}; /* CID */
512
513   cmap = flatten_cmap(cmap);
514   ASSERT(cmap);
515
516   icmap = CMap_new();
517   CMap_set_type(icmap, CMAP_TYPE_CID_TO_CODE);
518   CMap_add_codespacerange(icmap, range_min, range_max, 2);
519
520   if (cmap->mapTbl) {
521     codestr = NEW(cmap->profile.maxBytesIn, unsigned char);
522     memset(codestr, 0, cmap->profile.maxBytesIn);
523     add_inverse_map(icmap, cmap->mapTbl,
524                     codestr, 0, used_slot); /* top node */
525     RELEASE(codestr);
526   }
527
528   CMap_release(cmap);
529
530   return icmap;
531 }
532
533 static CMap *
534 flatten_cmap (CMap *cmap)
535 {
536   CMap     *fcmap;
537   rangeDef *range;
538   int       i;
539
540   ASSERT(cmap);
541
542   fcmap = CMap_new();
543
544   for (i = 0; i < cmap->codespace.num; i++) {
545     range = &(cmap->codespace.ranges[i]);
546     CMap_add_codespacerange(fcmap, range->codeLo, range->codeHi, range->dim);
547   }
548   CMap_set_CIDSysInfo(fcmap, cmap->CSI);
549   CMap_set_type (fcmap, cmap->type );
550   CMap_set_wmode(fcmap, cmap->wmode);
551
552   fcmap->flags   = cmap->flags;
553   fcmap->version = cmap->version;
554
555   while (cmap) {
556     if (cmap->mapTbl) {
557       unsigned char *codestr;
558
559       codestr = NEW(cmap->profile.maxBytesIn, unsigned char);
560       memset(codestr, 0, cmap->profile.maxBytesIn);
561       add_map(fcmap, cmap->mapTbl, codestr, 0); /* top node */
562       RELEASE(codestr);
563     }
564     cmap = cmap->useCMap;
565   }
566
567   return fcmap;
568 }
569
570 pdf_obj *
571 CMap_ToCode_stream (CMap *cmap, const char *cmap_name,
572                     CIDSysInfo *csi, int cmap_type,
573                     unsigned char *used_slot, int flags)
574 {
575   pdf_obj *stream = NULL;
576   CMap    *icmap;
577
578   ASSERT(cmap && cmap_name);
579
580   if (cmap->type !=
581       CMAP_TYPE_CODE_TO_CID)
582     return NULL;
583
584   icmap = invert_cmap(cmap, used_slot);
585   if (icmap) {
586     CMap_set_name(icmap, cmap_name);
587     if (csi)
588       CMap_set_CIDSysInfo(icmap, csi);
589     else {
590       CMap_set_CIDSysInfo(icmap, &(CSI_IDENTITY));
591     }
592     CMap_set_type(icmap, cmap_type);
593
594     stream = CMap_create_stream(icmap, flags);
595
596     CMap_release(icmap);
597   }
598
599   return stream;
600 }
601 #endif /* 0 */