static FT_Error load_format_20( TT_Face face, FT_Stream stream, FT_Long post_limit ) { FT_Memory memory = stream->memory; FT_Error error; FT_Int num_glyphs; FT_UShort num_names; FT_UShort* glyph_indices = 0; FT_Char** name_strings = 0; if ( FT_READ_USHORT( num_glyphs ) ) goto Exit; /* UNDOCUMENTED! The number of glyphs in this table can be smaller */ /* than the value in the maxp table (cf. cyberbit.ttf). */ /* There already exist fonts which have more than 32768 glyph names */ /* in this table, so the test for this threshold has been dropped. */ if ( num_glyphs > face->max_profile.numGlyphs ) { error = SFNT_Err_Invalid_File_Format; goto Exit; } /* load the indices */ { FT_Int n; if ( FT_NEW_ARRAY ( glyph_indices, num_glyphs ) || FT_FRAME_ENTER( num_glyphs * 2L ) ) goto Fail; for ( n = 0; n < num_glyphs; n++ ) glyph_indices[n] = FT_GET_USHORT(); FT_FRAME_EXIT(); } /* compute number of names stored in table */ { FT_Int n; num_names = 0; for ( n = 0; n < num_glyphs; n++ ) { FT_Int idx; idx = glyph_indices[n]; if ( idx >= 258 ) { idx -= 257; if ( idx > num_names ) num_names = (FT_UShort)idx; } } } /* now load the name strings */ { FT_UShort n; if ( FT_NEW_ARRAY( name_strings, num_names ) ) goto Fail; for ( n = 0; n < num_names; n++ ) { FT_UInt len; if ( FT_STREAM_POS() >= post_limit ) break; else { FT_TRACE6(( "load_format_20: %d byte left in post table\n", post_limit - FT_STREAM_POS() )); if ( FT_READ_BYTE( len ) ) goto Fail1; } if ( (FT_Int)len > post_limit || FT_STREAM_POS() > post_limit - (FT_Int)len ) { FT_ERROR(( "load_format_20:" " exceeding string length (%d)," " truncating at end of post table (%d byte left)\n", len, post_limit - FT_STREAM_POS() )); len = FT_MAX( 0, post_limit - FT_STREAM_POS() ); } if ( FT_NEW_ARRAY( name_strings[n], len + 1 ) || FT_STREAM_READ( name_strings[n], len ) ) goto Fail1; name_strings[n][len] = '\0'; } if ( n < num_names ) { FT_ERROR(( "load_format_20:" " all entries in post table are already parsed," " using NULL names for gid %d - %d\n", n, num_names - 1 )); for ( ; n < num_names; n++ ) if ( FT_NEW_ARRAY( name_strings[n], 1 ) ) goto Fail1; else name_strings[n][0] = '\0'; } } /* all right, set table fields and exit successfully */ { TT_Post_20 table = &face->postscript_names.names.format_20; table->num_glyphs = (FT_UShort)num_glyphs; table->num_names = (FT_UShort)num_names; table->glyph_indices = glyph_indices; table->glyph_names = name_strings; } return SFNT_Err_Ok; Fail1: { FT_UShort n; for ( n = 0; n < num_names; n++ ) FT_FREE( name_strings[n] ); } Fail: FT_FREE( name_strings ); FT_FREE( glyph_indices ); Exit: return error; }
static FT_Error pcf_get_encodings( FT_Stream stream, PCF_Face face ) { FT_Error error = PCF_Err_Ok; FT_Memory memory = FT_FACE(face)->memory; FT_ULong format, size; int firstCol, lastCol; int firstRow, lastRow; int nencoding, encodingOffset; int i, j; PCF_Encoding tmpEncoding = NULL, encoding = 0; error = pcf_seek_to_table_type( stream, face->toc.tables, face->toc.count, PCF_BDF_ENCODINGS, &format, &size ); if ( error ) return error; error = FT_Stream_EnterFrame( stream, 14 ); if ( error ) return error; format = FT_GET_ULONG_LE(); if ( PCF_BYTE_ORDER( format ) == MSBFirst ) { firstCol = FT_GET_SHORT(); lastCol = FT_GET_SHORT(); firstRow = FT_GET_SHORT(); lastRow = FT_GET_SHORT(); face->defaultChar = FT_GET_SHORT(); } else { firstCol = FT_GET_SHORT_LE(); lastCol = FT_GET_SHORT_LE(); firstRow = FT_GET_SHORT_LE(); lastRow = FT_GET_SHORT_LE(); face->defaultChar = FT_GET_SHORT_LE(); } FT_Stream_ExitFrame( stream ); if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) return PCF_Err_Invalid_File_Format; FT_TRACE4(( "pdf_get_encodings:\n" )); FT_TRACE4(( " firstCol %d, lastCol %d, firstRow %d, lastRow %d\n", firstCol, lastCol, firstRow, lastRow )); nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 ); if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) ) return PCF_Err_Out_Of_Memory; error = FT_Stream_EnterFrame( stream, 2 * nencoding ); if ( error ) goto Bail; for ( i = 0, j = 0 ; i < nencoding; i++ ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) encodingOffset = FT_GET_SHORT(); else encodingOffset = FT_GET_SHORT_LE(); if ( encodingOffset != -1 ) { tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) + firstRow ) * 256 ) + ( ( i % ( lastCol - firstCol + 1 ) ) + firstCol ); tmpEncoding[j].glyph = (FT_Short)encodingOffset; FT_TRACE5(( " code %d (0x%04X): idx %d\n", tmpEncoding[j].enc, tmpEncoding[j].enc, tmpEncoding[j].glyph )); j++; } } FT_Stream_ExitFrame( stream ); if ( FT_NEW_ARRAY( encoding, j ) ) goto Bail; for ( i = 0; i < j; i++ ) { encoding[i].enc = tmpEncoding[i].enc; encoding[i].glyph = tmpEncoding[i].glyph; } face->nencodings = j; face->encodings = encoding; FT_FREE( tmpEncoding ); return error; Bail: FT_FREE( encoding ); FT_FREE( tmpEncoding ); return error; }
af_face_globals_get_metrics( AF_FaceGlobals globals, FT_UInt gindex, FT_UInt options, AF_ScriptMetrics *ametrics ) { AF_ScriptMetrics metrics = NULL; FT_UInt gidx; AF_ScriptClass clazz; FT_UInt script = options & 15; const FT_Offset script_max = sizeof ( AF_SCRIPT_CLASSES_GET ) / sizeof ( AF_SCRIPT_CLASSES_GET[0] ); FT_Error error = AF_Err_Ok; if ( gindex >= (FT_ULong)globals->glyph_count ) { error = AF_Err_Invalid_Argument; goto Exit; } gidx = script; if ( gidx == 0 || gidx + 1 >= script_max ) gidx = globals->glyph_scripts[gindex] & AF_SCRIPT_LIST_NONE; clazz = AF_SCRIPT_CLASSES_GET[gidx]; if ( script == 0 ) script = clazz->script; metrics = globals->metrics[clazz->script]; if ( metrics == NULL ) { /* create the global metrics object when needed */ FT_Memory memory = globals->face->memory; if ( FT_ALLOC( metrics, clazz->script_metrics_size ) ) goto Exit; metrics->clazz = clazz; if ( clazz->script_metrics_init ) { error = clazz->script_metrics_init( metrics, globals->face ); if ( error ) { if ( clazz->script_metrics_done ) clazz->script_metrics_done( metrics ); FT_FREE( metrics ); goto Exit; } } globals->metrics[clazz->script] = metrics; } Exit: *ametrics = metrics; return error; }
FT_Stream_OpenGzip( FT_Stream stream, FT_Stream source ) { FT_Error error; FT_Memory memory = source->memory; FT_GZipFile zip = NULL; /* * check the header right now; this prevents allocating un-necessary * objects when we don't need them */ error = ft_gzip_check_header( source ); if ( error ) goto Exit; FT_ZERO( stream ); stream->memory = memory; if ( !FT_QNEW( zip ) ) { error = ft_gzip_file_init( zip, stream, source ); if ( error ) { FT_FREE( zip ); goto Exit; } stream->descriptor.pointer = zip; } /* * We use the following trick to try to dramatically improve the * performance while dealing with small files. If the original stream * size is less than a certain threshold, we try to load the whole font * file into memory. This saves us from using the 32KB buffer needed * to inflate the file, plus the two 4KB intermediate input/output * buffers used in the `FT_GZipFile' structure. */ { FT_ULong zip_size = ft_gzip_get_uncompressed_size( source ); if ( zip_size != 0 && zip_size < 40 * 1024 ) { FT_Byte* zip_buff = NULL; if ( !FT_ALLOC( zip_buff, zip_size ) ) { FT_ULong count; count = ft_gzip_file_io( zip, 0, zip_buff, zip_size ); if ( count == zip_size ) { ft_gzip_file_done( zip ); FT_FREE( zip ); stream->descriptor.pointer = NULL; stream->size = zip_size; stream->pos = 0; stream->base = zip_buff; stream->read = NULL; stream->close = ft_gzip_stream_close; goto Exit; } ft_gzip_file_io( zip, 0, NULL, 0 ); FT_FREE( zip_buff ); } error = FT_Err_Ok; } } stream->size = 0x7FFFFFFFL; /* don't know the real size! */ stream->pos = 0; stream->base = 0; stream->read = ft_gzip_stream_io; stream->close = ft_gzip_stream_close; Exit: return error; }
static FT_Error pcf_get_metrics( FT_Stream stream, PCF_Face face ) { FT_Error error = PCF_Err_Ok; FT_Memory memory = FT_FACE(face)->memory; FT_ULong format, size; PCF_Metric metrics = 0; FT_ULong nmetrics, i; error = pcf_seek_to_table_type( stream, face->toc.tables, face->toc.count, PCF_METRICS, &format, &size ); if ( error ) return error; if ( FT_READ_ULONG_LE( format ) ) goto Bail; if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ) return PCF_Err_Invalid_File_Format; if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_ULONG( nmetrics ); else (void)FT_READ_ULONG_LE( nmetrics ); } else { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_USHORT( nmetrics ); else (void)FT_READ_USHORT_LE( nmetrics ); } if ( error ) return PCF_Err_Invalid_File_Format; face->nmetrics = nmetrics; if ( !nmetrics ) return PCF_Err_Invalid_Table; FT_TRACE4(( "pcf_get_metrics:\n" )); FT_TRACE4(( " number of metrics: %d\n", nmetrics )); /* rough estimate */ if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) { if ( nmetrics > size / PCF_METRIC_SIZE ) return PCF_Err_Invalid_Table; } else { if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE ) return PCF_Err_Invalid_Table; } if ( FT_NEW_ARRAY( face->metrics, nmetrics ) ) return PCF_Err_Out_Of_Memory; metrics = face->metrics; for ( i = 0; i < nmetrics; i++ ) { error = pcf_get_metric( stream, format, metrics + i ); metrics[i].bits = 0; FT_TRACE5(( " idx %d: width=%d, " "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n", i, ( metrics + i )->characterWidth, ( metrics + i )->leftSideBearing, ( metrics + i )->rightSideBearing, ( metrics + i )->ascent, ( metrics + i )->descent, ( metrics + i )->attributes )); if ( error ) break; } if ( error ) FT_FREE( face->metrics ); Bail: return error; }
static FT_Error cff_index_init( CFF_Index idx, FT_Stream stream, FT_Bool load ) { FT_Error error; FT_Memory memory = stream->memory; FT_UShort count; FT_MEM_ZERO( idx, sizeof ( *idx ) ); idx->stream = stream; idx->start = FT_STREAM_POS(); if ( !FT_READ_USHORT( count ) && count > 0 ) { FT_Byte offsize; FT_ULong size; /* there is at least one element; read the offset size, */ /* then access the offset table to compute the index's total size */ if ( FT_READ_BYTE( offsize ) ) goto Exit; if ( offsize < 1 || offsize > 4 ) { error = FT_Err_Invalid_Table; goto Exit; } idx->count = count; idx->off_size = offsize; size = (FT_ULong)( count + 1 ) * offsize; idx->data_offset = idx->start + 3 + size; if ( FT_STREAM_SKIP( size - offsize ) ) goto Exit; size = cff_index_read_offset( idx, &error ); if ( error ) goto Exit; if ( size == 0 ) { error = CFF_Err_Invalid_Table; goto Exit; } idx->data_size = --size; if ( load ) { /* load the data */ if ( FT_FRAME_EXTRACT( size, idx->bytes ) ) goto Exit; } else { /* skip the data */ if ( FT_STREAM_SKIP( size ) ) goto Exit; } } Exit: if ( error ) FT_FREE( idx->offsets ); return error; }
FT_Stream_EnterFrame( FT_Stream stream, FT_ULong count ) { FT_Error error = FT_Err_Ok; FT_ULong read_bytes; /* check for nested frame access */ FT_ASSERT( stream && stream->cursor == 0 ); if ( stream->read ) { /* allocate the frame in memory */ FT_Memory memory = stream->memory; /* simple sanity check */ if ( count > stream->size ) { FT_ERROR(( "FT_Stream_EnterFrame:" " frame size (%lu) larger than stream size (%lu)\n", count, stream->size )); error = FT_THROW( Invalid_Stream_Operation ); goto Exit; } #ifdef FT_DEBUG_MEMORY /* assume _ft_debug_file and _ft_debug_lineno are already set */ stream->base = (unsigned char*)ft_mem_qalloc( memory, (FT_Long)count, &error ); if ( error ) goto Exit; #else if ( FT_QALLOC( stream->base, count ) ) goto Exit; #endif /* read it */ read_bytes = stream->read( stream, stream->pos, stream->base, count ); if ( read_bytes < count ) { FT_ERROR(( "FT_Stream_EnterFrame:" " invalid read; expected %lu bytes, got %lu\n", count, read_bytes )); FT_FREE( stream->base ); error = FT_THROW( Invalid_Stream_Operation ); } stream->cursor = stream->base; stream->limit = stream->cursor + count; stream->pos += read_bytes; } else { /* check current and new position */ if ( stream->pos >= stream->size || stream->size - stream->pos < count ) { FT_ERROR(( "FT_Stream_EnterFrame:" " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n", stream->pos, count, stream->size )); error = FT_THROW( Invalid_Stream_Operation ); goto Exit; } /* set cursor */ stream->cursor = stream->base + stream->pos; stream->limit = stream->cursor + count; stream->pos += count; } Exit: return error; }
T1_Face_Done( FT_Face t1face ) /* T1_Face */ { T1_Face face = (T1_Face)t1face; FT_Memory memory; T1_Font type1; if ( !face ) return; memory = face->root.memory; type1 = &face->type1; #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT /* release multiple masters information */ FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) ); if ( face->buildchar ) { FT_FREE( face->buildchar ); face->buildchar = NULL; face->len_buildchar = 0; } T1_Done_Blend( face ); face->blend = NULL; #endif /* release font info strings */ { PS_FontInfo info = &type1->font_info; FT_FREE( info->version ); FT_FREE( info->notice ); FT_FREE( info->full_name ); FT_FREE( info->family_name ); FT_FREE( info->weight ); } /* release top dictionary */ FT_FREE( type1->charstrings_len ); FT_FREE( type1->charstrings ); FT_FREE( type1->glyph_names ); FT_FREE( type1->subrs ); FT_FREE( type1->subrs_len ); ft_hash_num_free( type1->subrs_hash, memory ); FT_FREE( type1->subrs_hash ); FT_FREE( type1->subrs_block ); FT_FREE( type1->charstrings_block ); FT_FREE( type1->glyph_names_block ); FT_FREE( type1->encoding.char_index ); FT_FREE( type1->encoding.char_name ); FT_FREE( type1->font_name ); #ifndef T1_CONFIG_OPTION_NO_AFM /* release afm data if present */ if ( face->afm_data ) T1_Done_Metrics( memory, (AFM_FontInfo)face->afm_data ); #endif /* release unicode map, if any */ #if 0 FT_FREE( face->unicode_map_rec.maps ); face->unicode_map_rec.num_maps = 0; face->unicode_map = NULL; #endif face->root.family_name = NULL; face->root.style_name = NULL; }
T42_Face_Done( T42_Face face ) { T1_Font type1; PS_FontInfo info; FT_Memory memory; if ( !face ) return; type1 = &face->type1; info = &type1->font_info; memory = face->root.memory; /* delete internal ttf face prior to freeing face->ttf_data */ if ( face->ttf_face ) FT_Done_Face( face->ttf_face ); /* release font info strings */ FT_FREE( info->version ); FT_FREE( info->notice ); FT_FREE( info->full_name ); FT_FREE( info->family_name ); FT_FREE( info->weight ); /* release top dictionary */ FT_FREE( type1->charstrings_len ); FT_FREE( type1->charstrings ); FT_FREE( type1->glyph_names ); FT_FREE( type1->charstrings_block ); FT_FREE( type1->glyph_names_block ); FT_FREE( type1->encoding.char_index ); FT_FREE( type1->encoding.char_name ); FT_FREE( type1->font_name ); FT_FREE( face->ttf_data ); #if 0 /* release afm data if present */ if ( face->afm_data ) T1_Done_AFM( memory, (T1_AFM*)face->afm_data ); #endif /* release unicode map, if any */ FT_FREE( face->unicode_map.maps ); face->unicode_map.num_maps = 0; face->root.family_name = 0; face->root.style_name = 0; }
/* parse a PFM file -- for now, only read the kerning pairs */ static FT_Error T1_Read_PFM( FT_Face t1_face, FT_Stream stream, AFM_FontInfo fi ) { FT_Error error = T1_Err_Ok; FT_Memory memory = stream->memory; FT_Byte* start; FT_Byte* limit; FT_Byte* p; AFM_KernPair kp; FT_Int width_table_length; FT_CharMap oldcharmap; FT_CharMap charmap; FT_Int n; start = (FT_Byte*)stream->cursor; limit = (FT_Byte*)stream->limit; p = start; /* Figure out how long the width table is. */ /* This info is a little-endian short at offset 99. */ p = start + 99; if ( p + 2 > limit ) { error = T1_Err_Unknown_File_Format; goto Exit; } width_table_length = FT_PEEK_USHORT_LE( p ); p += 18 + width_table_length; if ( p + 0x12 > limit || FT_PEEK_USHORT_LE( p ) < 0x12 ) /* extension table is probably optional */ goto Exit; /* Kerning offset is 14 bytes from start of extensions table. */ p += 14; p = start + FT_PEEK_ULONG_LE( p ); if ( p == start ) /* zero offset means no table */ goto Exit; if ( p + 2 > limit ) { error = T1_Err_Unknown_File_Format; goto Exit; } fi->NumKernPair = FT_PEEK_USHORT_LE( p ); p += 2; if ( p + 4 * fi->NumKernPair > limit ) { error = T1_Err_Unknown_File_Format; goto Exit; } /* Actually, kerning pairs are simply optional! */ if ( fi->NumKernPair == 0 ) goto Exit; /* allocate the pairs */ if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) ) goto Exit; /* now, read each kern pair */ kp = fi->KernPairs; limit = p + 4 * fi->NumKernPair; /* PFM kerning data are stored by encoding rather than glyph index, */ /* so find the PostScript charmap of this font and install it */ /* temporarily. If we find no PostScript charmap, then just use */ /* the default and hope it is the right one. */ oldcharmap = t1_face->charmap; charmap = NULL; for ( n = 0; n < t1_face->num_charmaps; n++ ) { charmap = t1_face->charmaps[n]; /* check against PostScript pseudo platform */ if ( charmap->platform_id == 7 ) { error = FT_Set_Charmap( t1_face, charmap ); if ( error ) goto Exit; break; } } /* Kerning info is stored as: */ /* */ /* encoding of first glyph (1 byte) */ /* encoding of second glyph (1 byte) */ /* offset (little-endian short) */ for ( ; p < limit ; p += 4 ) { kp->index1 = FT_Get_Char_Index( t1_face, p[0] ); kp->index2 = FT_Get_Char_Index( t1_face, p[1] ); kp->x = (FT_Int)FT_PEEK_SHORT_LE(p + 2); kp->y = 0; kp++; } if ( oldcharmap != NULL ) error = FT_Set_Charmap( t1_face, oldcharmap ); if ( error ) goto Exit; /* now, sort the kern pairs according to their glyph indices */ ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ), compare_kern_pairs ); Exit: if ( error ) { FT_FREE( fi->KernPairs ); fi->NumKernPair = 0; } return error; }
/* convert a slot's glyph image into a bitmap */ static FT_Error ft_smooth_render_generic( FT_Renderer render, FT_GlyphSlot slot, FT_Render_Mode mode, const FT_Vector* origin, FT_Render_Mode required_mode ) { FT_Error error; FT_Outline* outline = NULL; FT_BBox cbox; FT_UInt width, height, height_org, width_org, pitch; FT_Bitmap* bitmap; FT_Memory memory; FT_Int hmul = mode == FT_RENDER_MODE_LCD; FT_Int vmul = mode == FT_RENDER_MODE_LCD_V; FT_Pos x_shift, y_shift, x_left, y_top; FT_Raster_Params params; /* check glyph image format */ if ( slot->format != render->glyph_format ) { error = Smooth_Err_Invalid_Argument; goto Exit; } /* check mode */ if ( mode != required_mode ) return Smooth_Err_Cannot_Render_Glyph; outline = &slot->outline; /* translate the outline to the new origin if needed */ if ( origin ) FT_Outline_Translate( outline, origin->x, origin->y ); /* compute the control box, and grid fit it */ FT_Outline_Get_CBox( outline, &cbox ); cbox.xMin = FT_PIX_FLOOR( cbox.xMin ); cbox.yMin = FT_PIX_FLOOR( cbox.yMin ); cbox.xMax = FT_PIX_CEIL( cbox.xMax ); cbox.yMax = FT_PIX_CEIL( cbox.yMax ); width = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 ); height = (FT_UInt)( ( cbox.yMax - cbox.yMin ) >> 6 ); bitmap = &slot->bitmap; memory = render->root.memory; width_org = width; height_org = height; /* release old bitmap buffer */ if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) { FT_FREE( bitmap->buffer ); slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; } /* allocate new one, depends on pixel format */ pitch = width; if ( hmul ) { width = width * 3; pitch = FT_PAD_CEIL( width, 4 ); } if ( vmul ) height *= 3; x_shift = (FT_Int) cbox.xMin; y_shift = (FT_Int) cbox.yMin; x_left = (FT_Int)( cbox.xMin >> 6 ); y_top = (FT_Int)( cbox.yMax >> 6 ); #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING if ( slot->library->lcd_filter_func ) { FT_Int extra = slot->library->lcd_extra; if ( hmul ) { x_shift -= 64 * ( extra >> 1 ); width += 3 * extra; pitch = FT_PAD_CEIL( width, 4 ); x_left -= extra >> 1; } if ( vmul ) { y_shift -= 64 * ( extra >> 1 ); height += 3 * extra; y_top += extra >> 1; } }
T1_Face_Done( T1_Face face ) { FT_Memory memory; T1_Font type1; if ( !face ) return; memory = face->root.memory; type1 = &face->type1; #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT /* release multiple masters information */ FT_ASSERT( ( face->len_buildchar == 0 ) == ( face->buildchar == NULL ) ); if ( face->buildchar ) { FT_FREE( face->buildchar ); face->buildchar = NULL; face->len_buildchar = 0; } T1_Done_Blend( face ); face->blend = 0; #endif /* release font info strings */ { PS_FontInfo info = &type1->font_info; FT_FREE( info->version ); FT_FREE( info->notice ); FT_FREE( info->full_name ); FT_FREE( info->family_name ); FT_FREE( info->weight ); } /* release top dictionary */ FT_FREE( type1->charstrings_len ); FT_FREE( type1->charstrings ); FT_FREE( type1->glyph_names ); FT_FREE( type1->subrs ); FT_FREE( type1->subrs_len ); FT_FREE( type1->subrs_block ); FT_FREE( type1->charstrings_block ); FT_FREE( type1->glyph_names_block ); FT_FREE( type1->encoding.char_index ); FT_FREE( type1->encoding.char_name ); FT_FREE( type1->font_name ); #ifndef T1_CONFIG_OPTION_NO_AFM /* release afm data if present */ if ( face->afm_data )
PCF_Face_Done( FT_Face pcfface ) /* PCF_Face */ { PCF_Face face = (PCF_Face)pcfface; FT_Memory memory = FT_FACE_MEMORY( face ); FT_FREE( face->encodings ); FT_FREE( face->metrics ); /* free properties */ { PCF_Property prop; FT_Int i; if ( face->properties ) { for ( i = 0; i < face->nprops; i++ ) { prop = &face->properties[i]; if ( prop ) { FT_FREE( prop->name ); if ( prop->isString ) FT_FREE( prop->value.atom ); } } } FT_FREE( face->properties ); } FT_FREE( face->toc.tables ); FT_FREE( pcfface->family_name ); FT_FREE( pcfface->style_name ); FT_FREE( pcfface->available_sizes ); FT_FREE( face->charset_encoding ); FT_FREE( face->charset_registry ); FT_TRACE4(( "PCF_Face_Done: done face\n" )); /* close gzip/LZW stream if any */ if ( pcfface->stream == &face->gzip_stream ) { FT_Stream_Close( &face->gzip_stream ); pcfface->stream = face->gzip_source; } }
static FT_Error load_format_25( TT_Face face, FT_Stream stream, FT_Long post_limit ) { FT_Memory memory = stream->memory; FT_Error error; FT_Int num_glyphs; FT_Char* offset_table = 0; FT_UNUSED( post_limit ); /* UNDOCUMENTED! This value appears only in the Apple TT specs. */ if ( FT_READ_USHORT( num_glyphs ) ) goto Exit; /* check the number of glyphs */ if ( num_glyphs > face->max_profile.numGlyphs || num_glyphs > 258 ) { error = SFNT_Err_Invalid_File_Format; goto Exit; } if ( FT_NEW_ARRAY( offset_table, num_glyphs ) || FT_STREAM_READ( offset_table, num_glyphs ) ) goto Fail; /* now check the offset table */ { FT_Int n; for ( n = 0; n < num_glyphs; n++ ) { FT_Long idx = (FT_Long)n + offset_table[n]; if ( idx < 0 || idx > num_glyphs ) { error = SFNT_Err_Invalid_File_Format; goto Fail; } } } /* OK, set table fields and exit successfully */ { TT_Post_25 table = &face->postscript_names.names.format_25; table->num_glyphs = (FT_UShort)num_glyphs; table->offsets = offset_table; } return SFNT_Err_Ok; Fail: FT_FREE( offset_table ); Exit: return error; }
static void t42_parse_sfnts( T42_Face face, T42_Loader loader ) { T42_Parser parser = &loader->parser; FT_Memory memory = parser->root.memory; FT_Byte* cur; FT_Byte* limit = parser->root.limit; FT_Error error; FT_Int num_tables = 0; FT_ULong count, ttf_size = 0; FT_Long n, string_size, old_string_size, real_size; FT_Byte* string_buf = NULL; FT_Bool alloc = 0; T42_Load_Status status; /* The format is */ /* */ /* /sfnts [ <hexstring> <hexstring> ... ] def */ /* */ /* or */ /* */ /* /sfnts [ */ /* <num_bin_bytes> RD <binary data> */ /* <num_bin_bytes> RD <binary data> */ /* ... */ /* ] def */ /* */ /* with exactly one space after the `RD' token. */ T1_Skip_Spaces( parser ); if ( parser->root.cursor >= limit || *parser->root.cursor++ != '[' ) { FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector!\n" )); error = T42_Err_Invalid_File_Format; goto Fail; } T1_Skip_Spaces( parser ); status = BEFORE_START; string_size = 0; old_string_size = 0; count = 0; while ( parser->root.cursor < limit ) { cur = parser->root.cursor; if ( *cur == ']' ) { parser->root.cursor++; goto Exit; } else if ( *cur == '<' ) { T1_Skip_PS_Token( parser ); if ( parser->root.error ) goto Exit; /* don't include delimiters */ string_size = (FT_Long)( ( parser->root.cursor - cur - 2 + 1 ) / 2 ); if ( FT_REALLOC( string_buf, old_string_size, string_size ) ) goto Fail; alloc = 1; parser->root.cursor = cur; (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 ); old_string_size = string_size; string_size = real_size; } else if ( ft_isdigit( *cur ) ) { string_size = T1_ToInt( parser ); T1_Skip_PS_Token( parser ); /* `RD' */ if ( parser->root.error ) return; string_buf = parser->root.cursor + 1; /* one space after `RD' */ parser->root.cursor += string_size + 1; if ( parser->root.cursor >= limit ) { FT_ERROR(( "t42_parse_sfnts: too many binary data!\n" )); error = T42_Err_Invalid_File_Format; goto Fail; } } /* A string can have a trailing zero byte for padding. Ignore it. */ if ( string_buf[string_size - 1] == 0 && ( string_size % 2 == 1 ) ) string_size--; for ( n = 0; n < string_size; n++ ) { switch ( status ) { case BEFORE_START: /* load offset table, 12 bytes */ if ( count < 12 ) { face->ttf_data[count++] = string_buf[n]; continue; } else { num_tables = 16 * face->ttf_data[4] + face->ttf_data[5]; status = BEFORE_TABLE_DIR; ttf_size = 12 + 16 * num_tables; if ( FT_REALLOC( face->ttf_data, 12, ttf_size ) ) goto Fail; } /* fall through */ case BEFORE_TABLE_DIR: /* the offset table is read; read the table directory */ if ( count < ttf_size ) { face->ttf_data[count++] = string_buf[n]; continue; } else { int i; FT_ULong len; for ( i = 0; i < num_tables; i++ ) { FT_Byte* p = face->ttf_data + 12 + 16 * i + 12; len = FT_PEEK_ULONG( p ); /* Pad to a 4-byte boundary length */ ttf_size += ( len + 3 ) & ~3; } status = OTHER_TABLES; face->ttf_size = ttf_size; /* there are no more than 256 tables, so no size check here */ if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables, ttf_size + 1 ) ) goto Fail; } /* fall through */ case OTHER_TABLES: /* all other tables are just copied */ if ( count >= ttf_size ) { FT_ERROR(( "t42_parse_sfnts: too many binary data!\n" )); error = T42_Err_Invalid_File_Format; goto Fail; } face->ttf_data[count++] = string_buf[n]; } } T1_Skip_Spaces( parser ); } /* if control reaches this point, the format was not valid */ error = T42_Err_Invalid_File_Format; Fail: parser->root.error = error; Exit: if ( alloc ) FT_FREE( string_buf ); }
static FT_String* tt_face_get_name( TT_Face face, FT_UShort nameid ) { FT_Memory memory = face->root.memory; FT_String* result = NULL; FT_UShort n; TT_NameEntryRec* rec; FT_Int found_apple = -1; FT_Int found_win = -1; FT_Int found_unicode = -1; FT_Bool is_english = 0; TT_NameEntry_ConvertFunc convert; rec = face->name_table.names; for ( n = 0; n < face->num_names; n++, rec++ ) { /* According to the OpenType 1.3 specification, only Microsoft or */ /* Apple platform IDs might be used in the `name' table. The */ /* `Unicode' platform is reserved for the `cmap' table, and the */ /* `Iso' one is deprecated. */ /* */ /* However, the Apple TrueType specification doesn't say the same */ /* thing and goes to suggest that all Unicode `name' table entries */ /* should be coded in UTF-16 (in big-endian format I suppose). */ /* */ if ( rec->nameID == nameid && rec->stringLength > 0 ) { switch ( rec->platformID ) { case TT_PLATFORM_APPLE_UNICODE: case TT_PLATFORM_ISO: /* there is `languageID' to check there. We should use this */ /* field only as a last solution when nothing else is */ /* available. */ /* */ found_unicode = n; break; case TT_PLATFORM_MACINTOSH: if ( rec->languageID == TT_MAC_LANGID_ENGLISH ) found_apple = n; break; case TT_PLATFORM_MICROSOFT: /* we only take a non-English name when there is nothing */ /* else available in the font */ /* */ if ( found_win == -1 || ( rec->languageID & 0x3FF ) == 0x009 ) { switch ( rec->encodingID ) { case TT_MS_ID_SYMBOL_CS: case TT_MS_ID_UNICODE_CS: case TT_MS_ID_UCS_4: is_english = FT_BOOL( ( rec->languageID & 0x3FF ) == 0x009 ); found_win = n; break; default: ; } } break; default: ; } } } /* some fonts contain invalid Unicode or Macintosh formatted entries; */ /* we will thus favor names encoded in Windows formats if available */ /* (provided it is an English name) */ /* */ convert = NULL; if ( found_win >= 0 && !( found_apple >= 0 && !is_english ) ) { rec = face->name_table.names + found_win; switch ( rec->encodingID ) { case TT_MS_ID_UNICODE_CS: case TT_MS_ID_SYMBOL_CS: convert = tt_name_entry_ascii_from_utf16; break; case TT_MS_ID_UCS_4: convert = tt_name_entry_ascii_from_ucs4; break; default: ; } } else if ( found_apple >= 0 ) { rec = face->name_table.names + found_apple; convert = tt_name_entry_ascii_from_other; } else if ( found_unicode >= 0 ) { rec = face->name_table.names + found_unicode; convert = tt_name_entry_ascii_from_utf16; } if ( rec && convert ) { if ( rec->string == NULL ) { FT_Error error = SFNT_Err_Ok; FT_Stream stream = face->name_table.stream; FT_UNUSED( error ); if ( FT_QNEW_ARRAY ( rec->string, rec->stringLength ) || FT_STREAM_SEEK( rec->stringOffset ) || FT_STREAM_READ( rec->string, rec->stringLength ) ) { FT_FREE( rec->string ); rec->stringLength = 0; result = NULL; goto Exit; } } result = convert( rec, memory ); } Exit: return result; }
cff_font_done( CFF_Font font ) { FT_Memory memory = font->memory; FT_UInt idx; cff_index_done( &font->global_subrs_index ); cff_index_done( &font->string_index ); cff_index_done( &font->font_dict_index ); cff_index_done( &font->name_index ); cff_index_done( &font->charstrings_index ); /* release font dictionaries, but only if working with */ /* a CID keyed CFF font */ if ( font->num_subfonts > 0 ) { for ( idx = 0; idx < font->num_subfonts; idx++ ) cff_subfont_done( memory, font->subfonts[idx] ); /* the subfonts array has been allocated as a single block */ FT_FREE( font->subfonts[0] ); } cff_encoding_done( &font->encoding ); cff_charset_done( &font->charset, font->stream ); cff_subfont_done( memory, &font->top_font ); CFF_Done_FD_Select( &font->fd_select, font->stream ); if (font->font_info != NULL) { FT_FREE( font->font_info->version ); FT_FREE( font->font_info->notice ); FT_FREE( font->font_info->full_name ); FT_FREE( font->font_info->family_name ); FT_FREE( font->font_info->weight ); FT_FREE( font->font_info ); } FT_FREE( font->registry ); FT_FREE( font->ordering ); FT_FREE( font->global_subrs ); FT_FREE( font->font_name ); }
sfnt_done_face( TT_Face face ) { FT_Memory memory = face->root.memory; SFNT_Service sfnt = (SFNT_Service)face->sfnt; if ( sfnt ) { /* destroy the postscript names table if it is loaded */ if ( sfnt->free_psnames ) sfnt->free_psnames( face ); /* destroy the embedded bitmaps table if it is loaded */ if ( sfnt->free_sbits ) sfnt->free_sbits( face ); } /* freeing the kerning table */ tt_face_done_kern( face ); /* freeing the collection table */ FT_FREE( face->ttc_header.offsets ); face->ttc_header.count = 0; /* freeing table directory */ FT_FREE( face->dir_tables ); face->num_tables = 0; { FT_Stream stream = FT_FACE_STREAM( face ); /* simply release the 'cmap' table frame */ FT_FRAME_RELEASE( face->cmap_table ); face->cmap_size = 0; } /* freeing the horizontal metrics */ #ifdef FT_OPTIMIZE_MEMORY { FT_Stream stream = FT_FACE_STREAM( face ); FT_FRAME_RELEASE( face->horz_metrics ); FT_FRAME_RELEASE( face->vert_metrics ); face->horz_metrics_size = 0; face->vert_metrics_size = 0; } #else FT_FREE( face->horizontal.long_metrics ); FT_FREE( face->horizontal.short_metrics ); #endif /* freeing the vertical ones, if any */ if ( face->vertical_info ) { FT_FREE( face->vertical.long_metrics ); FT_FREE( face->vertical.short_metrics ); face->vertical_info = 0; } /* freeing the gasp table */ FT_FREE( face->gasp.gaspRanges ); face->gasp.numRanges = 0; /* freeing the name table */ sfnt->free_names( face ); /* freeing the hdmx table */ sfnt->free_hdmx( face ); /* freeing family and style name */ FT_FREE( face->root.family_name ); FT_FREE( face->root.style_name ); /* freeing sbit size table */ FT_FREE( face->root.available_sizes ); face->root.num_fixed_sizes = 0; FT_FREE( face->postscript_name ); face->sfnt = 0; }
static FT_Error cff_charset_load( CFF_Charset charset, FT_UInt num_glyphs, FT_Stream stream, FT_ULong base_offset, FT_ULong offset, FT_Bool invert ) { FT_Memory memory = stream->memory; FT_Error error = CFF_Err_Ok; FT_UShort glyph_sid; /* If the the offset is greater than 2, we have to parse the */ /* charset table. */ if ( offset > 2 ) { FT_UInt j; charset->offset = base_offset + offset; /* Get the format of the table. */ if ( FT_STREAM_SEEK( charset->offset ) || FT_READ_BYTE( charset->format ) ) goto Exit; /* Allocate memory for sids. */ if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* assign the .notdef glyph */ charset->sids[0] = 0; switch ( charset->format ) { case 0: if ( num_glyphs > 0 ) { if ( FT_FRAME_ENTER( ( num_glyphs - 1 ) * 2 ) ) goto Exit; for ( j = 1; j < num_glyphs; j++ ) charset->sids[j] = FT_GET_USHORT(); FT_FRAME_EXIT(); } break; case 1: case 2: { FT_UInt nleft; FT_UInt i; j = 1; while ( j < num_glyphs ) { /* Read the first glyph sid of the range. */ if ( FT_READ_USHORT( glyph_sid ) ) goto Exit; /* Read the number of glyphs in the range. */ if ( charset->format == 2 ) { if ( FT_READ_USHORT( nleft ) ) goto Exit; } else { if ( FT_READ_BYTE( nleft ) ) goto Exit; } /* Fill in the range of sids -- `nleft + 1' glyphs. */ for ( i = 0; j < num_glyphs && i <= nleft; i++, j++, glyph_sid++ ) charset->sids[j] = glyph_sid; } } break; default: FT_ERROR(( "cff_charset_load: invalid table format!\n" )); error = CFF_Err_Invalid_File_Format; goto Exit; } } else { /* Parse default tables corresponding to offset == 0, 1, or 2. */ /* CFF specification intimates the following: */ /* */ /* In order to use a predefined charset, the following must be */ /* true: The charset constructed for the glyphs in the font's */ /* charstrings dictionary must match the predefined charset in */ /* the first num_glyphs. */ charset->offset = offset; /* record charset type */ switch ( (FT_UInt)offset ) { case 0: if ( num_glyphs > 229 ) { FT_ERROR(( "cff_charset_load: implicit charset larger than\n" "predefined charset (Adobe ISO-Latin)!\n" )); error = CFF_Err_Invalid_File_Format; goto Exit; } /* Allocate memory for sids. */ if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* Copy the predefined charset into the allocated memory. */ FT_ARRAY_COPY( charset->sids, cff_isoadobe_charset, num_glyphs ); break; case 1: if ( num_glyphs > 166 ) { FT_ERROR(( "cff_charset_load: implicit charset larger than\n" "predefined charset (Adobe Expert)!\n" )); error = CFF_Err_Invalid_File_Format; goto Exit; } /* Allocate memory for sids. */ if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* Copy the predefined charset into the allocated memory. */ FT_ARRAY_COPY( charset->sids, cff_expert_charset, num_glyphs ); break; case 2: if ( num_glyphs > 87 ) { FT_ERROR(( "cff_charset_load: implicit charset larger than\n" "predefined charset (Adobe Expert Subset)!\n" )); error = CFF_Err_Invalid_File_Format; goto Exit; } /* Allocate memory for sids. */ if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) ) goto Exit; /* Copy the predefined charset into the allocated memory. */ FT_ARRAY_COPY( charset->sids, cff_expertsubset_charset, num_glyphs ); break; default: error = CFF_Err_Invalid_File_Format; goto Exit; } } /* we have to invert the `sids' array for subsetted CID-keyed fonts */ if ( invert ) error = cff_charset_compute_cids( charset, num_glyphs, memory ); Exit: /* Clean up if there was an error. */ if ( error ) { FT_FREE( charset->sids ); FT_FREE( charset->cids ); charset->format = 0; charset->offset = 0; charset->sids = 0; } return error; }
TT_CharMap_Load( TT_Face face, TT_CMapTable cmap, FT_Stream stream ) { FT_Error error; FT_Memory memory; FT_UShort num_SH, num_Seg, i; FT_ULong j, n; FT_UShort u, l; TT_CMap0 cmap0; TT_CMap2 cmap2; TT_CMap4 cmap4; TT_CMap6 cmap6; TT_CMap8_12 cmap8_12; TT_CMap10 cmap10; TT_CMap2SubHeader cmap2sub; TT_CMap4Segment segments; TT_CMapGroup groups; if ( cmap->loaded ) return SFNT_Err_Ok; memory = stream->memory; if ( FT_STREAM_SEEK( cmap->offset ) ) return error; switch ( cmap->format ) { case 0: cmap0 = &cmap->c.cmap0; if ( FT_READ_USHORT( cmap0->language ) || FT_ALLOC( cmap0->glyphIdArray, 256L ) || FT_STREAM_READ( cmap0->glyphIdArray, 256L ) ) goto Fail; cmap->get_index = code_to_index0; cmap->get_next_char = code_to_next0; break; case 2: num_SH = 0; cmap2 = &cmap->c.cmap2; /* allocate subheader keys */ if ( FT_NEW_ARRAY( cmap2->subHeaderKeys, 256 ) || FT_FRAME_ENTER( 2L + 512L ) ) goto Fail; cmap2->language = FT_GET_USHORT(); for ( i = 0; i < 256; i++ ) { u = (FT_UShort)( FT_GET_USHORT() / 8 ); cmap2->subHeaderKeys[i] = u; if ( num_SH < u ) num_SH = u; } FT_FRAME_EXIT(); /* load subheaders */ cmap2->numGlyphId = l = (FT_UShort)( ( ( cmap->length - 2L * ( 256 + 3 ) - num_SH * 8L ) & 0xFFFFU ) / 2 ); if ( FT_NEW_ARRAY( cmap2->subHeaders, num_SH + 1 ) || FT_FRAME_ENTER( ( num_SH + 1 ) * 8L ) ) { FT_FREE( cmap2->subHeaderKeys ); goto Fail; } cmap2sub = cmap2->subHeaders; for ( i = 0; i <= num_SH; i++ ) { cmap2sub->firstCode = FT_GET_USHORT(); cmap2sub->entryCount = FT_GET_USHORT(); cmap2sub->idDelta = FT_GET_SHORT(); /* we apply the location offset immediately */ cmap2sub->idRangeOffset = (FT_UShort)( FT_GET_USHORT() - ( num_SH - i ) * 8 - 2 ); cmap2sub++; } FT_FRAME_EXIT(); /* load glyph IDs */ if ( FT_NEW_ARRAY( cmap2->glyphIdArray, l ) || FT_FRAME_ENTER( l * 2L ) ) { FT_FREE( cmap2->subHeaders ); FT_FREE( cmap2->subHeaderKeys ); goto Fail; } for ( i = 0; i < l; i++ ) cmap2->glyphIdArray[i] = FT_GET_USHORT(); FT_FRAME_EXIT(); cmap->get_index = code_to_index2; cmap->get_next_char = code_to_next2; break; case 4: cmap4 = &cmap->c.cmap4; /* load header */ if ( FT_FRAME_ENTER( 10L ) ) goto Fail; cmap4->language = FT_GET_USHORT(); cmap4->segCountX2 = FT_GET_USHORT(); cmap4->searchRange = FT_GET_USHORT(); cmap4->entrySelector = FT_GET_USHORT(); cmap4->rangeShift = FT_GET_USHORT(); num_Seg = (FT_UShort)( cmap4->segCountX2 / 2 ); FT_FRAME_EXIT(); /* load segments */ if ( FT_NEW_ARRAY( cmap4->segments, num_Seg ) || FT_FRAME_ENTER( ( num_Seg * 4 + 1 ) * 2L ) ) goto Fail; segments = cmap4->segments; for ( i = 0; i < num_Seg; i++ ) segments[i].endCount = FT_GET_USHORT(); (void)FT_GET_USHORT(); for ( i = 0; i < num_Seg; i++ ) segments[i].startCount = FT_GET_USHORT(); for ( i = 0; i < num_Seg; i++ ) segments[i].idDelta = FT_GET_SHORT(); for ( i = 0; i < num_Seg; i++ ) segments[i].idRangeOffset = FT_GET_USHORT(); FT_FRAME_EXIT(); cmap4->numGlyphId = l = (FT_UShort)( ( ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xFFFFU ) / 2 ); /* load IDs */ if ( FT_NEW_ARRAY( cmap4->glyphIdArray, l ) || FT_FRAME_ENTER( l * 2L ) ) { FT_FREE( cmap4->segments ); goto Fail; } for ( i = 0; i < l; i++ ) cmap4->glyphIdArray[i] = FT_GET_USHORT(); FT_FRAME_EXIT(); cmap4->last_segment = cmap4->segments; cmap->get_index = code_to_index4; cmap->get_next_char = code_to_next4; break; case 6: cmap6 = &cmap->c.cmap6; if ( FT_FRAME_ENTER( 6L ) ) goto Fail; cmap6->language = FT_GET_USHORT(); cmap6->firstCode = FT_GET_USHORT(); cmap6->entryCount = FT_GET_USHORT(); FT_FRAME_EXIT(); l = cmap6->entryCount; if ( FT_NEW_ARRAY( cmap6->glyphIdArray, l ) || FT_FRAME_ENTER( l * 2L ) ) goto Fail; for ( i = 0; i < l; i++ ) cmap6->glyphIdArray[i] = FT_GET_USHORT(); FT_FRAME_EXIT(); cmap->get_index = code_to_index6; cmap->get_next_char = code_to_next6; break; case 8: case 12: cmap8_12 = &cmap->c.cmap8_12; if ( FT_FRAME_ENTER( 8L ) ) goto Fail; cmap->length = FT_GET_ULONG(); cmap8_12->language = FT_GET_ULONG(); FT_FRAME_EXIT(); if ( cmap->format == 8 ) if ( FT_STREAM_SKIP( 8192L ) ) goto Fail; if ( FT_READ_ULONG( cmap8_12->nGroups ) ) goto Fail; n = cmap8_12->nGroups; if ( FT_NEW_ARRAY( cmap8_12->groups, n ) || FT_FRAME_ENTER( n * 3 * 4L ) ) goto Fail; groups = cmap8_12->groups; for ( j = 0; j < n; j++ ) { groups[j].startCharCode = FT_GET_ULONG(); groups[j].endCharCode = FT_GET_ULONG(); groups[j].startGlyphID = FT_GET_ULONG(); } FT_FRAME_EXIT(); cmap8_12->last_group = cmap8_12->groups; cmap->get_index = code_to_index8_12; cmap->get_next_char = code_to_next8_12; break; case 10: cmap10 = &cmap->c.cmap10; if ( FT_FRAME_ENTER( 16L ) ) goto Fail; cmap->length = FT_GET_ULONG(); cmap10->language = FT_GET_ULONG(); cmap10->startCharCode = FT_GET_ULONG(); cmap10->numChars = FT_GET_ULONG(); FT_FRAME_EXIT(); n = cmap10->numChars; if ( FT_NEW_ARRAY( cmap10->glyphs, n ) || FT_FRAME_ENTER( n * 2L ) ) goto Fail; for ( j = 0; j < n; j++ ) cmap10->glyphs[j] = FT_GET_USHORT(); FT_FRAME_EXIT(); cmap->get_index = code_to_index10; cmap->get_next_char = code_to_next10; break; default: /* corrupt character mapping table */ return SFNT_Err_Invalid_CharMap_Format; } return SFNT_Err_Ok; Fail: TT_CharMap_Free( face, cmap ); return error; }
static const char* sfnt_get_ps_name( TT_Face face ) { FT_Int n, found_win, found_apple; const char* result = NULL; /* shouldn't happen, but just in case to avoid memory leaks */ if ( face->postscript_name ) return face->postscript_name; /* scan the name table to see whether we have a Postscript name here, */ /* either in Macintosh or Windows platform encodings */ found_win = -1; found_apple = -1; for ( n = 0; n < face->num_names; n++ ) { TT_NameEntryRec* name = face->name_table.names + n; if ( name->nameID == 6 && name->stringLength > 0 ) { if ( name->platformID == 3 && name->encodingID == 1 && name->languageID == 0x409 ) found_win = n; if ( name->platformID == 1 && name->encodingID == 0 && name->languageID == 0 ) found_apple = n; } } if ( found_win != -1 ) { FT_Memory memory = face->root.memory; TT_NameEntryRec* name = face->name_table.names + found_win; FT_UInt len = name->stringLength / 2; FT_Error error = SFNT_Err_Ok; FT_UNUSED( error ); if ( !FT_ALLOC( result, name->stringLength + 1 ) ) { FT_Stream stream = face->name_table.stream; FT_String* r = (FT_String*)result; FT_Byte* p = (FT_Byte*)name->string; if ( FT_STREAM_SEEK( name->stringOffset ) || FT_FRAME_ENTER( name->stringLength ) ) { FT_FREE( result ); name->stringLength = 0; name->stringOffset = 0; FT_FREE( name->string ); goto Exit; } p = (FT_Byte*)stream->cursor; for ( ; len > 0; len--, p += 2 ) { if ( p[0] == 0 && p[1] >= 32 && p[1] < 128 ) *r++ = p[1]; } *r = '\0'; FT_FRAME_EXIT(); } goto Exit; } if ( found_apple != -1 ) { FT_Memory memory = face->root.memory; TT_NameEntryRec* name = face->name_table.names + found_apple; FT_UInt len = name->stringLength; FT_Error error = SFNT_Err_Ok; FT_UNUSED( error ); if ( !FT_ALLOC( result, len + 1 ) ) { FT_Stream stream = face->name_table.stream; if ( FT_STREAM_SEEK( name->stringOffset ) || FT_STREAM_READ( result, len ) ) { name->stringOffset = 0; name->stringLength = 0; FT_FREE( name->string ); FT_FREE( result ); goto Exit; } ((char*)result)[len] = '\0'; } } Exit: face->postscript_name = result; return result; }
T1_New_Parser( T1_Parser parser, FT_Stream stream, FT_Memory memory, PSAux_Service psaux ) { FT_Error error; FT_UShort tag; FT_ULong size; psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory ); parser->stream = stream; parser->base_len = 0; parser->base_dict = 0; parser->private_len = 0; parser->private_dict = 0; parser->in_pfb = 0; parser->in_memory = 0; parser->single_block = 0; /* check the header format */ error = check_type1_format( stream, "%!PS-AdobeFont", 14 ); if ( error ) { if ( error != T1_Err_Unknown_File_Format ) goto Exit; error = check_type1_format( stream, "%!FontType", 10 ); if ( error ) { FT_TRACE2(( "[not a Type1 font]\n" )); goto Exit; } } /******************************************************************/ /* */ /* Here a short summary of what is going on: */ /* */ /* When creating a new Type 1 parser, we try to locate and load */ /* the base dictionary if this is possible (i.e., for PFB */ /* files). Otherwise, we load the whole font into memory. */ /* */ /* When `loading' the base dictionary, we only setup pointers */ /* in the case of a memory-based stream. Otherwise, we */ /* allocate and load the base dictionary in it. */ /* */ /* parser->in_pfb is set if we are in a binary (`.pfb') font. */ /* parser->in_memory is set if we have a memory stream. */ /* */ /* try to compute the size of the base dictionary; */ /* look for a Postscript binary file tag, i.e., 0x8001 */ if ( FT_STREAM_SEEK( 0L ) ) goto Exit; error = read_pfb_tag( stream, &tag, &size ); if ( error ) goto Exit; if ( tag != 0x8001U ) { /* assume that this is a PFA file for now; an error will */ /* be produced later when more things are checked */ if ( FT_STREAM_SEEK( 0L ) ) goto Exit; size = stream->size; } else parser->in_pfb = 1; /* now, try to load `size' bytes of the `base' dictionary we */ /* found previously */ /* if it is a memory-based resource, set up pointers */ if ( !stream->read ) { parser->base_dict = (FT_Byte*)stream->base + stream->pos; parser->base_len = size; parser->in_memory = 1; /* check that the `size' field is valid */ if ( FT_STREAM_SKIP( size ) ) goto Exit; } else { /* read segment in memory -- this is clumsy, but so does the format */ if ( FT_ALLOC( parser->base_dict, size ) || FT_STREAM_READ( parser->base_dict, size ) ) goto Exit; parser->base_len = size; } parser->root.base = parser->base_dict; parser->root.cursor = parser->base_dict; parser->root.limit = parser->root.cursor + parser->base_len; Exit: if ( error && !parser->in_memory ) FT_FREE( parser->base_dict ); return error; }
static FT_Error pcf_get_properties( FT_Stream stream, PCF_Face face ) { PCF_ParseProperty props = 0; PCF_Property properties = NULL; FT_ULong nprops, i; FT_ULong format, size; FT_Error error; FT_Memory memory = FT_FACE(face)->memory; FT_ULong string_size; FT_String* strings = 0; error = pcf_seek_to_table_type( stream, face->toc.tables, face->toc.count, PCF_PROPERTIES, &format, &size ); if ( error ) goto Bail; if ( FT_READ_ULONG_LE( format ) ) goto Bail; FT_TRACE4(( "pcf_get_properties:\n" )); FT_TRACE4(( " format = %ld\n", format )); if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) goto Bail; if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_ULONG( nprops ); else (void)FT_READ_ULONG_LE( nprops ); if ( error ) goto Bail; FT_TRACE4(( " nprop = %d (truncate %d props)\n", (int)nprops, nprops - (int)nprops )); nprops = (int)nprops; /* rough estimate */ if ( nprops > size / PCF_PROPERTY_SIZE ) { error = PCF_Err_Invalid_Table; goto Bail; } face->nprops = (int)nprops; if ( FT_NEW_ARRAY( props, nprops ) ) goto Bail; for ( i = 0; i < nprops; i++ ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) { if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) ) goto Bail; } else { if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) ) goto Bail; } } /* pad the property array */ /* */ /* clever here - nprops is the same as the number of odd-units read, */ /* as only isStringProp are odd length (Keith Packard) */ /* */ if ( nprops & 3 ) { i = 4 - ( nprops & 3 ); if ( FT_STREAM_SKIP( i ) ) { error = PCF_Err_Invalid_Stream_Skip; goto Bail; } } if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_ULONG( string_size ); else (void)FT_READ_ULONG_LE( string_size ); if ( error ) goto Bail; FT_TRACE4(( " string_size = %ld\n", string_size )); /* rough estimate */ if ( string_size > size - nprops * PCF_PROPERTY_SIZE ) { error = PCF_Err_Invalid_Table; goto Bail; } if ( FT_NEW_ARRAY( strings, string_size ) ) goto Bail; error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size ); if ( error ) goto Bail; if ( FT_NEW_ARRAY( properties, nprops ) ) goto Bail; face->properties = properties; for ( i = 0; i < nprops; i++ ) { FT_Long name_offset = props[i].name; if ( ( name_offset < 0 ) || ( (FT_ULong)name_offset > string_size ) ) { error = PCF_Err_Invalid_Offset; goto Bail; } if ( FT_STRDUP( properties[i].name, strings + name_offset ) ) goto Bail; FT_TRACE4(( " %s:", properties[i].name )); properties[i].isString = props[i].isString; if ( props[i].isString ) { FT_Long value_offset = props[i].value; if ( ( value_offset < 0 ) || ( (FT_ULong)value_offset > string_size ) ) { error = PCF_Err_Invalid_Offset; goto Bail; } if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) ) goto Bail; FT_TRACE4(( " `%s'\n", properties[i].value.atom )); } else { properties[i].value.l = props[i].value; FT_TRACE4(( " %d\n", properties[i].value.l )); } } error = PCF_Err_Ok; Bail: FT_FREE( props ); FT_FREE( strings ); return error; }
cff_face_init( FT_Stream stream, FT_Face cffface, /* CFF_Face */ FT_Int face_index, FT_Int num_params, FT_Parameter* params ) { CFF_Face face = (CFF_Face)cffface; FT_Error error; SFNT_Service sfnt; FT_Service_PsCMaps psnames; PSHinter_Service pshinter; FT_Bool pure_cff = 1; FT_Bool sfnt_format = 0; FT_Library library = cffface->driver->root.library; #if 0 FT_FACE_FIND_GLOBAL_SERVICE( face, sfnt, SFNT ); FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_NAMES ); FT_FACE_FIND_GLOBAL_SERVICE( face, pshinter, POSTSCRIPT_HINTER ); if ( !sfnt ) goto Bad_Format; #else sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" ); if ( !sfnt ) goto Bad_Format; FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS ); pshinter = (PSHinter_Service)FT_Get_Module_Interface( library, "pshinter" ); #endif /* create input stream from resource */ if ( FT_STREAM_SEEK( 0 ) ) goto Exit; /* check whether we have a valid OpenType file */ error = sfnt->init_face( stream, face, face_index, num_params, params ); if ( !error ) { if ( face->format_tag != TTAG_OTTO ) /* `OTTO'; OpenType/CFF font */ { FT_TRACE2(( "[not a valid OpenType/CFF font]\n" )); goto Bad_Format; } /* if we are performing a simple font format check, exit immediately */ if ( face_index < 0 ) return CFF_Err_Ok; /* UNDOCUMENTED! A CFF in an SFNT can have only a single font. */ if ( face_index > 0 ) { FT_ERROR(( "cff_face_init: invalid face index\n" )); error = CFF_Err_Invalid_Argument; goto Exit; } sfnt_format = 1; /* now, the font can be either an OpenType/CFF font, or an SVG CEF */ /* font; in the latter case it doesn't have a `head' table */ error = face->goto_table( face, TTAG_head, stream, 0 ); if ( !error ) { pure_cff = 0; /* load font directory */ error = sfnt->load_face( stream, face, 0, num_params, params ); if ( error ) goto Exit; } else { /* load the `cmap' table explicitly */ error = sfnt->load_cmap( face, stream ); if ( error ) goto Exit; /* XXX: we don't load the GPOS table, as OpenType Layout */ /* support will be added later to a layout library on top of */ /* FreeType 2 */ } /* now load the CFF part of the file */ error = face->goto_table( face, TTAG_CFF, stream, 0 ); if ( error ) goto Exit; } else { /* rewind to start of file; we are going to load a pure-CFF font */ if ( FT_STREAM_SEEK( 0 ) ) goto Exit; error = CFF_Err_Ok; } /* now load and parse the CFF table in the file */ { CFF_Font cff; CFF_FontRecDict dict; FT_Memory memory = cffface->memory; FT_Int32 flags; FT_UInt i; if ( FT_NEW( cff ) ) goto Exit; face->extra.data = cff; error = cff_font_load( library, stream, face_index, cff, pure_cff ); if ( error ) goto Exit; cff->pshinter = pshinter; cff->psnames = (void*)psnames; cffface->face_index = face_index; /* Complement the root flags with some interesting information. */ /* Note that this is only necessary for pure CFF and CEF fonts; */ /* SFNT based fonts use the `name' table instead. */ cffface->num_glyphs = cff->num_glyphs; dict = &cff->top_font.font_dict; /* we need the `PSNames' module for CFF and CEF formats */ /* which aren't CID-keyed */ if ( dict->cid_registry == 0xFFFFU && !psnames ) { FT_ERROR(( "cff_face_init:" " cannot open CFF & CEF fonts\n" " " " without the `PSNames' module\n" )); goto Bad_Format; } if ( !dict->units_per_em ) dict->units_per_em = pure_cff ? 1000 : face->root.units_per_EM; /* Normalize the font matrix so that `matrix->xx' is 1; the */ /* scaling is done with `units_per_em' then (at this point, */ /* it already contains the scaling factor, but without */ /* normalization of the matrix). */ /* */ /* Note that the offsets must be expressed in integer font */ /* units. */ { FT_Matrix* matrix = &dict->font_matrix; FT_Vector* offset = &dict->font_offset; FT_ULong* upm = &dict->units_per_em; FT_Fixed temp = FT_ABS( matrix->yy ); if ( temp != 0x10000L ) { *upm = FT_DivFix( *upm, temp ); matrix->xx = FT_DivFix( matrix->xx, temp ); matrix->yx = FT_DivFix( matrix->yx, temp ); matrix->xy = FT_DivFix( matrix->xy, temp ); matrix->yy = FT_DivFix( matrix->yy, temp ); offset->x = FT_DivFix( offset->x, temp ); offset->y = FT_DivFix( offset->y, temp ); } offset->x >>= 16; offset->y >>= 16; } for ( i = cff->num_subfonts; i > 0; i-- ) { CFF_FontRecDict sub = &cff->subfonts[i - 1]->font_dict; CFF_FontRecDict top = &cff->top_font.font_dict; FT_Matrix* matrix; FT_Vector* offset; FT_ULong* upm; FT_Fixed temp; if ( sub->units_per_em ) { FT_Long scaling; if ( top->units_per_em > 1 && sub->units_per_em > 1 ) scaling = FT_MIN( top->units_per_em, sub->units_per_em ); else scaling = 1; FT_Matrix_Multiply_Scaled( &top->font_matrix, &sub->font_matrix, scaling ); FT_Vector_Transform_Scaled( &sub->font_offset, &top->font_matrix, scaling ); sub->units_per_em = FT_MulDiv( sub->units_per_em, top->units_per_em, scaling ); } else { sub->font_matrix = top->font_matrix; sub->font_offset = top->font_offset; sub->units_per_em = top->units_per_em; } matrix = &sub->font_matrix; offset = &sub->font_offset; upm = &sub->units_per_em; temp = FT_ABS( matrix->yy ); if ( temp != 0x10000L ) { *upm = FT_DivFix( *upm, temp ); /* if *upm is larger than 100*1000 we divide by 1000 -- */ /* this can happen if e.g. there is no top-font FontMatrix */ /* and the subfont FontMatrix already contains the complete */ /* scaling for the subfont (see section 5.11 of the PLRM) */ /* 100 is a heuristic value */ if ( *upm > 100L * 1000L ) *upm = ( *upm + 500 ) / 1000; matrix->xx = FT_DivFix( matrix->xx, temp ); matrix->yx = FT_DivFix( matrix->yx, temp ); matrix->xy = FT_DivFix( matrix->xy, temp ); matrix->yy = FT_DivFix( matrix->yy, temp ); offset->x = FT_DivFix( offset->x, temp ); offset->y = FT_DivFix( offset->y, temp ); } offset->x >>= 16; offset->y >>= 16; } if ( pure_cff ) { char* style_name = NULL; /* set up num_faces */ cffface->num_faces = cff->num_faces; /* compute number of glyphs */ if ( dict->cid_registry != 0xFFFFU ) cffface->num_glyphs = cff->charset.max_cid; else cffface->num_glyphs = cff->charstrings_index.count; /* set global bbox, as well as EM size */ cffface->bbox.xMin = dict->font_bbox.xMin >> 16; cffface->bbox.yMin = dict->font_bbox.yMin >> 16; cffface->bbox.xMax = ( dict->font_bbox.xMax + 0xFFFFU ) >> 16; cffface->bbox.yMax = ( dict->font_bbox.yMax + 0xFFFFU ) >> 16; cffface->units_per_EM = (FT_UShort)( dict->units_per_em ); cffface->ascender = (FT_Short)( cffface->bbox.yMax ); cffface->descender = (FT_Short)( cffface->bbox.yMin ); cffface->height = (FT_Short)( ( cffface->units_per_EM * 12 ) / 10 ); if ( cffface->height < cffface->ascender - cffface->descender ) cffface->height = (FT_Short)( cffface->ascender - cffface->descender ); cffface->underline_position = (FT_Short)( dict->underline_position >> 16 ); cffface->underline_thickness = (FT_Short)( dict->underline_thickness >> 16 ); /* retrieve font family & style name */ cffface->family_name = cff_index_get_name( &cff->name_index, face_index ); if ( cffface->family_name ) { char* full = cff_index_get_sid_string( &cff->string_index, dict->full_name, psnames ); char* fullp = full; char* family = cffface->family_name; char* family_name = 0; if ( dict->family_name ) { family_name = cff_index_get_sid_string( &cff->string_index, dict->family_name, psnames); if ( family_name ) family = family_name; } /* We try to extract the style name from the full name. */ /* We need to ignore spaces and dashes during the search. */ if ( full && family ) { while ( *fullp ) { /* skip common characters at the start of both strings */ if ( *fullp == *family ) { family++; fullp++; continue; } /* ignore spaces and dashes in full name during comparison */ if ( *fullp == ' ' || *fullp == '-' ) { fullp++; continue; } /* ignore spaces and dashes in family name during comparison */ if ( *family == ' ' || *family == '-' ) { family++; continue; } if ( !*family && *fullp ) { /* The full name begins with the same characters as the */ /* family name, with spaces and dashes removed. In this */ /* case, the remaining string in `fullp' will be used as */ /* the style name. */ style_name = cff_strcpy( memory, fullp ); } break; } if ( family_name ) FT_FREE( family_name ); FT_FREE( full ); } } else { char *cid_font_name = cff_index_get_sid_string( &cff->string_index, dict->cid_font_name, psnames ); /* do we have a `/FontName' for a CID-keyed font? */ if ( cid_font_name ) cffface->family_name = cid_font_name; } if ( style_name ) cffface->style_name = style_name; else /* assume "Regular" style if we don't know better */ cffface->style_name = cff_strcpy( memory, (char *)"Regular" ); /*******************************************************************/ /* */ /* Compute face flags. */ /* */ flags = (FT_UInt32)( FT_FACE_FLAG_SCALABLE | /* scalable outlines */ FT_FACE_FLAG_HORIZONTAL | /* horizontal data */ FT_FACE_FLAG_HINTER ); /* has native hinter */ if ( sfnt_format ) flags |= (FT_UInt32)FT_FACE_FLAG_SFNT; /* fixed width font? */ if ( dict->is_fixed_pitch ) flags |= (FT_UInt32)FT_FACE_FLAG_FIXED_WIDTH; /* XXX: WE DO NOT SUPPORT KERNING METRICS IN THE GPOS TABLE FOR NOW */ #if 0 /* kerning available? */ if ( face->kern_pairs ) flags |= (FT_UInt32)FT_FACE_FLAG_KERNING; #endif cffface->face_flags = flags; /*******************************************************************/ /* */ /* Compute style flags. */ /* */ flags = 0; if ( dict->italic_angle ) flags |= FT_STYLE_FLAG_ITALIC; { char *weight = cff_index_get_sid_string( &cff->string_index, dict->weight, psnames ); if ( weight ) if ( !ft_strcmp( weight, "Bold" ) || !ft_strcmp( weight, "Black" ) ) flags |= FT_STYLE_FLAG_BOLD; FT_FREE( weight ); } /* double check */ if ( !(flags & FT_STYLE_FLAG_BOLD) && cffface->style_name ) if ( !ft_strncmp( cffface->style_name, "Bold", 4 ) || !ft_strncmp( cffface->style_name, "Black", 5 ) ) flags |= FT_STYLE_FLAG_BOLD; cffface->style_flags = flags; } #ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES /* CID-keyed CFF fonts don't have glyph names -- the SFNT loader */ /* has unset this flag because of the 3.0 `post' table. */ if ( dict->cid_registry == 0xFFFFU ) cffface->face_flags |= FT_FACE_FLAG_GLYPH_NAMES; #endif if ( dict->cid_registry != 0xFFFFU && pure_cff ) cffface->face_flags |= FT_FACE_FLAG_CID_KEYED; /*******************************************************************/ /* */ /* Compute char maps. */ /* */ /* Try to synthesize a Unicode charmap if there is none available */ /* already. If an OpenType font contains a Unicode "cmap", we */ /* will use it, whatever be in the CFF part of the file. */ { FT_CharMapRec cmaprec; FT_CharMap cmap; FT_UInt nn; CFF_Encoding encoding = &cff->encoding; for ( nn = 0; nn < (FT_UInt)cffface->num_charmaps; nn++ ) { cmap = cffface->charmaps[nn]; /* Windows Unicode (3,1)? */ if ( cmap->platform_id == 3 && cmap->encoding_id == 1 ) goto Skip_Unicode; /* Deprecated Unicode platform id? */ if ( cmap->platform_id == 0 ) goto Skip_Unicode; /* Standard Unicode (deprecated) */ } /* since CID-keyed fonts don't contain glyph names, we can't */ /* construct a cmap */ if ( pure_cff && cff->top_font.font_dict.cid_registry != 0xFFFFU ) goto Exit; /* we didn't find a Unicode charmap -- synthesize one */ cmaprec.face = cffface; cmaprec.platform_id = 3; cmaprec.encoding_id = 1; cmaprec.encoding = FT_ENCODING_UNICODE; nn = (FT_UInt)cffface->num_charmaps; FT_CMap_New( &FT_CFF_CMAP_UNICODE_CLASS_REC_GET, NULL, &cmaprec, NULL ); /* if no Unicode charmap was previously selected, select this one */ if ( cffface->charmap == NULL && nn != (FT_UInt)cffface->num_charmaps ) cffface->charmap = cffface->charmaps[nn]; Skip_Unicode: if ( encoding->count > 0 ) { FT_CMap_Class clazz; cmaprec.face = cffface; cmaprec.platform_id = 7; /* Adobe platform id */ if ( encoding->offset == 0 ) { cmaprec.encoding_id = TT_ADOBE_ID_STANDARD; cmaprec.encoding = FT_ENCODING_ADOBE_STANDARD; clazz = &FT_CFF_CMAP_ENCODING_CLASS_REC_GET; } else if ( encoding->offset == 1 ) { cmaprec.encoding_id = TT_ADOBE_ID_EXPERT; cmaprec.encoding = FT_ENCODING_ADOBE_EXPERT; clazz = &FT_CFF_CMAP_ENCODING_CLASS_REC_GET; } else { cmaprec.encoding_id = TT_ADOBE_ID_CUSTOM; cmaprec.encoding = FT_ENCODING_ADOBE_CUSTOM; clazz = &FT_CFF_CMAP_ENCODING_CLASS_REC_GET; } FT_CMap_New( clazz, NULL, &cmaprec, NULL ); } } } Exit: return error; Bad_Format: error = CFF_Err_Unknown_File_Format; goto Exit; }
static FT_Error pcf_get_bitmaps( FT_Stream stream, PCF_Face face ) { FT_Error error = PCF_Err_Ok; FT_Memory memory = FT_FACE(face)->memory; FT_Long* offsets = NULL; FT_Long bitmapSizes[GLYPHPADOPTIONS]; FT_ULong format, size; FT_ULong nbitmaps, i, sizebitmaps = 0; error = pcf_seek_to_table_type( stream, face->toc.tables, face->toc.count, PCF_BITMAPS, &format, &size ); if ( error ) return error; error = FT_Stream_EnterFrame( stream, 8 ); if ( error ) return error; format = FT_GET_ULONG_LE(); if ( PCF_BYTE_ORDER( format ) == MSBFirst ) nbitmaps = FT_GET_ULONG(); else nbitmaps = FT_GET_ULONG_LE(); FT_Stream_ExitFrame( stream ); if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) return PCF_Err_Invalid_File_Format; FT_TRACE4(( "pcf_get_bitmaps:\n" )); FT_TRACE4(( " number of bitmaps: %d\n", nbitmaps )); /* XXX: PCF_Face->nmetrics is singed FT_Long, see pcf.h */ if ( face->nmetrics < 0 || nbitmaps != ( FT_ULong )face->nmetrics ) return PCF_Err_Invalid_File_Format; if ( FT_NEW_ARRAY( offsets, nbitmaps ) ) return error; for ( i = 0; i < nbitmaps; i++ ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_LONG( offsets[i] ); else (void)FT_READ_LONG_LE( offsets[i] ); FT_TRACE5(( " bitmap %d: offset %ld (0x%lX)\n", i, offsets[i], offsets[i] )); } if ( error ) goto Bail; for ( i = 0; i < GLYPHPADOPTIONS; i++ ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_LONG( bitmapSizes[i] ); else (void)FT_READ_LONG_LE( bitmapSizes[i] ); if ( error ) goto Bail; sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )]; FT_TRACE4(( " padding %d implies a size of %ld\n", i, bitmapSizes[i] )); } FT_TRACE4(( " %d bitmaps, padding index %ld\n", nbitmaps, PCF_GLYPH_PAD_INDEX( format ) )); FT_TRACE4(( " bitmap size = %d\n", sizebitmaps )); FT_UNUSED( sizebitmaps ); /* only used for debugging */ for ( i = 0; i < nbitmaps; i++ ) { /* rough estimate */ if ( ( offsets[i] < 0 ) || ( (FT_ULong)offsets[i] > size ) ) { FT_TRACE0(( "pcf_get_bitmaps:" " invalid offset to bitmap data of glyph %d\n", i )); } else face->metrics[i].bits = stream->pos + offsets[i]; } face->bitmapsFormat = format; Bail: FT_FREE( offsets ); return error; }
/* Create a new FT_Face from an SFNT resource, specified by res ID. */ static FT_Error FT_New_Face_From_SFNT( FT_Library library, ResID sfnt_id, FT_Long face_index, FT_Face* aface ) { Handle sfnt = NULL; FT_Byte* sfnt_data; size_t sfnt_size; FT_Error error = FT_Err_Ok; FT_Memory memory = library->memory; int is_cff, is_sfnt_ps; sfnt = GetResource( TTAG_sfnt, sfnt_id ); if ( sfnt == NULL ) return FT_THROW( Invalid_Handle ); sfnt_size = (FT_ULong)GetHandleSize( sfnt ); if ( FT_ALLOC( sfnt_data, (FT_Long)sfnt_size ) ) { ReleaseResource( sfnt ); return error; } ft_memcpy( sfnt_data, *sfnt, sfnt_size ); ReleaseResource( sfnt ); is_cff = sfnt_size > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 ); is_sfnt_ps = sfnt_size > 4 && !ft_memcmp( sfnt_data, "typ1", 4 ); if ( is_sfnt_ps ) { FT_Stream stream; if ( FT_NEW( stream ) ) goto Try_OpenType; FT_Stream_OpenMemory( stream, sfnt_data, sfnt_size ); if ( !open_face_PS_from_sfnt_stream( library, stream, face_index, 0, NULL, aface ) ) { FT_Stream_Close( stream ); FT_FREE( stream ); FT_FREE( sfnt_data ); goto Exit; } FT_FREE( stream ); } Try_OpenType: error = open_face_from_buffer( library, sfnt_data, sfnt_size, face_index, is_cff ? "cff" : "truetype", aface ); Exit: return error; }
static FT_Error pcf_read_TOC( FT_Stream stream, PCF_Face face ) { FT_Error error; PCF_Toc toc = &face->toc; PCF_Table tables; FT_Memory memory = FT_FACE(face)->memory; FT_UInt n; if ( FT_STREAM_SEEK ( 0 ) || FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) ) return PCF_Err_Cannot_Open_Resource; if ( toc->version != PCF_FILE_VERSION || toc->count > FT_ARRAY_MAX( face->toc.tables ) || toc->count == 0 ) return PCF_Err_Invalid_File_Format; if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) ) return PCF_Err_Out_Of_Memory; tables = face->toc.tables; for ( n = 0; n < toc->count; n++ ) { if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) ) goto Exit; tables++; } /* Sort tables and check for overlaps. Because they are almost */ /* always ordered already, an in-place bubble sort with simultaneous */ /* boundary checking seems appropriate. */ tables = face->toc.tables; for ( n = 0; n < toc->count - 1; n++ ) { FT_UInt i, have_change; have_change = 0; for ( i = 0; i < toc->count - 1 - n; i++ ) { PCF_TableRec tmp; if ( tables[i].offset > tables[i + 1].offset ) { tmp = tables[i]; tables[i] = tables[i + 1]; tables[i + 1] = tmp; have_change = 1; } if ( ( tables[i].size > tables[i + 1].offset ) || ( tables[i].offset > tables[i + 1].offset - tables[i].size ) ) return PCF_Err_Invalid_Offset; } if ( !have_change ) break; } #ifdef FT_DEBUG_LEVEL_TRACE { FT_UInt i, j; const char* name = "?"; FT_TRACE4(( "pcf_read_TOC:\n" )); FT_TRACE4(( " number of tables: %ld\n", face->toc.count )); tables = face->toc.tables; for ( i = 0; i < toc->count; i++ ) { for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] ); j++ ) if ( tables[i].type == (FT_UInt)( 1 << j ) ) name = tableNames[j]; FT_TRACE4(( " %d: type=%s, format=0x%X, " "size=%ld (0x%lX), offset=%ld (0x%lX)\n", i, name, tables[i].format, tables[i].size, tables[i].size, tables[i].offset, tables[i].offset )); } } #endif return PCF_Err_Ok; Exit: FT_FREE( face->toc.tables ); return error; }
t42_parser_init( T42_Parser parser, FT_Stream stream, FT_Memory memory, PSAux_Service psaux ) { FT_Error error = T42_Err_Ok; FT_Long size; psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory ); parser->stream = stream; parser->base_len = 0; parser->base_dict = 0; parser->in_memory = 0; /*******************************************************************/ /* */ /* Here a short summary of what is going on: */ /* */ /* When creating a new Type 42 parser, we try to locate and load */ /* the base dictionary, loading the whole font into memory. */ /* */ /* When `loading' the base dictionary, we only set up pointers */ /* in the case of a memory-based stream. Otherwise, we allocate */ /* and load the base dictionary in it. */ /* */ /* parser->in_memory is set if we have a memory stream. */ /* */ if ( FT_STREAM_SEEK( 0L ) || FT_FRAME_ENTER( 17 ) ) goto Exit; if ( ft_memcmp( stream->cursor, "%!PS-TrueTypeFont", 17 ) != 0 ) { FT_TRACE2(( "not a Type42 font\n" )); error = T42_Err_Unknown_File_Format; } FT_FRAME_EXIT(); if ( error || FT_STREAM_SEEK( 0 ) ) goto Exit; size = stream->size; /* now, try to load `size' bytes of the `base' dictionary we */ /* found previously */ /* if it is a memory-based resource, set up pointers */ if ( !stream->read ) { parser->base_dict = (FT_Byte*)stream->base + stream->pos; parser->base_len = size; parser->in_memory = 1; /* check that the `size' field is valid */ if ( FT_STREAM_SKIP( size ) ) goto Exit; } else { /* read segment in memory */ if ( FT_ALLOC( parser->base_dict, size ) || FT_STREAM_READ( parser->base_dict, size ) ) goto Exit; parser->base_len = size; } parser->root.base = parser->base_dict; parser->root.cursor = parser->base_dict; parser->root.limit = parser->root.cursor + parser->base_len; Exit: if ( error && !parser->in_memory ) FT_FREE( parser->base_dict ); return error; }
T1_Face_Done( T1_Face face ) { FT_Memory memory; T1_Font type1 = &face->type1; if ( face ) { memory = face->root.memory; #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT /* release multiple masters information */ T1_Done_Blend( face ); face->blend = 0; #endif /* release font info strings */ { PS_FontInfo info = &type1->font_info; FT_FREE( info->version ); FT_FREE( info->notice ); FT_FREE( info->full_name ); FT_FREE( info->family_name ); FT_FREE( info->weight ); } /* release top dictionary */ FT_FREE( type1->charstrings_len ); FT_FREE( type1->charstrings ); FT_FREE( type1->glyph_names ); FT_FREE( type1->subrs ); FT_FREE( type1->subrs_len ); FT_FREE( type1->subrs_block ); FT_FREE( type1->charstrings_block ); FT_FREE( type1->glyph_names_block ); FT_FREE( type1->encoding.char_index ); FT_FREE( type1->encoding.char_name ); FT_FREE( type1->font_name ); #ifndef T1_CONFIG_OPTION_NO_AFM /* release afm data if present */ if ( face->afm_data ) T1_Done_Metrics( memory, (T1_AFM*)face->afm_data ); #endif /* release unicode map, if any */ FT_FREE( face->unicode_map.maps ); face->unicode_map.num_maps = 0; face->root.family_name = 0; face->root.style_name = 0; } }
static FT_Error woff_open_font( FT_Stream stream, TT_Face face ) { FT_Memory memory = stream->memory; FT_Error error = FT_Err_Ok; WOFF_HeaderRec woff; WOFF_Table tables = NULL; WOFF_Table* indices = NULL; FT_ULong woff_offset; FT_Byte* sfnt = NULL; FT_Stream sfnt_stream = NULL; FT_Byte* sfnt_header; FT_ULong sfnt_offset; FT_Int nn; FT_ULong old_tag = 0; static const FT_Frame_Field woff_header_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE WOFF_HeaderRec FT_FRAME_START( 44 ), FT_FRAME_ULONG ( signature ), FT_FRAME_ULONG ( flavor ), FT_FRAME_ULONG ( length ), FT_FRAME_USHORT( num_tables ), FT_FRAME_USHORT( reserved ), FT_FRAME_ULONG ( totalSfntSize ), FT_FRAME_USHORT( majorVersion ), FT_FRAME_USHORT( minorVersion ), FT_FRAME_ULONG ( metaOffset ), FT_FRAME_ULONG ( metaLength ), FT_FRAME_ULONG ( metaOrigLength ), FT_FRAME_ULONG ( privOffset ), FT_FRAME_ULONG ( privLength ), FT_FRAME_END }; FT_ASSERT( stream == face->root.stream ); FT_ASSERT( FT_STREAM_POS() == 0 ); if ( FT_STREAM_READ_FIELDS( woff_header_fields, &woff ) ) return error; /* Make sure we don't recurse back here or hit TTC code. */ if ( woff.flavor == TTAG_wOFF || woff.flavor == TTAG_ttcf ) return FT_THROW( Invalid_Table ); /* Miscellaneous checks. */ if ( woff.length != stream->size || woff.num_tables == 0 || 44 + woff.num_tables * 20UL >= woff.length || 12 + woff.num_tables * 16UL >= woff.totalSfntSize || ( woff.totalSfntSize & 3 ) != 0 || ( woff.metaOffset == 0 && ( woff.metaLength != 0 || woff.metaOrigLength != 0 ) ) || ( woff.metaLength != 0 && woff.metaOrigLength == 0 ) || ( woff.privOffset == 0 && woff.privLength != 0 ) ) return FT_THROW( Invalid_Table ); if ( FT_ALLOC( sfnt, woff.totalSfntSize ) || FT_NEW( sfnt_stream ) ) goto Exit; sfnt_header = sfnt; /* Write sfnt header. */ { FT_UInt searchRange, entrySelector, rangeShift, x; x = woff.num_tables; entrySelector = 0; while ( x ) { x >>= 1; entrySelector += 1; } entrySelector--; searchRange = ( 1 << entrySelector ) * 16; rangeShift = woff.num_tables * 16 - searchRange; WRITE_ULONG ( sfnt_header, woff.flavor ); WRITE_USHORT( sfnt_header, woff.num_tables ); WRITE_USHORT( sfnt_header, searchRange ); WRITE_USHORT( sfnt_header, entrySelector ); WRITE_USHORT( sfnt_header, rangeShift ); } /* While the entries in the sfnt header must be sorted by the */ /* tag value, the tables themselves are not. We thus have to */ /* sort them by offset and check that they don't overlap. */ if ( FT_NEW_ARRAY( tables, woff.num_tables ) || FT_NEW_ARRAY( indices, woff.num_tables ) ) goto Exit; FT_TRACE2(( "\n" " tag offset compLen origLen checksum\n" " -------------------------------------------\n" )); if ( FT_FRAME_ENTER( 20L * woff.num_tables ) ) goto Exit; for ( nn = 0; nn < woff.num_tables; nn++ ) { WOFF_Table table = tables + nn; table->Tag = FT_GET_TAG4(); table->Offset = FT_GET_ULONG(); table->CompLength = FT_GET_ULONG(); table->OrigLength = FT_GET_ULONG(); table->CheckSum = FT_GET_ULONG(); FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx %08lx\n", (FT_Char)( table->Tag >> 24 ), (FT_Char)( table->Tag >> 16 ), (FT_Char)( table->Tag >> 8 ), (FT_Char)( table->Tag ), table->Offset, table->CompLength, table->OrigLength, table->CheckSum )); if ( table->Tag <= old_tag ) { FT_FRAME_EXIT(); error = FT_THROW( Invalid_Table ); goto Exit; } old_tag = table->Tag; indices[nn] = table; } FT_FRAME_EXIT(); /* Sort by offset. */ ft_qsort( indices, woff.num_tables, sizeof ( WOFF_Table ), compare_offsets ); /* Check offsets and lengths. */ woff_offset = 44 + woff.num_tables * 20L; sfnt_offset = 12 + woff.num_tables * 16L; for ( nn = 0; nn < woff.num_tables; nn++ ) { WOFF_Table table = indices[nn]; if ( table->Offset != woff_offset || table->CompLength > woff.length || table->Offset > woff.length - table->CompLength || table->OrigLength > woff.totalSfntSize || sfnt_offset > woff.totalSfntSize - table->OrigLength || table->CompLength > table->OrigLength ) { error = FT_THROW( Invalid_Table ); goto Exit; } table->OrigOffset = sfnt_offset; /* The offsets must be multiples of 4. */ woff_offset += ( table->CompLength + 3 ) & ~3U; sfnt_offset += ( table->OrigLength + 3 ) & ~3U; } /* * Final checks! * * We don't decode and check the metadata block. * We don't check table checksums either. * But other than those, I think we implement all * `MUST' checks from the spec. */ if ( woff.metaOffset ) { if ( woff.metaOffset != woff_offset || woff.metaOffset + woff.metaLength > woff.length ) { error = FT_THROW( Invalid_Table ); goto Exit; } /* We have padding only ... */ woff_offset += woff.metaLength; } if ( woff.privOffset ) { /* ... if it isn't the last block. */ woff_offset = ( woff_offset + 3 ) & ~3U; if ( woff.privOffset != woff_offset || woff.privOffset + woff.privLength > woff.length ) { error = FT_THROW( Invalid_Table ); goto Exit; } /* No padding for the last block. */ woff_offset += woff.privLength; } if ( sfnt_offset != woff.totalSfntSize || woff_offset != woff.length ) { error = FT_THROW( Invalid_Table ); goto Exit; } /* Write the tables. */ for ( nn = 0; nn < woff.num_tables; nn++ ) { WOFF_Table table = tables + nn; /* Write SFNT table entry. */ WRITE_ULONG( sfnt_header, table->Tag ); WRITE_ULONG( sfnt_header, table->CheckSum ); WRITE_ULONG( sfnt_header, table->OrigOffset ); WRITE_ULONG( sfnt_header, table->OrigLength ); /* Write table data. */ if ( FT_STREAM_SEEK( table->Offset ) || FT_FRAME_ENTER( table->CompLength ) ) goto Exit; if ( table->CompLength == table->OrigLength ) { /* Uncompressed data; just copy. */ ft_memcpy( sfnt + table->OrigOffset, stream->cursor, table->OrigLength ); } else { #ifdef FT_CONFIG_OPTION_USE_ZLIB /* Uncompress with zlib. */ FT_ULong output_len = table->OrigLength; error = FT_Gzip_Uncompress( memory, sfnt + table->OrigOffset, &output_len, stream->cursor, table->CompLength ); if ( error ) goto Exit; if ( output_len != table->OrigLength ) { error = FT_THROW( Invalid_Table ); goto Exit; } #else /* !FT_CONFIG_OPTION_USE_ZLIB */ error = FT_THROW( Unimplemented_Feature ); goto Exit; #endif /* !FT_CONFIG_OPTION_USE_ZLIB */ } FT_FRAME_EXIT(); /* We don't check whether the padding bytes in the WOFF file are */ /* actually '\0'. For the output, however, we do set them properly. */ sfnt_offset = table->OrigOffset + table->OrigLength; while ( sfnt_offset & 3 ) { sfnt[sfnt_offset] = '\0'; sfnt_offset++; } } /* Ok! Finally ready. Swap out stream and return. */ FT_Stream_OpenMemory( sfnt_stream, sfnt, woff.totalSfntSize ); sfnt_stream->memory = stream->memory; sfnt_stream->close = sfnt_stream_close; FT_Stream_Free( face->root.stream, ( face->root.face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 ); face->root.stream = sfnt_stream; face->root.face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM; Exit: FT_FREE( tables ); FT_FREE( indices ); if ( error ) { FT_FREE( sfnt ); FT_Stream_Close( sfnt_stream ); FT_FREE( sfnt_stream ); } return error; }