Back to index

texmacs  1.0.7.15
cmap_write.c
Go to the documentation of this file.
00001 /*  $Header: /home/cvsroot/dvipdfmx/src/cmap_write.c,v 1.6 2004/09/05 13:30:05 hirata Exp $
00002 
00003     This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
00004 
00005     Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
00006     the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00021 */
00022 
00023 /*
00024  * References:
00025  *
00026  *  PostScript Language Reference Manual, 3rd. ed. (Adobe Systems Inc.)
00027  *    5.11.4 CMap Dictionaries
00028  *    5.11.5 FMapType 9 Composite Fonts
00029  *  Building CMap Files for CID-Keyed Fonts, Adobe Technical Note #5099
00030  *  CID-Keyed Font Technology Overview, Adobe Technical Note #5092
00031  *  Adobe CMap and CIDFont Files Specification, Adobe Technical Specification #5014
00032  *
00033  *  Undefined Character Handling:
00034  *    PLRM 3rd. ed., sec. 5.11.5., "Handling Undefined Characters"
00035  *
00036  */
00037 
00038 #if HAVE_CONFIG_H
00039 #include "config.h"
00040 #endif
00041 
00042 #include <string.h>
00043 
00044 #include "system.h"
00045 #include "mem.h"
00046 #include "error.h"
00047 #include "dpxutil.h"
00048 
00049 #include "pdfobj.h"
00050 #include "pdfresource.h"
00051 
00052 #include "cmap_p.h"
00053 #include "cmap.h"
00054 
00055 #include "cmap_write.h"
00056 
00057 struct sbuf {
00058   char *buf;
00059   char *curptr;
00060   char *limptr;
00061 };
00062 
00063 static int write_map (mapDef *mtab, int count,
00064                     unsigned char *codestr, int depth,
00065                     struct sbuf *wbuf, pdf_obj *stream);
00066 #if 0
00067 /* Not completed yet */
00068 
00069 /* used_slot...
00070  * This is for collecting only used CIDs.
00071  * add_inverse_map never supports code-to-code of
00072  * cid-to-code mapping.
00073  */
00074 static int add_inverse_map (CMap *icmap, mapDef *mtab,
00075                          unsigned char *codestr, int depth,
00076                          unsigned char *used_slot);
00077 static int add_map         (CMap *cmap,  mapDef *mtab,
00078                          unsigned char *codestr, int depth);
00079 static CMap *invert_cmap  (CMap *cmap, unsigned char *used_slot);
00080 static CMap *flatten_cmap (CMap *cmap);
00081 #endif /* 0 */
00082 
00083 static int
00084 block_count (mapDef *mtab, int c)
00085 {
00086   int count = 0, n;
00087 
00088   n  = mtab[c].len - 1;
00089   c += 1;
00090   for (; c < 256; c++) {
00091     if (LOOKUP_CONTINUE(mtab[c].flag) ||
00092        !MAP_DEFINED(mtab[c].flag)     ||
00093        (MAP_TYPE(mtab[c].flag) != MAP_IS_CID &&
00094         MAP_TYPE(mtab[c].flag) != MAP_IS_CODE) ||
00095        mtab[c-1].len != mtab[c].len)
00096       break;
00097     else if (!memcmp(mtab[c-1].code, mtab[c].code, n) &&
00098             mtab[c-1].code[n] < 255 &&
00099             mtab[c-1].code[n] + 1 == mtab[c].code[n])
00100       count++;
00101     else {
00102       break;
00103     }
00104   }
00105 
00106   return count;
00107 }
00108 
00109 static int
00110 write_map (mapDef *mtab, int count,
00111           unsigned char *codestr, int depth,
00112           struct sbuf *wbuf, pdf_obj *stream)
00113 {
00114   int     c, i, block_length;
00115   mapDef *mtab1;
00116   /* Must be greater than 1 */
00117 #define BLOCK_LEN_MIN 2
00118   struct {
00119     int start, count;
00120   } blocks[256/BLOCK_LEN_MIN+1];
00121   int num_blocks = 0;
00122 
00123   for (c = 0; c < 256; c++) {
00124     codestr[depth] = (unsigned char) (c & 0xff);
00125     if (LOOKUP_CONTINUE(mtab[c].flag)) {
00126       mtab1 = mtab[c].next;
00127       count = write_map(mtab1, count,
00128                      codestr, depth + 1, wbuf, stream);
00129     } else {
00130       if (MAP_DEFINED(mtab[c].flag)) {
00131        switch (MAP_TYPE(mtab[c].flag)) {
00132        case MAP_IS_CID: case MAP_IS_CODE:
00133          block_length = block_count(mtab, c);
00134          if (block_length >= BLOCK_LEN_MIN) {
00135            blocks[num_blocks].start = c;
00136            blocks[num_blocks].count = block_length;
00137            num_blocks++;
00138            c += block_length;
00139          } else {
00140            *(wbuf->curptr)++ = '<';
00141            for (i = 0; i <= depth; i++)
00142              sputx(codestr[i], &(wbuf->curptr), wbuf->limptr);
00143            *(wbuf->curptr)++ = '>';
00144            *(wbuf->curptr)++ = ' ';
00145            *(wbuf->curptr)++ = '<';
00146            for (i = 0; i < mtab[c].len; i++)
00147              sputx(mtab[c].code[i], &(wbuf->curptr), wbuf->limptr);
00148            *(wbuf->curptr)++ = '>';
00149            *(wbuf->curptr)++ = '\n';
00150            count++;
00151          }
00152          break;
00153        case MAP_IS_NAME:
00154          ERROR("%s: Unexpected error...", CMAP_DEBUG_STR);
00155          break;
00156        case MAP_IS_NOTDEF:
00157          break;
00158        default:
00159          ERROR("%s: Unknown mapping type: %d",
00160               CMAP_DEBUG_STR, MAP_TYPE(mtab[c].flag));
00161        }
00162       }
00163     }
00164 
00165     /* Flush if necessary */
00166     if (count >= 100 ||
00167        wbuf->curptr >= wbuf->limptr ) {
00168       char fmt_buf[32];
00169       if (count > 100)
00170        ERROR("Unexpected error....: %d", count);
00171       sprintf(fmt_buf, "%d beginbfchar\n", count);
00172       pdf_add_stream(stream, fmt_buf,  strlen(fmt_buf));
00173       pdf_add_stream(stream,
00174                    wbuf->buf, (long) (wbuf->curptr - wbuf->buf));
00175       wbuf->curptr = wbuf->buf;
00176       pdf_add_stream(stream,
00177                    "endbfchar\n", strlen("endbfchar\n"));
00178       count = 0;
00179     }
00180   }
00181 
00182   if (num_blocks > 0) {
00183     char fmt_buf[32];
00184 
00185     if (count > 0) {
00186       sprintf(fmt_buf, "%d beginbfchar\n", count);
00187       pdf_add_stream(stream, fmt_buf,  strlen(fmt_buf));
00188       pdf_add_stream(stream,
00189                    wbuf->buf, (long) (wbuf->curptr - wbuf->buf));
00190       wbuf->curptr = wbuf->buf;
00191       pdf_add_stream(stream,
00192                    "endbfchar\n", strlen("endbfchar\n"));
00193       count = 0;
00194     }
00195     sprintf(fmt_buf, "%d beginbfrange\n", num_blocks);
00196     pdf_add_stream(stream, fmt_buf, strlen(fmt_buf));
00197     for (i = 0; i < num_blocks; i++) {
00198       int j;
00199 
00200       c = blocks[i].start;
00201       *(wbuf->curptr)++ = '<';
00202       for (j = 0; j < depth; j++)
00203        sputx(codestr[j], &(wbuf->curptr), wbuf->limptr);
00204       sputx(c, &(wbuf->curptr), wbuf->limptr);
00205       *(wbuf->curptr)++ = '>';
00206       *(wbuf->curptr)++ = ' ';
00207       *(wbuf->curptr)++ = '<';
00208       for (j = 0; j < depth; j++)
00209        sputx(codestr[j], &(wbuf->curptr), wbuf->limptr);
00210       sputx(c + blocks[i].count, &(wbuf->curptr), wbuf->limptr);
00211       *(wbuf->curptr)++ = '>';
00212       *(wbuf->curptr)++ = ' ';
00213       *(wbuf->curptr)++ = '<';
00214       for (j = 0; j < mtab[c].len; j++)
00215        sputx(mtab[c].code[j], &(wbuf->curptr), wbuf->limptr);
00216       *(wbuf->curptr)++ = '>';
00217       *(wbuf->curptr)++ = '\n';
00218     }
00219     pdf_add_stream(stream,
00220                  wbuf->buf, (long) (wbuf->curptr - wbuf->buf));
00221     wbuf->curptr = wbuf->buf;
00222     pdf_add_stream(stream,
00223                  "endbfrange\n", strlen("endbfrange\n"));
00224   }
00225 
00226   return count;
00227 }
00228 
00229 #define CMAP_BEGIN "\
00230 /CIDInit /ProcSet findresource begin\n\
00231 12 dict begin\n\
00232 begincmap\n\
00233 "
00234 
00235 #define CMAP_END "\
00236 endcmap\n\
00237 CMapName currentdict /CMap defineresource pop\n\
00238 end\n\
00239 end\n\
00240 "
00241 
00242 pdf_obj *
00243 CMap_create_stream (CMap *cmap, int flags) /* flags unused */
00244 {
00245   pdf_obj         *stream;
00246   pdf_obj         *stream_dict;
00247   CIDSysInfo      *csi;
00248   struct sbuf      wbuf;
00249   struct rangeDef *ranges;
00250   unsigned char   *codestr;
00251   int              i, j, count = 0;
00252 
00253   if (!cmap || !CMap_is_valid(cmap)) {
00254     WARN("Invalid CMap");
00255     return NULL;
00256   }
00257 
00258   if (cmap->type == CMAP_TYPE_IDENTITY)
00259     return NULL;
00260 
00261   stream      = pdf_new_stream(STREAM_COMPRESS);
00262   stream_dict = pdf_stream_dict(stream);
00263 
00264   csi = CMap_get_CIDSysInfo(cmap);
00265   if (!csi) {
00266     csi = (cmap->type != CMAP_TYPE_TO_UNICODE) ?
00267       &CSI_IDENTITY : &CSI_UNICODE;
00268   }
00269 
00270   if (cmap->type != CMAP_TYPE_TO_UNICODE) {
00271     pdf_obj *csi_dict;
00272 
00273     csi_dict = pdf_new_dict();
00274     pdf_add_dict(csi_dict,
00275                pdf_new_name("Registry"),
00276                pdf_new_string(csi->registry, strlen(csi->registry)));
00277     pdf_add_dict(csi_dict,
00278                pdf_new_name("Ordering"),
00279                pdf_new_string(csi->ordering, strlen(csi->ordering)));
00280     pdf_add_dict(csi_dict,
00281                pdf_new_name("Supplement"),
00282                pdf_new_number(csi->supplement));
00283 
00284     pdf_add_dict(stream_dict,
00285                pdf_new_name("Type"),
00286                pdf_new_name("CMap"));
00287     pdf_add_dict(stream_dict,
00288                pdf_new_name("CMapName"),
00289                pdf_new_name(cmap->name));
00290     pdf_add_dict(stream_dict,
00291                pdf_new_name("CIDSystemInfo"), csi_dict);
00292     if (cmap->wmode != 0)
00293       pdf_add_dict(stream_dict,
00294                  pdf_new_name("WMode"),
00295                  pdf_new_number(cmap->wmode));
00296   }
00297 
00298   /* TODO:
00299    * Predefined CMaps need not to be embedded.
00300    */
00301   if (cmap->useCMap) {
00302     ERROR("UseCMap found (not supported yet)...");
00303     if (CMap_is_Identity(cmap->useCMap)) { /* not sure */
00304       if (CMap_get_wmode(cmap) == 1) {
00305        pdf_add_dict(stream_dict,
00306                    pdf_new_name("UseCMap"),
00307                    pdf_new_name("Identity-V"));
00308       } else {
00309        pdf_add_dict(stream_dict,
00310                    pdf_new_name("UseCMap"),
00311                    pdf_new_name("Identity-H"));
00312       }
00313     } else {
00314       long     res_id;
00315       pdf_obj *ucmap_ref;
00316 
00317       res_id = pdf_findresource("CMap", CMap_get_name(cmap->useCMap));
00318       if (res_id >= 0) {
00319        ucmap_ref = pdf_get_resource_reference(res_id);
00320       } else {
00321        pdf_obj *ucmap_obj;
00322 
00323        ucmap_obj = CMap_create_stream(cmap->useCMap, 0);
00324        if (!ucmap_obj) {
00325          ERROR("Uh ah. I cannot continue...");
00326        }
00327 
00328        res_id = pdf_defineresource("CMap",
00329                                 CMap_get_name(cmap->useCMap),
00330                                 ucmap_obj, PDF_RES_FLUSH_IMMEDIATE);
00331        ucmap_ref = pdf_get_resource_reference(res_id);
00332       }
00333       pdf_add_dict(stream_dict, pdf_new_name("UseCMap"), ucmap_ref);
00334     }
00335   }
00336 
00337 #define WBUF_SIZE 4096
00338   wbuf.buf = NEW(WBUF_SIZE, char);
00339   codestr  = NEW(cmap->profile.maxBytesIn, unsigned char);
00340   memset(codestr, 0, cmap->profile.maxBytesIn);
00341 
00342   wbuf.curptr = wbuf.buf;
00343   wbuf.limptr = wbuf.buf + WBUF_SIZE -
00344     2 * (cmap->profile.maxBytesIn + cmap->profile.maxBytesOut) + 16;
00345 
00346   /* Start CMap */
00347   pdf_add_stream(stream, (void *) CMAP_BEGIN, strlen(CMAP_BEGIN));
00348 
00349   wbuf.curptr += sprintf(wbuf.curptr, "/CMapName /%s def\n", cmap->name);
00350   wbuf.curptr += sprintf(wbuf.curptr, "/CMapType %d def\n" , cmap->type);
00351   if (cmap->wmode != 0 &&
00352       cmap->type != CMAP_TYPE_TO_UNICODE)
00353     wbuf.curptr += sprintf(wbuf.curptr, "/WMode %d def\n", cmap->wmode);
00354 
00355 #define CMAP_CSI_FMT "/CIDSystemInfo <<\n\
00356   /Registry (%s)\n\
00357   /Ordering (%s)\n\
00358   /Supplement %d\n\
00359 >> def\n"
00360   wbuf.curptr += sprintf(wbuf.curptr, CMAP_CSI_FMT,
00361                       csi->registry, csi->ordering, csi->supplement);
00362   pdf_add_stream(stream, wbuf.buf, (long)(wbuf.curptr - wbuf.buf));
00363   wbuf.curptr = wbuf.buf;
00364 
00365   /* codespacerange */
00366   ranges = cmap->codespace.ranges;
00367   wbuf.curptr += sprintf(wbuf.curptr,
00368                       "%d begincodespacerange\n", cmap->codespace.num);
00369   for (i = 0; i < cmap->codespace.num; i++) {
00370     *(wbuf.curptr)++ = '<';
00371     for (j = 0; j < ranges[i].dim; j++) {
00372       sputx(ranges[i].codeLo[j], &(wbuf.curptr), wbuf.limptr);
00373     }
00374     *(wbuf.curptr)++ = '>';
00375     *(wbuf.curptr)++ = ' ';
00376     *(wbuf.curptr)++ = '<';
00377     for (j = 0; j < ranges[i].dim; j++) {
00378       sputx(ranges[i].codeHi[j], &(wbuf.curptr), wbuf.limptr);
00379     }
00380     *(wbuf.curptr)++ = '>';
00381     *(wbuf.curptr)++ = '\n';
00382   }
00383   pdf_add_stream(stream, wbuf.buf, (long)(wbuf.curptr - wbuf.buf));
00384   wbuf.curptr = wbuf.buf;
00385   pdf_add_stream(stream,
00386                "endcodespacerange\n", strlen("endcodespacerange\n"));
00387 
00388   /* CMap body */
00389   if (cmap->mapTbl) {
00390     count = write_map(cmap->mapTbl,
00391                     0, codestr, 0, &wbuf, stream); /* Top node */
00392     if (count > 0) { /* Flush */
00393       char fmt_buf[32];
00394       if (count > 100)
00395        ERROR("Unexpected error....: %d", count);
00396       sprintf(fmt_buf, "%d beginbfchar\n", count);
00397       pdf_add_stream(stream, fmt_buf,  strlen(fmt_buf));
00398       pdf_add_stream(stream,
00399                    wbuf.buf, (long) (wbuf.curptr - wbuf.buf));
00400       pdf_add_stream(stream,
00401                    "endbfchar\n", strlen("endbfchar\n"));
00402       count = 0;
00403       wbuf.curptr = wbuf.buf;
00404     }
00405   }
00406   /* End CMap */
00407   pdf_add_stream(stream, CMAP_END, strlen(CMAP_END));
00408 
00409   RELEASE(codestr);
00410   RELEASE(wbuf.buf);
00411 
00412   return stream;
00413 }
00414 
00415 #if 0
00416 /* Not completed yet */
00417 
00418 static int
00419 add_inverse_map (CMap *icmap, mapDef *mtab,
00420                unsigned char *codestr, int depth,
00421                unsigned char *used_slot)
00422 {
00423   CID     cid;
00424   int     c;
00425   mapDef *mtab1;
00426 
00427   for (c = 0; c < 256; c++) {
00428     codestr[depth] = (unsigned char) (c & 0xff);
00429     if (LOOKUP_CONTINUE(mtab[c].flag)) {
00430       mtab1 = mtab[c].next;
00431       add_inverse_map(icmap, mtab1, codestr, depth + 1, used_slot);
00432     } else {
00433       if (MAP_DEFINED(mtab[c].flag)) {
00434        switch (MAP_TYPE(mtab[c].flag)) {
00435          /* We should restrict it to to-CID mapping.
00436           * However...
00437           */
00438        case MAP_IS_CID: case MAP_IS_CODE:
00439          if (mtab[c].len == 2) {
00440            cid = (mtab[c].code[0] << 8)|mtab[c].code[1];
00441 #ifndef is_used_char2
00442 #define is_used_char2(b,c) (((b)[(c)/8]) & (1 << (7-((c)%8))))
00443 #endif
00444            if (!used_slot ||
00445               is_used_char2(used_slot, cid)) {
00446              CMap_add_bfchar(icmap,
00447                            mtab[c].code, mtab[c].len,
00448                            codestr, depth + 1);
00449            }
00450          }
00451          break;
00452        case MAP_IS_NAME:
00453          ERROR("%s: Unexpected error...", CMAP_DEBUG_STR);
00454          break;
00455        case MAP_IS_NOTDEF:
00456          break;
00457        default:
00458          ERROR("%s: Unknown mapping type: %d",
00459               CMAP_DEBUG_STR, MAP_TYPE(mtab[c].flag));
00460        }
00461       }
00462     }
00463   }
00464 
00465   return 0;
00466 }
00467 
00468 static int
00469 add_map (CMap *cmap, mapDef *mtab,
00470         unsigned char *codestr, int depth)
00471 {
00472   int     c;
00473   mapDef *mtab1;
00474 
00475   for (c = 0; c < 256; c++) {
00476     codestr[depth] = (unsigned char) (c & 0xff);
00477     if (LOOKUP_CONTINUE(mtab[c].flag)) {
00478       mtab1 = mtab[c].next;
00479       add_map(cmap, mtab1, codestr, depth + 1);
00480     } else {
00481       if (MAP_DEFINED(mtab[c].flag)) {
00482        switch (MAP_TYPE(mtab[c].flag)) {
00483        case MAP_IS_CID: case MAP_IS_CODE:
00484          CMap_add_bfchar(cmap,
00485                        codestr, depth + 1,
00486                        mtab[c].code, mtab[c].len);
00487          break;
00488        case MAP_IS_NAME:
00489          ERROR("%s: Unexpected error...", CMAP_DEBUG_STR);
00490          break;
00491        case MAP_IS_NOTDEF:
00492          break;
00493        default:
00494          ERROR("%s: Unknown mapping type: %d",
00495               CMAP_DEBUG_STR, MAP_TYPE(mtab[c].flag));
00496        }
00497       }
00498     }
00499   }
00500 
00501   return 0;
00502 }
00503 
00504 
00505 static CMap *
00506 invert_cmap (CMap *cmap, unsigned char *used_slot)
00507 {
00508   CMap *icmap;
00509   unsigned char *codestr;
00510   unsigned char  range_min[2] = {0x00, 0x00}; /* CID */
00511   unsigned char  range_max[2] = {0xff, 0xfe}; /* CID */
00512 
00513   cmap = flatten_cmap(cmap);
00514   ASSERT(cmap);
00515 
00516   icmap = CMap_new();
00517   CMap_set_type(icmap, CMAP_TYPE_CID_TO_CODE);
00518   CMap_add_codespacerange(icmap, range_min, range_max, 2);
00519 
00520   if (cmap->mapTbl) {
00521     codestr = NEW(cmap->profile.maxBytesIn, unsigned char);
00522     memset(codestr, 0, cmap->profile.maxBytesIn);
00523     add_inverse_map(icmap, cmap->mapTbl,
00524                   codestr, 0, used_slot); /* top node */
00525     RELEASE(codestr);
00526   }
00527 
00528   CMap_release(cmap);
00529 
00530   return icmap;
00531 }
00532 
00533 static CMap *
00534 flatten_cmap (CMap *cmap)
00535 {
00536   CMap     *fcmap;
00537   rangeDef *range;
00538   int       i;
00539 
00540   ASSERT(cmap);
00541 
00542   fcmap = CMap_new();
00543 
00544   for (i = 0; i < cmap->codespace.num; i++) {
00545     range = &(cmap->codespace.ranges[i]);
00546     CMap_add_codespacerange(fcmap, range->codeLo, range->codeHi, range->dim);
00547   }
00548   CMap_set_CIDSysInfo(fcmap, cmap->CSI);
00549   CMap_set_type (fcmap, cmap->type );
00550   CMap_set_wmode(fcmap, cmap->wmode);
00551 
00552   fcmap->flags   = cmap->flags;
00553   fcmap->version = cmap->version;
00554 
00555   while (cmap) {
00556     if (cmap->mapTbl) {
00557       unsigned char *codestr;
00558 
00559       codestr = NEW(cmap->profile.maxBytesIn, unsigned char);
00560       memset(codestr, 0, cmap->profile.maxBytesIn);
00561       add_map(fcmap, cmap->mapTbl, codestr, 0); /* top node */
00562       RELEASE(codestr);
00563     }
00564     cmap = cmap->useCMap;
00565   }
00566 
00567   return fcmap;
00568 }
00569 
00570 pdf_obj *
00571 CMap_ToCode_stream (CMap *cmap, const char *cmap_name,
00572                   CIDSysInfo *csi, int cmap_type,
00573                   unsigned char *used_slot, int flags)
00574 {
00575   pdf_obj *stream = NULL;
00576   CMap    *icmap;
00577 
00578   ASSERT(cmap && cmap_name);
00579 
00580   if (cmap->type !=
00581       CMAP_TYPE_CODE_TO_CID)
00582     return NULL;
00583 
00584   icmap = invert_cmap(cmap, used_slot);
00585   if (icmap) {
00586     CMap_set_name(icmap, cmap_name);
00587     if (csi)
00588       CMap_set_CIDSysInfo(icmap, csi);
00589     else {
00590       CMap_set_CIDSysInfo(icmap, &(CSI_IDENTITY));
00591     }
00592     CMap_set_type(icmap, cmap_type);
00593 
00594     stream = CMap_create_stream(icmap, flags);
00595 
00596     CMap_release(icmap);
00597   }
00598 
00599   return stream;
00600 }
00601 #endif /* 0 */