From 09607811ee9f819abbeca6c1366f4c447ef68314 Mon Sep 17 00:00:00 2001 From: Peter Breitenlohner Date: Mon, 8 Jul 2013 13:41:49 +0000 Subject: dvipdfm-x: Continue merging dvipdfmx and xdvipdfmx git-svn-id: svn://tug.org/texlive/trunk@31133 c570f23f-e606-0410-a88d-b1316a301751 --- Build/source/texk/dvipdfm-x/sfnt.c | 652 +++++++++++++++++++++++++++++++++++++ 1 file changed, 652 insertions(+) create mode 100644 Build/source/texk/dvipdfm-x/sfnt.c (limited to 'Build/source/texk/dvipdfm-x/sfnt.c') diff --git a/Build/source/texk/dvipdfm-x/sfnt.c b/Build/source/texk/dvipdfm-x/sfnt.c new file mode 100644 index 00000000000..727f665a389 --- /dev/null +++ b/Build/source/texk/dvipdfm-x/sfnt.c @@ -0,0 +1,652 @@ +/* + + This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. + + Copyright (C) 2002-2012 by Jin-Hwan Cho and Shunsaku Hirata, + the dvipdfmx project team. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +*/ + +/* Based on dvipdfmx-0.13.2c */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "system.h" + +#include "error.h" +#include "mem.h" +#include "mfileio.h" + +#include "sfnt.h" + +#ifdef XETEX +UNSIGNED_BYTE +ft_unsigned_byte(sfnt* f) +{ + unsigned char byte; + unsigned long length = 1; + + if (FT_Load_Sfnt_Table(f->ft_face, 0, f->loc, &byte, &length) != 0) + ERROR("sfnt: Freetype failure..."); + f->loc += 1; + + return byte; +} + +SIGNED_BYTE +ft_signed_byte(sfnt* f) +{ + int b = ft_unsigned_byte(f); + if (b >= 0x80) + b -= 0x100; + return (SIGNED_BYTE)b; +} + +UNSIGNED_PAIR +ft_unsigned_pair(sfnt* f) +{ + unsigned char buf[2]; + unsigned long length = 2; + + if (FT_Load_Sfnt_Table(f->ft_face, 0, f->loc, buf, &length) != 0) + ERROR("sfnt: Freetype failure..."); + f->loc += 2; + + return (UNSIGNED_PAIR)((unsigned)buf[0] << 8) + buf[1]; +} + +SIGNED_PAIR +ft_signed_pair(sfnt* f) +{ + int p = ft_unsigned_pair(f); + if (p >= 0x8000U) + p -= 0x10000U; + + return (SIGNED_PAIR)p; +} + +UNSIGNED_QUAD +ft_unsigned_quad(sfnt* f) +{ + unsigned char buf[4]; + unsigned long length = 4; + + if (FT_Load_Sfnt_Table(f->ft_face, 0, f->loc, buf, &length) != 0) + ERROR("sfnt: Freetype failure..."); + f->loc += 4; + + return ((unsigned long)buf[0] << 24) + ((unsigned long)buf[1] << 16) + + ((unsigned long)buf[2] << 8) + (unsigned long)buf[3]; +} + +unsigned long +ft_read(void* buf, unsigned long len, sfnt* f) +{ + unsigned long length = len; + if (FT_Load_Sfnt_Table(f->ft_face, 0, f->loc, buf, &length) != 0) + ERROR("sfnt: Freetype failure..."); + f->loc += len; + + return length; +} +#endif + +/* + * type: + * `true' (0x74727565): TrueType (Mac) + * `typ1' (0x74797031) (Mac): PostScript font housed in a sfnt wrapper + * 0x00010000: TrueType (Win)/OpenType + * `OTTO': PostScript CFF font with OpenType wrapper + * `ttcf': TrueType Collection +*/ +#define SFNT_TRUETYPE 0x00010000UL +#define SFNT_MAC_TRUE 0x74727565UL +#define SFNT_OPENTYPE 0x00010000UL +#define SFNT_POSTSCRIPT 0x4f54544fUL +#define SFNT_TTC 0x74746366UL + +#ifdef XETEX +sfnt * +sfnt_open (FT_Face face, int accept_types) +{ + sfnt *sfont; + ULONG type; + + if (!face || !FT_IS_SFNT(face)) + return NULL; + + sfont = NEW(1, sfnt); + sfont->ft_face = face; + sfont->type = 0; + sfont->loc = 0; + sfont->offset = 0; + + type = sfnt_get_ulong(sfont); + + if (type == SFNT_TRUETYPE || type == SFNT_MAC_TRUE) { + sfont->type = SFNT_TYPE_TRUETYPE; + } else if (type == SFNT_OPENTYPE) { + sfont->type = SFNT_TYPE_OPENTYPE; + } else if (type == SFNT_POSTSCRIPT) { + sfont->type = SFNT_TYPE_POSTSCRIPT; + } else if (type == SFNT_TTC) { + sfont->type = SFNT_TYPE_TTC; + } + + if ((sfont->type & accept_types) == 0) { + RELEASE(sfont); + return NULL; + } + + sfont->directory = NULL; + + return sfont; +} +#else /* not XETEX */ +sfnt * +sfnt_open (FILE *fp) +{ + sfnt *sfont; + ULONG type; + + ASSERT(fp); + + rewind(fp); + + sfont = NEW(1, sfnt); + + sfont->stream = fp; + + type = sfnt_get_ulong(sfont); + + if (type == SFNT_TRUETYPE) { + sfont->type = SFNT_TYPE_TRUETYPE; + } else if (type == SFNT_OPENTYPE) { + sfont->type = SFNT_TYPE_OPENTYPE; + } else if (type == SFNT_POSTSCRIPT) { + sfont->type = SFNT_TYPE_POSTSCRIPT; + } else if (type == SFNT_TTC) { + sfont->type = SFNT_TYPE_TTC; + } + + rewind(sfont->stream); + + sfont->directory = NULL; + sfont->offset = 0UL; + + return sfont; +} + +sfnt * +dfont_open (FILE *fp, int index) +{ + sfnt *sfont; + ULONG rdata_pos, map_pos, tags_pos, types_pos, res_pos, tag; + USHORT tags_num, types_num, i; + + ASSERT(fp); + + rewind(fp); + + sfont = NEW(1, sfnt); + + sfont->stream = fp; + + rdata_pos = sfnt_get_ulong(sfont); + map_pos = sfnt_get_ulong(sfont); + sfnt_seek_set(sfont, map_pos + 0x18); + tags_pos = map_pos + sfnt_get_ushort(sfont); + sfnt_seek_set(sfont, tags_pos); + tags_num = sfnt_get_ushort(sfont); + + for (i = 0; i <= tags_num; i++) { + tag = sfnt_get_ulong(sfont); /* tag name */ + types_num = sfnt_get_ushort(sfont); /* typefaces number */ + types_pos = tags_pos + sfnt_get_ushort(sfont); /* typefaces position */ + if (tag == 0x73666e74UL) /* "sfnt" */ + break; + } + + if (i > tags_num) { + RELEASE(sfont); + return NULL; + } + + sfnt_seek_set(sfont, types_pos); + if (index > types_num) { + ERROR("Invalid index %d for dfont.", index); + } + + for (i = 0; i <= types_num; i++) { + (void) sfnt_get_ushort(sfont); /* resource id */ + (void) sfnt_get_ushort(sfont); /* resource name position from name_list */ + res_pos = sfnt_get_ulong(sfont); /* resource flag (byte) + resource offset */ + sfnt_get_ulong(sfont); /* mbz */ + if (i == index) break; + } + + rewind(sfont->stream); + + sfont->type = SFNT_TYPE_DFONT; + sfont->directory = NULL; + sfont->offset = (res_pos & 0x00ffffffUL) + rdata_pos + 4; + + return sfont; +} +#endif + +static void +release_directory (struct sfnt_table_directory *td) +{ + long i; + + if (td) { + if (td->tables) { + for (i = 0; i < td->num_tables; i++) { + if (td->tables[i].data) + RELEASE(td->tables[i].data); + } + RELEASE(td->tables); + } + if (td->flags) + RELEASE(td->flags); + RELEASE(td); + } + + return; +} + +void +sfnt_close (sfnt *sfont) +{ + + if (sfont) { + if (sfont->directory) + release_directory(sfont->directory); + RELEASE(sfont); + } + + return; +} + +int +put_big_endian (void *s, LONG q, int n) +{ + int i; + char *p; + + p = (char *) s; + for (i = n - 1; i >= 0; i--) { + p[i] = (char) (q & 0xff); + q >>= 8; + } + + return n; +} + +/* Convert four-byte number to big endianess + * in a machine independent way. + */ +static void +convert_tag (char *tag, unsigned long u_tag) +{ + int i; + + for (i = 3; i >= 0; i--) { + tag[i] = (char) (u_tag % 256); + u_tag /= 256; + } + + return; +} + +/* + * Computes the max power of 2 <= n + */ +static unsigned +max2floor (unsigned n) +{ + int val = 1; + + while (n > 1) { + n /= 2; + val *= 2; + } + + return val; +} + +/* + * Computes the log2 of the max power of 2 <= n + */ +static unsigned +log2floor (unsigned n) +{ + unsigned val = 0; + + while (n > 1) { + n /= 2; + val++; + } + + return val; +} + +static ULONG +sfnt_calc_checksum(void *data, ULONG length) +{ + ULONG chksum = 0; + BYTE *p, *endptr; + int count = 0; + + p = (BYTE *) data; + endptr = p + length; + while (p < endptr) { + chksum += (p[0] << (8 * ( 3 - count))); + count = ((count + 1) & 3); + p++; + } + + return chksum; +} + +static int +find_table_index (struct sfnt_table_directory *td, const char *tag) +{ + int idx; + + if (!td) + return -1; + + for (idx = 0; idx < td->num_tables; idx++) { + if (!memcmp(td->tables[idx].tag, tag, 4)) + return idx; + } + + return -1; +} + +void +sfnt_set_table (sfnt *sfont, const char *tag, void *data, ULONG length) +{ + struct sfnt_table_directory *td; + int idx; + + ASSERT(sfont); + + td = sfont->directory; + idx = find_table_index(td, tag); + + if (idx < 0) { + idx = td->num_tables; + td->num_tables++; + td->tables = RENEW(td->tables, td->num_tables, struct sfnt_table); + memcpy(td->tables[idx].tag, tag, 4); + } + + td->tables[idx].check_sum = sfnt_calc_checksum(data, length); + td->tables[idx].offset = 0L; + td->tables[idx].length = length; + td->tables[idx].data = data; + + return; +} + +ULONG +sfnt_find_table_len (sfnt *sfont, const char *tag) +{ + ULONG length; + struct sfnt_table_directory *td; + int idx; + + ASSERT(sfont && tag); + + td = sfont->directory; + idx = find_table_index(td, tag); + if (idx < 0) + length = 0; + else { + length = td->tables[idx].length; + } + + return length; +} + +ULONG +sfnt_find_table_pos (sfnt *sfont, const char *tag) +{ + ULONG offset; + struct sfnt_table_directory *td; + int idx; + + ASSERT(sfont && tag); + + td = sfont->directory; + idx = find_table_index(td, tag); + if (idx < 0) + offset = 0; + else { + offset = td->tables[idx].offset; + } + + return offset; +} + +ULONG +sfnt_locate_table (sfnt *sfont, const char *tag) +{ + ULONG offset; + + ASSERT(sfont && tag); + + offset = sfnt_find_table_pos(sfont, tag); + if (offset == 0) + ERROR("sfnt: table not found..."); + + sfnt_seek_set(sfont, offset); + + return offset; +} + +int +sfnt_read_table_directory (sfnt *sfont, ULONG offset) +{ + struct sfnt_table_directory *td; + unsigned long i, u_tag; + + ASSERT(sfont); + + if (sfont->directory) + release_directory(sfont->directory); + + sfont->directory = td = NEW (1, struct sfnt_table_directory); + +#ifdef XETEX + ASSERT(sfont->ft_face); +#else + ASSERT(sfont->stream); +#endif + + sfnt_seek_set(sfont, offset); + + td->version = sfnt_get_ulong(sfont); + td->num_tables = sfnt_get_ushort(sfont); + td->search_range = sfnt_get_ushort(sfont); + td->entry_selector = sfnt_get_ushort(sfont); + td->range_shift = sfnt_get_ushort(sfont); + + td->flags = NEW(td->num_tables, char); + td->tables = NEW(td->num_tables, struct sfnt_table); + + for (i = 0; i < td->num_tables; i++) { + u_tag = sfnt_get_ulong(sfont); + + convert_tag(td->tables[i].tag, u_tag); + td->tables[i].check_sum = sfnt_get_ulong(sfont); + td->tables[i].offset = sfnt_get_ulong(sfont) + sfont->offset; + td->tables[i].length = sfnt_get_ulong(sfont); + td->tables[i].data = NULL; +//fprintf(stderr, "[%4s:%x]", td->tables[i].tag, td->tables[i].offset); + + td->flags[i] = 0; + } + + td->num_kept_tables = 0; + + return 0; +} + +int +sfnt_require_table (sfnt *sfont, const char *tag, int must_exist) +{ + struct sfnt_table_directory *td; + int idx; + + ASSERT(sfont && sfont->directory); + + td = sfont->directory; + idx = find_table_index(td, tag); + if (idx < 0) { + if (must_exist) + return -1; + } else { + td->flags[idx] |= SFNT_TABLE_REQUIRED; + td->num_kept_tables++; + } + + return 0; +} + +#include "pdfobj.h" + +/* + * o All tables begin on four byte boundries, and pad any remaining space + * between tables with zeros + * + * o Entries in the Table Directory must be sorted in ascending order by tag + * + * o The head table contains checksum of the whole font file. + * To compute: first set it to 0, sum the entire font as ULONG, + * then store 0xB1B0AFBA - sum. + */ + +static unsigned char wbuf[1024], padbytes[4] = {0, 0, 0, 0}; + +pdf_obj * +sfnt_create_FontFile_stream (sfnt *sfont) +{ + pdf_obj *stream; + pdf_obj *stream_dict; + struct sfnt_table_directory *td; + long offset, nb_read, length; + int i, sr; + char *p; + + ASSERT(sfont && sfont->directory); + + stream = pdf_new_stream(STREAM_COMPRESS); + + td = sfont->directory; + + /* Header */ + p = (char *) wbuf; + p += sfnt_put_ulong (p, td->version); + p += sfnt_put_ushort(p, td->num_kept_tables); + sr = max2floor(td->num_kept_tables) * 16; + p += sfnt_put_ushort(p, sr); + p += sfnt_put_ushort(p, log2floor(td->num_kept_tables)); + p += sfnt_put_ushort(p, td->num_kept_tables * 16 - sr); + + pdf_add_stream(stream, wbuf, 12); + + /* + * Compute start of actual tables (after headers). + */ + offset = 12 + 16 * td->num_kept_tables; + for (i = 0; i < td->num_tables; i++) { + /* This table must exist in FontFile */ + if (td->flags[i] & SFNT_TABLE_REQUIRED) { + if ((offset % 4) != 0) { + offset += 4 - (offset % 4); + } + + p = (char *) wbuf; + memcpy(p, td->tables[i].tag, 4); + p += 4; + p += sfnt_put_ulong(p, td->tables[i].check_sum); + p += sfnt_put_ulong(p, offset); + p += sfnt_put_ulong(p, td->tables[i].length); + pdf_add_stream(stream, wbuf, 16); + + offset += td->tables[i].length; + } + } + + offset = 12 + 16 * td->num_kept_tables; + for (i = 0; i < td->num_tables; i++) { + if (td->flags[i] & SFNT_TABLE_REQUIRED) { + if ((offset % 4) != 0) { + length = 4 - (offset % 4); + pdf_add_stream(stream, padbytes, length); + offset += length; + } + if (!td->tables[i].data) { +#ifdef XETEX + if (!sfont->ft_face) +#else + if (!sfont->stream) +#endif + { + pdf_release_obj(stream); + ERROR("Font file not opened or already closed..."); + return NULL; + } + + length = td->tables[i].length; + sfnt_seek_set(sfont, td->tables[i].offset); + while (length > 0) { + nb_read = sfnt_read(wbuf, MIN(length, 1024), sfont); + if (nb_read < 0) { + pdf_release_obj(stream); + ERROR("Reading file failed..."); + return NULL; + } else if (nb_read > 0) { + pdf_add_stream(stream, wbuf, nb_read); + } + length -= nb_read; + } + } else { + pdf_add_stream(stream, + td->tables[i].data, td->tables[i].length); + RELEASE(td->tables[i].data); + td->tables[i].data = NULL; + } + /* Set offset for next table */ + offset += td->tables[i].length; + } + } + + stream_dict = pdf_stream_dict(stream); + pdf_add_dict(stream_dict, + pdf_new_name("Length1"), + pdf_new_number(offset)); + + return stream; +} -- cgit v1.2.3