1 /**************************************************************************** 2 * 3 * cidparse.c 4 * 5 * CID-keyed Type1 parser (body). 6 * 7 * Copyright 1996-2018 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 <ft2build.h> 20 #include FT_INTERNAL_DEBUG_H 21 #include FT_INTERNAL_OBJECTS_H 22 #include FT_INTERNAL_STREAM_H 23 24 #include "cidparse.h" 25 26 #include "ciderrs.h" 27 28 29 /************************************************************************** 30 * 31 * The macro FT_COMPONENT is used in trace mode. It is an implicit 32 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log 33 * messages during execution. 34 */ 35 #undef FT_COMPONENT 36 #define FT_COMPONENT trace_cidparse 37 38 39 /*************************************************************************/ 40 /*************************************************************************/ 41 /*************************************************************************/ 42 /***** *****/ 43 /***** INPUT STREAM PARSER *****/ 44 /***** *****/ 45 /*************************************************************************/ 46 /*************************************************************************/ 47 /*************************************************************************/ 48 49 50 #define STARTDATA "StartData" 51 #define STARTDATA_LEN ( sizeof ( STARTDATA ) - 1 ) 52 #define SFNTS "/sfnts" 53 #define SFNTS_LEN ( sizeof ( SFNTS ) - 1 ) 54 55 56 FT_LOCAL_DEF( FT_Error ) cid_parser_new(CID_Parser * parser,FT_Stream stream,FT_Memory memory,PSAux_Service psaux)57 cid_parser_new( CID_Parser* parser, 58 FT_Stream stream, 59 FT_Memory memory, 60 PSAux_Service psaux ) 61 { 62 FT_Error error; 63 FT_ULong base_offset, offset, ps_len; 64 FT_Byte *cur, *limit; 65 FT_Byte *arg1, *arg2; 66 67 68 FT_ZERO( parser ); 69 psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory ); 70 71 parser->stream = stream; 72 73 base_offset = FT_STREAM_POS(); 74 75 /* first of all, check the font format in the header */ 76 if ( FT_FRAME_ENTER( 31 ) ) 77 goto Exit; 78 79 if ( ft_strncmp( (char *)stream->cursor, 80 "%!PS-Adobe-3.0 Resource-CIDFont", 31 ) ) 81 { 82 FT_TRACE2(( " not a CID-keyed font\n" )); 83 error = FT_THROW( Unknown_File_Format ); 84 } 85 86 FT_FRAME_EXIT(); 87 if ( error ) 88 goto Exit; 89 90 Again: 91 /* now, read the rest of the file until we find */ 92 /* `StartData' or `/sfnts' */ 93 { 94 /* 95 * The algorithm is as follows (omitting the case with less than 256 96 * bytes to fill for simplicity). 97 * 98 * 1. Fill the buffer with 256 + STARTDATA_LEN bytes. 99 * 100 * 2. Search for the STARTDATA and SFNTS strings at positions 101 * buffer[0], buffer[1], ..., 102 * buffer[255 + STARTDATA_LEN - SFNTS_LEN]. 103 * 104 * 3. Move the last STARTDATA_LEN bytes to buffer[0]. 105 * 106 * 4. Fill the buffer with 256 bytes, starting at STARTDATA_LEN. 107 * 108 * 5. Repeat with step 2. 109 * 110 */ 111 FT_Byte buffer[256 + STARTDATA_LEN + 1]; 112 113 /* values for the first loop */ 114 FT_ULong read_len = 256 + STARTDATA_LEN; 115 FT_ULong read_offset = 0; 116 FT_Byte* p = buffer; 117 118 119 for ( offset = FT_STREAM_POS(); ; offset += 256 ) 120 { 121 FT_ULong stream_len; 122 123 124 stream_len = stream->size - FT_STREAM_POS(); 125 126 read_len = FT_MIN( read_len, stream_len ); 127 if ( FT_STREAM_READ( p, read_len ) ) 128 goto Exit; 129 130 /* ensure that we do not compare with data beyond the buffer */ 131 p[read_len] = '\0'; 132 133 limit = p + read_len - SFNTS_LEN; 134 135 for ( p = buffer; p < limit; p++ ) 136 { 137 if ( p[0] == 'S' && 138 ft_strncmp( (char*)p, STARTDATA, STARTDATA_LEN ) == 0 ) 139 { 140 /* save offset of binary data after `StartData' */ 141 offset += (FT_ULong)( p - buffer ) + STARTDATA_LEN + 1; 142 goto Found; 143 } 144 else if ( p[1] == 's' && 145 ft_strncmp( (char*)p, SFNTS, SFNTS_LEN ) == 0 ) 146 { 147 offset += (FT_ULong)( p - buffer ) + SFNTS_LEN + 1; 148 goto Found; 149 } 150 } 151 152 if ( read_offset + read_len < STARTDATA_LEN ) 153 { 154 FT_TRACE2(( "cid_parser_new: no `StartData' keyword found\n" )); 155 error = FT_THROW( Invalid_File_Format ); 156 goto Exit; 157 } 158 159 FT_MEM_MOVE( buffer, 160 buffer + read_offset + read_len - STARTDATA_LEN, 161 STARTDATA_LEN ); 162 163 /* values for the next loop */ 164 read_len = 256; 165 read_offset = STARTDATA_LEN; 166 p = buffer + read_offset; 167 } 168 } 169 170 Found: 171 /* We have found the start of the binary data or the `/sfnts' token. */ 172 /* Now rewind and extract the frame corresponding to this PostScript */ 173 /* section. */ 174 175 ps_len = offset - base_offset; 176 if ( FT_STREAM_SEEK( base_offset ) || 177 FT_FRAME_EXTRACT( ps_len, parser->postscript ) ) 178 goto Exit; 179 180 parser->data_offset = offset; 181 parser->postscript_len = ps_len; 182 parser->root.base = parser->postscript; 183 parser->root.cursor = parser->postscript; 184 parser->root.limit = parser->root.cursor + ps_len; 185 parser->num_dict = -1; 186 187 /* Finally, we check whether `StartData' or `/sfnts' was real -- */ 188 /* it could be in a comment or string. We also get the arguments */ 189 /* of `StartData' to find out whether the data is represented in */ 190 /* binary or hex format. */ 191 192 arg1 = parser->root.cursor; 193 cid_parser_skip_PS_token( parser ); 194 cid_parser_skip_spaces ( parser ); 195 arg2 = parser->root.cursor; 196 cid_parser_skip_PS_token( parser ); 197 cid_parser_skip_spaces ( parser ); 198 199 limit = parser->root.limit; 200 cur = parser->root.cursor; 201 202 while ( cur <= limit - SFNTS_LEN ) 203 { 204 if ( parser->root.error ) 205 { 206 error = parser->root.error; 207 goto Exit; 208 } 209 210 if ( cur[0] == 'S' && 211 cur <= limit - STARTDATA_LEN && 212 ft_strncmp( (char*)cur, STARTDATA, STARTDATA_LEN ) == 0 ) 213 { 214 if ( ft_strncmp( (char*)arg1, "(Hex)", 5 ) == 0 ) 215 { 216 FT_Long tmp = ft_strtol( (const char *)arg2, NULL, 10 ); 217 218 219 if ( tmp < 0 ) 220 { 221 FT_ERROR(( "cid_parser_new: invalid length of hex data\n" )); 222 error = FT_THROW( Invalid_File_Format ); 223 } 224 else 225 parser->binary_length = (FT_ULong)tmp; 226 } 227 228 goto Exit; 229 } 230 else if ( cur[1] == 's' && 231 ft_strncmp( (char*)cur, SFNTS, SFNTS_LEN ) == 0 ) 232 { 233 FT_TRACE2(( "cid_parser_new: cannot handle Type 11 fonts\n" )); 234 error = FT_THROW( Unknown_File_Format ); 235 goto Exit; 236 } 237 238 cid_parser_skip_PS_token( parser ); 239 cid_parser_skip_spaces ( parser ); 240 arg1 = arg2; 241 arg2 = cur; 242 cur = parser->root.cursor; 243 } 244 245 /* we haven't found the correct `StartData'; go back and continue */ 246 /* searching */ 247 FT_FRAME_RELEASE( parser->postscript ); 248 if ( !FT_STREAM_SEEK( offset ) ) 249 goto Again; 250 251 Exit: 252 return error; 253 } 254 255 256 #undef STARTDATA 257 #undef STARTDATA_LEN 258 #undef SFNTS 259 #undef SFNTS_LEN 260 261 262 FT_LOCAL_DEF( void ) cid_parser_done(CID_Parser * parser)263 cid_parser_done( CID_Parser* parser ) 264 { 265 /* always free the private dictionary */ 266 if ( parser->postscript ) 267 { 268 FT_Stream stream = parser->stream; 269 270 271 FT_FRAME_RELEASE( parser->postscript ); 272 } 273 parser->root.funcs.done( &parser->root ); 274 } 275 276 277 /* END */ 278