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