1 /***************************************************************************/ 2 /* */ 3 /* cidparse.c */ 4 /* */ 5 /* CID-keyed Type1 parser (body). */ 6 /* */ 7 /* Copyright 1996-2015 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 FT_LOCAL_DEF( FT_Error ) 51 cid_parser_new( CID_Parser* parser, 52 FT_Stream stream, 53 FT_Memory memory, 54 PSAux_Service psaux ) 55 { 56 FT_Error error; 57 FT_ULong base_offset, offset, ps_len; 58 FT_Byte *cur, *limit; 59 FT_Byte *arg1, *arg2; 60 61 62 FT_MEM_ZERO( parser, sizeof ( *parser ) ); 63 psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory ); 64 65 parser->stream = stream; 66 67 base_offset = FT_STREAM_POS(); 68 69 /* first of all, check the font format in the header */ 70 if ( FT_FRAME_ENTER( 31 ) ) 71 goto Exit; 72 73 if ( ft_strncmp( (char *)stream->cursor, 74 "%!PS-Adobe-3.0 Resource-CIDFont", 31 ) ) 75 { 76 FT_TRACE2(( " not a CID-keyed font\n" )); 77 error = FT_THROW( Unknown_File_Format ); 78 } 79 80 FT_FRAME_EXIT(); 81 if ( error ) 82 goto Exit; 83 84 Again: 85 /* now, read the rest of the file until we find */ 86 /* `StartData' or `/sfnts' */ 87 { 88 FT_Byte buffer[256 + 10]; 89 FT_ULong read_len = 256 + 10; 90 FT_Byte* p = buffer; 91 92 93 for ( offset = FT_STREAM_POS(); ; offset += 256 ) 94 { 95 FT_ULong stream_len; 96 97 98 stream_len = stream->size - FT_STREAM_POS(); 99 if ( stream_len == 0 ) 100 { 101 FT_TRACE2(( "cid_parser_new: no `StartData' keyword found\n" )); 102 error = FT_THROW( Invalid_File_Format ); 103 goto Exit; 104 } 105 106 read_len = FT_MIN( read_len, stream_len ); 107 if ( FT_STREAM_READ( p, read_len ) ) 108 goto Exit; 109 110 if ( read_len < 256 ) 111 p[read_len] = '\0'; 112 113 limit = p + read_len - 10; 114 115 for ( p = buffer; p < limit; p++ ) 116 { 117 if ( p[0] == 'S' && ft_strncmp( (char*)p, "StartData", 9 ) == 0 ) 118 { 119 /* save offset of binary data after `StartData' */ 120 offset += (FT_ULong)( p - buffer + 10 ); 121 goto Found; 122 } 123 else if ( p[1] == 's' && ft_strncmp( (char*)p, "/sfnts", 6 ) == 0 ) 124 { 125 offset += (FT_ULong)( p - buffer + 7 ); 126 goto Found; 127 } 128 } 129 130 FT_MEM_MOVE( buffer, p, 10 ); 131 read_len = 256; 132 p = buffer + 10; 133 } 134 } 135 136 Found: 137 /* We have found the start of the binary data or the `/sfnts' token. */ 138 /* Now rewind and extract the frame corresponding to this PostScript */ 139 /* section. */ 140 141 ps_len = offset - base_offset; 142 if ( FT_STREAM_SEEK( base_offset ) || 143 FT_FRAME_EXTRACT( ps_len, parser->postscript ) ) 144 goto Exit; 145 146 parser->data_offset = offset; 147 parser->postscript_len = ps_len; 148 parser->root.base = parser->postscript; 149 parser->root.cursor = parser->postscript; 150 parser->root.limit = parser->root.cursor + ps_len; 151 parser->num_dict = -1; 152 153 /* Finally, we check whether `StartData' or `/sfnts' was real -- */ 154 /* it could be in a comment or string. We also get the arguments */ 155 /* of `StartData' to find out whether the data is represented in */ 156 /* binary or hex format. */ 157 158 arg1 = parser->root.cursor; 159 cid_parser_skip_PS_token( parser ); 160 cid_parser_skip_spaces ( parser ); 161 arg2 = parser->root.cursor; 162 cid_parser_skip_PS_token( parser ); 163 cid_parser_skip_spaces ( parser ); 164 165 limit = parser->root.limit; 166 cur = parser->root.cursor; 167 168 while ( cur < limit ) 169 { 170 if ( parser->root.error ) 171 { 172 error = parser->root.error; 173 goto Exit; 174 } 175 176 if ( cur[0] == 'S' && ft_strncmp( (char*)cur, "StartData", 9 ) == 0 ) 177 { 178 if ( ft_strncmp( (char*)arg1, "(Hex)", 5 ) == 0 ) 179 { 180 FT_Long tmp = ft_atol( (const char *)arg2 ); 181 182 183 if ( tmp < 0 ) 184 { 185 FT_ERROR(( "cid_parser_new: invalid length of hex data\n" )); 186 error = FT_THROW( Invalid_File_Format ); 187 } 188 else 189 parser->binary_length = (FT_ULong)tmp; 190 } 191 192 goto Exit; 193 } 194 else if ( cur[1] == 's' && ft_strncmp( (char*)cur, "/sfnts", 6 ) == 0 ) 195 { 196 FT_TRACE2(( "cid_parser_new: cannot handle Type 11 fonts\n" )); 197 error = FT_THROW( Unknown_File_Format ); 198 goto Exit; 199 } 200 201 cid_parser_skip_PS_token( parser ); 202 cid_parser_skip_spaces ( parser ); 203 arg1 = arg2; 204 arg2 = cur; 205 cur = parser->root.cursor; 206 } 207 208 /* we haven't found the correct `StartData'; go back and continue */ 209 /* searching */ 210 FT_FRAME_RELEASE( parser->postscript ); 211 if ( !FT_STREAM_SEEK( offset ) ) 212 goto Again; 213 214 Exit: 215 return error; 216 } 217 218 219 FT_LOCAL_DEF( void ) 220 cid_parser_done( CID_Parser* parser ) 221 { 222 /* always free the private dictionary */ 223 if ( parser->postscript ) 224 { 225 FT_Stream stream = parser->stream; 226 227 228 FT_FRAME_RELEASE( parser->postscript ); 229 } 230 parser->root.funcs.done( &parser->root ); 231 } 232 233 234 /* END */ 235