Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygent42parse.cGo to the documentation of this file.00001 /***************************************************************************/ 00002 /* */ 00003 /* t42parse.c */ 00004 /* */ 00005 /* Type 42 font parser (body). */ 00006 /* */ 00007 /* Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 by */ 00008 /* Roberto Alameda. */ 00009 /* */ 00010 /* This file is part of the FreeType project, and may only be used, */ 00011 /* modified, and distributed under the terms of the FreeType project */ 00012 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 00013 /* this file you indicate that you have read the license and */ 00014 /* understand and accept it fully. */ 00015 /* */ 00016 /***************************************************************************/ 00017 00018 00019 #include "t42parse.h" 00020 #include "t42error.h" 00021 #include FT_INTERNAL_DEBUG_H 00022 #include FT_INTERNAL_STREAM_H 00023 #include FT_INTERNAL_POSTSCRIPT_AUX_H 00024 00025 00026 /*************************************************************************/ 00027 /* */ 00028 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 00029 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 00030 /* messages during execution. */ 00031 /* */ 00032 #undef FT_COMPONENT 00033 #define FT_COMPONENT trace_t42 00034 00035 00036 static void 00037 t42_parse_font_matrix( T42_Face face, 00038 T42_Loader loader ); 00039 static void 00040 t42_parse_encoding( T42_Face face, 00041 T42_Loader loader ); 00042 00043 static void 00044 t42_parse_charstrings( T42_Face face, 00045 T42_Loader loader ); 00046 00047 static void 00048 t42_parse_sfnts( T42_Face face, 00049 T42_Loader loader ); 00050 00051 00052 /* as Type42 fonts have no Private dict, */ 00053 /* we set the last argument of T1_FIELD_XXX to 0 */ 00054 static const 00055 T1_FieldRec t42_keywords[] = 00056 { 00057 00058 #undef FT_STRUCTURE 00059 #define FT_STRUCTURE T1_FontInfo 00060 #undef T1CODE 00061 #define T1CODE T1_FIELD_LOCATION_FONT_INFO 00062 00063 T1_FIELD_STRING( "version", version, 0 ) 00064 T1_FIELD_STRING( "Notice", notice, 0 ) 00065 T1_FIELD_STRING( "FullName", full_name, 0 ) 00066 T1_FIELD_STRING( "FamilyName", family_name, 0 ) 00067 T1_FIELD_STRING( "Weight", weight, 0 ) 00068 T1_FIELD_NUM ( "ItalicAngle", italic_angle, 0 ) 00069 T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch, 0 ) 00070 T1_FIELD_NUM ( "UnderlinePosition", underline_position, 0 ) 00071 T1_FIELD_NUM ( "UnderlineThickness", underline_thickness, 0 ) 00072 00073 #undef FT_STRUCTURE 00074 #define FT_STRUCTURE PS_FontExtraRec 00075 #undef T1CODE 00076 #define T1CODE T1_FIELD_LOCATION_FONT_EXTRA 00077 00078 T1_FIELD_NUM ( "FSType", fs_type, 0 ) 00079 00080 #undef FT_STRUCTURE 00081 #define FT_STRUCTURE T1_FontRec 00082 #undef T1CODE 00083 #define T1CODE T1_FIELD_LOCATION_FONT_DICT 00084 00085 T1_FIELD_KEY ( "FontName", font_name, 0 ) 00086 T1_FIELD_NUM ( "PaintType", paint_type, 0 ) 00087 T1_FIELD_NUM ( "FontType", font_type, 0 ) 00088 T1_FIELD_FIXED( "StrokeWidth", stroke_width, 0 ) 00089 00090 #undef FT_STRUCTURE 00091 #define FT_STRUCTURE FT_BBox 00092 #undef T1CODE 00093 #define T1CODE T1_FIELD_LOCATION_BBOX 00094 00095 T1_FIELD_BBOX("FontBBox", xMin, 0 ) 00096 00097 T1_FIELD_CALLBACK( "FontMatrix", t42_parse_font_matrix, 0 ) 00098 T1_FIELD_CALLBACK( "Encoding", t42_parse_encoding, 0 ) 00099 T1_FIELD_CALLBACK( "CharStrings", t42_parse_charstrings, 0 ) 00100 T1_FIELD_CALLBACK( "sfnts", t42_parse_sfnts, 0 ) 00101 00102 { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } 00103 }; 00104 00105 00106 #define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l ) 00107 #define T1_Done_Table( p ) \ 00108 do \ 00109 { \ 00110 if ( (p)->funcs.done ) \ 00111 (p)->funcs.done( p ); \ 00112 } while ( 0 ) 00113 #define T1_Release_Table( p ) \ 00114 do \ 00115 { \ 00116 if ( (p)->funcs.release ) \ 00117 (p)->funcs.release( p ); \ 00118 } while ( 0 ) 00119 00120 #define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root ) 00121 #define T1_Skip_PS_Token( p ) (p)->root.funcs.skip_PS_token( &(p)->root ) 00122 00123 #define T1_ToInt( p ) \ 00124 (p)->root.funcs.to_int( &(p)->root ) 00125 #define T1_ToBytes( p, b, m, n, d ) \ 00126 (p)->root.funcs.to_bytes( &(p)->root, b, m, n, d ) 00127 00128 #define T1_ToFixedArray( p, m, f, t ) \ 00129 (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t ) 00130 #define T1_ToToken( p, t ) \ 00131 (p)->root.funcs.to_token( &(p)->root, t ) 00132 00133 #define T1_Load_Field( p, f, o, m, pf ) \ 00134 (p)->root.funcs.load_field( &(p)->root, f, o, m, pf ) 00135 #define T1_Load_Field_Table( p, f, o, m, pf ) \ 00136 (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf ) 00137 00138 00139 /********************* Parsing Functions ******************/ 00140 00141 FT_LOCAL_DEF( FT_Error ) 00142 t42_parser_init( T42_Parser parser, 00143 FT_Stream stream, 00144 FT_Memory memory, 00145 PSAux_Service psaux ) 00146 { 00147 FT_Error error = T42_Err_Ok; 00148 FT_Long size; 00149 00150 00151 psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory ); 00152 00153 parser->stream = stream; 00154 parser->base_len = 0; 00155 parser->base_dict = 0; 00156 parser->in_memory = 0; 00157 00158 /*******************************************************************/ 00159 /* */ 00160 /* Here a short summary of what is going on: */ 00161 /* */ 00162 /* When creating a new Type 42 parser, we try to locate and load */ 00163 /* the base dictionary, loading the whole font into memory. */ 00164 /* */ 00165 /* When `loading' the base dictionary, we only set up pointers */ 00166 /* in the case of a memory-based stream. Otherwise, we allocate */ 00167 /* and load the base dictionary in it. */ 00168 /* */ 00169 /* parser->in_memory is set if we have a memory stream. */ 00170 /* */ 00171 00172 if ( FT_STREAM_SEEK( 0L ) || 00173 FT_FRAME_ENTER( 17 ) ) 00174 goto Exit; 00175 00176 if ( ft_memcmp( stream->cursor, "%!PS-TrueTypeFont", 17 ) != 0 ) 00177 { 00178 FT_TRACE2(( "not a Type42 font\n" )); 00179 error = T42_Err_Unknown_File_Format; 00180 } 00181 00182 FT_FRAME_EXIT(); 00183 00184 if ( error || FT_STREAM_SEEK( 0 ) ) 00185 goto Exit; 00186 00187 size = stream->size; 00188 00189 /* now, try to load `size' bytes of the `base' dictionary we */ 00190 /* found previously */ 00191 00192 /* if it is a memory-based resource, set up pointers */ 00193 if ( !stream->read ) 00194 { 00195 parser->base_dict = (FT_Byte*)stream->base + stream->pos; 00196 parser->base_len = size; 00197 parser->in_memory = 1; 00198 00199 /* check that the `size' field is valid */ 00200 if ( FT_STREAM_SKIP( size ) ) 00201 goto Exit; 00202 } 00203 else 00204 { 00205 /* read segment in memory */ 00206 if ( FT_ALLOC( parser->base_dict, size ) || 00207 FT_STREAM_READ( parser->base_dict, size ) ) 00208 goto Exit; 00209 00210 parser->base_len = size; 00211 } 00212 00213 parser->root.base = parser->base_dict; 00214 parser->root.cursor = parser->base_dict; 00215 parser->root.limit = parser->root.cursor + parser->base_len; 00216 00217 Exit: 00218 if ( error && !parser->in_memory ) 00219 FT_FREE( parser->base_dict ); 00220 00221 return error; 00222 } 00223 00224 00225 FT_LOCAL_DEF( void ) 00226 t42_parser_done( T42_Parser parser ) 00227 { 00228 FT_Memory memory = parser->root.memory; 00229 00230 00231 /* free the base dictionary only when we have a disk stream */ 00232 if ( !parser->in_memory ) 00233 FT_FREE( parser->base_dict ); 00234 00235 parser->root.funcs.done( &parser->root ); 00236 } 00237 00238 00239 static int 00240 t42_is_space( FT_Byte c ) 00241 { 00242 return ( c == ' ' || c == '\t' || 00243 c == '\r' || c == '\n' || c == '\f' || 00244 c == '\0' ); 00245 } 00246 00247 00248 static void 00249 t42_parse_font_matrix( T42_Face face, 00250 T42_Loader loader ) 00251 { 00252 T42_Parser parser = &loader->parser; 00253 FT_Matrix* matrix = &face->type1.font_matrix; 00254 FT_Vector* offset = &face->type1.font_offset; 00255 FT_Face root = (FT_Face)&face->root; 00256 FT_Fixed temp[6]; 00257 FT_Fixed temp_scale; 00258 00259 00260 (void)T1_ToFixedArray( parser, 6, temp, 3 ); 00261 00262 temp_scale = FT_ABS( temp[3] ); 00263 00264 /* Set Units per EM based on FontMatrix values. We set the value to */ 00265 /* 1000 / temp_scale, because temp_scale was already multiplied by */ 00266 /* 1000 (in t1_tofixed, from psobjs.c). */ 00267 00268 root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L, 00269 temp_scale ) >> 16 ); 00270 00271 /* we need to scale the values by 1.0/temp_scale */ 00272 if ( temp_scale != 0x10000L ) 00273 { 00274 temp[0] = FT_DivFix( temp[0], temp_scale ); 00275 temp[1] = FT_DivFix( temp[1], temp_scale ); 00276 temp[2] = FT_DivFix( temp[2], temp_scale ); 00277 temp[4] = FT_DivFix( temp[4], temp_scale ); 00278 temp[5] = FT_DivFix( temp[5], temp_scale ); 00279 temp[3] = 0x10000L; 00280 } 00281 00282 matrix->xx = temp[0]; 00283 matrix->yx = temp[1]; 00284 matrix->xy = temp[2]; 00285 matrix->yy = temp[3]; 00286 00287 /* note that the offsets must be expressed in integer font units */ 00288 offset->x = temp[4] >> 16; 00289 offset->y = temp[5] >> 16; 00290 } 00291 00292 00293 static void 00294 t42_parse_encoding( T42_Face face, 00295 T42_Loader loader ) 00296 { 00297 T42_Parser parser = &loader->parser; 00298 FT_Byte* cur; 00299 FT_Byte* limit = parser->root.limit; 00300 00301 PSAux_Service psaux = (PSAux_Service)face->psaux; 00302 00303 00304 T1_Skip_Spaces( parser ); 00305 cur = parser->root.cursor; 00306 if ( cur >= limit ) 00307 { 00308 FT_ERROR(( "t42_parse_encoding: out of bounds\n" )); 00309 parser->root.error = T42_Err_Invalid_File_Format; 00310 return; 00311 } 00312 00313 /* if we have a number or `[', the encoding is an array, */ 00314 /* and we must load it now */ 00315 if ( ft_isdigit( *cur ) || *cur == '[' ) 00316 { 00317 T1_Encoding encode = &face->type1.encoding; 00318 FT_UInt count, n; 00319 PS_Table char_table = &loader->encoding_table; 00320 FT_Memory memory = parser->root.memory; 00321 FT_Error error; 00322 FT_Bool only_immediates = 0; 00323 00324 00325 /* read the number of entries in the encoding; should be 256 */ 00326 if ( *cur == '[' ) 00327 { 00328 count = 256; 00329 only_immediates = 1; 00330 parser->root.cursor++; 00331 } 00332 else 00333 count = (FT_UInt)T1_ToInt( parser ); 00334 00335 T1_Skip_Spaces( parser ); 00336 if ( parser->root.cursor >= limit ) 00337 return; 00338 00339 /* we use a T1_Table to store our charnames */ 00340 loader->num_chars = encode->num_chars = count; 00341 if ( FT_NEW_ARRAY( encode->char_index, count ) || 00342 FT_NEW_ARRAY( encode->char_name, count ) || 00343 FT_SET_ERROR( psaux->ps_table_funcs->init( 00344 char_table, count, memory ) ) ) 00345 { 00346 parser->root.error = error; 00347 return; 00348 } 00349 00350 /* We need to `zero' out encoding_table.elements */ 00351 for ( n = 0; n < count; n++ ) 00352 { 00353 char* notdef = (char *)".notdef"; 00354 00355 00356 T1_Add_Table( char_table, n, notdef, 8 ); 00357 } 00358 00359 /* Now we need to read records of the form */ 00360 /* */ 00361 /* ... charcode /charname ... */ 00362 /* */ 00363 /* for each entry in our table. */ 00364 /* */ 00365 /* We simply look for a number followed by an immediate */ 00366 /* name. Note that this ignores correctly the sequence */ 00367 /* that is often seen in type42 fonts: */ 00368 /* */ 00369 /* 0 1 255 { 1 index exch /.notdef put } for dup */ 00370 /* */ 00371 /* used to clean the encoding array before anything else. */ 00372 /* */ 00373 /* Alternatively, if the array is directly given as */ 00374 /* */ 00375 /* /Encoding [ ... ] */ 00376 /* */ 00377 /* we only read immediates. */ 00378 00379 n = 0; 00380 T1_Skip_Spaces( parser ); 00381 00382 while ( parser->root.cursor < limit ) 00383 { 00384 cur = parser->root.cursor; 00385 00386 /* we stop when we encounter `def' or `]' */ 00387 if ( *cur == 'd' && cur + 3 < limit ) 00388 { 00389 if ( cur[1] == 'e' && 00390 cur[2] == 'f' && 00391 t42_is_space( cur[3] ) ) 00392 { 00393 FT_TRACE6(( "encoding end\n" )); 00394 cur += 3; 00395 break; 00396 } 00397 } 00398 if ( *cur == ']' ) 00399 { 00400 FT_TRACE6(( "encoding end\n" )); 00401 cur++; 00402 break; 00403 } 00404 00405 /* check whether we have found an entry */ 00406 if ( ft_isdigit( *cur ) || only_immediates ) 00407 { 00408 FT_Int charcode; 00409 00410 00411 if ( only_immediates ) 00412 charcode = n; 00413 else 00414 { 00415 charcode = (FT_Int)T1_ToInt( parser ); 00416 T1_Skip_Spaces( parser ); 00417 } 00418 00419 cur = parser->root.cursor; 00420 00421 if ( *cur == '/' && cur + 2 < limit && n < count ) 00422 { 00423 FT_PtrDist len; 00424 00425 00426 cur++; 00427 00428 parser->root.cursor = cur; 00429 T1_Skip_PS_Token( parser ); 00430 if ( parser->root.error ) 00431 return; 00432 00433 len = parser->root.cursor - cur; 00434 00435 parser->root.error = T1_Add_Table( char_table, charcode, 00436 cur, len + 1 ); 00437 if ( parser->root.error ) 00438 return; 00439 char_table->elements[charcode][len] = '\0'; 00440 00441 n++; 00442 } 00443 } 00444 else 00445 { 00446 T1_Skip_PS_Token( parser ); 00447 if ( parser->root.error ) 00448 return; 00449 } 00450 00451 T1_Skip_Spaces( parser ); 00452 } 00453 00454 face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY; 00455 parser->root.cursor = cur; 00456 } 00457 00458 /* Otherwise, we should have either `StandardEncoding', */ 00459 /* `ExpertEncoding', or `ISOLatin1Encoding' */ 00460 else 00461 { 00462 if ( cur + 17 < limit && 00463 ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 ) 00464 face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD; 00465 00466 else if ( cur + 15 < limit && 00467 ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 ) 00468 face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT; 00469 00470 else if ( cur + 18 < limit && 00471 ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 ) 00472 face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1; 00473 00474 else 00475 { 00476 FT_ERROR(( "t42_parse_encoding: invalid token\n" )); 00477 parser->root.error = T42_Err_Invalid_File_Format; 00478 } 00479 } 00480 } 00481 00482 00483 typedef enum T42_Load_Status_ 00484 { 00485 BEFORE_START, 00486 BEFORE_TABLE_DIR, 00487 OTHER_TABLES 00488 00489 } T42_Load_Status; 00490 00491 00492 static void 00493 t42_parse_sfnts( T42_Face face, 00494 T42_Loader loader ) 00495 { 00496 T42_Parser parser = &loader->parser; 00497 FT_Memory memory = parser->root.memory; 00498 FT_Byte* cur; 00499 FT_Byte* limit = parser->root.limit; 00500 FT_Error error; 00501 FT_Int num_tables = 0; 00502 FT_ULong count, ttf_size = 0; 00503 00504 FT_Long n, string_size, old_string_size, real_size; 00505 FT_Byte* string_buf = NULL; 00506 FT_Bool allocated = 0; 00507 00508 T42_Load_Status status; 00509 00510 00511 /* The format is */ 00512 /* */ 00513 /* /sfnts [ <hexstring> <hexstring> ... ] def */ 00514 /* */ 00515 /* or */ 00516 /* */ 00517 /* /sfnts [ */ 00518 /* <num_bin_bytes> RD <binary data> */ 00519 /* <num_bin_bytes> RD <binary data> */ 00520 /* ... */ 00521 /* ] def */ 00522 /* */ 00523 /* with exactly one space after the `RD' token. */ 00524 00525 T1_Skip_Spaces( parser ); 00526 00527 if ( parser->root.cursor >= limit || *parser->root.cursor++ != '[' ) 00528 { 00529 FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector\n" )); 00530 error = T42_Err_Invalid_File_Format; 00531 goto Fail; 00532 } 00533 00534 T1_Skip_Spaces( parser ); 00535 status = BEFORE_START; 00536 string_size = 0; 00537 old_string_size = 0; 00538 count = 0; 00539 00540 while ( parser->root.cursor < limit ) 00541 { 00542 cur = parser->root.cursor; 00543 00544 if ( *cur == ']' ) 00545 { 00546 parser->root.cursor++; 00547 goto Exit; 00548 } 00549 00550 else if ( *cur == '<' ) 00551 { 00552 T1_Skip_PS_Token( parser ); 00553 if ( parser->root.error ) 00554 goto Exit; 00555 00556 /* don't include delimiters */ 00557 string_size = (FT_Long)( ( parser->root.cursor - cur - 2 + 1 ) / 2 ); 00558 if ( FT_REALLOC( string_buf, old_string_size, string_size ) ) 00559 goto Fail; 00560 00561 allocated = 1; 00562 00563 parser->root.cursor = cur; 00564 (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 ); 00565 old_string_size = string_size; 00566 string_size = real_size; 00567 } 00568 00569 else if ( ft_isdigit( *cur ) ) 00570 { 00571 if ( allocated ) 00572 { 00573 FT_ERROR(( "t42_parse_sfnts: " 00574 "can't handle mixed binary and hex strings\n" )); 00575 error = T42_Err_Invalid_File_Format; 00576 goto Fail; 00577 } 00578 00579 string_size = T1_ToInt( parser ); 00580 if ( string_size < 0 ) 00581 { 00582 FT_ERROR(( "t42_parse_sfnts: invalid string size\n" )); 00583 error = T42_Err_Invalid_File_Format; 00584 goto Fail; 00585 } 00586 00587 T1_Skip_PS_Token( parser ); /* `RD' */ 00588 if ( parser->root.error ) 00589 return; 00590 00591 string_buf = parser->root.cursor + 1; /* one space after `RD' */ 00592 00593 if ( limit - parser->root.cursor < string_size ) 00594 { 00595 FT_ERROR(( "t42_parse_sfnts: too many binary data\n" )); 00596 error = T42_Err_Invalid_File_Format; 00597 goto Fail; 00598 } 00599 else 00600 parser->root.cursor += string_size + 1; 00601 } 00602 00603 if ( !string_buf ) 00604 { 00605 FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" )); 00606 error = T42_Err_Invalid_File_Format; 00607 goto Fail; 00608 } 00609 00610 /* A string can have a trailing zero byte for padding. Ignore it. */ 00611 if ( string_buf[string_size - 1] == 0 && ( string_size % 2 == 1 ) ) 00612 string_size--; 00613 00614 if ( !string_size ) 00615 { 00616 FT_ERROR(( "t42_parse_sfnts: invalid string\n" )); 00617 error = T42_Err_Invalid_File_Format; 00618 goto Fail; 00619 } 00620 00621 for ( n = 0; n < string_size; n++ ) 00622 { 00623 switch ( status ) 00624 { 00625 case BEFORE_START: 00626 /* load offset table, 12 bytes */ 00627 if ( count < 12 ) 00628 { 00629 face->ttf_data[count++] = string_buf[n]; 00630 continue; 00631 } 00632 else 00633 { 00634 num_tables = 16 * face->ttf_data[4] + face->ttf_data[5]; 00635 status = BEFORE_TABLE_DIR; 00636 ttf_size = 12 + 16 * num_tables; 00637 00638 if ( FT_REALLOC( face->ttf_data, 12, ttf_size ) ) 00639 goto Fail; 00640 } 00641 /* fall through */ 00642 00643 case BEFORE_TABLE_DIR: 00644 /* the offset table is read; read the table directory */ 00645 if ( count < ttf_size ) 00646 { 00647 face->ttf_data[count++] = string_buf[n]; 00648 continue; 00649 } 00650 else 00651 { 00652 int i; 00653 FT_ULong len; 00654 00655 00656 for ( i = 0; i < num_tables; i++ ) 00657 { 00658 FT_Byte* p = face->ttf_data + 12 + 16 * i + 12; 00659 00660 00661 len = FT_PEEK_ULONG( p ); 00662 00663 /* Pad to a 4-byte boundary length */ 00664 ttf_size += ( len + 3 ) & ~3; 00665 } 00666 00667 status = OTHER_TABLES; 00668 face->ttf_size = ttf_size; 00669 00670 /* there are no more than 256 tables, so no size check here */ 00671 if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables, 00672 ttf_size + 1 ) ) 00673 goto Fail; 00674 } 00675 /* fall through */ 00676 00677 case OTHER_TABLES: 00678 /* all other tables are just copied */ 00679 if ( count >= ttf_size ) 00680 { 00681 FT_ERROR(( "t42_parse_sfnts: too many binary data\n" )); 00682 error = T42_Err_Invalid_File_Format; 00683 goto Fail; 00684 } 00685 face->ttf_data[count++] = string_buf[n]; 00686 } 00687 } 00688 00689 T1_Skip_Spaces( parser ); 00690 } 00691 00692 /* if control reaches this point, the format was not valid */ 00693 error = T42_Err_Invalid_File_Format; 00694 00695 Fail: 00696 parser->root.error = error; 00697 00698 Exit: 00699 if ( allocated ) 00700 FT_FREE( string_buf ); 00701 } 00702 00703 00704 static void 00705 t42_parse_charstrings( T42_Face face, 00706 T42_Loader loader ) 00707 { 00708 T42_Parser parser = &loader->parser; 00709 PS_Table code_table = &loader->charstrings; 00710 PS_Table name_table = &loader->glyph_names; 00711 PS_Table swap_table = &loader->swap_table; 00712 FT_Memory memory = parser->root.memory; 00713 FT_Error error; 00714 00715 PSAux_Service psaux = (PSAux_Service)face->psaux; 00716 00717 FT_Byte* cur; 00718 FT_Byte* limit = parser->root.limit; 00719 FT_UInt n; 00720 FT_UInt notdef_index = 0; 00721 FT_Byte notdef_found = 0; 00722 00723 00724 T1_Skip_Spaces( parser ); 00725 00726 if ( parser->root.cursor >= limit ) 00727 { 00728 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); 00729 error = T42_Err_Invalid_File_Format; 00730 goto Fail; 00731 } 00732 00733 if ( ft_isdigit( *parser->root.cursor ) ) 00734 { 00735 loader->num_glyphs = (FT_UInt)T1_ToInt( parser ); 00736 if ( parser->root.error ) 00737 return; 00738 } 00739 else if ( *parser->root.cursor == '<' ) 00740 { 00741 /* We have `<< ... >>'. Count the number of `/' in the dictionary */ 00742 /* to get its size. */ 00743 FT_UInt count = 0; 00744 00745 00746 T1_Skip_PS_Token( parser ); 00747 if ( parser->root.error ) 00748 return; 00749 T1_Skip_Spaces( parser ); 00750 cur = parser->root.cursor; 00751 00752 while ( parser->root.cursor < limit ) 00753 { 00754 if ( *parser->root.cursor == '/' ) 00755 count++; 00756 else if ( *parser->root.cursor == '>' ) 00757 { 00758 loader->num_glyphs = count; 00759 parser->root.cursor = cur; /* rewind */ 00760 break; 00761 } 00762 T1_Skip_PS_Token( parser ); 00763 if ( parser->root.error ) 00764 return; 00765 T1_Skip_Spaces( parser ); 00766 } 00767 } 00768 else 00769 { 00770 FT_ERROR(( "t42_parse_charstrings: invalid token\n" )); 00771 error = T42_Err_Invalid_File_Format; 00772 goto Fail; 00773 } 00774 00775 if ( parser->root.cursor >= limit ) 00776 { 00777 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); 00778 error = T42_Err_Invalid_File_Format; 00779 goto Fail; 00780 } 00781 00782 /* initialize tables */ 00783 00784 error = psaux->ps_table_funcs->init( code_table, 00785 loader->num_glyphs, 00786 memory ); 00787 if ( error ) 00788 goto Fail; 00789 00790 error = psaux->ps_table_funcs->init( name_table, 00791 loader->num_glyphs, 00792 memory ); 00793 if ( error ) 00794 goto Fail; 00795 00796 /* Initialize table for swapping index notdef_index and */ 00797 /* index 0 names and codes (if necessary). */ 00798 00799 error = psaux->ps_table_funcs->init( swap_table, 4, memory ); 00800 if ( error ) 00801 goto Fail; 00802 00803 n = 0; 00804 00805 for (;;) 00806 { 00807 /* The format is simple: */ 00808 /* `/glyphname' + index [+ def] */ 00809 00810 T1_Skip_Spaces( parser ); 00811 00812 cur = parser->root.cursor; 00813 if ( cur >= limit ) 00814 break; 00815 00816 /* We stop when we find an `end' keyword or '>' */ 00817 if ( *cur == 'e' && 00818 cur + 3 < limit && 00819 cur[1] == 'n' && 00820 cur[2] == 'd' && 00821 t42_is_space( cur[3] ) ) 00822 break; 00823 if ( *cur == '>' ) 00824 break; 00825 00826 T1_Skip_PS_Token( parser ); 00827 if ( parser->root.error ) 00828 return; 00829 00830 if ( *cur == '/' ) 00831 { 00832 FT_PtrDist len; 00833 00834 00835 if ( cur + 1 >= limit ) 00836 { 00837 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); 00838 error = T42_Err_Invalid_File_Format; 00839 goto Fail; 00840 } 00841 00842 cur++; /* skip `/' */ 00843 len = parser->root.cursor - cur; 00844 00845 error = T1_Add_Table( name_table, n, cur, len + 1 ); 00846 if ( error ) 00847 goto Fail; 00848 00849 /* add a trailing zero to the name table */ 00850 name_table->elements[n][len] = '\0'; 00851 00852 /* record index of /.notdef */ 00853 if ( *cur == '.' && 00854 ft_strcmp( ".notdef", 00855 (const char*)(name_table->elements[n]) ) == 0 ) 00856 { 00857 notdef_index = n; 00858 notdef_found = 1; 00859 } 00860 00861 T1_Skip_Spaces( parser ); 00862 00863 cur = parser->root.cursor; 00864 00865 (void)T1_ToInt( parser ); 00866 if ( parser->root.cursor >= limit ) 00867 { 00868 FT_ERROR(( "t42_parse_charstrings: out of bounds\n" )); 00869 error = T42_Err_Invalid_File_Format; 00870 goto Fail; 00871 } 00872 00873 len = parser->root.cursor - cur; 00874 00875 error = T1_Add_Table( code_table, n, cur, len + 1 ); 00876 if ( error ) 00877 goto Fail; 00878 00879 code_table->elements[n][len] = '\0'; 00880 00881 n++; 00882 if ( n >= loader->num_glyphs ) 00883 break; 00884 } 00885 } 00886 00887 loader->num_glyphs = n; 00888 00889 if ( !notdef_found ) 00890 { 00891 FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph\n" )); 00892 error = T42_Err_Invalid_File_Format; 00893 goto Fail; 00894 } 00895 00896 /* if /.notdef does not occupy index 0, do our magic. */ 00897 if ( ft_strcmp( (const char*)".notdef", 00898 (const char*)name_table->elements[0] ) ) 00899 { 00900 /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */ 00901 /* name and code entries to swap_table. Then place notdef_index */ 00902 /* name and code entries into swap_table. Then swap name and code */ 00903 /* entries at indices notdef_index and 0 using values stored in */ 00904 /* swap_table. */ 00905 00906 /* Index 0 name */ 00907 error = T1_Add_Table( swap_table, 0, 00908 name_table->elements[0], 00909 name_table->lengths [0] ); 00910 if ( error ) 00911 goto Fail; 00912 00913 /* Index 0 code */ 00914 error = T1_Add_Table( swap_table, 1, 00915 code_table->elements[0], 00916 code_table->lengths [0] ); 00917 if ( error ) 00918 goto Fail; 00919 00920 /* Index notdef_index name */ 00921 error = T1_Add_Table( swap_table, 2, 00922 name_table->elements[notdef_index], 00923 name_table->lengths [notdef_index] ); 00924 if ( error ) 00925 goto Fail; 00926 00927 /* Index notdef_index code */ 00928 error = T1_Add_Table( swap_table, 3, 00929 code_table->elements[notdef_index], 00930 code_table->lengths [notdef_index] ); 00931 if ( error ) 00932 goto Fail; 00933 00934 error = T1_Add_Table( name_table, notdef_index, 00935 swap_table->elements[0], 00936 swap_table->lengths [0] ); 00937 if ( error ) 00938 goto Fail; 00939 00940 error = T1_Add_Table( code_table, notdef_index, 00941 swap_table->elements[1], 00942 swap_table->lengths [1] ); 00943 if ( error ) 00944 goto Fail; 00945 00946 error = T1_Add_Table( name_table, 0, 00947 swap_table->elements[2], 00948 swap_table->lengths [2] ); 00949 if ( error ) 00950 goto Fail; 00951 00952 error = T1_Add_Table( code_table, 0, 00953 swap_table->elements[3], 00954 swap_table->lengths [3] ); 00955 if ( error ) 00956 goto Fail; 00957 00958 } 00959 00960 return; 00961 00962 Fail: 00963 parser->root.error = error; 00964 } 00965 00966 00967 static FT_Error 00968 t42_load_keyword( T42_Face face, 00969 T42_Loader loader, 00970 T1_Field field ) 00971 { 00972 FT_Error error; 00973 void* dummy_object; 00974 void** objects; 00975 FT_UInt max_objects = 0; 00976 00977 00978 /* if the keyword has a dedicated callback, call it */ 00979 if ( field->type == T1_FIELD_TYPE_CALLBACK ) 00980 { 00981 field->reader( (FT_Face)face, loader ); 00982 error = loader->parser.root.error; 00983 goto Exit; 00984 } 00985 00986 /* now the keyword is either a simple field or a table of fields; */ 00987 /* we are now going to take care of it */ 00988 00989 switch ( field->location ) 00990 { 00991 case T1_FIELD_LOCATION_FONT_INFO: 00992 dummy_object = &face->type1.font_info; 00993 break; 00994 00995 case T1_FIELD_LOCATION_FONT_EXTRA: 00996 dummy_object = &face->type1.font_extra; 00997 break; 00998 00999 case T1_FIELD_LOCATION_BBOX: 01000 dummy_object = &face->type1.font_bbox; 01001 break; 01002 01003 default: 01004 dummy_object = &face->type1; 01005 } 01006 01007 objects = &dummy_object; 01008 01009 if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY || 01010 field->type == T1_FIELD_TYPE_FIXED_ARRAY ) 01011 error = T1_Load_Field_Table( &loader->parser, field, 01012 objects, max_objects, 0 ); 01013 else 01014 error = T1_Load_Field( &loader->parser, field, 01015 objects, max_objects, 0 ); 01016 01017 Exit: 01018 return error; 01019 } 01020 01021 01022 FT_LOCAL_DEF( FT_Error ) 01023 t42_parse_dict( T42_Face face, 01024 T42_Loader loader, 01025 FT_Byte* base, 01026 FT_Long size ) 01027 { 01028 T42_Parser parser = &loader->parser; 01029 FT_Byte* limit; 01030 FT_Int n_keywords = (FT_Int)( sizeof ( t42_keywords ) / 01031 sizeof ( t42_keywords[0] ) ); 01032 01033 01034 parser->root.cursor = base; 01035 parser->root.limit = base + size; 01036 parser->root.error = T42_Err_Ok; 01037 01038 limit = parser->root.limit; 01039 01040 T1_Skip_Spaces( parser ); 01041 01042 while ( parser->root.cursor < limit ) 01043 { 01044 FT_Byte* cur; 01045 01046 01047 cur = parser->root.cursor; 01048 01049 /* look for `FontDirectory' which causes problems for some fonts */ 01050 if ( *cur == 'F' && cur + 25 < limit && 01051 ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 ) 01052 { 01053 FT_Byte* cur2; 01054 01055 01056 /* skip the `FontDirectory' keyword */ 01057 T1_Skip_PS_Token( parser ); 01058 T1_Skip_Spaces ( parser ); 01059 cur = cur2 = parser->root.cursor; 01060 01061 /* look up the `known' keyword */ 01062 while ( cur < limit ) 01063 { 01064 if ( *cur == 'k' && cur + 5 < limit && 01065 ft_strncmp( (char*)cur, "known", 5 ) == 0 ) 01066 break; 01067 01068 T1_Skip_PS_Token( parser ); 01069 if ( parser->root.error ) 01070 goto Exit; 01071 T1_Skip_Spaces ( parser ); 01072 cur = parser->root.cursor; 01073 } 01074 01075 if ( cur < limit ) 01076 { 01077 T1_TokenRec token; 01078 01079 01080 /* skip the `known' keyword and the token following it */ 01081 T1_Skip_PS_Token( parser ); 01082 T1_ToToken( parser, &token ); 01083 01084 /* if the last token was an array, skip it! */ 01085 if ( token.type == T1_TOKEN_TYPE_ARRAY ) 01086 cur2 = parser->root.cursor; 01087 } 01088 parser->root.cursor = cur2; 01089 } 01090 01091 /* look for immediates */ 01092 else if ( *cur == '/' && cur + 2 < limit ) 01093 { 01094 FT_PtrDist len; 01095 01096 01097 cur++; 01098 01099 parser->root.cursor = cur; 01100 T1_Skip_PS_Token( parser ); 01101 if ( parser->root.error ) 01102 goto Exit; 01103 01104 len = parser->root.cursor - cur; 01105 01106 if ( len > 0 && len < 22 && parser->root.cursor < limit ) 01107 { 01108 int i; 01109 01110 01111 /* now compare the immediate name to the keyword table */ 01112 01113 /* loop through all known keywords */ 01114 for ( i = 0; i < n_keywords; i++ ) 01115 { 01116 T1_Field keyword = (T1_Field)&t42_keywords[i]; 01117 FT_Byte *name = (FT_Byte*)keyword->ident; 01118 01119 01120 if ( !name ) 01121 continue; 01122 01123 if ( cur[0] == name[0] && 01124 len == (FT_PtrDist)ft_strlen( (const char *)name ) && 01125 ft_memcmp( cur, name, len ) == 0 ) 01126 { 01127 /* we found it -- run the parsing callback! */ 01128 parser->root.error = t42_load_keyword( face, 01129 loader, 01130 keyword ); 01131 if ( parser->root.error ) 01132 return parser->root.error; 01133 break; 01134 } 01135 } 01136 } 01137 } 01138 else 01139 { 01140 T1_Skip_PS_Token( parser ); 01141 if ( parser->root.error ) 01142 goto Exit; 01143 } 01144 01145 T1_Skip_Spaces( parser ); 01146 } 01147 01148 Exit: 01149 return parser->root.error; 01150 } 01151 01152 01153 FT_LOCAL_DEF( void ) 01154 t42_loader_init( T42_Loader loader, 01155 T42_Face face ) 01156 { 01157 FT_UNUSED( face ); 01158 01159 FT_MEM_ZERO( loader, sizeof ( *loader ) ); 01160 loader->num_glyphs = 0; 01161 loader->num_chars = 0; 01162 01163 /* initialize the tables -- simply set their `init' field to 0 */ 01164 loader->encoding_table.init = 0; 01165 loader->charstrings.init = 0; 01166 loader->glyph_names.init = 0; 01167 } 01168 01169 01170 FT_LOCAL_DEF( void ) 01171 t42_loader_done( T42_Loader loader ) 01172 { 01173 T42_Parser parser = &loader->parser; 01174 01175 01176 /* finalize tables */ 01177 T1_Release_Table( &loader->encoding_table ); 01178 T1_Release_Table( &loader->charstrings ); 01179 T1_Release_Table( &loader->glyph_names ); 01180 T1_Release_Table( &loader->swap_table ); 01181 01182 /* finalize parser */ 01183 t42_parser_done( parser ); 01184 } 01185 01186 01187 /* END */ Generated on Tue May 15 04:58:29 2012 for ReactOS by
1.6.3
|