Back to index

texmacs  1.0.7.15
subfont.c
Go to the documentation of this file.
00001 /*  $Header: /home/cvsroot/dvipdfmx/src/subfont.c,v 1.22 2008/01/13 21:25:31 matthias 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 #include <errno.h>
00024 
00025 #if HAVE_CONFIG_H
00026 #include "config.h"
00027 #endif
00028 
00029 #include "system.h"
00030 #include "mem.h"
00031 #include "error.h"
00032 #include "dpxfile.h"
00033 
00034 #include "subfont.h"
00035 
00036 static int verbose = 0;
00037 void
00038 subfont_set_verbose (void)
00039 {
00040   verbose++;
00041 }
00042 
00043 /* Don't forget fontmap reading now requires information
00044  * from SFD files. You must initialize at least sfd_file_
00045  * cache before starting loading of fontmaps.
00046  */
00047 
00048 /* Subfont Definition File:
00049  *  struct sfd_file_ is for storing subfont identifiers
00050  *  contained in a SFD file and for mapping string pair
00051  *  <SFD_file, Subfont_id> to internal code mapping table
00052  *  ID which is index within an array of struct sfd_rec_.
00053  *  We store code mapping tables in different place than
00054  *  struct sfd_file_.
00055  */
00056 struct sfd_file_
00057 {
00058   char  *ident;  /* SFD file name */
00059   char **sub_id; /* Subfont IDs   */
00060 
00061   int   *rec_id; /* indices within struct sfd_rec_ array "sfd_record" */
00062 
00063   int    max_subfonts;
00064   int    num_subfonts;
00065 };
00066 
00067 /* Mapping table */
00068 struct sfd_rec_
00069 {
00070   /* unsigned char  misbit[32]; */
00071   unsigned short vector[256]; /* 0 for undefined */
00072 };
00073 
00074 static void
00075 init_sfd_file_ (struct sfd_file_ *sfd)
00076 {
00077   sfd->ident  = NULL;
00078   sfd->sub_id = NULL;
00079   sfd->rec_id = NULL;
00080   sfd->max_subfonts = sfd->num_subfonts = 0;
00081 }
00082 
00083 static void
00084 clean_sfd_file_ (struct sfd_file_ *sfd)
00085 {
00086   int  i;
00087   if (sfd->ident)
00088     RELEASE(sfd->ident);
00089   if (sfd->sub_id) {
00090     for (i = 0; i < sfd->num_subfonts; i++) {
00091       if (sfd->sub_id[i])
00092         RELEASE(sfd->sub_id[i]);
00093     }
00094     RELEASE(sfd->sub_id);
00095   }
00096   if (sfd->rec_id)
00097     RELEASE(sfd->rec_id);
00098   init_sfd_file_(sfd);
00099 }
00100 
00101 static struct sfd_file_ *sfd_files = NULL;
00102 static int num_sfd_files = 0, max_sfd_files = 0;
00103 
00104 static struct sfd_rec_ *sfd_record = NULL;
00105 static int num_sfd_records = 0, max_sfd_records = 0;
00106 
00107 
00108 
00109 /* Another buffer...
00110  * We want buffer size at least 7 x 256 + a
00111  * 4096 is usually enough.
00112  */
00113 #define LINE_BUF_SIZE 4096
00114 static char line_buf[LINE_BUF_SIZE];
00115 
00116 /* Each lines describes character code mapping for each
00117  * subfonts. '#' is start of comment.
00118  * SFD file format uses a '\' before newline sequence
00119  * for line-continuation.
00120  */
00121 static char *
00122 readline (char *buf, int buf_len, FILE *fp)
00123 {
00124   char  *r, *q, *p = buf;
00125   int    n = 0, c = 0;
00126 
00127   while (buf_len - n > 0 && (q = mfgets(p, buf_len - n, fp))) {
00128     c++;
00129     r = strchr(q, '#');
00130     /* Comment is converted to single wsp (followed by a newline). */
00131     if (r) {
00132       *r = ' ';
00133       *(r + 1) = '\0';
00134     }
00135     if (strlen(q) == 0)
00136       break; /* empty line */
00137     n += strlen(q);
00138     q += strlen(q) - 1;
00139     if (*q != '\\')
00140       break;
00141     else { /* line continued */
00142       n -= 1;
00143       p  = buf + n;
00144     }
00145   }
00146   if (n >= buf_len - 1) {
00147     WARN("Possible buffer overflow in reading SFD file (buffer full, size=%d bytes)",
00148          buf_len - 1);
00149   }
00150 
00151   return  (c > 0 ? buf : NULL);
00152 }
00153 
00154 #define clear_vector(v) if ((v)) { \
00155   int __i; \
00156   for (__i = 0; __i < 256; __i++) \
00157     (v)[__i] = 0; \
00158 }
00159 
00160 /* subfont_id ( integer ':' | integer '_' integer | integer )*
00161  *
00162  *  0x32: ==> Subsequent integers are place into slots starting at 0x32.
00163  *    0x32: 0xA1A1 0xA1A2 ... ==> 0x32 is mappned to 0xA1A1, 0x33 to 0xA1A2
00164  *  0xA1A1_0xA1A5 ==> Expanded to 0xA1A1 0xA1A2 ... 0xA1A5
00165  */
00166 
00167 /* subfont_id is already consumed here. */
00168 static int
00169 read_sfd_record (struct sfd_rec_ *rec, const char *lbuf)
00170 {
00171   char  *p = (char *) lbuf, *q;
00172   int    repos  = 0;
00173   long   c,  v1 = 0, v2 = 0;
00174   int    curpos = 0;
00175   int    error  = 0;
00176 
00177 #define IS_TOKSEP(c) ((c) == '\0' || isspace((c)))
00178   for ( ; *p && isspace(*p); p++);
00179   while (!error && *p) {
00180     repos = 0; q = p;
00181     v1    = strtol(p, &q, 0);
00182     if (q == p ||
00183         (!IS_TOKSEP(*q) && *q != ':' && *q != '_')) {
00184       WARN("Unknown token in subfont mapping table: %c", *q);
00185       return  -1;
00186     }
00187 
00188     switch (*q) {
00189     case  ':':
00190       if (v1 < 0 || v1 > 0xff) {
00191         WARN("Invalud value for subfont table offset: %ld", v1);
00192         return  -1;
00193       }
00194       repos = 1;
00195       q++;
00196       break;
00197     case  '_':
00198       p  = q + 1;
00199       v2 = strtol(p, &q, 0);
00200       if (v1 < 0 || v1 > 0xffffL ||
00201           v2 < 0 || v2 > 0xffffL) {
00202         WARN("Invalid value in subfont mapping table: 0x%x_0x%x", v1, v2);
00203         return -1;
00204       } else if (q == p || !IS_TOKSEP(*q)) {
00205         WARN("Invalid char in subfont mapping table: %c", *q);
00206         return  -1;
00207       }
00208       break;
00209     default:
00210       if (v1 < 0 || v1 > 0xffffL) {
00211         WARN("Invalid character code in subfont mapping table: 0x%x", v1);
00212         return -1;
00213       }
00214       v2 = v1;
00215       break;
00216     }
00217 
00218     if (repos)
00219       curpos = v1;
00220     else {
00221       if (v2 < v1 || curpos + (v2 - v1) > 0xff) {
00222         WARN("Invalid range in subfont mapping: curpos=\"0x%02x\" range=\"0x%04x,0x%04x\"",
00223              curpos, v1, v2);
00224         return  -1;
00225       }
00226       for (c = v1; c <= v2; c++) {
00227         if (rec->vector[curpos] != 0) {
00228           WARN("Subfont mapping for slot=\"0x%02x\" already defined...", curpos);
00229           return  -1;
00230         }
00231         ASSERT( curpos >= 0 && curpos <= 255 );
00232         rec->vector[curpos++] = (unsigned short) c;
00233       }
00234     }
00235     for (p = q; *p && isspace(*p); p++);
00236   }
00237 
00238   return  error;
00239 }
00240 
00241 /* Scan for subfont IDs */
00242 static int
00243 scan_sfd_file (struct sfd_file_ *sfd, FILE *fp)
00244 {
00245   char  *id;
00246   char  *q, *p;
00247   int    n, lpos = 0;
00248 
00249   ASSERT( sfd && fp );
00250 
00251   if (verbose > 3) {
00252     MESG("\nsubfont>> Scanning SFD file \"%s\"...\n", sfd->ident);
00253   }
00254 
00255   rewind(fp);
00256   sfd->max_subfonts = sfd->num_subfonts = 0;
00257   while ((p = readline(line_buf, LINE_BUF_SIZE, fp)) != NULL) {
00258     lpos++;
00259     for ( ; *p && isspace(*p); p++);
00260     if (*p == 0)
00261       continue; /* empty */
00262 
00263     /* Saw non-wsp here */
00264     for (n = 0, q = p; *p && !isspace(*p); p++, n++);
00265     id = NEW(n + 1, char);
00266     memcpy(id, q, n); id[n] = '\0';
00267     if (sfd->num_subfonts >= sfd->max_subfonts) {
00268       sfd->max_subfonts += 16;
00269       sfd->sub_id = RENEW(sfd->sub_id, sfd->max_subfonts, char *);
00270     }
00271 
00272     if (verbose > 3) {
00273       MESG("subfont>>   id=\"%s\" at line=\"%d\"\n", id, lpos);
00274     }
00275     sfd->sub_id[sfd->num_subfonts] = id;
00276     sfd->num_subfonts++;
00277   }
00278 
00279   sfd->rec_id = NEW(sfd->num_subfonts, int);
00280   for (n = 0; n < sfd->num_subfonts; n++) {
00281     sfd->rec_id[n] = -1; /* Not loaded yet. We do lazy loading of map definitions. */
00282   }
00283 
00284   if (verbose > 3) {
00285     MESG("subfont>> %d entries found in SFD file \"%s\".\n", sfd->num_subfonts, sfd->ident);
00286   }
00287 
00288   return  0;
00289 }
00290 
00291 
00292 /* Open SFD file and gather subfont IDs. We do not read mapping tables
00293  * here but only read subfont IDs used in SFD file.
00294  */
00295 static int
00296 find_sfd_file (const char *sfd_name)
00297 {
00298   int    id = -1;
00299   int    i, error = -1;
00300 
00301   /* Check if we already opened SFD file */
00302   for (i = 0; i < num_sfd_files; i++) {
00303     if (!strcmp(sfd_files[i].ident, sfd_name)) {
00304       id = i;
00305       break;
00306     }
00307   }
00308 
00309   if (id < 0) {
00310     struct sfd_file_ *sfd = NULL;
00311     FILE  *fp;
00312 
00313     if (num_sfd_files >= max_sfd_files) {
00314       max_sfd_files += 8;
00315       sfd_files = RENEW(sfd_files, max_sfd_files, struct sfd_file_);
00316     }
00317     sfd = &sfd_files[num_sfd_files];
00318     init_sfd_file_(sfd);
00319     sfd->ident = NEW(strlen(sfd_name) + 1, char);
00320     strcpy(sfd->ident, sfd_name);
00321     fp = DPXFOPEN(sfd->ident, DPX_RES_TYPE_SFD);
00322     if (!fp) {
00323       clean_sfd_file_(sfd);
00324       return  -1;
00325     }
00326     error = scan_sfd_file(sfd, fp);
00327     DPXFCLOSE(fp);
00328     if (!error)
00329       id = num_sfd_files++;
00330     else {
00331       WARN("Error occured while reading SFD file \"%s\"", sfd_name);
00332       clean_sfd_file_(sfd);
00333       id = -1;
00334     }
00335   }
00336 
00337   return  id;
00338 }
00339 
00340 char **
00341 sfd_get_subfont_ids (const char *sfd_name, int *num_ids)
00342 {
00343   int  sfd_id;
00344 
00345   if (!sfd_name)
00346     return  NULL;
00347 
00348   sfd_id = find_sfd_file(sfd_name);
00349   if (sfd_id < 0)
00350     return  NULL;
00351 
00352   if (num_ids)
00353     *num_ids = sfd_files[sfd_id].num_subfonts;
00354   return  sfd_files[sfd_id].sub_id;
00355 }
00356 
00357 /* Make sure that sfd_name does not have the extension '.sfd'.
00358  * Mapping tables are actually read here.
00359  */
00360 int
00361 sfd_load_record (const char *sfd_name, const char *subfont_id)
00362 {
00363   int               rec_id = -1;
00364   struct sfd_file_ *sfd;
00365   FILE             *fp;
00366   int               sfd_id, i, error = 0;
00367   char             *p, *q;
00368 
00369   if (!sfd_name || !subfont_id)
00370     return  -1;
00371 
00372   sfd_id = find_sfd_file(sfd_name);
00373   if (sfd_id < 0)
00374     return  -1;
00375 
00376   sfd = &sfd_files[sfd_id];
00377   /* Check if we already loaded mapping table. */
00378   for (i = 0;
00379        i < sfd->num_subfonts && strcmp(sfd->sub_id[i], subfont_id); i++);
00380   if (i == sfd->num_subfonts) {
00381     WARN("Subfont id=\"%s\" not exist in SFD file \"%s\"...",
00382          subfont_id, sfd->ident);
00383     return  -1;
00384   } else if (sfd->rec_id[i] >= 0) {
00385     return  sfd->rec_id[i];
00386   }
00387 
00388   if (verbose > 3) {
00389     MESG("\nsubfont>> Loading SFD mapping table for <%s,%s>...",
00390          sfd->ident, subfont_id);
00391   }
00392 
00393   /* reopen */
00394   fp = DPXFOPEN(sfd->ident, DPX_RES_TYPE_SFD);
00395   if (!fp) {
00396     return  -1;
00397     /* ERROR("Could not open SFD file \"%s\"", sfd_name); */
00398   }
00399 
00400   /* Seek to record for 'sub_name'. */
00401   while ((p = readline(line_buf, LINE_BUF_SIZE, fp))) {
00402     for ( ; *p && isspace(*p); p++);
00403     if (*p == 0)
00404       continue; /* empty line */
00405 
00406     /* q = parse_ident(&p, p + strlen(p)); */
00407     for (q = p; *p && !isspace(*p); p++);
00408     *p = '\0'; p++;
00409     if (!strcmp(q, subfont_id)) {
00410       if (num_sfd_records >= max_sfd_records) {
00411         max_sfd_records += 16;
00412         sfd_record = RENEW(sfd_record, max_sfd_records, struct sfd_rec_);
00413       }
00414       clear_vector(sfd_record[num_sfd_records].vector);
00415       error = read_sfd_record(&sfd_record[num_sfd_records], p);
00416       if (error)
00417         WARN("Error occured while reading SFD file: file=\"%s\" subfont_id=\"%s\"",
00418              sfd->ident, subfont_id);
00419       else {
00420         rec_id = num_sfd_records++;
00421       }
00422     }
00423   }
00424   if (rec_id < 0) {
00425     WARN("Failed to load subfont mapping table for SFD=\"%s\" subfont_id=\"%s\"",
00426          sfd->ident, subfont_id);
00427   }
00428   sfd->rec_id[i] = rec_id;
00429   DPXFCLOSE(fp);
00430 
00431   if (verbose > 3) {
00432     int __i;
00433     if (rec_id >= 0) {
00434       MESG(" at id=\"%d\"", rec_id);
00435       MESG("\nsubfont>> Content of mapping table:");
00436       for (__i = 0; __i < 256; __i++) {
00437         if (__i % 16 == 0)
00438           MESG("\nsubfont>>  ");
00439         MESG(" %04x", sfd_record[rec_id].vector[__i]);
00440       }
00441     }
00442     MESG("\n");
00443   }
00444 
00445   return  rec_id;
00446 }
00447 
00448 
00449 /* Lookup mapping table */
00450 unsigned short
00451 lookup_sfd_record (int rec_id, unsigned char c)
00452 {
00453   if (!sfd_record ||
00454        rec_id < 0 || rec_id >= num_sfd_records)
00455     ERROR("Invalid subfont_id: %d", rec_id);
00456   return sfd_record[rec_id].vector[c];
00457 }
00458 
00459 void
00460 release_sfd_record (void)
00461 {
00462   int  i;
00463 
00464   if (sfd_record) {
00465     RELEASE(sfd_record);
00466   }
00467   if (sfd_files) {
00468     for (i = 0; i < num_sfd_files; i++) {
00469       clean_sfd_file_(&sfd_files[i]);
00470     }
00471     RELEASE(sfd_files);
00472   }
00473   sfd_record = NULL;
00474   sfd_files  = NULL;
00475   num_sfd_records = max_sfd_records = 0;
00476   num_sfd_files = max_sfd_files = 0;
00477 }
00478 
00479 
00480 #if  DPXTEST
00481 /* SFD file dumper */
00482 #ifdef HAVE_ICONV
00483 #include <iconv.h>
00484 #else
00485 typedef int iconv_t;
00486 #endif
00487 #include <string.h>
00488 
00489 static void
00490 dump_table (const char *sfd_name, const char *sub_name, iconv_t cd)
00491 {
00492   int  rec_id, i;
00493 
00494   rec_id = sfd_load_record(sfd_name, sub_name);
00495   if (rec_id < 0) {
00496     WARN("Could not load SFD mapping for \"%s\"", sub_name);
00497     return;
00498   }
00499   fprintf(stdout, "  <subfont id=\"%s\">\n", sub_name);
00500   for (i = 0; i < 256; i++) {
00501     unsigned short c = lookup_sfd_record(rec_id, i);
00502     char    *p, inbuf[2];
00503     char    *q, outbuf[32];
00504     size_t   r, inbufleft = 2, outbufleft = 32;
00505 
00506     if (c == 0)
00507       fprintf(stdout, "    <!-- %02x: undefined -->", i);
00508     else {
00509       fprintf(stdout, "    <a bi=\"%02x\" bo=\"%02x %02x\"", i, (c >> 8) & 0xff, c & 0xff);
00510       if (cd != (iconv_t) -1) {
00511         p = inbuf; q = outbuf;
00512         inbuf[0] = (c >> 8) & 0xff;
00513         inbuf[1] = c & 0xff;
00514 #ifdef HAVE_ICONV
00515         r = iconv(cd, &p, &inbufleft, &q, &outbufleft);
00516         if (r == -1) {
00517           if (verbose) {
00518             WARN("Conversion to Unicode failed for subfont-id=\"%s\" code=\"0x%02x\"",
00519                  sub_name, i);
00520             WARN(">> with: %s", strerror(errno));
00521           }
00522         } else {
00523           outbuf[32-outbufleft] = 0;
00524           fprintf(stdout, " uc=\"%s\"", outbuf);
00525         }
00526 #endif /* HAVE_ICONV */
00527       }
00528       fprintf(stdout, " />");
00529     }
00530     fprintf(stdout, "\n");
00531   }
00532   fprintf(stdout, "  </subfont>\n");
00533   return;
00534 }
00535 
00536 #define subfontDefinition_DTD "\
00537 <!ELEMENT subfontDefinition (subfont+)>\n\
00538 <!ATTLIST subfontDefinition\n\
00539   id CDATA #REQUIRED\n\
00540   output-encoding CDATA #IMPLIED\n\
00541 >\n\
00542 <!ELEMENT subfont (a*)>\n\
00543 <!ATTLIST subfont\n\
00544   id CDATA #REQUIRED\n\
00545 >\n\
00546 <!ELEMENT a EMPTY>\n\
00547 <!ATTLIST a\n\
00548   bi NMTOKENS #REQUIRED\n\
00549   bo NMTOKENS #REQUIRED\n\
00550   uc CDATA #IMPLIED\n\
00551 >\
00552 "
00553 
00554 void
00555 test_subfont_help (void)
00556 {
00557   fprintf(stdout, "usage: subfont [options] SFD_name\n");
00558   fprintf(stdout, "-e, --encoding string\n");
00559   fprintf(stdout, "  Target (output) encoding of SFD mapping is 'string'.\n");
00560   fprintf(stdout, "  It must be an encoding name recognized by iconv.\n");
00561   fprintf(stdout, "  With this option write Unicode character in auxiliary attribute 'uc'.\n");
00562   fprintf(stdout, "-s, --subfont-id string\n");
00563   fprintf(stdout, "  Load and dump mapping table only for subfont 'string'.\n");
00564 }
00565 
00566 int
00567 test_subfont_main (int argc, char *argv[])
00568 {
00569   char   *sfd_name = NULL, *sub_name = NULL;
00570   char   *from = NULL;
00571   int     i;
00572   iconv_t cd = (iconv_t) -1;
00573 
00574   for (;;) {
00575     int  c, optidx = 0;
00576     static struct option long_options[] = {
00577       {"encoding",   1, 0, 'e'}, /* for to-Unicode conversion */
00578       {"subfont-id", 1, 0, 's'},
00579       {"help",       0, 0, 'h'},
00580       {0, 0, 0, 0}
00581     };
00582     c = getopt_long(argc, argv, "e:s:h", long_options, &optidx);
00583     if (c == -1)
00584       break;
00585 
00586     switch (c) {
00587     case  'e':
00588       from = optarg;
00589       break;
00590     case  's':
00591       sub_name = optarg;
00592       break;
00593     case  'h':
00594       test_subfont_help();
00595       return  0;
00596       break;
00597     default:
00598       test_subfont_help();
00599       return  -1;
00600       break;
00601     }
00602   }
00603   if (optind < argc) {
00604     sfd_name = argv[optind++];
00605   }
00606 
00607   if (sfd_name == NULL) {
00608     WARN("No SFD file name specified.");
00609     test_subfont_help();
00610     return  -1;
00611   }
00612   if (!from)
00613     cd = (iconv_t) -1;
00614   else {
00615 #ifdef HAVE_ICONV
00616     cd = iconv_open("utf-8", from);
00617     if (cd == (iconv_t) -1) {
00618       WARN("Can't open iconv conversion descriptor for %s --> utf-8", from);
00619       return  -1;
00620     }
00621 #else
00622     WARN("Your system doesn't have iconv() in libc!");
00623 #endif
00624   }
00625 
00626   fprintf(stdout, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
00627   fprintf(stdout, "<!DOCTYPE subfontDefinition [\n%s\n]>\n",
00628           subfontDefinition_DTD);
00629   fprintf(stdout, "<subfontDefinition id=\"%s\" output-encoding=\"%s\">\n",
00630           sfd_name, from ? from : "unknown");
00631   if (sub_name == NULL || !strcmp(sub_name, "all")) {
00632     char **sub_id;
00633     int    num_ids = 0;
00634     sub_id = sfd_get_subfont_ids(sfd_name, &num_ids);
00635     if (!sub_id)
00636       WARN("Could not open SFD file: %s", sfd_name);
00637     else {
00638       for (i = 0; i < num_ids; i++)
00639         dump_table(sfd_name, sub_id[i], cd);
00640     }
00641   } else {
00642     dump_table(sfd_name, sub_name, cd);
00643   }
00644   fprintf(stdout, "</subfontDefinition>\n");
00645 
00646 #ifdef HAVE_ICONV
00647   if (cd != (iconv_t) -1)
00648     iconv_close(cd);
00649 #endif
00650 
00651   return  0;
00652 }
00653 
00654 #endif  /* DPXTEST */