/**************************************************************************** * * pklib.c * * FreeType font driver for METAFONT PK FONT files. * * Copyright 1996-2018 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, * modified, and distributed under the terms of the FreeType project * license, LICENSE.TXT. By continuing to use, modify, or distribute * this file you indicate that you have read the license and * understand and accept it fully. * */ #include #include FT_FREETYPE_H #include FT_INTERNAL_DEBUG_H #include FT_INTERNAL_STREAM_H #include FT_INTERNAL_OBJECTS_H #include FT_SYSTEM_H #include FT_CONFIG_CONFIG_H #include FT_ERRORS_H #include FT_TYPES_H #include "pk.h" #include "pkdrivr.h" #include "pkerror.h" /************************************************************************** * * The macro FT_COMPONENT is used in trace mode. It is an implicit * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log * messages during execution. */ #undef FT_COMPONENT #define FT_COMPONENT trace_pklib FT_Byte bits_table[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; /************************************************************************** * * PK font utility functions. * */ FT_Long pk_read_intn( FT_Stream, FT_Int ); FT_ULong pk_read_uintn( FT_Stream, FT_Int ); #define READ_UINT1( stream ) (FT_Byte)pk_read_uintn( stream, 1) #define READ_UINT2( stream ) (FT_Byte)pk_read_uintn( stream, 2) #define READ_UINT3( stream ) (FT_Byte)pk_read_uintn( stream, 3) #define READ_UINT4( stream ) (FT_Byte)pk_read_uintn( stream, 4) #define READ_UINTN( stream,n) (FT_ULong)pk_read_uintn( stream, n) #define READ_INT1( stream ) (FT_String)pk_read_intn( stream, 1) #define READ_INT2( stream ) (FT_String)pk_read_intn( stream, 2) #define READ_INT4( stream ) (FT_Long)pk_read_intn( stream, 4) /* * Reading a Number from file */ FT_ULong pk_read_uintn(FT_Stream stream, FT_Int size) { FT_ULong v,k; FT_Error error; FT_Byte tp; v = 0L; while (size >= 1) { if ( FT_READ_BYTE(tp) ) return 0; k =(FT_ULong)tp; v = v*256L + k; --size; } return v; } FT_Long pk_read_intn(FT_Stream stream, FT_Int size) { FT_Long v; FT_Byte tp; FT_Error error; FT_ULong z ; if ( FT_READ_BYTE(tp) ) return 0; z= (FT_ULong)tp; v = (FT_Long)z & 0xffL; if (v & 0x80L) v = v - 256L; --size; while (size >= 1) { if ( FT_READ_BYTE(tp) ) return 0; z= (FT_ULong)tp; v = v*256L + z; --size; } return v; } FT_Int pk_read_nyble_rest_cnt; FT_Int pk_read_nyble_max_bytes; void pk_read_nyble_init( FT_Int max ) { pk_read_nyble_rest_cnt = 0; pk_read_nyble_max_bytes = max; } FT_Int pk_read_nyble(FT_Stream stream) { static FT_Byte d; FT_Int v; switch (pk_read_nyble_rest_cnt) { case 0: d = READ_UINT1( stream ); if (--pk_read_nyble_max_bytes < 0) return -1L; v = d / 0x10; d = d % 0x10; pk_read_nyble_rest_cnt = 1; break; case 1: default: v = d; pk_read_nyble_rest_cnt = 0; break; } return v; } FT_Long pk_read_packed_number(FT_Long* repeat, FT_Stream stream, int dyn_f) { FT_Int d, n; FT_Long di; entry: d = pk_read_nyble( stream ); if (d == 0) { n = 0; do { di = pk_read_nyble( stream ); n++; } while (di == 0); for ( ; n > 0; n--) di = di*16 + pk_read_nyble( stream ); return di - 15 + (13 - dyn_f)*16 + dyn_f; } if (d <= dyn_f) return d; if (d <= 13) return (d - dyn_f - 1)*16 + pk_read_nyble( stream ) + dyn_f + 1; *repeat = 1; if (d == 14) *repeat = pk_read_packed_number(repeat, stream, dyn_f); goto entry; } FT_Int pk_read_14( FT_Stream stream, FT_Int dyn_f, FT_Int bw, FT_ULong rs, PK_Bitmap bm, FT_Long cc ) { FT_Long x, y, x8, xm; FT_Byte *bm_ptr; FT_ULong bit16_buff; FT_Int rest_bit16_buff; static FT_UInt mask_table[] = { 0xdead, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xdead }; if (rs == 0) return 0; x8 = bm->bbx_width / 8; xm = bm->bbx_width % 8; bm_ptr = bm->bitmap; bit16_buff = READ_UINT1( stream ) << 8; rest_bit16_buff = 8; --rs; for(y = 0; y < bm->bbx_height; y++) { for(x = 0; x < x8; x++) { *(bm_ptr++) = bit16_buff >> 8; rest_bit16_buff -= 8; bit16_buff = (bit16_buff << 8) & 0xffff; if (rs > 0) { bit16_buff |= (READ_UINT1( stream ) << (8 - rest_bit16_buff)); rest_bit16_buff += 8; --rs; } } if (xm != 0) { *(bm_ptr++) = (bit16_buff >> 8) & mask_table[xm]; rest_bit16_buff -= xm; bit16_buff = (bit16_buff << xm) & 0xffff; if (rest_bit16_buff < 8) { if (rs > 0) { bit16_buff |= (READ_UINT1( stream ) << (8 - rest_bit16_buff)); rest_bit16_buff += 8; --rs; } } } } return 0; } FT_Int pk_read_n14( FT_Stream stream, FT_Int dyn_f, FT_Int bw, FT_ULong rs, PK_Bitmap bm, FT_Long cc ) { FT_Long x, y, xx, yy, repeat; FT_Int bits, b_p; FT_Byte *p, *p0, *p1; pk_read_nyble_init(rs); p = bm->bitmap; bw = 1-bw; bits = 0; for (y = 0; y < bm->bbx_height; ) { b_p = 0; repeat = 0; p0 = p; for (x = 0; x < bm->bbx_width; x++) { if (bits == 0) { bw = 1-bw; if ((bits = pk_read_packed_number(&repeat, stream, dyn_f)) < 0) return -1; } if (bw == 1) *p = *p | bits_table[b_p]; --bits; if (++b_p >= 8) { b_p = 0; p++; } } if (b_p != 0) p++; y++; for (yy = 0; yy < repeat; yy++) { p1 = p0; for (xx = 0; xx < bm->raster; xx++) *(p++) = *(p1++); y++; } } return 0; } /************************************************************************** * * API. * */ FT_LOCAL_DEF( FT_Error ) pk_load_font(FT_Stream stream, FT_Memory extmemory, PK_Glyph *goptr ) { PK_Glyph go; FT_Byte instr, pre, id;; FT_ULong ds, check_sum, hppp, vppp, k; FT_UInt flag, dny_f, bw, ess, size; FT_ULong cc, tfm, dx, dy, dm, w, h, rs; FT_Long hoff, voff, mv_x, mv_y, gptr; FT_Int bc, ec, nchars, index, i; FT_Error error = FT_Err_Ok; FT_Memory memory = extmemory; /* needed for FT_NEW */ go = NULL; nchars = -1; if( FT_STREAM_SEEK( 0 ) ) goto Exit; pre = READ_UINT1( stream ); if (pre != PK_PRE) { error = FT_THROW( Unknown_File_Format ); goto Exit; } id = READ_UINT1( stream ); if (id != PK_ID) { error = FT_THROW( Unknown_File_Format ); goto Exit; } k = READ_UINT1( stream ); if ( FT_STREAM_SKIP( k ) ) goto Exit; ds = READ_INT4( stream ); check_sum = READ_INT4( stream ); hppp = READ_INT4( stream ); vppp = READ_INT4( stream ); gptr = stream->pos; #if 0 /* read min & max char code */ bc = 256; ec = -1; for (;;) { instr = READ_UINT1( stream ); if (instr == PK_POST) break; switch ((int) instr) { case PK_XXX1: k = (FT_ULong)READ_UINT1( stream ); if ( FT_STREAM_SKIP( k ) ) goto Exit; break; case PK_XXX2: k = (FT_ULong)READ_UINT2( stream ); if ( FT_STREAM_SKIP( k ) ) goto Exit; break; case PK_XXX3: k = (FT_ULong)READ_UINT3( stream ); if ( FT_STREAM_SKIP( k ) ) goto Exit; break; case PK_XXX4: k = (FT_ULong)READ_UINT4( stream ); if ( FT_STREAM_SKIP( k ) ) goto Exit; break; case PK_YYY: if ( FT_STREAM_SKIP( 4 ) ) goto Exit; break; case PK_NO_OP: break; default: size = instr & 0x3; instr >>= 2; ess = instr & 0x1; if (ess == 0) { /* short */ rs = (FT_ULong)(size*256) + (FT_ULong)READ_UINT1( stream ); cc = (FT_ULong)READ_UINT1( stream ); } else if ((ess == 1) && (size != 3)) { /* extended short */ rs = (FT_ULong)(size*65536) + (FT_ULong)READ_UINT2( stream ); cc = (FT_ULong)READ_UINT1( stream ); } else { /* standard */ rs = READ_UINT4( stream ); cc = (FT_ULong)READ_UINT4( stream ); } if ( FT_STREAM_SKIP( rs ) ) goto Exit; if (cc < bc) bc = cc; if (cc > ec) ec = cc; break; } } #else bc = 0; ec = 255; #endif nchars = ec - bc + 1; if( FT_ALLOC(go, sizeof(PK_GlyphRec)) ) goto Exit; if( FT_ALLOC_MULT(go->bm_table, sizeof(PK_BitmapRec), nchars) ) goto Exit; for (i = 0; i < nchars; i++) go->bm_table[i].bitmap = NULL; go->ds = (FT_UInt)ds/(1<<20); go->hppp = (FT_UInt)hppp/(1<<16); go->vppp = (FT_UInt)vppp/(1<<16); go->font_bbx_w = 0; go->font_bbx_h = 0; go->font_bbx_xoff = 0; go->font_bbx_yoff = 0; go->code_min = bc; go->code_max = ec; /* read glyphs */ if( FT_STREAM_SEEK( gptr ) ) goto Exit; for (;;) { if ((instr = READ_UINT1( stream )) == PK_POST) break; switch ((FT_Int)instr) { case PK_XXX1: k = (FT_ULong)READ_UINT1( stream ); if ( FT_STREAM_SKIP( k ) ) goto Exit; break; case PK_XXX2: k = (FT_ULong)READ_UINT2( stream ); if ( FT_STREAM_SKIP( k ) ) goto Exit; break; case PK_XXX3: k = (FT_ULong)READ_UINT3( stream ); if ( FT_STREAM_SKIP( k ) ) goto Exit; break; case PK_XXX4: k = (FT_ULong)READ_UINT4( stream ); if ( FT_STREAM_SKIP( k ) ) goto Exit; break; case PK_YYY: if ( FT_STREAM_SKIP( 4 ) ) goto Exit; break; case PK_NO_OP: break; default: flag = instr; size = flag % 0x04; flag = flag >> 2; ess = flag % 0x02; flag = flag >> 1; bw = flag % 0x02; flag = flag >> 1; dny_f = flag % 0x10; if (ess == 0) { /* short */ rs = (FT_ULong)(size*256) + (FT_ULong)READ_UINT1( stream ) - (FT_ULong)8; cc = (FT_ULong)READ_UINT1( stream ); tfm = (FT_ULong)READ_UINT3( stream ); dm = (FT_ULong)READ_UINT1( stream ); w = (FT_ULong)READ_UINT1( stream ); h = (FT_ULong)READ_UINT1( stream ); hoff = (FT_Long)READ_INT1( stream ); voff = (FT_Long)READ_INT1( stream ); mv_x = dm; mv_y = 0; } else if ((ess == 1) && (size != 3)) { /* extended short */ rs = (FT_ULong)(size*65536) + (FT_ULong)READ_UINT2( stream ) - (FT_ULong)13; cc = (FT_ULong)READ_UINT1( stream ); tfm = (FT_ULong)READ_UINT3( stream ); dm = (FT_ULong)READ_UINT2( stream ); w = (FT_ULong)READ_UINT2( stream ); h = (FT_ULong)READ_UINT2( stream ); hoff = (FT_Long)READ_INT2( stream ); voff = (FT_Long)READ_INT2( stream ); mv_x = dm; mv_y = 0; } else { /* standard */ rs = READ_UINT4( stream ) - (FT_ULong)28; cc = READ_UINT4( stream ); tfm = READ_UINT4( stream ); dx = READ_UINT4( stream ); dy = READ_UINT4( stream ); w = READ_UINT4( stream ); h = READ_UINT4( stream ); hoff = READ_INT4( stream ); voff = READ_INT4( stream ); mv_x = (FT_UInt)dx/(FT_UInt)(1<<16); mv_y = (FT_UInt)dy/(FT_UInt)(1<<16); } if ((cc < go->code_min) || (go->code_max < cc)) { error = FT_THROW( Invalid_File_Format ); goto Exit; } index = cc - go->code_min; go->bm_table[index].bbx_width = w; go->bm_table[index].bbx_height = h; go->bm_table[index].raster = (w+7)/8; go->bm_table[index].off_x = -hoff; go->bm_table[index].off_y = voff; go->bm_table[index].mv_x = mv_x; go->bm_table[index].mv_y = mv_y; go->bm_table[index].bitmap = (unsigned char*)malloc(h*((w+7)/8)); if (go->bm_table[index].bitmap == NULL) { error = FT_THROW( Invalid_File_Format ); goto Exit; } memset(go->bm_table[index].bitmap, 0, h*((w+7)/8)); if (dny_f == 14) { if (pk_read_14(stream, dny_f, bw, rs, &(go->bm_table[index]), cc) < 0) { FT_ERROR(( "pk_load_font: error in `pk_read_14'\n" )); error = FT_THROW( Unknown_File_Format ); goto Exit; } } else { if (pk_read_n14(stream, dny_f, bw, rs, &(go->bm_table[index]), cc) < 0) { FT_ERROR(( "pk_load_font: error in `pk_read_n14'\n" )); error = FT_THROW( Unknown_File_Format ); goto Exit; } } if (go->font_bbx_w < w) go->font_bbx_w = w; if (go->font_bbx_h < h) go->font_bbx_h = h; if (go->font_bbx_xoff > -hoff) go->font_bbx_xoff = -hoff; if (go->font_bbx_yoff > (voff - h)) go->font_bbx_yoff = (voff - h); } } *goptr = go; return error; Exit: if (go != NULL) { for (i = 0; i < nchars; i++) { if (go->bm_table[i].bitmap != NULL) FT_FREE(go->bm_table[i].bitmap); } FT_FREE(go->bm_table); FT_FREE(go); } return error; } FT_LOCAL_DEF( void ) pk_free_font( PK_Face face ) { FT_Memory memory = FT_FACE( face )->memory; PK_Glyph go = face->pk_glyph; FT_UInt nchars = FT_FACE( face )->num_glyphs,i; if ( !go ) return; if( go->bm_table ) { for (i = 0; i < nchars; i++) { if (go->bm_table[i].bitmap != NULL) FT_FREE(go->bm_table[i].bitmap); } } FT_FREE(go->bm_table); FT_FREE(go); } /* END */