1 // -*- related-file-name: "../include/efont/otfpost.hh" -*-
2 
3 /* otfpost.{cc,hh} -- OpenType post table
4  *
5  * Copyright (c) 2006-2019 Eddie Kohler
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version. This program is distributed in the hope that it will be
11  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13  * Public License for more details.
14  */
15 
16 #ifdef HAVE_CONFIG_H
17 # include <config.h>
18 #endif
19 #include <efont/otfpost.hh>
20 #include <lcdf/error.hh>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <efont/otfdata.hh>     // for ntohl()
25 
26 #define USHORT_AT(d)            (Data::u16_aligned(d))
27 #define SHORT_AT(d)             (Data::s16_aligned(d))
28 #define ULONG_AT(d)             (Data::u32_aligned(d))
29 #define LONG_AT(d)              (Data::s32_aligned(d))
30 
31 namespace Efont { namespace OpenType {
32 
33 static const char * const mac_names[] = {
34     ".notdef", ".null", "nonmarkingreturn", "space",            // 0-3
35     "exclam", "quotedbl", "numbersign", "dollar",               // 4-7
36     "percent", "ampersand", "quotesingle", "parenleft",         // 8-11
37     "parenright", "asterisk", "plus", "comma",                  // 12-15
38     "hyphen", "period", "slash", "zero",                        // 16-19
39     "one", "two", "three", "four",                              // 20-23
40     "five", "six", "seven", "eight",                            // 24-27
41     "nine", "colon", "semicolon", "less",                       // 28-31
42     "equal", "greater", "question", "at",                       // 32-35
43     "A", "B", "C", "D",                                         // 36-39
44     "E", "F", "G", "H",                                         // 40-43
45     "I", "J", "K", "L",                                         // 44-47
46     "M", "N", "O", "P",                                         // 48-51
47     "Q", "R", "S", "T",                                         // 52-55
48     "U", "V", "W", "X",                                         // 56-59
49     "Y", "Z", "bracketleft", "backslash",                       // 60-63
50     "bracketright", "asciicircum", "underscore", "grave",       // 64-67
51     "a", "b", "c", "d",                                         // 68-71
52     "e", "f", "g", "h",                                         // 72-75
53     "i", "j", "k", "l",                                         // 76-79
54     "m", "n", "o", "p",                                         // 80-83
55     "q", "r", "s", "t",                                         // 84-87
56     "u", "v", "w", "x",                                         // 88-91
57     "y", "z", "braceleft", "bar",                               // 92-95
58     "braceright", "asciitilde", "Adieresis", "Aring",           // 96-99
59     "Ccedilla", "Eacute", "Ntilde", "Odieresis",                // 100-103
60     "Udieresis", "aacute", "agrave", "acircumflex",             // 104-107
61     "adieresis", "atilde", "aring", "ccedilla",                 // 108-111
62     "eacute", "egrave", "ecircumflex", "edieresis",             // 112-115
63     "iacute", "igrave", "icircumflex", "idieresis",             // 116-119
64     "ntilde", "oacute", "ograve", "ocircumflex",                // 120-123
65     "odieresis", "otilde", "uacute", "ugrave",                  // 124-127
66     "ucircumflex", "udieresis", "dagger", "degree",             // 128-131
67     "cent", "sterling", "section", "bullet",                    // 132-135
68     "paragraph", "germandbls", "registered", "copyright",       // 136-139
69     "trademark", "acute", "dieresis", "notequal",               // 140-143
70     "AE", "Oslash", "infinity", "plusminus",                    // 144-147
71     "lessequal", "greaterequal", "yen", "mu",                   // 148-151
72     "partialdiff", "summation", "product", "pi",                // 152-155
73     "integral", "ordfeminine", "ordmasculine", "Omega",         // 156-159
74     "ae", "oslash", "questiondown", "exclamdown",               // 160-163
75     "logicalnot", "radical", "florin", "approxequal",           // 164-167
76     "Delta", "guillemotleft", "guillemotright", "ellipsis",     // 168-171
77     "nonbreakingspace", "Agrave", "Atilde", "Otilde",           // 172-175
78     "OE", "oe", "endash", "emdash",                             // 176-179
79     "quotedblleft", "quotedblright", "quoteleft", "quoteright", // 180-183
80     "divide", "lozenge", "ydieresis", "Ydieresis",              // 184-187
81     "fraction", "currency", "guilsinglleft", "guilsinglright",  // 188-191
82     "fi", "fl", "daggerdbl", "periodcentered",                  // 192-195
83     "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", // 196-199
84     "Ecircumflex", "Aacute", "Edieresis", "Egrave",             // 200-203
85     "Iacute", "Icircumflex", "Idieresis", "Igrave",             // 204-207
86     "Oacute", "Ocircumflex", "apple", "Ograve",                 // 208-211
87     "Uacute", "Ucircumflex", "Ugrave", "dotlessi",              // 212-215
88     "circumflex", "tilde", "macron", "breve",                   // 216-219
89     "dotaccent", "ring", "cedilla", "hungarumlaut",             // 220-223
90     "ogonek", "caron", "Lslash", "lslash",                      // 224-227
91     "Scaron", "scaron", "Zcaron", "zcaron",                     // 228-231
92     "brokenbar", "Eth", "eth", "Yacute",                        // 232-235
93     "yacute", "Thorn", "thorn", "minus",                        // 236-239
94     "multiply", "onesuperior", "twosuperior", "threesuperior",  // 240-243
95     "onehalf", "onequarter", "threequarters", "franc",          // 244-247
96     "Gbreve", "gbreve", "Idotaccent", "Scedilla",               // 248-251
97     "scedilla", "Cacute", "cacute", "Ccaron",                   // 252-255
98     "ccaron", "dcroat"                                          // 256-257
99 };
100 
101 
Post(const String & s,ErrorHandler * errh)102 Post::Post(const String &s, ErrorHandler *errh)
103     : _str(s), _version(0)
104 {
105     _str.align_long();
106     _error = parse_header(errh ? errh : ErrorHandler::silent_handler());
107 }
108 
109 int
parse_header(ErrorHandler * errh)110 Post::parse_header(ErrorHandler *errh)
111 {
112     // HEADER FORMAT:
113     // 0        FIXED   version
114     // 4        FIXED   italicAngle
115     // 8        FWORD   underlinePosition
116     // 10       FWORD   underlineThickness
117     // 12       ULONG   isFixedPitch
118     // 16       ULONG   minMemType42
119     // 20       ULONG   maxMemType42
120     // 24       ULONG   minMemType1
121     // 28       ULONG   maxMemType1
122     int len = _str.length();
123     const uint8_t *data = _str.udata();
124     if (HEADER_SIZE > len)
125         return errh->error("OTF post table too small"), -EFAULT;
126     _version = USHORT_AT(data); // ignore minor version number
127                                 // except that version 2.5 isn't compatible
128     if (_version < 1 || _version > 3
129         || (_version == 2 && USHORT_AT(data + 2) == 0x5000))
130         return errh->error("bad post version number"), -ERANGE;
131     if (_version == 2) {
132         // VERSION 2.0 GLYPH NAMES FORMAT:
133         // 32   USHORT  numberOfGlyphs
134         // 34   USHORT  glyphNameIndex[mumberOfGlyphs]
135         //      CHAR    names[...]
136         if (HEADER_SIZE + 2 > len
137             || ((_nglyphs = USHORT_AT(data + HEADER_SIZE)),
138                 HEADER_SIZE + 2 + 2 * _nglyphs > len))
139             return errh->error("OTF post table too small for glyph map"), -EFAULT;
140         int pos = HEADER_SIZE + 2 + 2 * _nglyphs;
141         while (pos < len && pos + data[pos] < len) {
142             _extend_glyph_names.push_back(pos);
143             pos += 1 + data[pos];
144         }
145         const uint8_t *gni = data + HEADER_SIZE + 2;
146         for (int i = 0, g; i < _nglyphs; ++i, gni += 2)
147             if ((g = USHORT_AT(gni)) >= _extend_glyph_names.size() + N_MAC_GLYPHS)
148                 return errh->error("bad glyph name index in post");
149     } else if (_version == 1)
150         _nglyphs = N_MAC_GLYPHS;
151     else
152         _nglyphs = -1;
153 
154     return 0;
155 }
156 
157 double
italic_angle() const158 Post::italic_angle() const
159 {
160     if (error() < 0)
161         return -1;
162     return (double) LONG_AT(_str.udata() + 4) / 65536.;
163 }
164 
165 bool
is_fixed_pitch() const166 Post::is_fixed_pitch() const
167 {
168     if (error() < 0)
169         return false;
170     return ULONG_AT(_str.udata() + 12) != 0;
171 }
172 
173 bool
glyph_names(Vector<PermString> & gnames) const174 Post::glyph_names(Vector<PermString> &gnames) const
175 {
176     gnames.clear();
177     if (error() < 0)
178         return false;
179     if (_version == 1) {
180         for (int i = 0; i < N_MAC_GLYPHS; i++)
181             gnames.push_back(mac_names[i]);
182         return true;
183     } else if (_version == 2) {
184         const uint8_t *data = _str.udata();
185         const uint8_t *gni = data + HEADER_SIZE + 2;
186         for (int i = 0; i < _nglyphs; i++, gni += 2) {
187             int g = USHORT_AT(gni);
188             if (g < N_MAC_GLYPHS)
189                 gnames.push_back(mac_names[g]);
190             else {
191                 const uint8_t *n = data + _extend_glyph_names[g - N_MAC_GLYPHS];
192                 gnames.push_back(PermString((const char *) n + 1, *n));
193             }
194         }
195         return true;
196     } else
197         return false;
198 }
199 
200 }}
201