diff options
Diffstat (limited to 'Build/source/texk/dvipdf-x/subfont.c')
-rw-r--r-- | Build/source/texk/dvipdf-x/subfont.c | 657 |
1 files changed, 657 insertions, 0 deletions
diff --git a/Build/source/texk/dvipdf-x/subfont.c b/Build/source/texk/dvipdf-x/subfont.c new file mode 100644 index 00000000000..001dec358d3 --- /dev/null +++ b/Build/source/texk/dvipdf-x/subfont.c @@ -0,0 +1,657 @@ +/* + + 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. +*/ + +#include <errno.h> + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include "system.h" +#include "mem.h" +#include "error.h" +#include "dpxfile.h" + +#include "subfont.h" + +static int verbose = 0; +void +subfont_set_verbose (void) +{ + verbose++; +} + +/* Don't forget fontmap reading now requires information + * from SFD files. You must initialize at least sfd_file_ + * cache before starting loading of fontmaps. + */ + +/* Subfont Definition File: + * struct sfd_file_ is for storing subfont identifiers + * contained in a SFD file and for mapping string pair + * <SFD_file, Subfont_id> to internal code mapping table + * ID which is index within an array of struct sfd_rec_. + * We store code mapping tables in different place than + * struct sfd_file_. + */ +struct sfd_file_ +{ + char *ident; /* SFD file name */ + char **sub_id; /* Subfont IDs */ + + int *rec_id; /* indices within struct sfd_rec_ array "sfd_record" */ + + int max_subfonts; + int num_subfonts; +}; + +/* Mapping table */ +struct sfd_rec_ +{ + /* unsigned char misbit[32]; */ + unsigned short vector[256]; /* 0 for undefined */ +}; + +static void +init_sfd_file_ (struct sfd_file_ *sfd) +{ + sfd->ident = NULL; + sfd->sub_id = NULL; + sfd->rec_id = NULL; + sfd->max_subfonts = sfd->num_subfonts = 0; +} + +static void +clean_sfd_file_ (struct sfd_file_ *sfd) +{ + int i; + if (sfd->ident) + RELEASE(sfd->ident); + if (sfd->sub_id) { + for (i = 0; i < sfd->num_subfonts; i++) { + if (sfd->sub_id[i]) + RELEASE(sfd->sub_id[i]); + } + RELEASE(sfd->sub_id); + } + if (sfd->rec_id) + RELEASE(sfd->rec_id); + init_sfd_file_(sfd); +} + +static struct sfd_file_ *sfd_files = NULL; +static int num_sfd_files = 0, max_sfd_files = 0; + +static struct sfd_rec_ *sfd_record = NULL; +static int num_sfd_records = 0, max_sfd_records = 0; + + + +/* Another buffer... + * We want buffer size at least 7 x 256 + a + * 4096 is usually enough. + */ +#define LINE_BUF_SIZE 4096 +static char line_buf[LINE_BUF_SIZE]; + +/* Each lines describes character code mapping for each + * subfonts. '#' is start of comment. + * SFD file format uses a '\' before newline sequence + * for line-continuation. + */ +static char * +readline (char *buf, int buf_len, FILE *fp) +{ + char *r, *q, *p = buf; + int n = 0, c = 0; + + while (buf_len - n > 0 && (q = mfgets(p, buf_len - n, fp))) { + c++; + r = strchr(q, '#'); + /* Comment is converted to single wsp (followed by a newline). */ + if (r) { + *r = ' '; + *(r + 1) = '\0'; + } + if (strlen(q) == 0) + break; /* empty line */ + n += strlen(q); + q += strlen(q) - 1; + if (*q != '\\') + break; + else { /* line continued */ + n -= 1; + p = buf + n; + } + } + if (n >= buf_len - 1) { + WARN("Possible buffer overflow in reading SFD file (buffer full, size=%d bytes)", + buf_len - 1); + } + + return (c > 0 ? buf : NULL); +} + +#define clear_vector(v) if ((v)) { \ + int __i; \ + for (__i = 0; __i < 256; __i++) \ + (v)[__i] = 0; \ +} + +/* subfont_id ( integer ':' | integer '_' integer | integer )* + * + * 0x32: ==> Subsequent integers are place into slots starting at 0x32. + * 0x32: 0xA1A1 0xA1A2 ... ==> 0x32 is mappned to 0xA1A1, 0x33 to 0xA1A2 + * 0xA1A1_0xA1A5 ==> Expanded to 0xA1A1 0xA1A2 ... 0xA1A5 + */ + +/* subfont_id is already consumed here. */ +static int +read_sfd_record (struct sfd_rec_ *rec, const char *lbuf) +{ + const char *p = lbuf, *q; + char *r; + int repos = 0; + long c, v1 = 0, v2 = 0; + int curpos = 0; + int error = 0; + +#define IS_TOKSEP(c) ((c) == '\0' || isspace((c))) + for ( ; *p && isspace(*p); p++); + while (!error && *p) { + repos = 0; q = p; + v1 = strtol(p, &r, 0); + q = r; + if (q == p || + (!IS_TOKSEP(*q) && *q != ':' && *q != '_')) { + WARN("Unknown token in subfont mapping table: %c", *q); + return -1; + } + + switch (*q) { + case ':': + if (v1 < 0 || v1 > 0xff) { + WARN("Invalud value for subfont table offset: %ld", v1); + return -1; + } + repos = 1; + q++; + break; + case '_': + p = q + 1; + v2 = strtol(p, &r, 0); + q = r; + if (v1 < 0 || v1 > 0xffffL || + v2 < 0 || v2 > 0xffffL) { + WARN("Invalid value in subfont mapping table: 0x%x_0x%x", v1, v2); + return -1; + } else if (q == p || !IS_TOKSEP(*q)) { + WARN("Invalid char in subfont mapping table: %c", *q); + return -1; + } + break; + default: + if (v1 < 0 || v1 > 0xffffL) { + WARN("Invalid character code in subfont mapping table: 0x%x", v1); + return -1; + } + v2 = v1; + break; + } + + if (repos) + curpos = v1; + else { + if (v2 < v1 || curpos + (v2 - v1) > 0xff) { + WARN("Invalid range in subfont mapping: curpos=\"0x%02x\" range=\"0x%04x,0x%04x\"", + curpos, v1, v2); + return -1; + } + for (c = v1; c <= v2; c++) { + if (rec->vector[curpos] != 0) { + WARN("Subfont mapping for slot=\"0x%02x\" already defined...", curpos); + return -1; + } + ASSERT( curpos >= 0 && curpos <= 255 ); + rec->vector[curpos++] = (unsigned short) c; + } + } + for (p = q; *p && isspace(*p); p++); + } + + return error; +} + +/* Scan for subfont IDs */ +static int +scan_sfd_file (struct sfd_file_ *sfd, FILE *fp) +{ + char *id; + char *q, *p; + int n, lpos = 0; + + ASSERT( sfd && fp ); + + if (verbose > 3) { + MESG("\nsubfont>> Scanning SFD file \"%s\"...\n", sfd->ident); + } + + rewind(fp); + sfd->max_subfonts = sfd->num_subfonts = 0; + while ((p = readline(line_buf, LINE_BUF_SIZE, fp)) != NULL) { + lpos++; + for ( ; *p && isspace(*p); p++); + if (*p == 0) + continue; /* empty */ + + /* Saw non-wsp here */ + for (n = 0, q = p; *p && !isspace(*p); p++, n++); + id = NEW(n + 1, char); + memcpy(id, q, n); id[n] = '\0'; + if (sfd->num_subfonts >= sfd->max_subfonts) { + sfd->max_subfonts += 16; + sfd->sub_id = RENEW(sfd->sub_id, sfd->max_subfonts, char *); + } + + if (verbose > 3) { + MESG("subfont>> id=\"%s\" at line=\"%d\"\n", id, lpos); + } + sfd->sub_id[sfd->num_subfonts] = id; + sfd->num_subfonts++; + } + + sfd->rec_id = NEW(sfd->num_subfonts, int); + for (n = 0; n < sfd->num_subfonts; n++) { + sfd->rec_id[n] = -1; /* Not loaded yet. We do lazy loading of map definitions. */ + } + + if (verbose > 3) { + MESG("subfont>> %d entries found in SFD file \"%s\".\n", sfd->num_subfonts, sfd->ident); + } + + return 0; +} + + +/* Open SFD file and gather subfont IDs. We do not read mapping tables + * here but only read subfont IDs used in SFD file. + */ +static int +find_sfd_file (const char *sfd_name) +{ + int id = -1; + int i, error = -1; + + /* Check if we already opened SFD file */ + for (i = 0; i < num_sfd_files; i++) { + if (!strcmp(sfd_files[i].ident, sfd_name)) { + id = i; + break; + } + } + + if (id < 0) { + struct sfd_file_ *sfd = NULL; + FILE *fp; + + if (num_sfd_files >= max_sfd_files) { + max_sfd_files += 8; + sfd_files = RENEW(sfd_files, max_sfd_files, struct sfd_file_); + } + sfd = &sfd_files[num_sfd_files]; + init_sfd_file_(sfd); + sfd->ident = NEW(strlen(sfd_name) + 1, char); + strcpy(sfd->ident, sfd_name); + fp = DPXFOPEN(sfd->ident, DPX_RES_TYPE_SFD); + if (!fp) { + clean_sfd_file_(sfd); + return -1; + } + error = scan_sfd_file(sfd, fp); + DPXFCLOSE(fp); + if (!error) + id = num_sfd_files++; + else { + WARN("Error occured while reading SFD file \"%s\"", sfd_name); + clean_sfd_file_(sfd); + id = -1; + } + } + + return id; +} + +char ** +sfd_get_subfont_ids (const char *sfd_name, int *num_ids) +{ + int sfd_id; + + if (!sfd_name) + return NULL; + + sfd_id = find_sfd_file(sfd_name); + if (sfd_id < 0) + return NULL; + + if (num_ids) + *num_ids = sfd_files[sfd_id].num_subfonts; + return sfd_files[sfd_id].sub_id; +} + +/* Make sure that sfd_name does not have the extension '.sfd'. + * Mapping tables are actually read here. + */ +int +sfd_load_record (const char *sfd_name, const char *subfont_id) +{ + int rec_id = -1; + struct sfd_file_ *sfd; + FILE *fp; + int sfd_id, i, error = 0; + char *p, *q; + + if (!sfd_name || !subfont_id) + return -1; + + sfd_id = find_sfd_file(sfd_name); + if (sfd_id < 0) + return -1; + + sfd = &sfd_files[sfd_id]; + /* Check if we already loaded mapping table. */ + for (i = 0; + i < sfd->num_subfonts && strcmp(sfd->sub_id[i], subfont_id); i++); + if (i == sfd->num_subfonts) { + WARN("Subfont id=\"%s\" not exist in SFD file \"%s\"...", + subfont_id, sfd->ident); + return -1; + } else if (sfd->rec_id[i] >= 0) { + return sfd->rec_id[i]; + } + + if (verbose > 3) { + MESG("\nsubfont>> Loading SFD mapping table for <%s,%s>...", + sfd->ident, subfont_id); + } + + /* reopen */ + fp = DPXFOPEN(sfd->ident, DPX_RES_TYPE_SFD); + if (!fp) { + return -1; + /* ERROR("Could not open SFD file \"%s\"", sfd_name); */ + } + + /* Seek to record for 'sub_name'. */ + while ((p = readline(line_buf, LINE_BUF_SIZE, fp))) { + for ( ; *p && isspace(*p); p++); + if (*p == 0) + continue; /* empty line */ + + /* q = parse_ident(&p, p + strlen(p)); */ + for (q = p; *p && !isspace(*p); p++); + *p = '\0'; p++; + if (!strcmp(q, subfont_id)) { + if (num_sfd_records >= max_sfd_records) { + max_sfd_records += 16; + sfd_record = RENEW(sfd_record, max_sfd_records, struct sfd_rec_); + } + clear_vector(sfd_record[num_sfd_records].vector); + error = read_sfd_record(&sfd_record[num_sfd_records], p); + if (error) + WARN("Error occured while reading SFD file: file=\"%s\" subfont_id=\"%s\"", + sfd->ident, subfont_id); + else { + rec_id = num_sfd_records++; + } + } + } + if (rec_id < 0) { + WARN("Failed to load subfont mapping table for SFD=\"%s\" subfont_id=\"%s\"", + sfd->ident, subfont_id); + } + sfd->rec_id[i] = rec_id; + DPXFCLOSE(fp); + + if (verbose > 3) { + int __i; + if (rec_id >= 0) { + MESG(" at id=\"%d\"", rec_id); + MESG("\nsubfont>> Content of mapping table:"); + for (__i = 0; __i < 256; __i++) { + if (__i % 16 == 0) + MESG("\nsubfont>> "); + MESG(" %04x", sfd_record[rec_id].vector[__i]); + } + } + MESG("\n"); + } + + return rec_id; +} + + +/* Lookup mapping table */ +unsigned short +lookup_sfd_record (int rec_id, unsigned char c) +{ + if (!sfd_record || + rec_id < 0 || rec_id >= num_sfd_records) + ERROR("Invalid subfont_id: %d", rec_id); + return sfd_record[rec_id].vector[c]; +} + +void +release_sfd_record (void) +{ + int i; + + if (sfd_record) { + RELEASE(sfd_record); + } + if (sfd_files) { + for (i = 0; i < num_sfd_files; i++) { + clean_sfd_file_(&sfd_files[i]); + } + RELEASE(sfd_files); + } + sfd_record = NULL; + sfd_files = NULL; + num_sfd_records = max_sfd_records = 0; + num_sfd_files = max_sfd_files = 0; +} + + +#if DPXTEST +/* SFD file dumper */ +#ifdef HAVE_ICONV +#include <iconv.h> +#else +typedef int iconv_t; +#endif +#include <string.h> + +static void +dump_table (const char *sfd_name, const char *sub_name, iconv_t cd) +{ + int rec_id, i; + + rec_id = sfd_load_record(sfd_name, sub_name); + if (rec_id < 0) { + WARN("Could not load SFD mapping for \"%s\"", sub_name); + return; + } + fprintf(stdout, " <subfont id=\"%s\">\n", sub_name); + for (i = 0; i < 256; i++) { + unsigned short c = lookup_sfd_record(rec_id, i); + char *p, inbuf[2]; + char *q, outbuf[32]; + size_t r, inbufleft = 2, outbufleft = 32; + + if (c == 0) + fprintf(stdout, " <!-- %02x: undefined -->", i); + else { + fprintf(stdout, " <a bi=\"%02x\" bo=\"%02x %02x\"", i, (c >> 8) & 0xff, c & 0xff); + if (cd != (iconv_t) -1) { + p = inbuf; q = outbuf; + inbuf[0] = (c >> 8) & 0xff; + inbuf[1] = c & 0xff; +#ifdef HAVE_ICONV + r = iconv(cd, &p, &inbufleft, &q, &outbufleft); + if (r == -1) { + if (verbose) { + WARN("Conversion to Unicode failed for subfont-id=\"%s\" code=\"0x%02x\"", + sub_name, i); + WARN(">> with: %s", strerror(errno)); + } + } else { + outbuf[32-outbufleft] = 0; + fprintf(stdout, " uc=\"%s\"", outbuf); + } +#endif /* HAVE_ICONV */ + } + fprintf(stdout, " />"); + } + fprintf(stdout, "\n"); + } + fprintf(stdout, " </subfont>\n"); + return; +} + +#define subfontDefinition_DTD "\ +<!ELEMENT subfontDefinition (subfont+)>\n\ +<!ATTLIST subfontDefinition\n\ + id CDATA #REQUIRED\n\ + output-encoding CDATA #IMPLIED\n\ +>\n\ +<!ELEMENT subfont (a*)>\n\ +<!ATTLIST subfont\n\ + id CDATA #REQUIRED\n\ +>\n\ +<!ELEMENT a EMPTY>\n\ +<!ATTLIST a\n\ + bi NMTOKENS #REQUIRED\n\ + bo NMTOKENS #REQUIRED\n\ + uc CDATA #IMPLIED\n\ +>\ +" + +void +test_subfont_help (void) +{ + fprintf(stdout, "usage: subfont [options] SFD_name\n"); + fprintf(stdout, "-e, --encoding string\n"); + fprintf(stdout, " Target (output) encoding of SFD mapping is 'string'.\n"); + fprintf(stdout, " It must be an encoding name recognized by iconv.\n"); + fprintf(stdout, " With this option write Unicode character in auxiliary attribute 'uc'.\n"); + fprintf(stdout, "-s, --subfont-id string\n"); + fprintf(stdout, " Load and dump mapping table only for subfont 'string'.\n"); +} + +int +test_subfont_main (int argc, char *argv[]) +{ + char *sfd_name = NULL, *sub_name = NULL; + char *from = NULL; + int i; + iconv_t cd = (iconv_t) -1; + + for (;;) { + int c, optidx = 0; + static struct option long_options[] = { + {"encoding", 1, 0, 'e'}, /* for to-Unicode conversion */ + {"subfont-id", 1, 0, 's'}, + {"help", 0, 0, 'h'}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, "e:s:h", long_options, &optidx); + if (c == -1) + break; + + switch (c) { + case 'e': + from = optarg; + break; + case 's': + sub_name = optarg; + break; + case 'h': + test_subfont_help(); + return 0; + break; + default: + test_subfont_help(); + return -1; + break; + } + } + if (optind < argc) { + sfd_name = argv[optind++]; + } + + if (sfd_name == NULL) { + WARN("No SFD file name specified."); + test_subfont_help(); + return -1; + } + if (!from) + cd = (iconv_t) -1; + else { +#ifdef HAVE_ICONV + cd = iconv_open("utf-8", from); + if (cd == (iconv_t) -1) { + WARN("Can't open iconv conversion descriptor for %s --> utf-8", from); + return -1; + } +#else + WARN("Your system doesn't have iconv() in libc!"); +#endif + } + + fprintf(stdout, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); + fprintf(stdout, "<!DOCTYPE subfontDefinition [\n%s\n]>\n", + subfontDefinition_DTD); + fprintf(stdout, "<subfontDefinition id=\"%s\" output-encoding=\"%s\">\n", + sfd_name, from ? from : "unknown"); + if (sub_name == NULL || !strcmp(sub_name, "all")) { + char **sub_id; + int num_ids = 0; + sub_id = sfd_get_subfont_ids(sfd_name, &num_ids); + if (!sub_id) + WARN("Could not open SFD file: %s", sfd_name); + else { + for (i = 0; i < num_ids; i++) + dump_table(sfd_name, sub_id[i], cd); + } + } else { + dump_table(sfd_name, sub_name, cd); + } + fprintf(stdout, "</subfontDefinition>\n"); + +#ifdef HAVE_ICONV + if (cd != (iconv_t) -1) + iconv_close(cd); +#endif + + return 0; +} + +#endif /* DPXTEST */ |