Werner Lemberg | 8c90c22 | 2002-06-08 06:47:18 +0000 | [diff] [blame] | 1 | /***************************************************************************/ |
| 2 | /* */ |
| 3 | /* t42parse.c */ |
| 4 | /* */ |
| 5 | /* Type 42 font parser (body). */ |
| 6 | /* */ |
Werner Lemberg | 1d565fb | 2005-02-13 21:42:42 +0000 | [diff] [blame] | 7 | /* Copyright 2002, 2003, 2004, 2005 by Roberto Alameda. */ |
Werner Lemberg | 8c90c22 | 2002-06-08 06:47:18 +0000 | [diff] [blame] | 8 | /* */ |
| 9 | /* This file is part of the FreeType project, and may only be used, */ |
| 10 | /* modified, and distributed under the terms of the FreeType project */ |
| 11 | /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ |
| 12 | /* this file you indicate that you have read the license and */ |
| 13 | /* understand and accept it fully. */ |
| 14 | /* */ |
| 15 | /***************************************************************************/ |
| 16 | |
| 17 | |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 18 | #include "t42parse.h" |
Werner Lemberg | 8c90c22 | 2002-06-08 06:47:18 +0000 | [diff] [blame] | 19 | #include "t42error.h" |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 20 | #include FT_INTERNAL_DEBUG_H |
| 21 | #include FT_INTERNAL_STREAM_H |
| 22 | #include FT_LIST_H |
| 23 | #include FT_INTERNAL_POSTSCRIPT_AUX_H |
| 24 | |
Werner Lemberg | 8c90c22 | 2002-06-08 06:47:18 +0000 | [diff] [blame] | 25 | |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 26 | /*************************************************************************/ |
| 27 | /* */ |
| 28 | /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ |
| 29 | /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ |
| 30 | /* messages during execution. */ |
| 31 | /* */ |
| 32 | #undef FT_COMPONENT |
| 33 | #define FT_COMPONENT trace_t42 |
| 34 | |
Werner Lemberg | 8c90c22 | 2002-06-08 06:47:18 +0000 | [diff] [blame] | 35 | |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 36 | static void |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 37 | t42_parse_font_matrix( T42_Face face, |
| 38 | T42_Loader loader ); |
| 39 | static void |
| 40 | t42_parse_encoding( T42_Face face, |
| 41 | T42_Loader loader ); |
David Turner | 3c40d73 | 2003-08-17 22:31:23 +0000 | [diff] [blame] | 42 | |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 43 | static void |
| 44 | t42_parse_charstrings( T42_Face face, |
| 45 | T42_Loader loader ); |
David Turner | 3c40d73 | 2003-08-17 22:31:23 +0000 | [diff] [blame] | 46 | |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 47 | static void |
| 48 | t42_parse_sfnts( T42_Face face, |
| 49 | T42_Loader loader ); |
| 50 | |
| 51 | |
| 52 | static const |
| 53 | T1_FieldRec t42_keywords[] = { |
| 54 | |
| 55 | #undef FT_STRUCTURE |
| 56 | #define FT_STRUCTURE T1_FontInfo |
| 57 | #undef T1CODE |
| 58 | #define T1CODE T1_FIELD_LOCATION_FONT_INFO |
| 59 | |
Werner Lemberg | 64f1ba9 | 2003-07-25 22:09:53 +0000 | [diff] [blame] | 60 | T1_FIELD_STRING( "version", version ) |
| 61 | T1_FIELD_STRING( "Notice", notice ) |
| 62 | T1_FIELD_STRING( "FullName", full_name ) |
| 63 | T1_FIELD_STRING( "FamilyName", family_name ) |
| 64 | T1_FIELD_STRING( "Weight", weight ) |
David Turner | 3c40d73 | 2003-08-17 22:31:23 +0000 | [diff] [blame] | 65 | T1_FIELD_NUM ( "ItalicAngle", italic_angle ) |
Werner Lemberg | 64f1ba9 | 2003-07-25 22:09:53 +0000 | [diff] [blame] | 66 | T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch ) |
David Turner | 3c40d73 | 2003-08-17 22:31:23 +0000 | [diff] [blame] | 67 | T1_FIELD_NUM ( "UnderlinePosition", underline_position ) |
| 68 | T1_FIELD_NUM ( "UnderlineThickness", underline_thickness ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 69 | |
| 70 | #undef FT_STRUCTURE |
| 71 | #define FT_STRUCTURE T1_FontRec |
| 72 | #undef T1CODE |
| 73 | #define T1CODE T1_FIELD_LOCATION_FONT_DICT |
| 74 | |
Werner Lemberg | 64f1ba9 | 2003-07-25 22:09:53 +0000 | [diff] [blame] | 75 | T1_FIELD_KEY ( "FontName", font_name ) |
| 76 | T1_FIELD_NUM ( "PaintType", paint_type ) |
| 77 | T1_FIELD_NUM ( "FontType", font_type ) |
| 78 | T1_FIELD_FIXED( "StrokeWidth", stroke_width ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 79 | |
Werner Lemberg | fdc042b | 2003-06-12 04:59:07 +0000 | [diff] [blame] | 80 | #undef FT_STRUCTURE |
| 81 | #define FT_STRUCTURE FT_BBox |
| 82 | #undef T1CODE |
| 83 | #define T1CODE T1_FIELD_LOCATION_BBOX |
| 84 | |
| 85 | T1_FIELD_BBOX("FontBBox", xMin ) |
| 86 | |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 87 | T1_FIELD_CALLBACK( "FontMatrix", t42_parse_font_matrix ) |
| 88 | T1_FIELD_CALLBACK( "Encoding", t42_parse_encoding ) |
| 89 | T1_FIELD_CALLBACK( "CharStrings", t42_parse_charstrings ) |
| 90 | T1_FIELD_CALLBACK( "sfnts", t42_parse_sfnts ) |
| 91 | |
| 92 | { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0 } |
| 93 | }; |
| 94 | |
| 95 | |
| 96 | #define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l ) |
| 97 | #define T1_Done_Table( p ) \ |
| 98 | do \ |
| 99 | { \ |
| 100 | if ( (p)->funcs.done ) \ |
| 101 | (p)->funcs.done( p ); \ |
| 102 | } while ( 0 ) |
| 103 | #define T1_Release_Table( p ) \ |
| 104 | do \ |
| 105 | { \ |
| 106 | if ( (p)->funcs.release ) \ |
| 107 | (p)->funcs.release( p ); \ |
| 108 | } while ( 0 ) |
| 109 | |
Werner Lemberg | 52f911a | 2003-10-07 05:49:41 +0000 | [diff] [blame] | 110 | #define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root ) |
| 111 | #define T1_Skip_PS_Token( p ) (p)->root.funcs.skip_PS_token( &(p)->root ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 112 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 113 | #define T1_ToInt( p ) \ |
| 114 | (p)->root.funcs.to_int( &(p)->root ) |
| 115 | #define T1_ToBytes( p, b, m, n, d ) \ |
| 116 | (p)->root.funcs.to_bytes( &(p)->root, b, m, n, d ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 117 | |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 118 | #define T1_ToFixedArray( p, m, f, t ) \ |
| 119 | (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t ) |
| 120 | #define T1_ToToken( p, t ) \ |
| 121 | (p)->root.funcs.to_token( &(p)->root, t ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 122 | |
| 123 | #define T1_Load_Field( p, f, o, m, pf ) \ |
| 124 | (p)->root.funcs.load_field( &(p)->root, f, o, m, pf ) |
| 125 | #define T1_Load_Field_Table( p, f, o, m, pf ) \ |
| 126 | (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf ) |
| 127 | |
| 128 | |
| 129 | /********************* Parsing Functions ******************/ |
| 130 | |
| 131 | FT_LOCAL_DEF( FT_Error ) |
| 132 | t42_parser_init( T42_Parser parser, |
| 133 | FT_Stream stream, |
| 134 | FT_Memory memory, |
| 135 | PSAux_Service psaux ) |
| 136 | { |
Werner Lemberg | 8c90c22 | 2002-06-08 06:47:18 +0000 | [diff] [blame] | 137 | FT_Error error = T42_Err_Ok; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 138 | FT_Long size; |
| 139 | |
| 140 | |
| 141 | psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory ); |
| 142 | |
| 143 | parser->stream = stream; |
| 144 | parser->base_len = 0; |
| 145 | parser->base_dict = 0; |
| 146 | parser->in_memory = 0; |
| 147 | |
| 148 | /*******************************************************************/ |
| 149 | /* */ |
| 150 | /* Here a short summary of what is going on: */ |
| 151 | /* */ |
| 152 | /* When creating a new Type 42 parser, we try to locate and load */ |
| 153 | /* the base dictionary, loading the whole font into memory. */ |
| 154 | /* */ |
Werner Lemberg | 3864f4e | 2003-09-30 06:43:54 +0000 | [diff] [blame] | 155 | /* When `loading' the base dictionary, we only set up pointers */ |
| 156 | /* in the case of a memory-based stream. Otherwise, we allocate */ |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 157 | /* and load the base dictionary in it. */ |
| 158 | /* */ |
| 159 | /* parser->in_memory is set if we have a memory stream. */ |
| 160 | /* */ |
| 161 | |
David Turner | 58609c4 | 2005-03-15 23:31:48 +0000 | [diff] [blame] | 162 | if ( FT_STREAM_SEEK( 0L ) || |
| 163 | FT_FRAME_ENTER( 17 ) ) |
| 164 | goto Exit; |
| 165 | |
| 166 | if ( ft_memcmp( stream->cursor, "%!PS-TrueTypeFont", 17 ) != 0 ) |
| 167 | { |
| 168 | FT_TRACE2(( "not a Type42 font\n" )); |
| 169 | error = T42_Err_Unknown_File_Format; |
| 170 | } |
| 171 | |
| 172 | FT_FRAME_EXIT(); |
| 173 | |
| 174 | if ( error || FT_STREAM_SEEK( 0 ) ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 175 | goto Exit; |
| 176 | |
| 177 | size = stream->size; |
| 178 | |
| 179 | /* now, try to load `size' bytes of the `base' dictionary we */ |
| 180 | /* found previously */ |
| 181 | |
| 182 | /* if it is a memory-based resource, set up pointers */ |
| 183 | if ( !stream->read ) |
| 184 | { |
| 185 | parser->base_dict = (FT_Byte*)stream->base + stream->pos; |
| 186 | parser->base_len = size; |
| 187 | parser->in_memory = 1; |
| 188 | |
| 189 | /* check that the `size' field is valid */ |
| 190 | if ( FT_STREAM_SKIP( size ) ) |
| 191 | goto Exit; |
| 192 | } |
| 193 | else |
| 194 | { |
| 195 | /* read segment in memory */ |
Werner Lemberg | 8c90c22 | 2002-06-08 06:47:18 +0000 | [diff] [blame] | 196 | if ( FT_ALLOC( parser->base_dict, size ) || |
| 197 | FT_STREAM_READ( parser->base_dict, size ) ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 198 | goto Exit; |
| 199 | |
| 200 | parser->base_len = size; |
| 201 | } |
| 202 | |
David Turner | 58609c4 | 2005-03-15 23:31:48 +0000 | [diff] [blame] | 203 | parser->root.base = parser->base_dict; |
| 204 | parser->root.cursor = parser->base_dict; |
| 205 | parser->root.limit = parser->root.cursor + parser->base_len; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 206 | |
| 207 | Exit: |
| 208 | if ( error && !parser->in_memory ) |
| 209 | FT_FREE( parser->base_dict ); |
| 210 | |
| 211 | return error; |
| 212 | } |
| 213 | |
| 214 | |
| 215 | FT_LOCAL_DEF( void ) |
| 216 | t42_parser_done( T42_Parser parser ) |
| 217 | { |
| 218 | FT_Memory memory = parser->root.memory; |
| 219 | |
| 220 | |
| 221 | /* free the base dictionary only when we have a disk stream */ |
| 222 | if ( !parser->in_memory ) |
| 223 | FT_FREE( parser->base_dict ); |
| 224 | |
| 225 | parser->root.funcs.done( &parser->root ); |
| 226 | } |
| 227 | |
| 228 | |
| 229 | static int |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 230 | t42_is_space( FT_Byte c ) |
| 231 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 232 | return ( c == ' ' || c == '\t' || |
| 233 | c == '\r' || c == '\n' || c == '\f' || |
| 234 | c == '\0' ); |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 235 | } |
| 236 | |
| 237 | |
| 238 | static void |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 239 | t42_parse_font_matrix( T42_Face face, |
| 240 | T42_Loader loader ) |
| 241 | { |
| 242 | T42_Parser parser = &loader->parser; |
| 243 | FT_Matrix* matrix = &face->type1.font_matrix; |
| 244 | FT_Vector* offset = &face->type1.font_offset; |
| 245 | FT_Face root = (FT_Face)&face->root; |
| 246 | FT_Fixed temp[6]; |
| 247 | FT_Fixed temp_scale; |
| 248 | |
| 249 | |
| 250 | (void)T1_ToFixedArray( parser, 6, temp, 3 ); |
| 251 | |
Werner Lemberg | dfa4619 | 2004-03-05 09:26:24 +0000 | [diff] [blame] | 252 | temp_scale = FT_ABS( temp[3] ); |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 253 | |
| 254 | /* Set Units per EM based on FontMatrix values. We set the value to */ |
| 255 | /* 1000 / temp_scale, because temp_scale was already multiplied by */ |
| 256 | /* 1000 (in t1_tofixed, from psobjs.c). */ |
| 257 | |
| 258 | root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L, |
| 259 | temp_scale ) >> 16 ); |
| 260 | |
| 261 | /* we need to scale the values by 1.0/temp_scale */ |
| 262 | if ( temp_scale != 0x10000L ) { |
| 263 | temp[0] = FT_DivFix( temp[0], temp_scale ); |
| 264 | temp[1] = FT_DivFix( temp[1], temp_scale ); |
| 265 | temp[2] = FT_DivFix( temp[2], temp_scale ); |
| 266 | temp[4] = FT_DivFix( temp[4], temp_scale ); |
| 267 | temp[5] = FT_DivFix( temp[5], temp_scale ); |
| 268 | temp[3] = 0x10000L; |
| 269 | } |
| 270 | |
| 271 | matrix->xx = temp[0]; |
| 272 | matrix->yx = temp[1]; |
| 273 | matrix->xy = temp[2]; |
| 274 | matrix->yy = temp[3]; |
| 275 | |
| 276 | /* note that the offsets must be expressed in integer font units */ |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 277 | offset->x = temp[4] >> 16; |
| 278 | offset->y = temp[5] >> 16; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 279 | } |
| 280 | |
| 281 | |
| 282 | static void |
| 283 | t42_parse_encoding( T42_Face face, |
| 284 | T42_Loader loader ) |
| 285 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 286 | T42_Parser parser = &loader->parser; |
| 287 | FT_Byte* cur; |
| 288 | FT_Byte* limit = parser->root.limit; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 289 | |
| 290 | PSAux_Service psaux = (PSAux_Service)face->psaux; |
| 291 | |
| 292 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 293 | T1_Skip_Spaces( parser ); |
| 294 | cur = parser->root.cursor; |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 295 | if ( cur >= limit ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 296 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 297 | FT_ERROR(( "t42_parse_encoding: out of bounds!\n" )); |
| 298 | parser->root.error = T42_Err_Invalid_File_Format; |
| 299 | return; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 300 | } |
| 301 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 302 | /* if we have a number or `[', the encoding is an array, */ |
| 303 | /* and we must load it now */ |
| 304 | if ( ft_isdigit( *cur ) || *cur == '[' ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 305 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 306 | T1_Encoding encode = &face->type1.encoding; |
| 307 | FT_UInt count, n; |
| 308 | PS_Table char_table = &loader->encoding_table; |
| 309 | FT_Memory memory = parser->root.memory; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 310 | FT_Error error; |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 311 | FT_Bool only_immediates = 0; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 312 | |
| 313 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 314 | /* read the number of entries in the encoding; should be 256 */ |
| 315 | if ( *cur == '[' ) |
| 316 | { |
| 317 | count = 256; |
| 318 | only_immediates = 1; |
| 319 | parser->root.cursor++; |
| 320 | } |
| 321 | else |
| 322 | count = (FT_UInt)T1_ToInt( parser ); |
Werner Lemberg | 3864f4e | 2003-09-30 06:43:54 +0000 | [diff] [blame] | 323 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 324 | T1_Skip_Spaces( parser ); |
| 325 | if ( parser->root.cursor >= limit ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 326 | return; |
| 327 | |
| 328 | /* we use a T1_Table to store our charnames */ |
| 329 | loader->num_chars = encode->num_chars = count; |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 330 | if ( FT_NEW_ARRAY( encode->char_index, count ) || |
| 331 | FT_NEW_ARRAY( encode->char_name, count ) || |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 332 | FT_SET_ERROR( psaux->ps_table_funcs->init( |
| 333 | char_table, count, memory ) ) ) |
| 334 | { |
| 335 | parser->root.error = error; |
| 336 | return; |
| 337 | } |
| 338 | |
| 339 | /* We need to `zero' out encoding_table.elements */ |
| 340 | for ( n = 0; n < count; n++ ) |
| 341 | { |
| 342 | char* notdef = (char *)".notdef"; |
| 343 | |
| 344 | |
| 345 | T1_Add_Table( char_table, n, notdef, 8 ); |
| 346 | } |
| 347 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 348 | /* Now we need to read records of the form */ |
| 349 | /* */ |
| 350 | /* ... charcode /charname ... */ |
| 351 | /* */ |
| 352 | /* for each entry in our table. */ |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 353 | /* */ |
| 354 | /* We simply look for a number followed by an immediate */ |
| 355 | /* name. Note that this ignores correctly the sequence */ |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 356 | /* that is often seen in type42 fonts: */ |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 357 | /* */ |
| 358 | /* 0 1 255 { 1 index exch /.notdef put } for dup */ |
| 359 | /* */ |
| 360 | /* used to clean the encoding array before anything else. */ |
| 361 | /* */ |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 362 | /* Alternatively, if the array is directly given as */ |
| 363 | /* */ |
| 364 | /* /Encoding [ ... ] */ |
| 365 | /* */ |
| 366 | /* we only read immediates. */ |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 367 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 368 | n = 0; |
Werner Lemberg | 4795b36 | 2003-10-23 16:24:10 +0000 | [diff] [blame] | 369 | T1_Skip_Spaces( parser ); |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 370 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 371 | while ( parser->root.cursor < limit ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 372 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 373 | cur = parser->root.cursor; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 374 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 375 | /* we stop when we encounter `def' or `]' */ |
| 376 | if ( *cur == 'd' && cur + 3 < limit ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 377 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 378 | if ( cur[1] == 'e' && |
| 379 | cur[2] == 'f' && |
| 380 | t42_is_space( cur[3] ) ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 381 | { |
| 382 | FT_TRACE6(( "encoding end\n" )); |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 383 | cur += 3; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 384 | break; |
| 385 | } |
| 386 | } |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 387 | if ( *cur == ']' ) |
| 388 | { |
| 389 | FT_TRACE6(( "encoding end\n" )); |
| 390 | cur++; |
| 391 | break; |
| 392 | } |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 393 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 394 | /* check whether we've found an entry */ |
| 395 | if ( ft_isdigit( *cur ) || only_immediates ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 396 | { |
| 397 | FT_Int charcode; |
| 398 | |
| 399 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 400 | if ( only_immediates ) |
| 401 | charcode = n; |
| 402 | else |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 403 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 404 | charcode = (FT_Int)T1_ToInt( parser ); |
| 405 | T1_Skip_Spaces( parser ); |
| 406 | } |
| 407 | |
| 408 | cur = parser->root.cursor; |
| 409 | |
| 410 | if ( *cur == '/' && cur + 2 < limit && n < count ) |
| 411 | { |
Werner Lemberg | 3864f4e | 2003-09-30 06:43:54 +0000 | [diff] [blame] | 412 | FT_PtrDist len; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 413 | |
| 414 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 415 | cur++; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 416 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 417 | parser->root.cursor = cur; |
| 418 | T1_Skip_PS_Token( parser ); |
Werner Lemberg | 1d565fb | 2005-02-13 21:42:42 +0000 | [diff] [blame] | 419 | if ( parser->root.error ) |
| 420 | return; |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 421 | |
| 422 | len = parser->root.cursor - cur; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 423 | |
| 424 | parser->root.error = T1_Add_Table( char_table, charcode, |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 425 | cur, len + 1 ); |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 426 | if ( parser->root.error ) |
| 427 | return; |
Werner Lemberg | 1d565fb | 2005-02-13 21:42:42 +0000 | [diff] [blame] | 428 | char_table->elements[charcode][len] = '\0'; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 429 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 430 | n++; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 431 | } |
| 432 | } |
| 433 | else |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 434 | T1_Skip_PS_Token( parser ); |
Werner Lemberg | 4795b36 | 2003-10-23 16:24:10 +0000 | [diff] [blame] | 435 | |
| 436 | T1_Skip_Spaces( parser ); |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 437 | } |
| 438 | |
| 439 | face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; |
| 440 | parser->root.cursor = cur; |
| 441 | } |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 442 | |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 443 | /* Otherwise, we should have either `StandardEncoding', */ |
| 444 | /* `ExpertEncoding', or `ISOLatin1Encoding' */ |
| 445 | else |
| 446 | { |
| 447 | if ( cur + 17 < limit && |
| 448 | ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) |
| 449 | face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; |
| 450 | |
| 451 | else if ( cur + 15 < limit && |
| 452 | ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) |
| 453 | face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; |
| 454 | |
| 455 | else if ( cur + 18 < limit && |
| 456 | ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) |
| 457 | face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; |
| 458 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 459 | else |
| 460 | { |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 461 | FT_ERROR(( "t42_parse_encoding: invalid token!\n" )); |
Werner Lemberg | 8c90c22 | 2002-06-08 06:47:18 +0000 | [diff] [blame] | 462 | parser->root.error = T42_Err_Invalid_File_Format; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 463 | } |
| 464 | } |
| 465 | } |
| 466 | |
| 467 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 468 | typedef enum |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 469 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 470 | BEFORE_START, |
| 471 | BEFORE_TABLE_DIR, |
| 472 | OTHER_TABLES |
David Turner | 3c40d73 | 2003-08-17 22:31:23 +0000 | [diff] [blame] | 473 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 474 | } T42_Load_Status; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 475 | |
| 476 | |
| 477 | static void |
| 478 | t42_parse_sfnts( T42_Face face, |
| 479 | T42_Loader loader ) |
| 480 | { |
| 481 | T42_Parser parser = &loader->parser; |
| 482 | FT_Memory memory = parser->root.memory; |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 483 | FT_Byte* cur; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 484 | FT_Byte* limit = parser->root.limit; |
| 485 | FT_Error error; |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 486 | FT_Int num_tables = 0; |
| 487 | FT_ULong count, ttf_size = 0; |
| 488 | |
| 489 | FT_Long n, string_size, old_string_size, real_size; |
| 490 | FT_Byte* string_buf = NULL; |
| 491 | FT_Bool alloc = 0; |
| 492 | |
| 493 | T42_Load_Status status; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 494 | |
| 495 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 496 | /* The format is */ |
| 497 | /* */ |
| 498 | /* /sfnts [ <hexstring> <hexstring> ... ] def */ |
| 499 | /* */ |
| 500 | /* or */ |
| 501 | /* */ |
| 502 | /* /sfnts [ */ |
| 503 | /* <num_bin_bytes> RD <binary data> */ |
| 504 | /* <num_bin_bytes> RD <binary data> */ |
| 505 | /* ... */ |
| 506 | /* ] def */ |
| 507 | /* */ |
| 508 | /* with exactly one space after the `RD' token. */ |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 509 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 510 | T1_Skip_Spaces( parser ); |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 511 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 512 | if ( parser->root.cursor >= limit || *parser->root.cursor++ != '[' ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 513 | { |
| 514 | FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector!\n" )); |
Werner Lemberg | 8c90c22 | 2002-06-08 06:47:18 +0000 | [diff] [blame] | 515 | error = T42_Err_Invalid_File_Format; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 516 | goto Fail; |
| 517 | } |
| 518 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 519 | T1_Skip_Spaces( parser ); |
| 520 | status = BEFORE_START; |
Werner Lemberg | 17d7581 | 2003-10-20 08:29:46 +0000 | [diff] [blame] | 521 | string_size = 0; |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 522 | old_string_size = 0; |
| 523 | count = 0; |
| 524 | |
| 525 | while ( parser->root.cursor < limit ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 526 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 527 | cur = parser->root.cursor; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 528 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 529 | if ( *cur == ']' ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 530 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 531 | parser->root.cursor++; |
| 532 | goto Exit; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 533 | } |
| 534 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 535 | else if ( *cur == '<' ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 536 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 537 | T1_Skip_PS_Token( parser ); |
| 538 | if ( parser->root.error ) |
| 539 | goto Exit; |
| 540 | |
| 541 | /* don't include delimiters */ |
| 542 | string_size = (FT_Long)( ( parser->root.cursor - cur - 2 + 1 ) / 2 ); |
| 543 | if ( FT_REALLOC( string_buf, old_string_size, string_size ) ) |
| 544 | goto Fail; |
| 545 | |
| 546 | alloc = 1; |
| 547 | |
| 548 | parser->root.cursor = cur; |
| 549 | (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 ); |
| 550 | old_string_size = string_size; |
| 551 | string_size = real_size; |
| 552 | } |
| 553 | |
| 554 | else if ( ft_isdigit( *cur ) ) |
| 555 | { |
| 556 | string_size = T1_ToInt( parser ); |
| 557 | |
| 558 | T1_Skip_PS_Token( parser ); /* `RD' */ |
Werner Lemberg | 1d565fb | 2005-02-13 21:42:42 +0000 | [diff] [blame] | 559 | if ( parser->root.error ) |
| 560 | return; |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 561 | |
| 562 | string_buf = parser->root.cursor + 1; /* one space after `RD' */ |
| 563 | |
| 564 | parser->root.cursor += string_size + 1; |
| 565 | if ( parser->root.cursor >= limit ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 566 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 567 | FT_ERROR(( "t42_parse_sfnts: too many binary data!\n" )); |
| 568 | error = T42_Err_Invalid_File_Format; |
| 569 | goto Fail; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 570 | } |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 571 | } |
| 572 | |
| 573 | /* A string can have a trailing zero byte for padding. Ignore it. */ |
| 574 | if ( string_buf[string_size - 1] == 0 && ( string_size % 2 == 1 ) ) |
| 575 | string_size--; |
| 576 | |
| 577 | for ( n = 0; n < string_size; n++ ) |
| 578 | { |
| 579 | switch ( status ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 580 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 581 | case BEFORE_START: |
| 582 | /* load offset table, 12 bytes */ |
| 583 | if ( count < 12 ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 584 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 585 | face->ttf_data[count++] = string_buf[n]; |
| 586 | continue; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 587 | } |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 588 | else |
| 589 | { |
| 590 | num_tables = 16 * face->ttf_data[4] + face->ttf_data[5]; |
| 591 | status = BEFORE_TABLE_DIR; |
| 592 | ttf_size = 12 + 16 * num_tables; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 593 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 594 | if ( FT_REALLOC( face->ttf_data, 12, ttf_size ) ) |
| 595 | goto Fail; |
| 596 | } |
| 597 | /* fall through */ |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 598 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 599 | case BEFORE_TABLE_DIR: |
| 600 | /* the offset table is read; read the table directory */ |
| 601 | if ( count < ttf_size ) |
| 602 | { |
| 603 | face->ttf_data[count++] = string_buf[n]; |
| 604 | continue; |
| 605 | } |
| 606 | else |
| 607 | { |
| 608 | int i; |
| 609 | FT_ULong len; |
| 610 | |
| 611 | |
| 612 | for ( i = 0; i < num_tables; i++ ) |
| 613 | { |
| 614 | FT_Byte* p = face->ttf_data + 12 + 16 * i + 12; |
| 615 | |
| 616 | |
| 617 | len = FT_PEEK_ULONG( p ); |
| 618 | |
| 619 | /* Pad to a 4-byte boundary length */ |
| 620 | ttf_size += ( len + 3 ) & ~3; |
| 621 | } |
| 622 | |
| 623 | status = OTHER_TABLES; |
| 624 | face->ttf_size = ttf_size; |
| 625 | |
| 626 | if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables, |
| 627 | ttf_size + 1 ) ) |
| 628 | goto Fail; |
| 629 | } |
| 630 | /* fall through */ |
| 631 | |
| 632 | case OTHER_TABLES: |
| 633 | /* all other tables are just copied */ |
| 634 | if ( count >= ttf_size ) |
| 635 | { |
| 636 | FT_ERROR(( "t42_parse_sfnts: too many binary data!\n" )); |
| 637 | error = T42_Err_Invalid_File_Format; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 638 | goto Fail; |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 639 | } |
| 640 | face->ttf_data[count++] = string_buf[n]; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 641 | } |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 642 | } |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 643 | |
| 644 | T1_Skip_Spaces( parser ); |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 645 | } |
| 646 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 647 | /* if control reaches this point, the format was not valid */ |
Werner Lemberg | 8c90c22 | 2002-06-08 06:47:18 +0000 | [diff] [blame] | 648 | error = T42_Err_Invalid_File_Format; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 649 | |
| 650 | Fail: |
| 651 | parser->root.error = error; |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 652 | |
| 653 | Exit: |
| 654 | if ( alloc ) |
| 655 | FT_FREE( string_buf ); |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 656 | } |
| 657 | |
| 658 | |
| 659 | static void |
| 660 | t42_parse_charstrings( T42_Face face, |
| 661 | T42_Loader loader ) |
| 662 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 663 | T42_Parser parser = &loader->parser; |
| 664 | PS_Table code_table = &loader->charstrings; |
| 665 | PS_Table name_table = &loader->glyph_names; |
| 666 | PS_Table swap_table = &loader->swap_table; |
| 667 | FT_Memory memory = parser->root.memory; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 668 | FT_Error error; |
| 669 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 670 | PSAux_Service psaux = (PSAux_Service)face->psaux; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 671 | |
| 672 | FT_Byte* cur; |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 673 | FT_Byte* limit = parser->root.limit; |
| 674 | FT_UInt n; |
| 675 | FT_UInt notdef_index = 0; |
| 676 | FT_Byte notdef_found = 0; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 677 | |
| 678 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 679 | T1_Skip_Spaces( parser ); |
| 680 | |
| 681 | if ( parser->root.cursor >= limit ) |
| 682 | { |
| 683 | FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" )); |
| 684 | error = T42_Err_Invalid_File_Format; |
| 685 | goto Fail; |
| 686 | } |
| 687 | |
| 688 | if ( ft_isdigit( *parser->root.cursor ) ) |
| 689 | { |
| 690 | loader->num_glyphs = (FT_UInt)T1_ToInt( parser ); |
| 691 | if ( parser->root.error ) |
| 692 | return; |
| 693 | } |
| 694 | else if ( *parser->root.cursor == '<' ) |
| 695 | { |
| 696 | /* We have `<< ... >>'. Count the number of `/' in the dictionary */ |
| 697 | /* to get its size. */ |
| 698 | FT_UInt count = 0; |
| 699 | |
| 700 | |
| 701 | T1_Skip_PS_Token( parser ); |
Werner Lemberg | 1d565fb | 2005-02-13 21:42:42 +0000 | [diff] [blame] | 702 | if ( parser->root.error ) |
| 703 | return; |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 704 | T1_Skip_Spaces( parser ); |
| 705 | cur = parser->root.cursor; |
| 706 | |
| 707 | while ( parser->root.cursor < limit ) |
| 708 | { |
| 709 | if ( *parser->root.cursor == '/' ) |
| 710 | count++; |
| 711 | else if ( *parser->root.cursor == '>' ) |
| 712 | { |
| 713 | loader->num_glyphs = count; |
| 714 | parser->root.cursor = cur; /* rewind */ |
| 715 | break; |
| 716 | } |
| 717 | T1_Skip_PS_Token( parser ); |
Werner Lemberg | 1d565fb | 2005-02-13 21:42:42 +0000 | [diff] [blame] | 718 | if ( parser->root.error ) |
| 719 | return; |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 720 | T1_Skip_Spaces( parser ); |
| 721 | } |
| 722 | } |
| 723 | else |
| 724 | { |
| 725 | FT_ERROR(( "t42_parse_charstrings: invalid token!\n" )); |
| 726 | error = T42_Err_Invalid_File_Format; |
| 727 | goto Fail; |
| 728 | } |
| 729 | |
| 730 | if ( parser->root.cursor >= limit ) |
| 731 | { |
| 732 | FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" )); |
| 733 | error = T42_Err_Invalid_File_Format; |
| 734 | goto Fail; |
| 735 | } |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 736 | |
| 737 | /* initialize tables */ |
| 738 | |
| 739 | error = psaux->ps_table_funcs->init( code_table, |
| 740 | loader->num_glyphs, |
| 741 | memory ); |
| 742 | if ( error ) |
| 743 | goto Fail; |
| 744 | |
| 745 | error = psaux->ps_table_funcs->init( name_table, |
| 746 | loader->num_glyphs, |
| 747 | memory ); |
| 748 | if ( error ) |
| 749 | goto Fail; |
| 750 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 751 | /* Initialize table for swapping index notdef_index and */ |
| 752 | /* index 0 names and codes (if necessary). */ |
| 753 | |
| 754 | error = psaux->ps_table_funcs->init( swap_table, 4, memory ); |
| 755 | if ( error ) |
| 756 | goto Fail; |
| 757 | |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 758 | n = 0; |
| 759 | |
| 760 | for (;;) |
| 761 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 762 | /* The format is simple: */ |
| 763 | /* `/glyphname' + index [+ def] */ |
| 764 | |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 765 | T1_Skip_Spaces( parser ); |
| 766 | |
| 767 | cur = parser->root.cursor; |
| 768 | if ( cur >= limit ) |
| 769 | break; |
| 770 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 771 | /* We stop when we find an `end' keyword or '>' */ |
| 772 | if ( *cur == 'e' && |
| 773 | cur + 3 < limit && |
| 774 | cur[1] == 'n' && |
| 775 | cur[2] == 'd' && |
| 776 | t42_is_space( cur[3] ) ) |
| 777 | break; |
| 778 | if ( *cur == '>' ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 779 | break; |
| 780 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 781 | T1_Skip_PS_Token( parser ); |
Werner Lemberg | 1d565fb | 2005-02-13 21:42:42 +0000 | [diff] [blame] | 782 | if ( parser->root.error ) |
| 783 | return; |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 784 | |
| 785 | if ( *cur == '/' ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 786 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 787 | FT_PtrDist len; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 788 | |
| 789 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 790 | if ( cur + 1 >= limit ) |
| 791 | { |
| 792 | FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" )); |
| 793 | error = T42_Err_Invalid_File_Format; |
| 794 | goto Fail; |
| 795 | } |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 796 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 797 | cur++; /* skip `/' */ |
| 798 | len = parser->root.cursor - cur; |
| 799 | |
| 800 | error = T1_Add_Table( name_table, n, cur, len + 1 ); |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 801 | if ( error ) |
| 802 | goto Fail; |
| 803 | |
| 804 | /* add a trailing zero to the name table */ |
| 805 | name_table->elements[n][len] = '\0'; |
| 806 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 807 | /* record index of /.notdef */ |
| 808 | if ( *cur == '.' && |
| 809 | ft_strcmp( ".notdef", |
| 810 | (const char*)(name_table->elements[n]) ) == 0 ) |
| 811 | { |
| 812 | notdef_index = n; |
| 813 | notdef_found = 1; |
| 814 | } |
| 815 | |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 816 | T1_Skip_Spaces( parser ); |
| 817 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 818 | cur = parser->root.cursor; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 819 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 820 | (void)T1_ToInt( parser ); |
| 821 | if ( parser->root.cursor >= limit ) |
| 822 | { |
| 823 | FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" )); |
| 824 | error = T42_Err_Invalid_File_Format; |
| 825 | goto Fail; |
| 826 | } |
| 827 | |
| 828 | len = parser->root.cursor - cur; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 829 | |
| 830 | error = T1_Add_Table( code_table, n, cur, len + 1 ); |
| 831 | if ( error ) |
| 832 | goto Fail; |
| 833 | |
| 834 | code_table->elements[n][len] = '\0'; |
| 835 | |
| 836 | n++; |
| 837 | if ( n >= loader->num_glyphs ) |
| 838 | break; |
| 839 | } |
| 840 | } |
| 841 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 842 | loader->num_glyphs = n; |
| 843 | |
| 844 | if ( !notdef_found ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 845 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 846 | FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph!\n" )); |
Werner Lemberg | 8c90c22 | 2002-06-08 06:47:18 +0000 | [diff] [blame] | 847 | error = T42_Err_Invalid_File_Format; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 848 | goto Fail; |
| 849 | } |
| 850 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 851 | /* if /.notdef does not occupy index 0, do our magic. */ |
| 852 | if ( ft_strcmp( (const char*)".notdef", |
| 853 | (const char*)name_table->elements[0] ) ) |
| 854 | { |
| 855 | /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ |
| 856 | /* name and code entries to swap_table. Then place notdef_index */ |
| 857 | /* name and code entries into swap_table. Then swap name and code */ |
| 858 | /* entries at indices notdef_index and 0 using values stored in */ |
| 859 | /* swap_table. */ |
| 860 | |
| 861 | /* Index 0 name */ |
| 862 | error = T1_Add_Table( swap_table, 0, |
| 863 | name_table->elements[0], |
| 864 | name_table->lengths [0] ); |
| 865 | if ( error ) |
| 866 | goto Fail; |
| 867 | |
| 868 | /* Index 0 code */ |
| 869 | error = T1_Add_Table( swap_table, 1, |
| 870 | code_table->elements[0], |
| 871 | code_table->lengths [0] ); |
| 872 | if ( error ) |
| 873 | goto Fail; |
| 874 | |
| 875 | /* Index notdef_index name */ |
| 876 | error = T1_Add_Table( swap_table, 2, |
| 877 | name_table->elements[notdef_index], |
| 878 | name_table->lengths [notdef_index] ); |
| 879 | if ( error ) |
| 880 | goto Fail; |
| 881 | |
| 882 | /* Index notdef_index code */ |
| 883 | error = T1_Add_Table( swap_table, 3, |
| 884 | code_table->elements[notdef_index], |
| 885 | code_table->lengths [notdef_index] ); |
| 886 | if ( error ) |
| 887 | goto Fail; |
| 888 | |
| 889 | error = T1_Add_Table( name_table, notdef_index, |
| 890 | swap_table->elements[0], |
| 891 | swap_table->lengths [0] ); |
| 892 | if ( error ) |
| 893 | goto Fail; |
| 894 | |
| 895 | error = T1_Add_Table( code_table, notdef_index, |
| 896 | swap_table->elements[1], |
| 897 | swap_table->lengths [1] ); |
| 898 | if ( error ) |
| 899 | goto Fail; |
| 900 | |
| 901 | error = T1_Add_Table( name_table, 0, |
| 902 | swap_table->elements[2], |
| 903 | swap_table->lengths [2] ); |
| 904 | if ( error ) |
| 905 | goto Fail; |
| 906 | |
| 907 | error = T1_Add_Table( code_table, 0, |
| 908 | swap_table->elements[3], |
| 909 | swap_table->lengths [3] ); |
| 910 | if ( error ) |
| 911 | goto Fail; |
| 912 | |
| 913 | } |
| 914 | |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 915 | return; |
| 916 | |
| 917 | Fail: |
| 918 | parser->root.error = error; |
| 919 | } |
| 920 | |
| 921 | |
| 922 | static FT_Error |
| 923 | t42_load_keyword( T42_Face face, |
| 924 | T42_Loader loader, |
| 925 | T1_Field field ) |
| 926 | { |
| 927 | FT_Error error; |
| 928 | void* dummy_object; |
| 929 | void** objects; |
| 930 | FT_UInt max_objects = 0; |
| 931 | |
| 932 | |
| 933 | /* if the keyword has a dedicated callback, call it */ |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 934 | if ( field->type == T1_FIELD_TYPE_CALLBACK ) |
| 935 | { |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 936 | field->reader( (FT_Face)face, loader ); |
| 937 | error = loader->parser.root.error; |
| 938 | goto Exit; |
| 939 | } |
| 940 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 941 | /* now the keyword is either a simple field or a table of fields; */ |
| 942 | /* we are now going to take care of it */ |
| 943 | |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 944 | switch ( field->location ) |
| 945 | { |
| 946 | case T1_FIELD_LOCATION_FONT_INFO: |
| 947 | dummy_object = &face->type1.font_info; |
Werner Lemberg | fdc042b | 2003-06-12 04:59:07 +0000 | [diff] [blame] | 948 | break; |
| 949 | |
| 950 | case T1_FIELD_LOCATION_BBOX: |
| 951 | dummy_object = &face->type1.font_bbox; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 952 | break; |
| 953 | |
| 954 | default: |
| 955 | dummy_object = &face->type1; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 956 | } |
| 957 | |
Werner Lemberg | fdc042b | 2003-06-12 04:59:07 +0000 | [diff] [blame] | 958 | objects = &dummy_object; |
| 959 | |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 960 | if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || |
| 961 | field->type == T1_FIELD_TYPE_FIXED_ARRAY ) |
| 962 | error = T1_Load_Field_Table( &loader->parser, field, |
| 963 | objects, max_objects, 0 ); |
| 964 | else |
| 965 | error = T1_Load_Field( &loader->parser, field, |
| 966 | objects, max_objects, 0 ); |
| 967 | |
| 968 | Exit: |
| 969 | return error; |
| 970 | } |
| 971 | |
| 972 | |
| 973 | FT_LOCAL_DEF( FT_Error ) |
| 974 | t42_parse_dict( T42_Face face, |
| 975 | T42_Loader loader, |
| 976 | FT_Byte* base, |
| 977 | FT_Long size ) |
| 978 | { |
Werner Lemberg | 7386197 | 2003-06-05 04:31:05 +0000 | [diff] [blame] | 979 | T42_Parser parser = &loader->parser; |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 980 | FT_Byte* limit; |
Werner Lemberg | dc8ad54 | 2003-12-09 02:12:14 +0000 | [diff] [blame] | 981 | FT_Int n_keywords = (FT_Int)( sizeof ( t42_keywords ) / |
| 982 | sizeof ( t42_keywords[0] ) ); |
David Turner | 3c40d73 | 2003-08-17 22:31:23 +0000 | [diff] [blame] | 983 | |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 984 | |
| 985 | parser->root.cursor = base; |
| 986 | parser->root.limit = base + size; |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 987 | parser->root.error = T42_Err_Ok; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 988 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 989 | limit = parser->root.limit; |
| 990 | |
| 991 | T1_Skip_Spaces( parser ); |
| 992 | |
| 993 | while ( parser->root.cursor < limit ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 994 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 995 | FT_Byte* cur; |
| 996 | |
| 997 | |
| 998 | cur = parser->root.cursor; |
| 999 | |
| 1000 | /* look for `FontDirectory' which causes problems for some fonts */ |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 1001 | if ( *cur == 'F' && cur + 25 < limit && |
| 1002 | ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 ) |
| 1003 | { |
| 1004 | FT_Byte* cur2; |
| 1005 | |
| 1006 | |
| 1007 | /* skip the `FontDirectory' keyword */ |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 1008 | T1_Skip_PS_Token( parser ); |
| 1009 | T1_Skip_Spaces ( parser ); |
| 1010 | cur = cur2 = parser->root.cursor; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 1011 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 1012 | /* look up the `known' keyword */ |
| 1013 | while ( cur < limit ) |
| 1014 | { |
| 1015 | if ( *cur == 'k' && cur + 5 < limit && |
| 1016 | ft_strncmp( (char*)cur, "known", 5 ) == 0 ) |
| 1017 | break; |
| 1018 | |
| 1019 | T1_Skip_PS_Token( parser ); |
Werner Lemberg | 1d565fb | 2005-02-13 21:42:42 +0000 | [diff] [blame] | 1020 | if ( parser->root.error ) |
| 1021 | goto Exit; |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 1022 | T1_Skip_Spaces ( parser ); |
| 1023 | cur = parser->root.cursor; |
| 1024 | } |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 1025 | |
| 1026 | if ( cur < limit ) |
| 1027 | { |
| 1028 | T1_TokenRec token; |
| 1029 | |
| 1030 | |
| 1031 | /* skip the `known' keyword and the token following it */ |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 1032 | T1_Skip_PS_Token( parser ); |
| 1033 | T1_ToToken( parser, &token ); |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 1034 | |
| 1035 | /* if the last token was an array, skip it! */ |
| 1036 | if ( token.type == T1_TOKEN_TYPE_ARRAY ) |
| 1037 | cur2 = parser->root.cursor; |
| 1038 | } |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 1039 | parser->root.cursor = cur2; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 1040 | } |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 1041 | |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 1042 | /* look for immediates */ |
| 1043 | else if ( *cur == '/' && cur + 2 < limit ) |
| 1044 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 1045 | FT_PtrDist len; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 1046 | |
| 1047 | |
| 1048 | cur++; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 1049 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 1050 | parser->root.cursor = cur; |
| 1051 | T1_Skip_PS_Token( parser ); |
Werner Lemberg | 1d565fb | 2005-02-13 21:42:42 +0000 | [diff] [blame] | 1052 | if ( parser->root.error ) |
| 1053 | goto Exit; |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 1054 | |
| 1055 | len = parser->root.cursor - cur; |
| 1056 | |
| 1057 | if ( len > 0 && len < 22 && parser->root.cursor < limit ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 1058 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 1059 | int i; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 1060 | |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 1061 | |
| 1062 | /* now compare the immediate name to the keyword table */ |
| 1063 | |
| 1064 | /* loop through all known keywords */ |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 1065 | for ( i = 0; i < n_keywords; i++ ) |
| 1066 | { |
| 1067 | T1_Field keyword = (T1_Field)&t42_keywords[i]; |
| 1068 | FT_Byte *name = (FT_Byte*)keyword->ident; |
| 1069 | |
| 1070 | |
| 1071 | if ( !name ) |
| 1072 | continue; |
| 1073 | |
Werner Lemberg | 3605e47 | 2004-11-12 07:02:45 +0000 | [diff] [blame] | 1074 | if ( cur[0] == name[0] && |
| 1075 | len == (FT_PtrDist)ft_strlen( (const char *)name ) && |
| 1076 | ft_memcmp( cur, name, len ) == 0 ) |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 1077 | { |
| 1078 | /* we found it -- run the parsing callback! */ |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 1079 | parser->root.error = t42_load_keyword( face, |
| 1080 | loader, |
| 1081 | keyword ); |
| 1082 | if ( parser->root.error ) |
| 1083 | return parser->root.error; |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 1084 | break; |
| 1085 | } |
| 1086 | } |
| 1087 | } |
| 1088 | } |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 1089 | else |
Werner Lemberg | 1d565fb | 2005-02-13 21:42:42 +0000 | [diff] [blame] | 1090 | { |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 1091 | T1_Skip_PS_Token( parser ); |
Werner Lemberg | 1d565fb | 2005-02-13 21:42:42 +0000 | [diff] [blame] | 1092 | if ( parser->root.error ) |
| 1093 | goto Exit; |
| 1094 | } |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 1095 | |
| 1096 | T1_Skip_Spaces( parser ); |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 1097 | } |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 1098 | |
Werner Lemberg | 1d565fb | 2005-02-13 21:42:42 +0000 | [diff] [blame] | 1099 | Exit: |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 1100 | return parser->root.error; |
| 1101 | } |
| 1102 | |
| 1103 | |
| 1104 | FT_LOCAL_DEF( void ) |
| 1105 | t42_loader_init( T42_Loader loader, |
| 1106 | T42_Face face ) |
| 1107 | { |
| 1108 | FT_UNUSED( face ); |
| 1109 | |
Werner Lemberg | b3d5e9c | 2002-07-28 05:05:24 +0000 | [diff] [blame] | 1110 | FT_MEM_ZERO( loader, sizeof ( *loader ) ); |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 1111 | loader->num_glyphs = 0; |
| 1112 | loader->num_chars = 0; |
| 1113 | |
| 1114 | /* initialize the tables -- simply set their `init' field to 0 */ |
| 1115 | loader->encoding_table.init = 0; |
| 1116 | loader->charstrings.init = 0; |
| 1117 | loader->glyph_names.init = 0; |
| 1118 | } |
| 1119 | |
| 1120 | |
| 1121 | FT_LOCAL_DEF( void ) |
| 1122 | t42_loader_done( T42_Loader loader ) |
| 1123 | { |
| 1124 | T42_Parser parser = &loader->parser; |
| 1125 | |
| 1126 | |
| 1127 | /* finalize tables */ |
| 1128 | T1_Release_Table( &loader->encoding_table ); |
| 1129 | T1_Release_Table( &loader->charstrings ); |
| 1130 | T1_Release_Table( &loader->glyph_names ); |
Werner Lemberg | e3f4198 | 2003-10-16 15:48:39 +0000 | [diff] [blame] | 1131 | T1_Release_Table( &loader->swap_table ); |
David Turner | 9f95bab | 2002-06-07 07:23:06 +0000 | [diff] [blame] | 1132 | |
| 1133 | /* finalize parser */ |
| 1134 | t42_parser_done( parser ); |
| 1135 | } |
| 1136 | |
| 1137 | |
Werner Lemberg | 8c90c22 | 2002-06-08 06:47:18 +0000 | [diff] [blame] | 1138 | /* END */ |