• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  *
3  * cidparse.c
4  *
5  *   CID-keyed Type1 parser (body).
6  *
7  * Copyright (C) 1996-2019 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  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