/* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. Copyright (C) 2002-2020 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project team. Copyright (C) 1998, 1999 by Mark A. Wicks 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. */ #ifdef HAVE_CONFIG_H #include #endif #include "system.h" #include "numbers.h" #include "error.h" #include "mem.h" #include "dpxconf.h" #include "dpxfile.h" /* pdfdev... */ #include "pdfdev.h" #include "tfm.h" #include "dvi.h" #include "vf.h" #include "dvipdfmx.h" #include "dvicodes.h" #define VF_ALLOC_SIZE 16u #define VF_ID 202 #define FIX_WORD_BASE 1048576.0 #define TEXPT2PT (72.0/72.27) #define FW2PT (TEXPT2PT/((double)(FIX_WORD_BASE))) struct font_def { int32_t font_id /* id used internally in vf file */; uint32_t checksum, size, design_size; char *directory, *name; int tfm_id; /* id returned by TFM module */ int dev_id; /* id returned by DEV module */ }; struct vf { char *tex_name; spt_t ptsize; uint32_t design_size; /* A fixword-pts quantity */ int num_dev_fonts, max_dev_fonts; struct font_def *dev_fonts; unsigned char **ch_pkt, message_flag; uint32_t *pkt_len; unsigned num_chars; }; struct vf *vf_fonts = NULL; int num_vf_fonts = 0, max_vf_fonts = 0; static void read_header(FILE *vf_file, int thisfont) { /* Check for usual signature */ if (get_unsigned_byte (vf_file) == PRE && get_unsigned_byte (vf_file) == VF_ID) { /* If here, assume it's a legitimate vf file */ /* skip comment */ skip_bytes (get_unsigned_byte (vf_file), vf_file); /* Skip checksum */ skip_bytes (4, vf_file); vf_fonts[thisfont].design_size = get_positive_quad(vf_file, "VF", "design_size"); } else { /* Try to fail gracefully and return an error to caller */ fprintf (stderr, "VF file may be corrupt\n"); } } static void resize_vf_fonts(int size) { int i; if (size > max_vf_fonts) { vf_fonts = RENEW (vf_fonts, size, struct vf); for (i=max_vf_fonts; i (a_vf->num_chars)) { size = MAX (size, a_vf->num_chars+256); a_vf->ch_pkt = RENEW (a_vf->ch_pkt, size, unsigned char *); a_vf->pkt_len = RENEW (a_vf->pkt_len, size, uint32_t); for (i=a_vf->num_chars; ich_pkt)[i] = NULL; (a_vf->pkt_len)[i] = 0; } a_vf->num_chars = size; } } static void read_a_char_def(FILE *vf_file, int thisfont, uint32_t pkt_len, uint32_t ch) { unsigned char *pkt; #ifdef DEBUG fprintf (stderr, "read_a_char_def: len=%u, ch=%u\n", pkt_len, ch); #endif /* Resize and initialize character arrays if necessary */ if (ch >= vf_fonts[thisfont].num_chars) { resize_one_vf_font (vf_fonts+thisfont, ch+1); } if (pkt_len > 0) { pkt = NEW (pkt_len, unsigned char); if (fread (pkt, 1, pkt_len, vf_file) != pkt_len) ERROR ("VF file ended prematurely."); (vf_fonts[thisfont].ch_pkt)[ch] = pkt; } (vf_fonts[thisfont].pkt_len)[ch] = pkt_len; return; } static void read_a_font_def(FILE *vf_file, int32_t font_id, int thisfont) { struct font_def *dev_font; int dir_length, name_length; #ifdef DEBUG fprintf (stderr, "read_a_font_def: font_id = %d\n", font_id); #endif if (vf_fonts[thisfont].num_dev_fonts >= vf_fonts[thisfont].max_dev_fonts) { vf_fonts[thisfont].max_dev_fonts += VF_ALLOC_SIZE; vf_fonts[thisfont].dev_fonts = RENEW (vf_fonts[thisfont].dev_fonts, vf_fonts[thisfont].max_dev_fonts, struct font_def); } dev_font = vf_fonts[thisfont].dev_fonts+ vf_fonts[thisfont].num_dev_fonts; dev_font -> font_id = font_id; dev_font -> checksum = get_unsigned_quad (vf_file); dev_font -> size = get_positive_quad (vf_file, "VF", "font_size"); dev_font -> design_size = get_positive_quad (vf_file, "VF", "font_design_size"); dir_length = get_unsigned_byte (vf_file); name_length = get_unsigned_byte (vf_file); dev_font -> directory = NEW (dir_length+1, char); dev_font -> name = NEW (name_length+1, char); fread (dev_font -> directory, 1, dir_length, vf_file); fread (dev_font -> name, 1, name_length, vf_file); (dev_font -> directory)[dir_length] = 0; (dev_font -> name)[name_length] = 0; vf_fonts[thisfont].num_dev_fonts += 1; dev_font->tfm_id = tfm_open (dev_font -> name, 1); /* must exist */ dev_font->dev_id = dvi_locate_font (dev_font->name, sqxfw (vf_fonts[thisfont].ptsize, dev_font->size)); #ifdef DEBUG fprintf (stderr, "[%s/%s]\n", dev_font -> directory, dev_font -> name); #endif return; } static void process_vf_file (FILE *vf_file, int thisfont) { int eof = 0, code; int32_t font_id; while (!eof) { code = get_unsigned_byte (vf_file); switch (code) { case FNT_DEF1: case FNT_DEF2: case FNT_DEF3: case FNT_DEF4: font_id = get_unsigned_num (vf_file, code-FNT_DEF1); read_a_font_def (vf_file, font_id, thisfont); break; default: if (code < 242) { /* For a short packet, code is the pkt_len */ uint32_t ch = get_unsigned_byte (vf_file); /* Skip over TFM width since we already know it */ skip_bytes (3, vf_file); read_a_char_def (vf_file, thisfont, code, ch); break; } if (code == 242) { uint32_t pkt_len = get_positive_quad (vf_file, "VF", "pkt_len"); uint32_t ch = get_unsigned_quad (vf_file); /* Skip over TFM width since we already know it */ skip_bytes (4, vf_file); if (ch < 0x1000000U) read_a_char_def (vf_file, thisfont, pkt_len, ch); else { fprintf (stderr, "char=%u\n", ch); ERROR ("Long character (>24 bits) in VF file.\nI can't handle long characters!\n"); } break; } if (code == POST) { eof = 1; break; } fprintf (stderr, "Quitting on code=%d\n", code); eof = 1; break; } } return; } /* Unfortunately, the following code isn't smart enough to load the vf only once for multiple point sizes. You will get a separate copy of each VF in memory (and a separate opening and reading of the file) for each point size. Since VFs are pretty small, I guess this is tolerable for now. In any case, the PDF file will never repeat a physical font name */ /* Note: This code needs to be able to recurse */ /* Global variables such as num_vf_fonts require careful attention */ int vf_locate_font (const char *tex_name, spt_t ptsize) { int thisfont = -1, i; char *full_vf_file_name; FILE *vf_file; /* Has this name and ptsize already been loaded as a VF? */ for (i=0; i 1) fprintf (stderr, "(VF:%s", full_vf_file_name); if (num_vf_fonts >= max_vf_fonts) { resize_vf_fonts (max_vf_fonts + VF_ALLOC_SIZE); } thisfont = num_vf_fonts++; { /* Initialize some pointers and such */ vf_fonts[thisfont].tex_name = NEW (strlen(tex_name)+1, char); strcpy (vf_fonts[thisfont].tex_name, tex_name); vf_fonts[thisfont].ptsize = ptsize; vf_fonts[thisfont].num_chars = 0; vf_fonts[thisfont].ch_pkt = NULL; vf_fonts[thisfont].pkt_len = NULL; } read_header(vf_file, thisfont); process_vf_file (vf_file, thisfont); if (dpx_conf.verbose_level > 0) fprintf (stderr, ")"); MFCLOSE (vf_file); } if (full_vf_file_name) RELEASE(full_vf_file_name); } return thisfont; } #define next_byte() (*((*start)++)) static int unsigned_byte (unsigned char **start, unsigned char *end) { int byte = 0; if (*start < end) byte = next_byte(); else ERROR ("Premature end of DVI byte stream in VF font\n"); return byte; } static int32_t get_pkt_signed_num (unsigned char **start, unsigned char *end, unsigned char num) { int32_t val = 0; if (end-*start > num) { val = next_byte(); if (val > 0x7f) val -= 0x100; switch (num) { case 3: val = (val << 8) | next_byte(); case 2: val = (val << 8) | next_byte(); case 1: val = (val << 8) | next_byte(); default: break; } } else ERROR ("Premature end of DVI byte stream in VF font\n"); return val; } static int32_t get_pkt_unsigned_num (unsigned char **start, unsigned char *end, unsigned char num) { int32_t val = 0; if (end-*start > num) { val = next_byte(); switch (num) { case 3: if (val > 0x7f) val -= 0x100; val = (val << 8) | next_byte(); case 2: val = (val << 8) | next_byte(); case 1: val = (val << 8) | next_byte(); default: break; } } else ERROR ("Premature end of DVI byte stream in VF font\n"); return val; } static void vf_putrule (unsigned char **start, unsigned char *end, spt_t ptsize) { int32_t height = get_pkt_signed_num (start, end, 3); int32_t width = get_pkt_signed_num (start, end, 3); dvi_rule (sqxfw (ptsize, width), sqxfw (ptsize, height)); } static void vf_setrule (unsigned char **start, unsigned char *end, spt_t ptsize) { int32_t height = get_pkt_signed_num (start, end, 3); int32_t s_width = sqxfw (ptsize, get_pkt_signed_num (start, end, 3)); dvi_rule (s_width, sqxfw (ptsize, height)); dvi_right (s_width); } static void vf_fnt (int32_t font_id, int vf_font) { int i; for (i=0; i 0) WARN("VF:%s", p+8); } else { dvi_do_special(buffer, len); } } RELEASE(buffer); } else { ERROR ("Premature end of DVI byte stream in VF font."); } *start += len; return; } void vf_set_char(int32_t ch, int vf_font) { unsigned char opcode; unsigned char *start, *end; spt_t ptsize; int default_font = -1; if (vf_font < num_vf_fonts) { /* Initialize to the first font or -1 if undefined */ ptsize = vf_fonts[vf_font].ptsize; if (vf_fonts[vf_font].num_dev_fonts > 0) default_font = ((vf_fonts[vf_font].dev_fonts)[0]).dev_id; dvi_vf_init (default_font); if (ch >= vf_fonts[vf_font].num_chars || !(start = (vf_fonts[vf_font].ch_pkt)[ch])) { if (tfm_is_jfm(vf_fonts[vf_font].dev_fonts[0].tfm_id) && ch < 0x1000000 && dpx_conf.compat_mode != dpx_mode_xdv_mode) { /* fallback multibyte character for (u)pTeX */ if (dpx_conf.verbose_level == 1) if (vf_fonts[vf_font].message_flag == 0) { WARN ("Fallback multibyte character in virtual font: VF:%s to TFM:%s", vf_fonts[vf_font].tex_name, vf_fonts[vf_font].dev_fonts[0].name); vf_fonts[vf_font].message_flag = 1; } if (dpx_conf.verbose_level > 1) WARN ("Fallback multibyte character in virtual font: VF:%s char=0x%06x(%d) to TFM:%s", vf_fonts[vf_font].tex_name, ch, ch, vf_fonts[vf_font].dev_fonts[0].name); dvi_set (ch); dvi_vf_finish(); return; } fprintf (stderr, "\nchar=0x%x(%d)\n", ch, ch); fprintf (stderr, "Tried to set a nonexistent character in a virtual font"); start = end = NULL; } else { end = start + (vf_fonts[vf_font].pkt_len)[ch]; } while (start && start < end) { opcode = *(start++); #ifdef DEBUG fprintf (stderr, "VF opcode: %d", opcode); if (isprint (opcode)) fprintf (stderr, " (\'%c\')\n", opcode); else fprintf (stderr, "\n"); #endif switch (opcode) { case SET1: case SET2: case SET3: dvi_set (get_pkt_unsigned_num (&start, end, opcode-SET1)); break; case SET4: ERROR ("Multibyte (>24 bits) character in VF packet.\nI can't handle this!"); break; case SET_RULE: vf_setrule(&start, end, ptsize); break; case PUT1: case PUT2: case PUT3: dvi_put (get_pkt_unsigned_num (&start, end, opcode-PUT1)); break; case PUT4: ERROR ("Multibyte (>24 bits) character in VF packet.\nI can't handle this!"); break; case PUT_RULE: vf_putrule(&start, end, ptsize); break; case NOP: break; case PUSH: dvi_push(); break; case POP: dvi_pop(); break; case RIGHT1: case RIGHT2: case RIGHT3: case RIGHT4: dvi_right (sqxfw (ptsize, get_pkt_signed_num (&start, end, opcode-RIGHT1))); break; case W0: dvi_w0(); break; case W1: case W2: case W3: case W4: dvi_w (sqxfw (ptsize, get_pkt_signed_num (&start, end, opcode-W1))); break; case X0: dvi_x0(); break; case X1: case X2: case X3: case X4: dvi_x (sqxfw (ptsize, get_pkt_signed_num (&start, end, opcode-X1))); break; case DOWN1: case DOWN2: case DOWN3: case DOWN4: dvi_down (sqxfw (ptsize, get_pkt_signed_num (&start, end, opcode-DOWN1))); break; case Y0: dvi_y0(); break; case Y1: case Y2: case Y3: case Y4: dvi_y (sqxfw (ptsize, get_pkt_signed_num (&start, end, opcode-Y1))); break; case Z0: dvi_z0(); break; case Z1: case Z2: case Z3: case Z4: dvi_z (sqxfw (ptsize, get_pkt_signed_num (&start, end, opcode-Z1))); break; case FNT1: case FNT2: case FNT3: case FNT4: vf_fnt (get_pkt_signed_num (&start, end, opcode-FNT1), vf_font); break; case XXX1: case XXX2: case XXX3: case XXX4: { int32_t len = get_pkt_unsigned_num (&start, end, opcode-XXX1); if (len < 0) WARN("VF: Special with %d bytes???", len); else vf_xxx (len, &start, end); } break; case PTEXDIR: dvi_dirchg (unsigned_byte (&start, end)); break; default: if (opcode <= SET_CHAR_127) { dvi_set (opcode); } else if (opcode >= FNT_NUM_0 && opcode <= FNT_NUM_63) { vf_fnt (opcode - FNT_NUM_0, vf_font); } else { fprintf (stderr, "Unexpected opcode: %d\n", opcode); ERROR ("Unexpected opcode in vf file\n"); } } } dvi_vf_finish(); } else { fprintf (stderr, "vf_set_char: font: %d", vf_font); ERROR ("Font not loaded\n"); } return; } void vf_close_all_fonts(void) { int i; int j; struct font_def *one_font; for (i=0; i directory); RELEASE (one_font -> name); } if (vf_fonts[i].dev_fonts != NULL) RELEASE (vf_fonts[i].dev_fonts); } if (vf_fonts != NULL) RELEASE (vf_fonts); return; } #if defined(LIBDPX) #include "vf_ng.c" #endif /* LIBDPX */