1% sfnt.w
2%
3% Copyright 2002 by Jin-Hwan Cho and Shunsaku Hirata,
4% the dvipdfmx project team <dvipdfmx@@project.ktug.or.kr>
5% Copyright 2006-2008 Taco Hoekwater <taco@@luatex.org>
6%
7% This file is part of LuaTeX.
8%
9% LuaTeX is free software; you can redistribute it and/or modify it under
10% the terms of the GNU General Public License as published by the Free
11% Software Foundation; either version 2 of the License, or (at your
12% option) any later version.
13%
14% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
15% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17% License for more details.
18%
19% You should have received a copy of the GNU General Public License along
20% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
21
22@ Based on dvipdfmx-0.13.2c
23@c
24
25
26#include "ptexlib.h"
27
28#if  HAVE_CONFIG_H
29#  include <w2c/config.h>
30#endif                          /* |HAVE_CONFIG_H_| */
31
32#include <string.h>
33
34#include "font/sfnt.h"
35
36@ type:
37
38 `true' (0x74727565): TrueType (Mac)
39
40 `typ1' (0x74797031) (Mac): PostScript font housed in a sfnt wrapper
41
42 0x00010000: TrueType (Win)/OpenType
43
44 `OTTO': PostScript CFF font with OpenType wrapper
45
46 `ttcf': TrueType Collection
47
48@c
49#define SFNT_TRUETYPE   0x00010000UL
50#define SFNT_MAC_TRUE 0x74727565UL
51#define SFNT_OPENTYPE   0x00010000UL
52#define SFNT_POSTSCRIPT 0x4f54544fUL
53#define SFNT_TTC        0x74746366UL
54
55sfnt *sfnt_open(unsigned char *buff, int buflen)
56{
57    sfnt *sfont;
58    ULONG type;
59
60    sfont = xmalloc(sizeof(sfnt));
61    sfont->loc = 0;
62    sfont->buffer = buff;
63    sfont->buflen = buflen;
64
65    type = sfnt_get_ulong(sfont);
66
67    if (type == SFNT_TRUETYPE || type == SFNT_MAC_TRUE) {
68        sfont->type = SFNT_TYPE_TRUETYPE;
69    } else if (type == SFNT_OPENTYPE) {
70        sfont->type = SFNT_TYPE_OPENTYPE;
71    } else if (type == SFNT_POSTSCRIPT) {
72        sfont->type = SFNT_TYPE_POSTSCRIPT;
73    } else if (type == SFNT_TTC) {
74        sfont->type = SFNT_TYPE_TTC;
75    }
76
77    sfont->loc = 0;
78    sfont->directory = NULL;
79    return sfont;
80}
81
82static void release_directory(struct sfnt_table_directory *td)
83{
84    long i;
85
86    if (td) {
87        if (td->tables) {
88            for (i = 0; i < td->num_tables; i++) {
89                if (td->tables[i].data)
90                    RELEASE(td->tables[i].data);
91            }
92            RELEASE(td->tables);
93        }
94        if (td->flags)
95            RELEASE(td->flags);
96        RELEASE(td);
97    }
98
99    return;
100}
101
102void sfnt_close(sfnt * sfont)
103{
104
105    if (sfont) {
106        if (sfont->directory)
107            release_directory(sfont->directory);
108        RELEASE(sfont);
109    }
110
111    return;
112}
113
114int put_big_endian(void *s, LONG q, int n)
115{
116    int i;
117    char *p;
118
119    p = (char *) s;
120    for (i = n - 1; i >= 0; i--) {
121        p[i] = (char) (q & 0xff);
122        q >>= 8;
123    }
124
125    return n;
126}
127
128@ Convert four-byte number to big endianess in a machine independent way.
129
130@c
131static void convert_tag(char *tag, unsigned long u_tag)
132{
133    int i;
134
135    for (i = 3; i >= 0; i--) {
136        tag[i] = (char) (u_tag % 256);
137        u_tag /= 256;
138    }
139
140    return;
141}
142
143
144@ Computes the max power of 2 <= n
145
146@c
147static unsigned max2floor(unsigned n)
148{
149    int val = 1;
150
151    while (n > 1) {
152        n /= 2;
153        val *= 2;
154    }
155
156    return (unsigned) val;
157}
158
159
160@ Computes the log2 of the max power of 2 <= n
161
162@c
163static unsigned log2floor(unsigned n)
164{
165    unsigned val = 0;
166
167    while (n > 1) {
168        n /= 2;
169        val++;
170    }
171
172    return val;
173}
174
175@ @c
176static ULONG sfnt_calc_checksum(void *data, ULONG length)
177{
178    ULONG chksum = 0;
179    BYTE *p, *endptr;
180    ULONG count = 0;
181
182    p = (BYTE *) data;
183    endptr = p + length;
184    while (p < endptr) {
185        chksum = chksum + (ULONG) (p[0] << (8 * (3 - count)));
186        count = ((count + 1) & 3);
187        p++;
188    }
189
190    return chksum;
191}
192
193@ @c
194static int find_table_index(struct sfnt_table_directory *td, const char *tag)
195{
196    int idx;
197
198    if (!td)
199        return -1;
200
201    for (idx = 0; idx < td->num_tables; idx++) {
202        if (!memcmp(td->tables[idx].tag, tag, 4))
203            return idx;
204    }
205
206    return -1;
207}
208
209@ @c
210void sfnt_set_table(sfnt * sfont, const char *tag, void *data, ULONG length)
211{
212    struct sfnt_table_directory *td;
213    int idx;
214
215    ASSERT(sfont);
216
217    td = sfont->directory;
218    idx = find_table_index(td, tag);
219
220    if (idx < 0) {
221        idx = td->num_tables;
222        td->num_tables++;
223        td->tables = RENEW(td->tables, td->num_tables, struct sfnt_table);
224        memcpy(td->tables[idx].tag, tag, 4);
225    }
226
227    td->tables[idx].check_sum = sfnt_calc_checksum(data, length);
228    td->tables[idx].offset = 0L;
229    td->tables[idx].length = length;
230    td->tables[idx].data = data;
231
232    return;
233}
234
235@ @c
236ULONG sfnt_find_table_len(sfnt * sfont, const char *tag)
237{
238    ULONG length;
239    struct sfnt_table_directory *td;
240    int idx;
241
242    ASSERT(sfont && tag);
243
244    td = sfont->directory;
245    idx = find_table_index(td, tag);
246    if (idx < 0)
247        length = 0;
248    else {
249        length = td->tables[idx].length;
250    }
251
252    return length;
253}
254
255@ @c
256ULONG sfnt_find_table_pos(sfnt * sfont, const char *tag)
257{
258    ULONG offset;
259    struct sfnt_table_directory *td;
260    int idx;
261
262    ASSERT(sfont && tag);
263
264    td = sfont->directory;
265    idx = find_table_index(td, tag);
266    if (idx < 0)
267        offset = 0;
268    else {
269        offset = td->tables[idx].offset;
270    }
271
272    return offset;
273}
274
275@ @c
276ULONG sfnt_locate_table(sfnt * sfont, const char *tag)
277{
278    ULONG offset;
279
280    ASSERT(sfont && tag);
281
282    offset = sfnt_find_table_pos(sfont, tag);
283    if (offset == 0)
284        TT_ERROR("sfnt: table not found...");
285
286    sfnt_seek_set(sfont, (long) offset);
287
288    return offset;
289}
290
291@ @c
292int sfnt_read_table_directory(sfnt * sfont, ULONG offset)
293{
294    struct sfnt_table_directory *td;
295    unsigned long i, u_tag;
296
297    ASSERT(sfont);
298
299    if (sfont->directory)
300        release_directory(sfont->directory);
301    sfont->directory = td = NEW(1, struct sfnt_table_directory);
302
303    ASSERT(sfont->buffer);
304    sfnt_seek_set(sfont, (long) offset);
305
306    td->version = sfnt_get_ulong(sfont);
307    td->num_tables = sfnt_get_ushort(sfont);
308    td->search_range = sfnt_get_ushort(sfont);
309    td->entry_selector = sfnt_get_ushort(sfont);
310    td->range_shift = sfnt_get_ushort(sfont);
311
312    td->flags = NEW(td->num_tables, char);
313    td->tables = NEW(td->num_tables, struct sfnt_table);
314
315    for (i = 0; i < td->num_tables; i++) {
316        u_tag = sfnt_get_ulong(sfont);
317
318        convert_tag(td->tables[i].tag, u_tag);
319        td->tables[i].check_sum = sfnt_get_ulong(sfont);
320        td->tables[i].offset = sfnt_get_ulong(sfont);
321        td->tables[i].length = sfnt_get_ulong(sfont);
322        td->tables[i].data = NULL;
323
324        td->flags[i] = 0;
325    }
326
327    td->num_kept_tables = 0;
328
329    return 0;
330}
331
332@ @c
333int sfnt_require_table(sfnt * sfont, const char *tag, int must_exist)
334{
335    struct sfnt_table_directory *td;
336    int idx;
337
338    ASSERT(sfont && sfont->directory);
339
340    td = sfont->directory;
341    idx = find_table_index(td, tag);
342    if (idx < 0) {
343        if (must_exist)
344            return -1;
345    } else {
346        td->flags[idx] |= SFNT_TABLE_REQUIRED;
347        td->num_kept_tables++;
348    }
349
350    return 0;
351}
352
353
354
355@ All tables begin on four byte boundries, and pad any remaining space
356  between tables with zeros
357
358  Entries in the Table Directory must be sorted in ascending order by tag
359
360  The head table contains checksum of the whole font file.
361  To compute:  first set it to 0, sum the entire font as ULONG,
362  then store 0xB1B0AFBA - sum.
363
364@c
365#  include "font/luatexfont.h"
366#  undef MIN
367#  define MIN(a, b) (((a) < (b)) ? (a) : (b))
368#  define STREAM_COMPRESS
369
370static unsigned char wbuf[1024], padbytes[4] = { 0, 0, 0, 0 };
371
372pdf_obj *sfnt_create_FontFile_stream(sfnt * sfont)
373{
374    pdf_obj *stream;
375    struct sfnt_table_directory *td;
376    long offset, nb_read, length;
377    int i, sr;
378    char *p;
379
380    ASSERT(sfont && sfont->directory);
381
382    stream = pdf_new_stream(STREAM_COMPRESS);
383
384    td = sfont->directory;
385
386    /* Header */
387    p = (char *) wbuf;
388    p += sfnt_put_ulong(p, (LONG) td->version);
389    p += sfnt_put_ushort(p, td->num_kept_tables);
390    sr = (int) (max2floor(td->num_kept_tables) * 16);
391    p += sfnt_put_ushort(p, sr);
392    p += sfnt_put_ushort(p, log2floor(td->num_kept_tables));
393    p += sfnt_put_ushort(p, td->num_kept_tables * 16 - sr);
394
395    pdf_add_stream(stream, wbuf, 12);
396
397    /*
398     Compute start of actual tables (after headers).
399     */
400    offset = 12 + 16 * td->num_kept_tables;
401    for (i = 0; i < td->num_tables; i++) {
402        /* This table must exist in FontFile */
403        if (td->flags[i] & SFNT_TABLE_REQUIRED) {
404            if ((offset % 4) != 0) {
405                offset += 4 - (offset % 4);
406            }
407
408            p = (char *) wbuf;
409            memcpy(p, td->tables[i].tag, 4);
410            p += 4;
411            p += sfnt_put_ulong(p, (LONG) td->tables[i].check_sum);
412            p += sfnt_put_ulong(p, offset);
413            p += sfnt_put_ulong(p, (LONG) td->tables[i].length);
414            pdf_add_stream(stream, wbuf, 16);
415
416            offset = (long) (offset + (long) td->tables[i].length);
417        }
418    }
419
420    offset = 12 + 16 * td->num_kept_tables;
421    for (i = 0; i < td->num_tables; i++) {
422        if (td->flags[i] & SFNT_TABLE_REQUIRED) {
423            if ((offset % 4) != 0) {
424                length = 4 - (offset % 4);
425                pdf_add_stream(stream, padbytes, length);
426                offset += length;
427            }
428            if (!td->tables[i].data) {
429                if (!sfont->buffer)
430                {
431                    pdf_release_obj(stream);
432                    TT_ERROR("Font file not opened or already closed...");
433                    return NULL;
434                }
435
436                length = (long) td->tables[i].length;
437                sfnt_seek_set(sfont, (long) td->tables[i].offset);
438                while (length > 0) {
439                    nb_read = sfnt_read(wbuf, (int) MIN(length, 1024), sfont);
440                    if (nb_read < 0) {
441                        pdf_release_obj(stream);
442                        TT_ERROR("Reading file failed...");
443                        return NULL;
444                    } else if (nb_read > 0) {
445                        pdf_add_stream(stream, wbuf, nb_read);
446                    }
447                    length -= nb_read;
448                }
449            } else {
450                pdf_add_stream(stream,
451                               (unsigned char *) td->tables[i].data,
452                               (long) td->tables[i].length);
453                RELEASE(td->tables[i].data);
454                td->tables[i].data = NULL;
455            }
456            /* Set offset for next table */
457            offset = (long) (offset + (long) td->tables[i].length);
458        }
459    }
460
461    return stream;
462}
463