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 )
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 )
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