Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygent1parse.c
Go to the documentation of this file.
00001 /***************************************************************************/ 00002 /* */ 00003 /* t1parse.c */ 00004 /* */ 00005 /* Type 1 parser (body). */ 00006 /* */ 00007 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2008, 2009 by */ 00008 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 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 /*************************************************************************/ 00020 /* */ 00021 /* The Type 1 parser is in charge of the following: */ 00022 /* */ 00023 /* - provide an implementation of a growing sequence of objects called */ 00024 /* a `T1_Table' (used to build various tables needed by the loader). */ 00025 /* */ 00026 /* - opening .pfb and .pfa files to extract their top-level and private */ 00027 /* dictionaries. */ 00028 /* */ 00029 /* - read numbers, arrays & strings from any dictionary. */ 00030 /* */ 00031 /* See `t1load.c' to see how data is loaded from the font file. */ 00032 /* */ 00033 /*************************************************************************/ 00034 00035 00036 #include <ft2build.h> 00037 #include FT_INTERNAL_DEBUG_H 00038 #include FT_INTERNAL_STREAM_H 00039 #include FT_INTERNAL_POSTSCRIPT_AUX_H 00040 00041 #include "t1parse.h" 00042 00043 #include "t1errors.h" 00044 00045 00046 /*************************************************************************/ 00047 /* */ 00048 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 00049 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 00050 /* messages during execution. */ 00051 /* */ 00052 #undef FT_COMPONENT 00053 #define FT_COMPONENT trace_t1parse 00054 00055 00056 /*************************************************************************/ 00057 /*************************************************************************/ 00058 /*************************************************************************/ 00059 /***** *****/ 00060 /***** INPUT STREAM PARSER *****/ 00061 /***** *****/ 00062 /*************************************************************************/ 00063 /*************************************************************************/ 00064 /*************************************************************************/ 00065 00066 00067 /* see Adobe Technical Note 5040.Download_Fonts.pdf */ 00068 00069 static FT_Error 00070 read_pfb_tag( FT_Stream stream, 00071 FT_UShort *atag, 00072 FT_ULong *asize ) 00073 { 00074 FT_Error error; 00075 FT_UShort tag; 00076 FT_ULong size; 00077 00078 00079 *atag = 0; 00080 *asize = 0; 00081 00082 if ( !FT_READ_USHORT( tag ) ) 00083 { 00084 if ( tag == 0x8001U || tag == 0x8002U ) 00085 { 00086 if ( !FT_READ_ULONG_LE( size ) ) 00087 *asize = size; 00088 } 00089 00090 *atag = tag; 00091 } 00092 00093 return error; 00094 } 00095 00096 00097 static FT_Error 00098 check_type1_format( FT_Stream stream, 00099 const char* header_string, 00100 size_t header_length ) 00101 { 00102 FT_Error error; 00103 FT_UShort tag; 00104 FT_ULong dummy; 00105 00106 00107 if ( FT_STREAM_SEEK( 0 ) ) 00108 goto Exit; 00109 00110 error = read_pfb_tag( stream, &tag, &dummy ); 00111 if ( error ) 00112 goto Exit; 00113 00114 /* We assume that the first segment in a PFB is always encoded as */ 00115 /* text. This might be wrong (and the specification doesn't insist */ 00116 /* on that), but we have never seen a counterexample. */ 00117 if ( tag != 0x8001U && FT_STREAM_SEEK( 0 ) ) 00118 goto Exit; 00119 00120 if ( !FT_FRAME_ENTER( header_length ) ) 00121 { 00122 error = T1_Err_Ok; 00123 00124 if ( ft_memcmp( stream->cursor, header_string, header_length ) != 0 ) 00125 error = T1_Err_Unknown_File_Format; 00126 00127 FT_FRAME_EXIT(); 00128 } 00129 00130 Exit: 00131 return error; 00132 } 00133 00134 00135 FT_LOCAL_DEF( FT_Error ) 00136 T1_New_Parser( T1_Parser parser, 00137 FT_Stream stream, 00138 FT_Memory memory, 00139 PSAux_Service psaux ) 00140 { 00141 FT_Error error; 00142 FT_UShort tag; 00143 FT_ULong size; 00144 00145 00146 psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory ); 00147 00148 parser->stream = stream; 00149 parser->base_len = 0; 00150 parser->base_dict = 0; 00151 parser->private_len = 0; 00152 parser->private_dict = 0; 00153 parser->in_pfb = 0; 00154 parser->in_memory = 0; 00155 parser->single_block = 0; 00156 00157 /* check the header format */ 00158 error = check_type1_format( stream, "%!PS-AdobeFont", 14 ); 00159 if ( error ) 00160 { 00161 if ( error != T1_Err_Unknown_File_Format ) 00162 goto Exit; 00163 00164 error = check_type1_format( stream, "%!FontType", 10 ); 00165 if ( error ) 00166 { 00167 FT_TRACE2(( "[not a Type1 font]\n" )); 00168 goto Exit; 00169 } 00170 } 00171 00172 /******************************************************************/ 00173 /* */ 00174 /* Here a short summary of what is going on: */ 00175 /* */ 00176 /* When creating a new Type 1 parser, we try to locate and load */ 00177 /* the base dictionary if this is possible (i.e., for PFB */ 00178 /* files). Otherwise, we load the whole font into memory. */ 00179 /* */ 00180 /* When `loading' the base dictionary, we only setup pointers */ 00181 /* in the case of a memory-based stream. Otherwise, we */ 00182 /* allocate and load the base dictionary in it. */ 00183 /* */ 00184 /* parser->in_pfb is set if we are in a binary (`.pfb') font. */ 00185 /* parser->in_memory is set if we have a memory stream. */ 00186 /* */ 00187 00188 /* try to compute the size of the base dictionary; */ 00189 /* look for a Postscript binary file tag, i.e., 0x8001 */ 00190 if ( FT_STREAM_SEEK( 0L ) ) 00191 goto Exit; 00192 00193 error = read_pfb_tag( stream, &tag, &size ); 00194 if ( error ) 00195 goto Exit; 00196 00197 if ( tag != 0x8001U ) 00198 { 00199 /* assume that this is a PFA file for now; an error will */ 00200 /* be produced later when more things are checked */ 00201 if ( FT_STREAM_SEEK( 0L ) ) 00202 goto Exit; 00203 size = stream->size; 00204 } 00205 else 00206 parser->in_pfb = 1; 00207 00208 /* now, try to load `size' bytes of the `base' dictionary we */ 00209 /* found previously */ 00210 00211 /* if it is a memory-based resource, set up pointers */ 00212 if ( !stream->read ) 00213 { 00214 parser->base_dict = (FT_Byte*)stream->base + stream->pos; 00215 parser->base_len = size; 00216 parser->in_memory = 1; 00217 00218 /* check that the `size' field is valid */ 00219 if ( FT_STREAM_SKIP( size ) ) 00220 goto Exit; 00221 } 00222 else 00223 { 00224 /* read segment in memory -- this is clumsy, but so does the format */ 00225 if ( FT_ALLOC( parser->base_dict, size ) || 00226 FT_STREAM_READ( parser->base_dict, size ) ) 00227 goto Exit; 00228 parser->base_len = size; 00229 } 00230 00231 parser->root.base = parser->base_dict; 00232 parser->root.cursor = parser->base_dict; 00233 parser->root.limit = parser->root.cursor + parser->base_len; 00234 00235 Exit: 00236 if ( error && !parser->in_memory ) 00237 FT_FREE( parser->base_dict ); 00238 00239 return error; 00240 } 00241 00242 00243 FT_LOCAL_DEF( void ) 00244 T1_Finalize_Parser( T1_Parser parser ) 00245 { 00246 FT_Memory memory = parser->root.memory; 00247 00248 00249 /* always free the private dictionary */ 00250 FT_FREE( parser->private_dict ); 00251 00252 /* free the base dictionary only when we have a disk stream */ 00253 if ( !parser->in_memory ) 00254 FT_FREE( parser->base_dict ); 00255 00256 parser->root.funcs.done( &parser->root ); 00257 } 00258 00259 00260 FT_LOCAL_DEF( FT_Error ) 00261 T1_Get_Private_Dict( T1_Parser parser, 00262 PSAux_Service psaux ) 00263 { 00264 FT_Stream stream = parser->stream; 00265 FT_Memory memory = parser->root.memory; 00266 FT_Error error = T1_Err_Ok; 00267 FT_ULong size; 00268 00269 00270 if ( parser->in_pfb ) 00271 { 00272 /* in the case of the PFB format, the private dictionary can be */ 00273 /* made of several segments. We thus first read the number of */ 00274 /* segments to compute the total size of the private dictionary */ 00275 /* then re-read them into memory. */ 00276 FT_Long start_pos = FT_STREAM_POS(); 00277 FT_UShort tag; 00278 00279 00280 parser->private_len = 0; 00281 for (;;) 00282 { 00283 error = read_pfb_tag( stream, &tag, &size ); 00284 if ( error ) 00285 goto Fail; 00286 00287 if ( tag != 0x8002U ) 00288 break; 00289 00290 parser->private_len += size; 00291 00292 if ( FT_STREAM_SKIP( size ) ) 00293 goto Fail; 00294 } 00295 00296 /* Check that we have a private dictionary there */ 00297 /* and allocate private dictionary buffer */ 00298 if ( parser->private_len == 0 ) 00299 { 00300 FT_ERROR(( "T1_Get_Private_Dict:" 00301 " invalid private dictionary section\n" )); 00302 error = T1_Err_Invalid_File_Format; 00303 goto Fail; 00304 } 00305 00306 if ( FT_STREAM_SEEK( start_pos ) || 00307 FT_ALLOC( parser->private_dict, parser->private_len ) ) 00308 goto Fail; 00309 00310 parser->private_len = 0; 00311 for (;;) 00312 { 00313 error = read_pfb_tag( stream, &tag, &size ); 00314 if ( error || tag != 0x8002U ) 00315 { 00316 error = T1_Err_Ok; 00317 break; 00318 } 00319 00320 if ( FT_STREAM_READ( parser->private_dict + parser->private_len, 00321 size ) ) 00322 goto Fail; 00323 00324 parser->private_len += size; 00325 } 00326 } 00327 else 00328 { 00329 /* We have already `loaded' the whole PFA font file into memory; */ 00330 /* if this is a memory resource, allocate a new block to hold */ 00331 /* the private dict. Otherwise, simply overwrite into the base */ 00332 /* dictionary block in the heap. */ 00333 00334 /* first of all, look at the `eexec' keyword */ 00335 FT_Byte* cur = parser->base_dict; 00336 FT_Byte* limit = cur + parser->base_len; 00337 FT_Byte c; 00338 00339 00340 Again: 00341 for (;;) 00342 { 00343 c = cur[0]; 00344 if ( c == 'e' && cur + 9 < limit ) /* 9 = 5 letters for `eexec' + */ 00345 /* newline + 4 chars */ 00346 { 00347 if ( cur[1] == 'e' && 00348 cur[2] == 'x' && 00349 cur[3] == 'e' && 00350 cur[4] == 'c' ) 00351 break; 00352 } 00353 cur++; 00354 if ( cur >= limit ) 00355 { 00356 FT_ERROR(( "T1_Get_Private_Dict:" 00357 " could not find `eexec' keyword\n" )); 00358 error = T1_Err_Invalid_File_Format; 00359 goto Exit; 00360 } 00361 } 00362 00363 /* check whether `eexec' was real -- it could be in a comment */ 00364 /* or string (as e.g. in u003043t.gsf from ghostscript) */ 00365 00366 parser->root.cursor = parser->base_dict; 00367 parser->root.limit = cur + 9; 00368 00369 cur = parser->root.cursor; 00370 limit = parser->root.limit; 00371 00372 while ( cur < limit ) 00373 { 00374 if ( *cur == 'e' && ft_strncmp( (char*)cur, "eexec", 5 ) == 0 ) 00375 goto Found; 00376 00377 T1_Skip_PS_Token( parser ); 00378 if ( parser->root.error ) 00379 break; 00380 T1_Skip_Spaces ( parser ); 00381 cur = parser->root.cursor; 00382 } 00383 00384 /* we haven't found the correct `eexec'; go back and continue */ 00385 /* searching */ 00386 00387 cur = limit; 00388 limit = parser->base_dict + parser->base_len; 00389 goto Again; 00390 00391 /* now determine where to write the _encrypted_ binary private */ 00392 /* dictionary. We overwrite the base dictionary for disk-based */ 00393 /* resources and allocate a new block otherwise */ 00394 00395 Found: 00396 parser->root.limit = parser->base_dict + parser->base_len; 00397 00398 T1_Skip_PS_Token( parser ); 00399 cur = parser->root.cursor; 00400 00401 /* according to the Type1 spec, the first cipher byte must not be */ 00402 /* an ASCII whitespace character code (blank, tab, carriage return */ 00403 /* or line feed). We have seen Type 1 fonts with two line feed */ 00404 /* characters... So skip now all whitespace character codes. */ 00405 while ( cur < limit && 00406 ( *cur == ' ' || 00407 *cur == '\t' || 00408 *cur == '\r' || 00409 *cur == '\n' ) ) 00410 ++cur; 00411 if ( cur >= limit ) 00412 { 00413 FT_ERROR(( "T1_Get_Private_Dict:" 00414 " `eexec' not properly terminated\n" )); 00415 error = T1_Err_Invalid_File_Format; 00416 goto Exit; 00417 } 00418 00419 size = parser->base_len - ( cur - parser->base_dict ); 00420 00421 if ( parser->in_memory ) 00422 { 00423 /* note that we allocate one more byte to put a terminating `0' */ 00424 if ( FT_ALLOC( parser->private_dict, size + 1 ) ) 00425 goto Fail; 00426 parser->private_len = size; 00427 } 00428 else 00429 { 00430 parser->single_block = 1; 00431 parser->private_dict = parser->base_dict; 00432 parser->private_len = size; 00433 parser->base_dict = 0; 00434 parser->base_len = 0; 00435 } 00436 00437 /* now determine whether the private dictionary is encoded in binary */ 00438 /* or hexadecimal ASCII format -- decode it accordingly */ 00439 00440 /* we need to access the next 4 bytes (after the final \r following */ 00441 /* the `eexec' keyword); if they all are hexadecimal digits, then */ 00442 /* we have a case of ASCII storage */ 00443 00444 if ( ft_isxdigit( cur[0] ) && ft_isxdigit( cur[1] ) && 00445 ft_isxdigit( cur[2] ) && ft_isxdigit( cur[3] ) ) 00446 { 00447 /* ASCII hexadecimal encoding */ 00448 FT_Long len; 00449 00450 00451 parser->root.cursor = cur; 00452 (void)psaux->ps_parser_funcs->to_bytes( &parser->root, 00453 parser->private_dict, 00454 parser->private_len, 00455 &len, 00456 0 ); 00457 parser->private_len = len; 00458 00459 /* put a safeguard */ 00460 parser->private_dict[len] = '\0'; 00461 } 00462 else 00463 /* binary encoding -- copy the private dict */ 00464 FT_MEM_MOVE( parser->private_dict, cur, size ); 00465 } 00466 00467 /* we now decrypt the encoded binary private dictionary */ 00468 psaux->t1_decrypt( parser->private_dict, parser->private_len, 55665U ); 00469 00470 /* replace the four random bytes at the beginning with whitespace */ 00471 parser->private_dict[0] = ' '; 00472 parser->private_dict[1] = ' '; 00473 parser->private_dict[2] = ' '; 00474 parser->private_dict[3] = ' '; 00475 00476 parser->root.base = parser->private_dict; 00477 parser->root.cursor = parser->private_dict; 00478 parser->root.limit = parser->root.cursor + parser->private_len; 00479 00480 Fail: 00481 Exit: 00482 return error; 00483 } 00484 00485 00486 /* END */ Generated on Fri May 25 2012 04:32:35 for ReactOS by
1.7.6.1
|