cidparse.c (9681B)
1 /**************************************************************************** 2 * 3 * cidparse.c 4 * 5 * CID-keyed Type1 parser (body). 6 * 7 * Copyright (C) 1996-2025 by 8 * David Turner, Robert Wilhelm, and Werner Lemberg. 9 * 10 * This file is part of the FreeType project, and may only be used, 11 * modified, and distributed under the terms of the FreeType project 12 * license, LICENSE.TXT. By continuing to use, modify, or distribute 13 * this file you indicate that you have read the license and 14 * understand and accept it fully. 15 * 16 */ 17 18 19 #include <freetype/internal/ftdebug.h> 20 #include <freetype/internal/ftobjs.h> 21 #include <freetype/internal/ftstream.h> 22 23 #include "cidparse.h" 24 25 #include "ciderrs.h" 26 27 28 /************************************************************************** 29 * 30 * The macro FT_COMPONENT is used in trace mode. It is an implicit 31 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log 32 * messages during execution. 33 */ 34 #undef FT_COMPONENT 35 #define FT_COMPONENT cidparse 36 37 38 /*************************************************************************/ 39 /*************************************************************************/ 40 /*************************************************************************/ 41 /***** *****/ 42 /***** INPUT STREAM PARSER *****/ 43 /***** *****/ 44 /*************************************************************************/ 45 /*************************************************************************/ 46 /*************************************************************************/ 47 48 49 #define STARTDATA "StartData" 50 #define STARTDATA_LEN ( sizeof ( STARTDATA ) - 1 ) 51 #define SFNTS "/sfnts" 52 #define SFNTS_LEN ( sizeof ( SFNTS ) - 1 ) 53 54 55 FT_LOCAL_DEF( FT_Error ) 56 cid_parser_new( CID_Parser* parser, 57 FT_Stream stream, 58 FT_Memory memory, 59 PSAux_Service psaux ) 60 { 61 FT_Error error; 62 FT_ULong base_offset, offset, ps_len; 63 FT_Byte *cur, *limit; 64 FT_Byte *arg1, *arg2; 65 66 67 FT_ZERO( parser ); 68 psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory ); 69 70 parser->stream = stream; 71 72 base_offset = FT_STREAM_POS(); 73 74 /* first of all, check the font format in the header */ 75 if ( FT_FRAME_ENTER( 31 ) ) 76 { 77 FT_TRACE2(( " not a CID-keyed font\n" )); 78 error = FT_THROW( Unknown_File_Format ); 79 goto Exit; 80 } 81 82 if ( ft_strncmp( (char *)stream->cursor, 83 "%!PS-Adobe-3.0 Resource-CIDFont", 31 ) ) 84 { 85 FT_TRACE2(( " not a CID-keyed font\n" )); 86 error = FT_THROW( Unknown_File_Format ); 87 } 88 89 FT_FRAME_EXIT(); 90 if ( error ) 91 goto Exit; 92 93 if ( !stream->read ) { 94 /* just parse memory-based streams */ 95 offset = stream->size; 96 } 97 else 98 { 99 /* Find the last `StartData` or `/sfnts`. The parser requires */ 100 /* contiguous memory; attempt to pin as little as necessary. */ 101 102 /* 103 * The algorithm is as follows (omitting the case with less than 256 104 * bytes to fill for simplicity). 105 * 106 * 1. Fill the buffer with 256 + STARTDATA_LEN bytes. 107 * 108 * 2. Search for the STARTDATA and SFNTS strings at positions 109 * buffer[0], buffer[1], ..., 110 * buffer[255 + STARTDATA_LEN - SFNTS_LEN]. 111 * 112 * 3. Move the last STARTDATA_LEN bytes to buffer[0]. 113 * 114 * 4. Fill the buffer with 256 bytes, starting at STARTDATA_LEN. 115 * 116 * 5. Repeat with step 2. 117 * 118 */ 119 FT_Byte buffer[256 + STARTDATA_LEN + 1]; 120 121 /* values for the first loop */ 122 FT_ULong read_len = 256 + STARTDATA_LEN; 123 FT_ULong read_offset = 0; 124 FT_Byte* p = buffer; 125 126 127 offset = 0; 128 while ( 1 ) 129 { 130 FT_ULong stream_len; 131 132 133 stream_len = stream->size - FT_STREAM_POS(); 134 135 read_len = FT_MIN( read_len, stream_len ); 136 if ( read_len && FT_STREAM_READ( p, read_len ) ) 137 goto Exit; 138 139 /* ensure that we do not compare with data beyond the buffer */ 140 p[read_len] = '\0'; 141 142 limit = p + read_len - SFNTS_LEN; 143 144 for ( p = buffer; p < limit; p++ ) 145 { 146 if ( p[0] == 'S' && 147 ft_strncmp( (char*)p, STARTDATA, STARTDATA_LEN ) == 0 ) 148 { 149 /* save offset of binary data after `StartData' */ 150 offset = FT_STREAM_POS() - read_len - read_offset 151 + (FT_ULong)( p - buffer ) + STARTDATA_LEN + 1; 152 } 153 else if ( p[1] == 's' && 154 ft_strncmp( (char*)p, SFNTS, SFNTS_LEN ) == 0 ) 155 { 156 offset = FT_STREAM_POS() - read_len - read_offset 157 + (FT_ULong)( p - buffer ) + SFNTS_LEN + 1; 158 } 159 } 160 161 if ( read_offset + read_len <= STARTDATA_LEN ) 162 { 163 if ( offset ) 164 goto Found; 165 166 FT_TRACE2(( "cid_parser_new: no `StartData` keyword found\n" )); 167 error = FT_THROW( Invalid_File_Format ); 168 goto Exit; 169 } 170 171 FT_MEM_MOVE( buffer, 172 buffer + read_offset + read_len - STARTDATA_LEN, 173 STARTDATA_LEN ); 174 175 /* values for the next loop */ 176 read_len = 256; 177 read_offset = STARTDATA_LEN; 178 p = buffer + read_offset; 179 } 180 } 181 182 Found: 183 /* We have found an efficient range to look for the binary data or */ 184 /* `/sfnts' token. Now rewind and extract the frame corresponding to */ 185 /* this PostScript section. */ 186 187 ps_len = offset - base_offset; 188 if ( FT_STREAM_SEEK( base_offset ) || 189 FT_FRAME_EXTRACT( ps_len, parser->postscript ) ) 190 goto Exit; 191 192 parser->data_offset = offset; 193 parser->postscript_len = ps_len; 194 parser->root.base = parser->postscript; 195 parser->root.cursor = parser->postscript; 196 parser->root.limit = parser->root.cursor + ps_len; 197 parser->num_dict = FT_UINT_MAX; 198 199 /* Find the first real `StartData' or `/sfnts' -- the last one */ 200 /* could be in a comment or string. We also get the arguments */ 201 /* of `StartData' to find out whether the data is represented in */ 202 /* binary or hex format. */ 203 204 arg1 = parser->root.cursor; 205 cid_parser_skip_PS_token( parser ); 206 cid_parser_skip_spaces ( parser ); 207 arg2 = parser->root.cursor; 208 cid_parser_skip_PS_token( parser ); 209 cid_parser_skip_spaces ( parser ); 210 211 limit = parser->root.limit; 212 cur = parser->root.cursor; 213 214 while ( cur <= limit - SFNTS_LEN ) 215 { 216 if ( parser->root.error ) 217 { 218 error = parser->root.error; 219 goto Exit; 220 } 221 222 if ( cur[0] == 'S' && 223 cur <= limit - STARTDATA_LEN && 224 ft_strncmp( (char*)cur, STARTDATA, STARTDATA_LEN ) == 0 ) 225 { 226 T1_TokenRec type_token; 227 FT_Long binary_length; 228 FT_ULong found_offset; 229 230 231 parser->root.cursor = arg1; 232 cid_parser_to_token( parser, &type_token ); 233 if ( type_token.limit - type_token.start == 5 && 234 ft_memcmp( (char*)type_token.start, "(Hex)", 5 ) == 0 ) 235 { 236 parser->root.cursor = arg2; 237 binary_length = cid_parser_to_int( parser ); 238 if ( binary_length < 0 ) 239 { 240 FT_ERROR(( "cid_parser_new: invalid length of hex data\n" )); 241 error = FT_THROW( Invalid_File_Format ); 242 } 243 else 244 parser->binary_length = (FT_ULong)binary_length; 245 } 246 247 /* set the real values for the parser, if different */ 248 found_offset = (FT_ULong)( cur - parser->postscript ) 249 + STARTDATA_LEN + 1; 250 if ( found_offset != offset ) 251 { 252 FT_FRAME_RELEASE( parser->postscript ); 253 254 ps_len = found_offset - base_offset; 255 if ( FT_STREAM_SEEK( base_offset ) || 256 FT_FRAME_EXTRACT( ps_len, parser->postscript ) ) 257 goto Exit; 258 259 parser->data_offset = found_offset; 260 parser->postscript_len = ps_len; 261 parser->root.base = parser->postscript; 262 parser->root.cursor = parser->postscript; 263 parser->root.limit = parser->root.cursor + ps_len; 264 } 265 goto Exit; 266 } 267 else if ( cur[1] == 's' && 268 ft_strncmp( (char*)cur, SFNTS, SFNTS_LEN ) == 0 ) 269 { 270 FT_TRACE2(( "cid_parser_new: cannot handle Type 11 fonts\n" )); 271 error = FT_THROW( Unknown_File_Format ); 272 goto Exit; 273 } 274 275 cid_parser_skip_PS_token( parser ); 276 cid_parser_skip_spaces ( parser ); 277 arg1 = arg2; 278 arg2 = cur; 279 cur = parser->root.cursor; 280 } 281 282 FT_TRACE2(( "cid_parser_new: no `StartData` token found\n" )); 283 error = FT_THROW( Invalid_File_Format ); 284 285 Exit: 286 return error; 287 } 288 289 290 #undef STARTDATA 291 #undef STARTDATA_LEN 292 #undef SFNTS 293 #undef SFNTS_LEN 294 295 296 FT_LOCAL_DEF( void ) 297 cid_parser_done( CID_Parser* parser ) 298 { 299 /* always free the private dictionary */ 300 if ( parser->postscript ) 301 { 302 FT_Stream stream = parser->stream; 303 304 305 FT_FRAME_RELEASE( parser->postscript ); 306 } 307 parser->root.funcs.done( &parser->root ); 308 } 309 310 311 /* END */