OSDN Git Service

updated with TeX Live 2014.
[putex/putex.git] / src / dvipdfmx-pu / src / agl.c
1 /*  
2
3     This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
4
5     Copyright (C) 2007-2012 by Jin-Hwan Cho and Shunsaku Hirata,
6     the dvipdfmx project team.
7
8     Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
9
10     This program is free software; you can redistribute it and/or modify
11     it under the terms of the GNU General Public License as published by
12     the Free Software Foundation; either version 2 of the License, or
13     (at your option) any later version.
14
15     This program is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18     GNU General Public License for more details.
19
20     You should have received a copy of the GNU General Public License
21     along with this program; if not, write to the Free Software
22     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
23 */
24
25 /*
26  * References:
27  *
28  *  Unicode and Glyph Names, ver. 2.3., Adobe Solution Network
29  *  http://partners.adobe.com/asn/tech/type/unicodegn.jsp
30  */
31
32 #if HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include <string.h>
37 #include <ctype.h>
38
39 #include "system.h"
40 #include "mem.h"
41 #include "error.h"
42
43 #include "mfileio.h"
44 #include "pdfparse.h"
45
46 /* Hash */
47 #include "dpxutil.h"
48
49 #include "dpxfile.h"
50
51 #include "unicode.h"
52
53 #include "agl.h"
54
55 static int verbose = 0;
56
57 void
58 agl_set_verbose (void)
59 {
60   verbose++;
61 }
62
63 static agl_name *
64 agl_new_name (void)
65 {
66   agl_name *agln;
67
68   agln = NEW(1, agl_name);
69   agln->name   = NULL;
70   agln->suffix = NULL;
71   agln->n_components = 0;
72   agln->alternate = NULL;
73   agln->is_predef = 0;
74
75   return agln;
76 }
77
78 static void
79 agl_release_name (agl_name *agln)
80 {
81   agl_name *next;
82
83   while (agln) {
84     next = agln->alternate;
85     if (agln->name)
86       RELEASE(agln->name);
87     if (agln->suffix)
88       RELEASE(agln->suffix);
89     agln->name = NULL;
90     RELEASE(agln);
91     agln = next;
92   }
93 }
94
95 char *
96 agl_chop_suffix (const char *glyphname, char **suffix)
97 {
98   char  *name, *p;
99   int    len;
100
101   ASSERT(glyphname && suffix);
102
103   p = strchr(glyphname, '.');
104   if (p) {
105     len = strlen(glyphname) - strlen(p);
106     if (len < 1) {
107       name = NULL;
108       *suffix = NEW(strlen(glyphname), char);
109       strcpy(*suffix, glyphname+1);
110     } else {
111       p++;
112       name = NEW(len + 1, char);
113       strncpy(name, glyphname, len);
114       name[len] = '\0';
115       if (p[0] == '\0') {
116         *suffix = NULL;
117       } else {
118         *suffix = NEW(strlen(p) + 1, char);
119         strcpy(*suffix, p);
120       }
121     }
122   } else {
123     name = NEW(strlen(glyphname) + 1, char);
124     strcpy(name, glyphname);
125     *suffix = NULL;
126   }
127
128   return name;
129 }
130
131 static const char * const modifiers[] = {
132   "acute", "breve", "caron", "cedilla", "circumflex",
133   "dieresis", "dotaccent", "grave", "hungarumlaut",
134   "macron", "ogonek", "ring", "tilde", "commaaccent", 
135   "slash",
136
137   /* The following entries are not accent nor something
138    * but PS font may have those "small" version...
139    */
140   "ampersand", "exclam", "exclamdown",
141   "question","questiondown",
142   NULL
143 };
144
145 static int
146 skip_capital (const char **p, const char *endptr)
147 {
148   long slen = 0, len;
149
150   len = (long) (endptr - (*p));
151
152   if (len >= 2 &&
153       ((**p == 'A' && *(*p+1) == 'E') ||
154        (**p == 'O' && *(*p+1) == 'E'))) {
155     *p  += 2;
156     slen = 2;
157   } else if (len >= 3 &&
158              **p     == 'E' &&
159              *(*p+1) == 't' &&
160              *(*p+2) == 'h') {
161     *p  += 3;
162     slen = 3;
163   } else if (len >= 5 &&
164              **p     == 'T' &&
165              *(*p+1) == 'h' &&
166              *(*p+2) == 'o' &&
167              *(*p+3) == 'r' &&
168              *(*p+4) == 'n') {
169     *p  += 5;
170     slen = 5;
171   } else if (len >= 1 &&
172              **p >= 'A' && **p <= 'Z') {
173     *p  += 1;
174     slen = 1;
175   }
176
177   return slen;
178 }
179
180 static int
181 skip_modifier (const char **p, const char *endptr)
182 {
183   long slen = 0, len;
184   int  i;
185
186   len = (long) (endptr - (*p));
187
188   for (i = 0; modifiers[i] != NULL; i++) {
189     if ((len >= strlen(modifiers[i]) &&
190          !memcmp(*p, modifiers[i], len))) {
191       slen = strlen(modifiers[i]);
192       *p  += slen;
193       break;
194     }
195   }
196
197   return slen;
198 }
199
200 static int
201 is_smallcap (const char *glyphname)
202 {
203   long  len, slen;
204   const char *p, *endptr;
205
206   if (!glyphname)
207     return 0;
208
209   p   = glyphname;
210   len = strlen(glyphname);
211   if (len < 6 ||
212       strcmp(p + len - 5, "small"))
213     return 0;
214
215   endptr = p + len - 5;
216
217   len -= 5;
218   slen = skip_modifier(&p, endptr);
219   if (slen == len)
220     return 1;  /* Acutesmall, Gravesmall, etc */
221   else if (slen > 0) { /* ??? */
222     return 0;
223   }
224
225   len -= skip_capital(&p, endptr);
226   if (len == 0) {
227     return 1;  /* Asmall, AEsmall, etc */
228   }
229
230   while (len > 0) { /* allow multiple accent */
231     slen = skip_modifier(&p, endptr);
232     if (slen == 0)
233       return 0;
234     len -= slen;
235   }
236
237   return 1;
238 }
239
240 #define SUFFIX_LIST_MAX  16
241 #define AGL_VAR_SMCP_IDX 0
242 static struct {
243   const char   *key;
244   const char   *otl_tag;
245   const char   *suffixes[SUFFIX_LIST_MAX];
246 } var_list[] = {
247   {"small"       , "smcp", {"sc", NULL}},
248   {"swash"       , "swsh", {NULL}},
249   {"superior"    , "sups", {NULL}},
250   {"inferior"    , "sinf", {NULL}},
251   {"numerator"   , "numr", {NULL}},
252   {"denominator" , "dnom", {NULL}},
253   {"oldstyle"    , "onum", {NULL}},
254
255   /* The following only used by TeX, there are no
256    * corresponding OTL feat. tag.
257    */
258   {"display" , NULL, {NULL}},
259   {"text"    , NULL, {NULL}},
260   {"big"     , NULL, {NULL}},
261   {"bigg"    , NULL, {NULL}},
262   {"Big"     , NULL, {NULL}},
263   {"Bigg"    , NULL, {NULL}},
264   {NULL, NULL, {NULL}}
265 };
266
267 const char *
268 agl_suffix_to_otltag (const char *suffix)
269 {
270   int i, j;
271   
272   for (i = 0; var_list[i].key; i++) {
273     for (j = 0; var_list[i].suffixes[j]; j++) {
274       if (!strcmp(suffix, var_list[i].suffixes[j]))
275         return var_list[i].otl_tag; 
276     }
277     if (!strcmp(suffix, var_list[i].key))
278       return var_list[i].otl_tag;
279     if (var_list[i].otl_tag &&
280         !strcmp(suffix, var_list[i].otl_tag))
281       return var_list[i].otl_tag;
282   }
283   
284   return NULL;
285 }
286
287 static int
288 agl_guess_name (const char *glyphname)
289 {
290   int i, len;
291
292   if (is_smallcap(glyphname))
293     return AGL_VAR_SMCP_IDX;
294
295   len = strlen(glyphname);
296   for (i = 1; var_list[i].key != NULL; i++) {
297     if (len > strlen(var_list[i].key) &&
298         !strcmp(glyphname+len-strlen(var_list[i].key), var_list[i].key)
299         ) {
300       return i;
301     }
302   }
303
304   return -1;
305 }
306
307 static agl_name *
308 agl_normalized_name (char *glyphname)
309 {
310   agl_name *agln;
311   char     *suffix;
312   int       i, n;
313
314   if (!glyphname)
315     return NULL;
316
317   agln   = agl_new_name();
318   suffix = strchr(glyphname, '.');
319   if (suffix) {
320     n = strlen(glyphname) - strlen(suffix);
321     if (suffix[1] != '\0') {
322       agln->suffix = NEW(strlen(suffix), char);
323       strcpy(agln->suffix, suffix+1);
324     }
325     agln->name    = NEW(n+1, char);
326     memcpy(agln->name, glyphname, n);
327     agln->name[n] = '\0';
328   } else if (is_smallcap(glyphname)) {
329     n = strlen(glyphname) - 5;
330     agln->suffix = NEW(3, char);
331     strcpy(agln->suffix, "sc");
332     agln->name   = NEW(n+1, char);
333     for (i = 0; i < n; i++) {
334       agln->name[i] = isupper(glyphname[i]) ?
335         (glyphname[i] + 32) : glyphname[i];
336     }
337     agln->name[n] = '\0';
338   } else {
339     int var_idx;
340
341 #define SET_STRING(p,s) do {\
342   (p) = NEW(strlen((s))+1, char);\
343   strcpy((p),(s));\
344 } while (0)
345     var_idx = agl_guess_name(glyphname);
346     if (var_idx < 0 ||
347         !var_list[var_idx].key) {
348         n = strlen(glyphname);
349     } else {
350         n = strlen(glyphname) - strlen(var_list[var_idx].key);
351         if (var_list[var_idx].suffixes[0])
352             SET_STRING(agln->suffix, var_list[var_idx].suffixes[0]);
353         else {
354             SET_STRING(agln->suffix, var_list[var_idx].key);
355         }
356     }
357     agln->name    = NEW(n+1, char);
358     memcpy(agln->name, glyphname, n);
359     agln->name[n] = '\0';
360   }
361   
362   return agln;
363 }
364
365 static struct ht_table aglmap;
366
367 static void CDECL
368 hval_free (void *hval)
369 {
370   agl_release_name((struct agl_name *) hval);
371 }
372
373 void
374 agl_init_map (void)
375 {
376   ht_init_table(&aglmap, hval_free);
377   agl_load_listfile(AGL_EXTRA_LISTFILE, 0);
378   if (agl_load_listfile(AGL_PREDEF_LISTFILE, 1) < 0) {
379     WARN("Failed to load AGL file \"%s\"...", AGL_PREDEF_LISTFILE);
380   }
381   if (agl_load_listfile(AGL_DEFAULT_LISTFILE, 0) < 0) {
382     WARN("Failed to load AGL file \"%s\"...", AGL_DEFAULT_LISTFILE);
383   }
384 }
385
386 void
387 agl_close_map (void)
388 {
389   ht_clear_table(&aglmap);
390 }
391
392 #define WBUF_SIZE 1024
393
394 int
395 agl_load_listfile (const char *filename, int is_predef)
396 {
397   int   count = 0;
398   const char *p, *endptr;
399   char *nextptr;
400   char  wbuf[WBUF_SIZE];
401   FILE *fp;
402
403   if (!filename)
404     return  -1;
405
406   fp = DPXFOPEN(filename, DPX_RES_TYPE_AGL);
407   if (!fp) {
408     return -1;
409   }
410
411   if (verbose)
412     MESG("<AGL:%s", filename);
413
414   while ((p = mfgets(wbuf, WBUF_SIZE, fp)) != NULL) {
415     agl_name *agln, *duplicate;
416     char     *name;
417     int       n_unicodes, i;
418     long      unicodes[AGL_MAX_UNICODES];
419
420     endptr = p + strlen(p);
421     skip_white(&p, endptr);
422
423     /* Need table version check. */
424     if (!p || p[0] == '#' || p >= endptr)
425       continue;
426     nextptr = strchr(p, ';');
427     if (!nextptr || nextptr == p)
428       continue;
429
430     name = parse_ident(&p, nextptr);
431
432     skip_white(&p, endptr);
433     if (!name || p[0] != ';') {
434       WARN("Invalid AGL entry: %s", wbuf);
435       if (name)
436         RELEASE(name);
437       continue;
438     }
439
440     p++;
441     skip_white(&p, endptr);
442
443     n_unicodes = 0;
444     while (p < endptr &&
445            ((p[0]  >= '0' && p[0] <= '9') ||
446             (p[0]  >= 'A' && p[0] <= 'F'))
447           ) {
448
449       if (n_unicodes >= AGL_MAX_UNICODES) {
450         WARN("Too many Unicode values");
451         break;
452       }
453       unicodes[n_unicodes++] = strtol(p, &nextptr, 16);
454
455       p = nextptr;
456       skip_white(&p, endptr);
457     }
458
459     if (n_unicodes == 0) {
460       WARN("AGL entry ignored (no mapping): %s", wbuf);
461       RELEASE(name);
462       continue;
463     }
464
465     agln = agl_normalized_name(name);
466     agln->is_predef = is_predef;
467     agln->n_components = n_unicodes;
468     for (i = 0; i < n_unicodes; i++) {
469       agln->unicodes[i] = unicodes[i];
470     }
471
472     duplicate = ht_lookup_table(&aglmap, name, strlen(name));
473     if (!duplicate)
474       ht_append_table(&aglmap, name, strlen(name), agln);
475     else {
476       while (duplicate->alternate)
477         duplicate = duplicate->alternate;
478       duplicate->alternate = agln;
479     }
480
481     if (verbose > 3) {
482       if (agln->suffix)
483         MESG("agl: %s [%s.%s] -->", name, agln->name, agln->suffix);
484       else
485         MESG("agl: %s [%s] -->", name, agln->name);
486       for (i = 0; i < agln->n_components; i++) {
487         if (agln->unicodes[i] > 0xffff) {
488           MESG(" U+%06X", agln->unicodes[i]);
489         } else {
490           MESG(" U+%04X", agln->unicodes[i]);
491         }
492       }
493       MESG("\n");
494     }
495
496     RELEASE(name);
497     count++;
498   }
499   DPXFCLOSE(fp);
500
501   if (verbose)
502     MESG(">");
503
504   return count;
505 }
506
507 agl_name *
508 agl_lookup_list (const char *glyphname)
509 {
510   agl_name *agln;
511
512   if (!glyphname)
513     return NULL;
514
515   agln = ht_lookup_table(&aglmap, glyphname, strlen(glyphname));
516
517   return agln;
518 }
519
520 int
521 agl_name_is_unicode (const char *glyphname)
522 {
523   char c, *suffix;
524   int  i, len;
525
526   if (!glyphname)
527     return 0;
528
529   suffix = strchr(glyphname, '.');
530   len    = (int) (suffix ? suffix - glyphname : strlen(glyphname));
531   /*
532    * uni02ac is invalid glyph name and mapped to th empty string.
533    */
534   if (len >= 7 && (len - 3) % 4 == 0 &&
535       !strncmp(glyphname, "uni", 3)) {
536     c = glyphname[3];
537     /*
538      * Check if the 4th character is uppercase hexadecimal digit.
539      * "union" should not be treated as Unicode glyph name.
540      */
541     if (isdigit(c) || (c >= 'A' && c <= 'F'))
542       return 1;
543     else
544       return 0;
545   } else if (len <= 7 && len >= 5 &&
546              glyphname[0] == 'u') {
547     for (i = 1; i < len - 1; i++) {
548       c = glyphname[i];
549       if (!isdigit(c) && (c < 'A' || c > 'F'))
550         return 0;
551     }
552     return 1;
553   }
554
555   return 0;
556 }
557
558 long
559 agl_name_convert_unicode (const char *glyphname)
560 {
561   long  ucv = -1;
562   const char *p;
563
564   if (!agl_name_is_unicode(glyphname))
565     return -1;
566
567   if (strlen(glyphname) > 7 && *(glyphname+7) != '.') {
568     WARN("Mapping to multiple Unicode characters not supported.");
569     return -1;
570   }
571
572   if (glyphname[1] == 'n')
573     p = glyphname + 3;
574   else
575     p = glyphname + 1;
576   ucv = 0;
577   while (*p != '\0' && *p != '.') {
578     if (!isdigit(*p) && (*p < 'A' || *p > 'F')) {
579       WARN("Invalid char %c in Unicode glyph name %s.", *p, glyphname);
580       return -1;
581     }
582     ucv <<= 4;
583     ucv += isdigit(*p) ? *p - '0' : *p - 'A' + 10;
584     p++;
585   }
586
587   if (!UC_is_valid(ucv)) {
588     if (ucv < 0x10000) {
589       WARN("Invalid Unicode code value U+%04X.", ucv);
590     } else {
591       WARN("Invalid Unicode code value U+%06X.", ucv);
592     }
593     ucv = -1;
594   }
595
596   return ucv;
597 }
598
599
600
601 static long
602 xtol (const char *start, int len)
603 {
604   long v = 0;
605
606   while (len-- > 0) {
607     v <<= 4;
608     if (isdigit(*start)) {
609       v += *start - '0';
610     } else if (*start >= 'A' && *start <= 'F') {
611       v += *start - 'A' + 10;
612     } else {
613       return -1;
614     }
615     start++;
616   }
617
618   return v;
619 }
620
621 #define IS_PUA(u) (((u) >= 0x00E000L && (u) <= 0x00F8FFL) || \
622   ((u) >= 0x0F0000L && (u) <= 0x0FFFFDL) || \
623   ((u) >= 0x100000L && (u) <= 0x10FFFDL) \
624 )
625
626 static long
627 put_unicode_glyph (const char *name,
628                    unsigned char **dstpp, unsigned char *limptr)
629 {
630   const char *p;
631   long  len = 0, ucv;
632
633   p   = name;
634   ucv = 0;
635
636   if (p[1] != 'n') {
637     p   += 1;
638     ucv  = xtol(p, strlen(p));
639     len += UC_sput_UTF16BE (ucv, dstpp, limptr);
640   } else {
641     p += 3;
642     while (*p != '\0') {
643       ucv  = xtol(p, 4);
644       len += UC_sput_UTF16BE (ucv, dstpp, limptr);
645       p   += 4;
646     }
647   }
648
649   return len;
650 }
651
652 long
653 agl_sput_UTF16BE (const char *glyphstr,
654                   unsigned char **dstpp, unsigned char *limptr,
655                   int *fail_count)
656 {
657   long  len   = 0;
658   int   count = 0;
659   const char *p, *endptr;
660
661   ASSERT(glyphstr && dstpp);
662
663   p      =  glyphstr;
664   endptr = strchr(p, '.');
665   if (!endptr)
666     endptr = p + strlen(p);
667
668   while (p < endptr) {
669     char     *name;
670     const char *delim;
671     long      sub_len;
672     int       i;
673     agl_name *agln0, *agln1 = NULL;
674
675     delim = strchr(p, '_');
676     if (delim == p) {
677       /*
678        * Glyph names starting with a underscore or two subsequent
679        * underscore in glyph name not allowed?
680        */
681       WARN("Invalid glyph name component in \"%s\".", glyphstr);
682       count++;
683       if (fail_count)
684         *fail_count = count;
685       return len; /* Cannot continue */
686     } else if (!delim || delim > endptr) {
687       delim = endptr;
688     }
689     sub_len = (long) (delim - p);
690
691     name = NEW(sub_len+1, char);
692     memcpy(name, p, sub_len);
693     name[sub_len] = '\0';
694
695     if (agl_name_is_unicode(name)) {
696       sub_len = put_unicode_glyph(name, dstpp, limptr);
697       if (sub_len > 0)
698         len += sub_len;
699       else {
700         count++;
701       }
702     } else {
703       agln1 = agl_lookup_list(name);
704       if (!agln1 || (agln1->n_components == 1 &&
705                      IS_PUA(agln1->unicodes[0]))) {
706         agln0 = agl_normalized_name(name);
707         if (agln0) {
708           if (verbose > 1 && agln0->suffix) {
709             WARN("agl: fix %s --> %s.%s",
710                  name, agln0->name, agln0->suffix);
711           }
712           agln1 = agl_lookup_list(agln0->name);
713           agl_release_name(agln0);
714         }
715       }
716       if (agln1) {
717         for (i = 0; i < agln1->n_components; i++) {
718           len += UC_sput_UTF16BE (agln1->unicodes[i], dstpp, limptr);
719         }
720       } else {
721         if (verbose) {
722           WARN("No Unicode mapping for glyph name \"%s\" found.", name);
723         }
724         count++;
725       }
726     }
727     RELEASE(name);
728     p = delim + 1;
729   }
730
731   if (fail_count)
732     *fail_count = count;
733   return len;
734 }
735
736 int
737 agl_get_unicodes (const char *glyphstr,
738                   long *unicodes, int max_unicodes)
739 {
740   int   count = 0;
741   const char *p, *endptr;
742
743   p      = glyphstr;
744   endptr = strchr(p, '.');
745   if (!endptr)
746     endptr = p + strlen(p);
747
748   while (p < endptr) {
749     char     *name;
750     const char *delim;
751     long      sub_len;
752     int       i;
753     agl_name *agln0, *agln1 = NULL;
754
755     delim = strchr(p, '_');
756     if (delim == p) {
757       /*
758        * Glyph names starting with a underscore or two subsequent
759        * underscore in glyph name not allowed?
760        */
761       WARN("Invalid glyph name component in \"%s\".", glyphstr);
762       return -1; /* Cannot continue */
763     } else if (!delim || delim > endptr) {
764       delim = endptr;
765     }
766     sub_len = (long) (delim - p);
767
768     name = NEW(sub_len+1, char);
769     memcpy(name, p, sub_len);
770     name[sub_len] = '\0';
771
772     if (agl_name_is_unicode(name)) {
773       p  = name;
774       if (p[1] != 'n') { /* uXXXXXXXX */
775         if (count >= max_unicodes) {
776           RELEASE(name);
777           return -1;
778         }
779         p++;
780         unicodes[count++] = xtol(p, strlen(p));
781       } else {
782         p += 3;
783         while (*p != '\0') {
784           if (count >= max_unicodes) {
785             RELEASE(name);
786             return -1;
787           }
788           unicodes[count++] = xtol(p, 4);
789           p += 4;
790         }
791       }
792     } else {
793       agln1 = agl_lookup_list(name);
794       if (!agln1 || (agln1->n_components == 1 &&
795                      IS_PUA(agln1->unicodes[0]))) {
796         agln0 = agl_normalized_name(name);
797         if (agln0) {
798           if (verbose > 1 && agln0->suffix) {
799             WARN("agl: fix %s --> %s.%s",
800                  name, agln0->name, agln0->suffix);
801           }
802           agln1 = agl_lookup_list(agln0->name);
803           agl_release_name(agln0);
804         }
805       }
806       if (agln1) {
807         if (count + agln1->n_components > max_unicodes) {
808           RELEASE(name);
809           return -1;
810         }
811         for (i = 0; i < agln1->n_components; i++) {
812           unicodes[count++] = agln1->unicodes[i];
813         }
814       } else {
815         if (verbose > 1)
816           WARN("No Unicode mapping for glyph name \"%s\" found.", name);
817         RELEASE(name);
818         return -1;
819       }
820     }
821     RELEASE(name);
822     p = delim + 1;
823   }
824
825   return count;
826 }