| /**************************************************************************** |
| * |
| * tfmobjs.c |
| * |
| * FreeType auxiliary TFM module. |
| * |
| * 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 <ft2build.h> |
| #include FT_FREETYPE_H |
| #include FT_INTERNAL_STREAM_H |
| #include FT_INTERNAL_DEBUG_H |
| #include FT_INTERNAL_TFM_H |
| |
| #include "tfmobjs.h" |
| #include "tfmmod.h" |
| #include "tfmerr.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_tfmobjs |
| |
| /************************************************************************** |
| * |
| * Global TFM parameters. |
| * |
| */ |
| #define tfm_size 30000 /* maximum length of tfm data, in bytes */ |
| #define lig_size 5000 /* maximum length of lig kern program, in words */ |
| #define hash_size 5003 |
| |
| /************************************************************************** |
| * |
| * TFM font utility functions. |
| * |
| */ |
| |
| long tfm_read_intn(FT_Stream,int); |
| unsigned long tfm_read_uintn(FT_Stream,int); |
| |
| #define READ_UINT1( stream ) (FT_ULong)tfm_read_uintn( stream, 1) |
| #define READ_UINT2( stream ) (FT_ULong)tfm_read_uintn( stream, 2) |
| #define READ_UINT4( stream ) (FT_ULong)tfm_read_uintn( stream, 4) |
| #define READ_INT4( stream ) (FT_Long)tfm_read_intn( stream, 4) |
| |
| /* |
| * Reading a Number from file |
| */ |
| unsigned long |
| tfm_read_uintn(FT_Stream stream, int size) |
| { |
| unsigned long v,k; |
| FT_Error error = FT_Err_Ok; |
| FT_Byte tp; |
| v = 0L; |
| while (size >= 1) |
| { |
| if ( FT_READ_BYTE(tp) ) |
| return 0; |
| k =(unsigned long)tp; |
| v = v*256L + k; |
| --size; |
| } |
| return v; |
| } |
| |
| long |
| tfm_read_intn(FT_Stream stream, int size) |
| { |
| long v; |
| FT_Byte tp; |
| FT_Error error= FT_Err_Ok; |
| unsigned long z ; |
| if ( FT_READ_BYTE(tp) ) |
| return 0; |
| z= (unsigned long)tp; |
| v = (long)z & 0xffL; |
| if (v & 0x80L) |
| v = v - 256L; |
| --size; |
| while (size >= 1) |
| { |
| if ( FT_READ_BYTE(tp) ) |
| return 0; |
| z= (unsigned long)tp; |
| v = v*256L + z; |
| --size; |
| } |
| return v; |
| } |
| |
| /************************************************************************** |
| * |
| * API. |
| * |
| */ |
| |
| FT_LOCAL_DEF( FT_Error ) |
| tfm_init( TFM_Parser parser, |
| FT_Memory memory, |
| FT_Stream stream ) |
| { |
| parser->memory = memory; |
| parser->stream = stream; |
| parser->FontInfo = NULL; |
| parser->user_data = NULL; |
| |
| return FT_Err_Ok; |
| } |
| |
| |
| FT_LOCAL( void ) |
| tfm_close( TFM_Parser parser ) |
| { |
| FT_UNUSED( parser ); |
| |
| /* nothing */ |
| } |
| |
| |
| FT_LOCAL_DEF( FT_Error ) |
| tfm_parse_metrics( TFM_Parser parser ) |
| { |
| FT_Memory memory = parser->memory; |
| TFM_FontInfo fi = parser->FontInfo; |
| FT_Stream stream = parser->stream; |
| FT_Error error = FT_ERR( Syntax_Error ); |
| |
| FT_ULong lf, lh, nc, nci; |
| FT_ULong offset_char_info, offset_param; |
| FT_ULong nw, nh, nd, ni, nl, nk, ne, np, bc, ec; |
| |
| FT_Long *w, *h, *d; |
| FT_ULong *ci, v; |
| |
| FT_ULong i; |
| FT_Long bbxw, bbxh, xoff, yoff; |
| |
| if ( !fi ) |
| return FT_THROW( Invalid_Argument ); |
| |
| fi->width = NULL; |
| fi->height = NULL; |
| fi->depth = NULL; |
| ci = NULL; |
| w = NULL; |
| h = NULL; |
| d = NULL; |
| |
| fi->font_bbx_w = 0.0; |
| fi->font_bbx_h = 0.0; |
| fi->font_bbx_xoff = 0.0; |
| fi->font_bbx_yoff = 0.0; |
| |
| if( FT_STREAM_SEEK( 0 ) ) |
| return error; |
| |
| /* Checking the correctness of the TFM file */ |
| if( READ_UINT1( stream ) > 127 ) |
| { |
| FT_ERROR(( "Malformed TFM file: The first byte of the input file exceeds 127!\n" )); |
| error = FT_THROW( Unknown_File_Format ); |
| goto Exit; |
| } |
| |
| if( FT_STREAM_SEEK( 0 ) ) |
| return error; |
| |
| lf = READ_UINT2( stream ); |
| lh = READ_UINT2( stream ); |
| bc = READ_UINT2( stream ); |
| ec = READ_UINT2( stream ); |
| nw = READ_UINT2( stream ); |
| nh = READ_UINT2( stream ); |
| nd = READ_UINT2( stream ); |
| ni = READ_UINT2( stream ); |
| nl = READ_UINT2( stream ); |
| nk = READ_UINT2( stream ); |
| ne = READ_UINT2( stream ); |
| np = READ_UINT2( stream ); |
| |
| /* Uncomment this to check for the tfm file's header info if this program returns malformed tfm file */ |
| /* |
| FT_TRACE6(( "tfm_parse_metrics: First 24 bytes in the tfm file:\n" |
| " lf : %ld\n" |
| " lh : %ld\n" |
| " bc : %d\n" |
| " ec : %d\n" |
| " nw : %d\n" |
| " nh : %d\n" |
| " nd : %d\n" |
| " ni : %d\n" |
| " nl : %d\n" |
| " nk : %d\n" |
| " ne : %d\n" |
| " np : %d\n", lf, lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np )); |
| */ |
| |
| if( lf == 0 || ((4*lf) - 1) > tfm_size) |
| { |
| FT_ERROR(( "Malformed TFM file: The file claims to have length zero, but that's impossible!\n" )); |
| error = FT_THROW( Unknown_File_Format ); |
| goto Exit; |
| } |
| |
| if(lh < 2) |
| { |
| FT_ERROR(( "Malformed TFM file: The header length is only %ld\n",lh )); |
| error = FT_THROW( Unknown_File_Format ); |
| goto Exit; |
| } |
| |
| if( nl > lig_size ) |
| { |
| FT_ERROR(( "Malformed TFM file: The lig/kern program is longer than I can handle!\n" )); |
| error = FT_THROW( Unknown_File_Format ); |
| goto Exit; |
| } |
| |
| if( ne > 256 ) |
| { |
| FT_ERROR(( "Malformed TFM file: There are %ld extensible recipes!\n",ne )); |
| error = FT_THROW( Unknown_File_Format ); |
| goto Exit; |
| } |
| |
| if ( ((signed)(fi->begin_char-1) > (signed)fi->end_char) || |
| ( fi->end_char > 255) || |
| ( ne > 256 ) ) |
| { |
| FT_ERROR(( "tfm_parse_metrics: Incorrect header information in `tfm' file.\n" )); |
| error = FT_THROW( Unknown_File_Format ); |
| goto Exit; |
| } |
| |
| if ( lf != 6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np ) |
| { |
| FT_ERROR(( "tfm_parse_metrics: Incorrect header information in `tfm' file.\n" )); |
| error = FT_THROW( Unknown_File_Format ); |
| goto Exit; |
| } |
| |
| fi->begin_char = bc; |
| fi->end_char = ec; |
| fi->cs = READ_INT4( stream ); /* Check Sum */ |
| fi->ds = READ_INT4( stream ); /* Design Size */ |
| fi->design_size = (FT_ULong)((double)(fi->ds)/(double)(1<<20)); |
| |
| if( fi->cs <= 0 ) |
| { |
| error = FT_THROW( Unknown_File_Format ); |
| goto Exit; |
| } |
| |
| nc = fi->end_char - fi->begin_char + 1; |
| nci = nc; |
| |
| ci = (FT_ULong*)calloc(nci, sizeof(FT_ULong)); |
| w = (FT_Long*)calloc(nw, sizeof(FT_ULong)); |
| h = (FT_Long*)calloc(nh, sizeof(FT_ULong)); |
| d = (FT_Long*)calloc(nd, sizeof(FT_ULong)); |
| |
| if ((ci == NULL) || (w == NULL) || (h == NULL) || (d == NULL)) |
| { |
| error = FT_THROW( Invalid_Argument ); |
| goto Exit; |
| } |
| |
| offset_char_info = 4*(6+lh); |
| if( FT_STREAM_SEEK( offset_char_info ) ) /* Skip over coding scheme and font family name */ |
| goto Exit; |
| |
| for (i = 0; i < nci; i++) |
| ci[i] = READ_UINT4( stream ); |
| |
| offset_param = stream->pos + 4*(nw + nh + nd + ni + nl + nk + ne); |
| |
| for (i = 0; i < nw; i++) |
| w[i] = READ_INT4( stream ); |
| for (i = 0; i < nh; i++) |
| h[i] = READ_INT4( stream ); |
| for (i = 0; i < nd; i++) |
| d[i] = READ_INT4( stream ); |
| |
| fi->width = (FT_Long*)calloc(nc, sizeof(FT_Long)); |
| fi->height = (FT_Long*)calloc(nc, sizeof(FT_Long)); |
| fi->depth = (FT_Long*)calloc(nc, sizeof(FT_Long)); |
| |
| if ((fi->width == NULL) || (fi->height == NULL) || (fi->depth == NULL)) |
| { |
| error = FT_THROW( Invalid_Argument ); |
| goto Exit; |
| } |
| |
| bbxw = 0; |
| bbxh = 0; |
| xoff = 0; |
| yoff = 0; |
| |
| for (i = 0; i < nc; i++) |
| { |
| v = ci[i] / 0x10000L; |
| fi->depth[i] = d[v & 0xf]; v >>= 4; |
| fi->height[i] = h[v & 0xf]; v >>= 4; |
| fi->width[i] = w[v & 0xff]; |
| |
| if (bbxw < fi->width[i]) |
| bbxw = fi->width[i]; |
| |
| if (bbxh < (fi->height[i] + fi->depth[i])) |
| bbxh = fi->height[i] + fi->depth[i]; |
| |
| if (yoff > -fi->depth[i]) |
| yoff = -fi->depth[i]; |
| } |
| |
| fi->font_bbx_w = (FT_ULong)(fi->design_size * ((double)bbxw / (double)(1<<20))); |
| fi->font_bbx_h = (FT_ULong)(fi->design_size * ((FT_ULong)bbxh / (double)(1<<20))); |
| fi->font_bbx_xoff = (FT_ULong)(fi->design_size * ((double)xoff / (double)(1<<20))); |
| fi->font_bbx_yoff = (FT_ULong)(fi->design_size * ((double)yoff / (double)(1<<20))); |
| |
| if( FT_STREAM_SEEK( offset_param ) ) |
| return error; |
| if (FT_READ_ULONG(fi->slant) ) |
| return error; |
| fi->slant = (FT_ULong)((double)fi->slant/(double)(1<<20)); |
| |
| Exit: |
| FT_FREE(ci); |
| FT_FREE(w); |
| FT_FREE(h); |
| FT_FREE(d); |
| return error; |
| } |
| |
| |
| /* END */ |