xref: /aosp_15_r20/external/freetype/src/cid/cidparse.c (revision 63949dbd25bcc50c4e1178497ff9e9574d44fc5a)
1 /****************************************************************************
2  *
3  * cidparse.c
4  *
5  *   CID-keyed Type1 parser (body).
6  *
7  * Copyright (C) 1996-2023 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 )
cid_parser_new(CID_Parser * parser,FT_Stream stream,FT_Memory memory,PSAux_Service psaux)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   Again:
94     /* now, read the rest of the file until we find */
95     /* `StartData' or `/sfnts'                      */
96     {
97       /*
98        * The algorithm is as follows (omitting the case with less than 256
99        * bytes to fill for simplicity).
100        *
101        * 1. Fill the buffer with 256 + STARTDATA_LEN bytes.
102        *
103        * 2. Search for the STARTDATA and SFNTS strings at positions
104        *    buffer[0], buffer[1], ...,
105        *    buffer[255 + STARTDATA_LEN - SFNTS_LEN].
106        *
107        * 3. Move the last STARTDATA_LEN bytes to buffer[0].
108        *
109        * 4. Fill the buffer with 256 bytes, starting at STARTDATA_LEN.
110        *
111        * 5. Repeat with step 2.
112        *
113        */
114       FT_Byte  buffer[256 + STARTDATA_LEN + 1];
115 
116       /* values for the first loop */
117       FT_ULong  read_len    = 256 + STARTDATA_LEN;
118       FT_ULong  read_offset = 0;
119       FT_Byte*  p           = buffer;
120 
121 
122       for ( offset = FT_STREAM_POS(); ; offset += 256 )
123       {
124         FT_ULong  stream_len;
125 
126 
127         stream_len = stream->size - FT_STREAM_POS();
128 
129         read_len = FT_MIN( read_len, stream_len );
130         if ( FT_STREAM_READ( p, read_len ) )
131           goto Exit;
132 
133         /* ensure that we do not compare with data beyond the buffer */
134         p[read_len] = '\0';
135 
136         limit = p + read_len - SFNTS_LEN;
137 
138         for ( p = buffer; p < limit; p++ )
139         {
140           if ( p[0] == 'S'                                           &&
141                ft_strncmp( (char*)p, STARTDATA, STARTDATA_LEN ) == 0 )
142           {
143             /* save offset of binary data after `StartData' */
144             offset += (FT_ULong)( p - buffer ) + STARTDATA_LEN + 1;
145             goto Found;
146           }
147           else if ( p[1] == 's'                                   &&
148                     ft_strncmp( (char*)p, SFNTS, SFNTS_LEN ) == 0 )
149           {
150             offset += (FT_ULong)( p - buffer ) + SFNTS_LEN + 1;
151             goto Found;
152           }
153         }
154 
155         if ( read_offset + read_len < STARTDATA_LEN )
156         {
157           FT_TRACE2(( "cid_parser_new: no `StartData' keyword found\n" ));
158           error = FT_THROW( Invalid_File_Format );
159           goto Exit;
160         }
161 
162         FT_MEM_MOVE( buffer,
163                      buffer + read_offset + read_len - STARTDATA_LEN,
164                      STARTDATA_LEN );
165 
166         /* values for the next loop */
167         read_len    = 256;
168         read_offset = STARTDATA_LEN;
169         p           = buffer + read_offset;
170       }
171     }
172 
173   Found:
174     /* We have found the start of the binary data or the `/sfnts' token. */
175     /* Now rewind and extract the frame corresponding to this PostScript */
176     /* section.                                                          */
177 
178     ps_len = offset - base_offset;
179     if ( FT_STREAM_SEEK( base_offset )                  ||
180          FT_FRAME_EXTRACT( ps_len, parser->postscript ) )
181       goto Exit;
182 
183     parser->data_offset    = offset;
184     parser->postscript_len = ps_len;
185     parser->root.base      = parser->postscript;
186     parser->root.cursor    = parser->postscript;
187     parser->root.limit     = parser->root.cursor + ps_len;
188     parser->num_dict       = FT_UINT_MAX;
189 
190     /* Finally, we check whether `StartData' or `/sfnts' was real --  */
191     /* it could be in a comment or string.  We also get the arguments */
192     /* of `StartData' to find out whether the data is represented in  */
193     /* binary or hex format.                                          */
194 
195     arg1 = parser->root.cursor;
196     cid_parser_skip_PS_token( parser );
197     cid_parser_skip_spaces  ( parser );
198     arg2 = parser->root.cursor;
199     cid_parser_skip_PS_token( parser );
200     cid_parser_skip_spaces  ( parser );
201 
202     limit = parser->root.limit;
203     cur   = parser->root.cursor;
204 
205     while ( cur <= limit - SFNTS_LEN )
206     {
207       if ( parser->root.error )
208       {
209         error = parser->root.error;
210         goto Exit;
211       }
212 
213       if ( cur[0] == 'S'                                           &&
214            cur <= limit - STARTDATA_LEN                            &&
215            ft_strncmp( (char*)cur, STARTDATA, STARTDATA_LEN ) == 0 )
216       {
217         T1_TokenRec  type_token;
218         FT_Long      binary_length;
219 
220 
221         parser->root.cursor = arg1;
222         cid_parser_to_token( parser, &type_token );
223         if ( type_token.limit - type_token.start == 5              &&
224              ft_memcmp( (char*)type_token.start, "(Hex)", 5 ) == 0 )
225         {
226           parser->root.cursor = arg2;
227           binary_length = cid_parser_to_int( parser );
228           if ( binary_length < 0 )
229           {
230             FT_ERROR(( "cid_parser_new: invalid length of hex data\n" ));
231             error = FT_THROW( Invalid_File_Format );
232           }
233           else
234             parser->binary_length = (FT_ULong)binary_length;
235         }
236 
237         goto Exit;
238       }
239       else if ( cur[1] == 's'                                   &&
240                 ft_strncmp( (char*)cur, SFNTS, SFNTS_LEN ) == 0 )
241       {
242         FT_TRACE2(( "cid_parser_new: cannot handle Type 11 fonts\n" ));
243         error = FT_THROW( Unknown_File_Format );
244         goto Exit;
245       }
246 
247       cid_parser_skip_PS_token( parser );
248       cid_parser_skip_spaces  ( parser );
249       arg1 = arg2;
250       arg2 = cur;
251       cur  = parser->root.cursor;
252     }
253 
254     /* we haven't found the correct `StartData'; go back and continue */
255     /* searching                                                      */
256     FT_FRAME_RELEASE( parser->postscript );
257     if ( !FT_STREAM_SEEK( offset ) )
258       goto Again;
259 
260   Exit:
261     return error;
262   }
263 
264 
265 #undef STARTDATA
266 #undef STARTDATA_LEN
267 #undef SFNTS
268 #undef SFNTS_LEN
269 
270 
271   FT_LOCAL_DEF( void )
cid_parser_done(CID_Parser * parser)272   cid_parser_done( CID_Parser*  parser )
273   {
274     /* always free the private dictionary */
275     if ( parser->postscript )
276     {
277       FT_Stream  stream = parser->stream;
278 
279 
280       FT_FRAME_RELEASE( parser->postscript );
281     }
282     parser->root.funcs.done( &parser->root );
283   }
284 
285 
286 /* END */
287