summaryrefslogtreecommitdiff
path: root/pl/pllfont.c
diff options
context:
space:
mode:
Diffstat (limited to 'pl/pllfont.c')
-rw-r--r--pl/pllfont.c389
1 files changed, 389 insertions, 0 deletions
diff --git a/pl/pllfont.c b/pl/pllfont.c
new file mode 100644
index 000000000..bfc95194e
--- /dev/null
+++ b/pl/pllfont.c
@@ -0,0 +1,389 @@
+/* Portions Copyright (C) 2001 artofcode LLC.
+ Portions Copyright (C) 1996, 2001 Artifex Software Inc.
+ Portions Copyright (C) 1988, 2000 Aladdin Enterprises.
+ This software is based in part on the work of the Independent JPEG Group.
+ All Rights Reserved.
+
+ This software is distributed under license and may not be copied, modified
+ or distributed except as expressly authorized under the terms of that
+ license. Refer to licensing information at http://www.artifex.com/ or
+ contact Artifex Software, Inc., 101 Lucas Valley Road #110,
+ San Rafael, CA 94903, (415)492-9861, for further information. */
+/*$Id$ */
+
+/* pclfont.c */
+/* PCL5 font preloading */
+#include "ctype_.h"
+#include "stdio_.h"
+#include "string_.h"
+/* The following are all for gxfont42.h, except for gp.h. */
+#include "gx.h"
+#include "gp.h"
+#include "gsccode.h"
+#include "gserrors.h"
+#include "gsmatrix.h"
+#include "gsutil.h"
+#include "gxfont.h"
+#include "gxfont42.h"
+#include "strmio.h"
+#include "plfont.h"
+#include "pldict.h"
+#include "pllfont.h"
+#include "plftable.h"
+#include "plvalue.h"
+
+/* Load some built-in fonts. This must be done at initialization time, but
+ * after the state and memory are set up. Return an indication of whether
+ * at least one font was successfully loaded. XXX The existing code is more
+ * than a bit of a hack. Approach: expect to find some fonts in one or more
+ * of a given list of directories with names *.ttf. Load whichever ones are
+ * found in the table below. Probably very little of this code can be
+ * salvaged for later.
+ */
+
+/* utilities for poking around in tt files. It returns true if it a tt
+ file, false if not. Also returns false if there are any I/O
+ failures */
+static bool
+is_ttfile(stream *ttfile)
+{
+ /* check if an open file a ttfile saving and restoring the file position */
+ long pos; /* saved file position */
+ byte buffer[4]; /* version number buffer */
+ bool is_tt; /* true if a tt file */
+ if ( (pos = sftell( ttfile )) < 0 )
+ return false;
+ /* seek to beginning */
+ if ( sfseek( ttfile, 0L, SEEK_SET ) )
+ return false;
+ /* read 4 byte version number */
+ is_tt = false;
+ if ( ( sfread( &buffer, 1, 4, ttfile ) == 4 ) &&
+ ( pl_get_uint32( buffer ) == 0x10000 ) )
+ is_tt = true;
+ /* restore the file position */
+ if ( sfseek( ttfile, pos, SEEK_SET ) < 0 )
+ return false;
+ return is_tt;
+}
+
+/* get the windows truetype font file name - position 4 in the name
+ table. Assumes file is a reasonable tt_file - use is_ttfile() to
+ check before calling this procedure. */
+#define WINDOWSNAME 4
+#define PSNAME 6
+
+static
+int get_name_from_tt_file(stream *tt_file, gs_memory_t *mem, char *pfontfilename, int nameoffset)
+{
+ /* check if an open file a ttfile saving and restoring the file position */
+ long pos; /* saved file position */
+ unsigned long len;
+ char *ptr = pfontfilename;
+ byte *ptt_font_data;
+
+ if ( (pos = sftell( tt_file )) < 0 )
+ return -1;
+ /* seek to end and get the file length and allocate a buffer
+ for the entire file */
+ if ( sfseek( tt_file, 0L, SEEK_END ) )
+ return -1;
+ len = sftell( tt_file );
+
+ /* allocate a buffer for the entire file */
+ ptt_font_data = gs_alloc_bytes( mem, len, "get_name_from_tt_file" );
+ if ( ptt_font_data == NULL )
+ return_error(gs_error_VMerror );
+
+ /* seek back to the beginning of the file and read the data
+ into the buffer */
+ if ( ( sfseek( tt_file, 0L, SEEK_SET ) == 0 ) &&
+ ( sfread( ptt_font_data, 1, len, tt_file ) == len ) )
+ ; /* ok */
+ else {
+ gs_free_object( mem, ptt_font_data, "get_name_from_tt_file" );
+ return -1;
+ }
+
+ {
+ /* find the "name" table */
+ byte *pnum_tables_data = ptt_font_data + 4;
+ byte *ptable_directory_data = ptt_font_data + 12;
+ int table;
+ for ( table = 0; table < pl_get_uint16( pnum_tables_data ); table++ )
+ if ( !memcmp( ptable_directory_data + (table * 16), "name", 4 ) ) {
+ unsigned int offset =
+ pl_get_uint32( ptable_directory_data + (table * 16) + 8 );
+ byte *name_table = ptt_font_data + offset;
+ /* the offset to the string pool */
+ unsigned short storageOffset = pl_get_uint16( name_table + 4 );
+ byte *name_recs = name_table + 6;
+ {
+ /* 4th entry in the name table - the complete name */
+ unsigned short length =
+ pl_get_uint16( name_recs + (12 * nameoffset) + 8 );
+ unsigned short offset =
+ pl_get_uint16( name_recs + (12 * nameoffset) + 10 );
+ int k;
+ for ( k = 0; k < length; k++ ) {
+ /* hack around unicode if necessary */
+ int c = name_table[storageOffset + offset + k];
+ if ( isprint( c ) )
+ *ptr++ = (char)c;
+ }
+ }
+ break;
+ }
+ }
+ /* free up the data and restore the file position */
+ gs_free_object( mem, ptt_font_data, "get_name_from_tt_file" );
+ if ( sfseek( tt_file, pos, SEEK_SET ) < 0 )
+ return -1;
+ /* null terminate the fontname string and return success. Note
+ the string can be 0 length if no fontname was found. */
+ *ptr = '\0';
+
+ /* trim trailing white space */
+ {
+ int i = strlen(pfontfilename);
+ while (--i >= 0) {
+ if (!isspace(pfontfilename[i]))
+ break;
+ }
+ pfontfilename[++i] = '\0';
+ }
+
+ return 0;
+}
+
+#ifdef DEBUG
+static bool
+lookup_pjl_number(pl_dict_t *pfontdict, int pjl_font_number)
+{
+ pl_dict_enum_t dictp;
+ gs_const_string key;
+ void *value;
+ pl_dict_enum_begin(pfontdict, &dictp);
+ while ( pl_dict_enum_next(&dictp, &key, &value) ) {
+ pl_font_t *plfont = value;
+ if (plfont->params.pjl_font_number == pjl_font_number)
+ return true;
+ }
+ return false;
+}
+
+static void
+check_resident_fonts(pl_dict_t *pfontdict, gs_memory_t *mem)
+{
+ int i;
+ for (i = 0;
+ strlen(resident_table[i].full_font_name) != 0;
+ i ++)
+ if (!lookup_pjl_number(pfontdict, i)) {
+ int j;
+ dprintf2("%s (entry %d) not found\n", resident_table[i].full_font_name, i);
+ dprintf("pxl unicode name:");
+ for (j = 0;
+ j < sizeof(resident_table[i].unicode_fontname);
+ j++)
+ dprintf1("'%c'", resident_table[i].unicode_fontname[j]);
+ dprintf("\n");
+ }
+}
+#endif
+
+/* NOTES ABOUT NB NB - if the font dir necessary */
+ int
+pl_load_built_in_fonts(const char *pathname, gs_memory_t *mem,
+ pl_dict_t *pfontdict, gs_font_dir *pdir,
+ int storage, bool use_unicode_names_for_keys)
+{
+ const font_resident_t *residentp;
+ /* get rid of this should be keyed by pjl font number */
+ byte key[3];
+ bool one_font_found = false;
+
+ if ( pathname == NULL ) {
+ /* no font pathname */
+ return 0;
+ }
+ /* don't load fonts more than once */
+ if (pl_dict_length(pfontdict, true) > 0 ) {
+ return true;
+ }
+
+ /* Enumerate through the files in the path */
+ {
+ /* max pathname of 1024 including pattern */
+ char tmp_path_copy[1024];
+ char *tmp_pathp;
+ const char pattern[] = "*";
+ /* make a copy of the path for strtok */
+ strcpy( tmp_path_copy, pathname );
+ for ( tmp_pathp = tmp_path_copy;
+ (tmp_pathp = strtok( tmp_pathp, ";" ) ) != NULL; /* NB shouldn't use strtok */
+ tmp_pathp = NULL ) {
+ int code;
+ file_enum *fe;
+ stream *in = NULL;
+
+ /* handle trailing separator */
+ bool append_separator = false;
+ int separator_length = strlen(gp_file_name_directory_separator());
+ int offset = strlen(tmp_pathp) - separator_length;
+ /* make sure the filename string ends in directory separator */
+ if (strcmp(tmp_pathp + offset, gp_file_name_directory_separator()) != 0)
+ append_separator = true;
+
+ /* concatenate path and pattern */
+ if ( (strlen( pattern ) +
+ strlen( tmp_pathp) + 1 ) +
+ (append_separator ? separator_length : 0) > sizeof( tmp_path_copy ) ) {
+ dprintf1("path name %s too long\n", tmp_pathp );
+ continue;
+ }
+
+ strcpy( tmp_path_copy, tmp_pathp );
+
+ if (append_separator == true)
+ strcat(tmp_path_copy, gp_file_name_directory_separator());
+
+ /* NOTE the gp code code takes care of converting * to *.* */
+ strcat( tmp_path_copy, pattern );
+
+ /* enumerate all files on the current path */
+ fe = gp_enumerate_files_init( tmp_path_copy,
+ strlen( tmp_path_copy ), mem );
+
+ /* loop through the files */
+ while ( ( code = gp_enumerate_files_next( fe,
+ tmp_path_copy,
+ sizeof( tmp_path_copy ) ) ) >= 0 ) {
+ char buffer[1024];
+
+
+ pl_font_t *plfont;
+
+ /* loop failed/continued and left the file open */
+ if ( in != NULL )
+ sfclose( in );
+
+ if ( code > sizeof( tmp_path_copy ) ) {
+ dprintf("filename length exceeds file name storage buffer length\n");
+ continue;
+ }
+ /* null terminate the string */
+ tmp_path_copy[code] = '\0';
+
+ in = sfopen( tmp_path_copy, "rb", mem);
+ if ( in == NULL ) { /* shouldn't happen */
+ dprintf1("cannot open file %s\n", tmp_path_copy );
+ continue;
+ }
+
+ if ( !is_ttfile( in ) ) {
+ #ifdef DEBUG
+ if ( gs_debug_c('=') ) {
+ dprintf1("%s not a TrueType file\n", tmp_path_copy);
+ }
+ #endif
+ continue;
+ }
+ code = get_name_from_tt_file( in, mem, buffer, PSNAME);
+ if ( code < 0 ) {
+ dprintf1("input output failure on TrueType File %s\n", tmp_path_copy );
+ continue;
+ }
+
+ if ( strlen( buffer ) == 0 ) {
+ dprintf1("could not extract font file name from file %s\n", tmp_path_copy );
+ continue;
+ }
+
+ /* lookup the font file name in the resident table */
+ for ( residentp = resident_table; strlen(residentp->full_font_name); ++residentp )
+ if ( strcmp( buffer, residentp->full_font_name ) == 0 )
+ /* found it */
+ break;
+
+ /* hit sentinnel, nothing found */
+ if ( !strlen(residentp->full_font_name) ) {
+ #ifdef DEBUG
+ if ( gs_debug_c('=') ) {
+ dprintf2("TrueType font %s in file %s not found in table\n", buffer, tmp_path_copy);
+ code = get_name_from_tt_file( in, mem, buffer, WINDOWSNAME);
+ dprintf1("Windows name %s\n", buffer);
+ }
+ #endif
+ continue;
+ }
+
+ /* load the font file into memory. NOTE: this closes the file - argh... */
+ if ( pl_load_tt_font(in, pdir, mem,
+ gs_next_ids(mem, 1), &plfont,
+ buffer) < 0 ) {
+ /* vm error but we continue anyway */
+ dprintf1("Failed loading font %s\n", tmp_path_copy);
+ continue;
+ }
+
+ /* save some bookkepping in the loop, if in is not
+ NULL at the beginning we know the file was left
+ open because of an error */
+ in = NULL;
+
+ plfont->storage = storage;
+ plfont->data_are_permanent = false;
+ if ( residentp->params.symbol_set != 0 )
+ plfont->font_type = plft_8bit;
+ plfont->params = residentp->params;
+ memcpy(plfont->character_complement,
+ residentp->character_complement, 8);
+ /* use the offset in the table as the pjl font number */
+ /* for unicode keying of the dictionary use the unicode
+ font name, otherwise use the keys. */
+ if ( use_unicode_names_for_keys )
+ pl_dict_put( pfontdict, (const byte *)residentp->unicode_fontname, 32, plfont );
+ else {
+ key[2] = (byte)(residentp - resident_table);
+ key[0] = key[1] = 0;
+ pl_dict_put( pfontdict, key, sizeof(key), plfont );
+
+ }
+ /* leave data stored in the file */
+ if ( pl_store_resident_font_data_in_file( tmp_path_copy, mem, plfont ) < 0 ) {
+ dprintf1("%s could not store data", tmp_path_copy );
+ continue;
+ }
+ /* mark the font as found */
+ one_font_found = true;
+ } /* next file */
+ } /* next directory */
+ }
+#ifdef DEBUG
+ if ( gs_debug_c('=') )
+ check_resident_fonts(pfontdict, mem);
+#endif
+ if ( one_font_found )
+ return true;
+ else
+ return false;
+}
+
+/* These are not implemented */
+
+/* load simm fonts given a path */
+ int
+pl_load_simm_fonts(const char *pathname, gs_memory_t *mem, pl_dict_t *pfontdict, gs_font_dir *pdir, int storage)
+{
+ /* not implemented */
+ return 0;
+}
+
+/* load simm fonts given a path */
+ int
+pl_load_cartridge_fonts(const char *pathname, gs_memory_t *mem, pl_dict_t *pfontdict, gs_font_dir *pdir, int storage)
+{
+ /* not implemented */
+ return 0;
+}