151 |
/* Type 42 fonts, and will generally be invalid. */ |
/* Type 42 fonts, and will generally be invalid. */ |
152 |
/* */ |
/* */ |
153 |
static FT_Error |
static FT_Error |
154 |
sfnt_dir_check( FT_Stream stream, |
sfnt_dir_check( SFNT_Header sfnt, |
155 |
FT_ULong offset, |
FT_Stream stream ) |
156 |
FT_UInt num_tables ) |
{ |
|
{ |
|
157 |
FT_Error error; |
FT_Error error; |
158 |
FT_UInt nn; |
FT_UInt nn; |
159 |
FT_UInt has_head = 0, has_sing = 0, has_meta = 0; |
FT_UInt has_head = 0, has_sing = 0, has_meta = 0; |
160 |
|
FT_ULong offset = sfnt->offset + 12; |
161 |
|
|
162 |
const FT_ULong glyx_tag = FT_MAKE_TAG( 'g', 'l', 'y', 'x' ); |
const FT_ULong glyx_tag = FT_MAKE_TAG( 'g', 'l', 'y', 'x' ); |
163 |
const FT_ULong locx_tag = FT_MAKE_TAG( 'l', 'o', 'c', 'x' ); |
const FT_ULong locx_tag = FT_MAKE_TAG( 'l', 'o', 'c', 'x' ); |
176 |
}; |
}; |
177 |
|
|
178 |
|
|
179 |
/* if 'num_tables' is 0, read the table count from the file */ |
if ( sfnt->num_tables == 0 || |
180 |
if ( num_tables == 0 ) |
offset + sfnt->num_tables * 16 > stream->size ) |
181 |
{ |
return SFNT_Err_Unknown_File_Format; |
|
if ( FT_STREAM_SEEK( offset ) || |
|
|
FT_STREAM_SKIP( 4 ) || |
|
|
FT_READ_USHORT( num_tables ) || |
|
|
FT_STREAM_SKIP( 6 ) ) |
|
|
goto Bad_Format; |
|
182 |
|
|
183 |
if ( offset + 12 + num_tables*16 > stream->size ) |
if ( FT_STREAM_SEEK( offset ) ) |
184 |
goto Bad_Format; |
return error; |
|
} |
|
|
else if ( FT_STREAM_SEEK( offset + 12 ) ) |
|
|
goto Bad_Format; |
|
185 |
|
|
186 |
for ( nn = 0; nn < num_tables; nn++ ) |
for ( nn = 0; nn < sfnt->num_tables; nn++ ) |
187 |
{ |
{ |
188 |
TT_TableRec table; |
TT_TableRec table; |
189 |
|
|
190 |
|
|
191 |
if ( FT_STREAM_READ_FIELDS( sfnt_dir_entry_fields, &table ) ) |
if ( FT_STREAM_READ_FIELDS( sfnt_dir_entry_fields, &table ) ) |
192 |
goto Bad_Format; |
return error; |
193 |
|
|
194 |
if ( table.Offset + table.Length > stream->size && |
if ( table.Offset + table.Length > stream->size && |
195 |
table.Tag != glyx_tag && table.Tag != locx_tag ) |
table.Tag != glyx_tag && table.Tag != locx_tag ) |
196 |
goto Bad_Format; |
return SFNT_Err_Unknown_File_Format; |
197 |
|
|
198 |
if ( table.Tag == TTAG_head ) |
if ( table.Tag == TTAG_head || table.Tag == TTAG_bhed ) |
199 |
{ |
{ |
200 |
FT_UInt32 magic; |
FT_UInt32 magic; |
201 |
|
|
202 |
|
#ifndef TT_CONFIG_OPTION_EMBEDDED_BITMAPS |
203 |
#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS |
if ( table.Tag == TTAG_head ) |
204 |
head_retry: |
#endif |
205 |
#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ |
has_head = 1; |
|
|
|
|
has_head = 1; |
|
206 |
|
|
207 |
/* The table length should be 0x36, but certain font tools |
/* The table length should be 0x36, but certain font tools |
208 |
* make it 0x38, so we will just check that it is greater. |
* make it 0x38, so we will just check that it is greater. |
211 |
* the table must be padded to 32-bit lengths, but this doesn't |
* the table must be padded to 32-bit lengths, but this doesn't |
212 |
* apply to the value of its "Length" field! |
* apply to the value of its "Length" field! |
213 |
*/ |
*/ |
214 |
if ( table.Length < 0x36 || |
if ( table.Length < 0x36 ) |
215 |
FT_STREAM_SEEK( table.Offset + 12 ) || |
return SFNT_Err_Unknown_File_Format; |
|
FT_READ_ULONG( magic ) || |
|
|
magic != 0x5F0F3CF5UL ) |
|
|
goto Bad_Format; |
|
216 |
|
|
217 |
if ( FT_STREAM_SEEK( offset + 28 + 16*nn ) ) |
if ( FT_STREAM_SEEK( table.Offset + 12 ) || |
218 |
goto Bad_Format; |
FT_READ_ULONG( magic ) ) |
219 |
} |
return error; |
220 |
|
|
221 |
#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS |
if ( magic != 0x5F0F3CF5UL ) |
222 |
else if ( table.Tag == TTAG_bhed ) |
return SFNT_Err_Unknown_File_Format; |
|
goto head_retry; |
|
|
#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ |
|
223 |
|
|
224 |
|
if ( FT_STREAM_SEEK( offset + ( nn + 1 ) * 16 ) ) |
225 |
|
return error; |
226 |
|
} |
227 |
else if ( table.Tag == TTAG_SING ) |
else if ( table.Tag == TTAG_SING ) |
228 |
has_sing = 1; |
has_sing = 1; |
229 |
else if ( table.Tag == TTAG_META ) |
else if ( table.Tag == TTAG_META ) |
230 |
has_meta = 1; |
has_meta = 1; |
231 |
} |
} |
232 |
|
|
233 |
/* when sing and meta are present, head is not present */ |
if ( has_head || ( has_sing && has_meta ) ) |
234 |
if ( has_sing && has_meta && has_head == 0 ) |
return SFNT_Err_Ok; |
235 |
goto Exit; |
else |
236 |
|
return SFNT_Err_Unknown_File_Format; |
237 |
/* otherwise, treat a missing head as a failure */ |
} |
|
if ( has_head == 0 ) |
|
|
goto Bad_Format; |
|
238 |
|
|
|
Exit: |
|
|
return error; |
|
239 |
|
|
240 |
Bad_Format: |
/* Fill in face->ttc_header. If the font is not a TTC, it is */ |
241 |
error = SFNT_Err_Unknown_File_Format; |
/* synthesized into a TTC with one offset table. */ |
242 |
goto Exit; |
static FT_Error |
243 |
|
sfnt_init( FT_Stream stream, |
244 |
|
TT_Face face ) |
245 |
|
{ |
246 |
|
FT_Memory memory = stream->memory; |
247 |
|
FT_Error error; |
248 |
|
FT_ULong tag, offset; |
249 |
|
|
250 |
|
static const FT_Frame_Field ttc_header_fields[] = |
251 |
|
{ |
252 |
|
#undef FT_STRUCTURE |
253 |
|
#define FT_STRUCTURE TTC_HeaderRec |
254 |
|
|
255 |
|
FT_FRAME_START( 8 ), |
256 |
|
FT_FRAME_LONG( version ), |
257 |
|
FT_FRAME_LONG( count ), |
258 |
|
FT_FRAME_END |
259 |
|
}; |
260 |
|
|
261 |
|
face->ttc_header.tag = 0; |
262 |
|
face->ttc_header.version = 0; |
263 |
|
face->ttc_header.count = 0; |
264 |
|
|
265 |
|
offset = FT_STREAM_POS(); |
266 |
|
|
267 |
|
if ( FT_READ_ULONG( tag ) ) |
268 |
|
return error; |
269 |
|
|
270 |
|
face->ttc_header.tag = TTAG_ttcf; |
271 |
|
|
272 |
|
if ( tag == TTAG_ttcf ) |
273 |
|
{ |
274 |
|
FT_Int n; |
275 |
|
|
276 |
|
|
277 |
|
FT_TRACE3(( "sfnt_init: file is a collection\n" )); |
278 |
|
|
279 |
|
if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) ) |
280 |
|
return error; |
281 |
|
|
282 |
|
/* now read the offsets of each font in the file */ |
283 |
|
if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ) |
284 |
|
return error; |
285 |
|
|
286 |
|
if ( FT_FRAME_ENTER( face->ttc_header.count * 4L ) ) |
287 |
|
return error; |
288 |
|
|
289 |
|
for ( n = 0; n < face->ttc_header.count; n++ ) |
290 |
|
face->ttc_header.offsets[n] = FT_GET_ULONG(); |
291 |
|
|
292 |
|
FT_FRAME_EXIT(); |
293 |
|
} |
294 |
|
else |
295 |
|
{ |
296 |
|
face->ttc_header.version = 1 << 16; |
297 |
|
face->ttc_header.count = 1; |
298 |
|
|
299 |
|
if ( FT_NEW( face->ttc_header.offsets) ) |
300 |
|
return error; |
301 |
|
|
302 |
|
face->ttc_header.offsets[0] = offset; |
303 |
|
} |
304 |
|
|
305 |
|
return error; |
306 |
} |
} |
307 |
|
|
308 |
|
|
342 |
FT_Long face_index, |
FT_Long face_index, |
343 |
SFNT_Header sfnt ) |
SFNT_Header sfnt ) |
344 |
{ |
{ |
345 |
FT_Error error; |
FT_Error error; |
|
FT_ULong font_format_tag, format_tag, offset; |
|
|
FT_Memory memory = stream->memory; |
|
346 |
|
|
347 |
static const FT_Frame_Field sfnt_header_fields[] = |
static const FT_Frame_Field sfnt_header_fields[] = |
348 |
{ |
{ |
357 |
FT_FRAME_END |
FT_FRAME_END |
358 |
}; |
}; |
359 |
|
|
|
static const FT_Frame_Field ttc_header_fields[] = |
|
|
{ |
|
|
#undef FT_STRUCTURE |
|
|
#define FT_STRUCTURE TTC_HeaderRec |
|
|
|
|
|
FT_FRAME_START( 8 ), |
|
|
FT_FRAME_LONG( version ), |
|
|
FT_FRAME_LONG( count ), |
|
|
FT_FRAME_END |
|
|
}; |
|
|
|
|
360 |
|
|
361 |
FT_TRACE2(( "tt_face_load_sfnt_header: %08p, %ld\n", |
FT_TRACE2(( "tt_face_load_sfnt_header: %08p, %ld\n", |
362 |
face, face_index )); |
face, face_index )); |
363 |
|
|
364 |
face->ttc_header.tag = 0; |
error = sfnt_init( stream, face ); |
365 |
face->ttc_header.version = 0; |
if ( error ) |
366 |
face->ttc_header.count = 0; |
return error; |
|
|
|
|
face->num_tables = 0; |
|
|
|
|
|
/* First of all, read the first 4 bytes. If it is `ttcf', then the */ |
|
|
/* file is a TrueType collection, otherwise it is a single-face font. */ |
|
|
/* */ |
|
|
offset = FT_STREAM_POS(); |
|
|
|
|
|
if ( FT_READ_ULONG( font_format_tag ) ) |
|
|
goto Exit; |
|
|
|
|
|
format_tag = font_format_tag; |
|
|
|
|
|
if ( font_format_tag == TTAG_ttcf ) |
|
|
{ |
|
|
FT_Int n; |
|
|
|
|
|
|
|
|
FT_TRACE3(( "tt_face_load_sfnt_header: file is a collection\n" )); |
|
|
|
|
|
/* It is a TrueType collection, i.e. a file containing several */ |
|
|
/* font files. Read the font directory now */ |
|
|
if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) ) |
|
|
goto Exit; |
|
|
|
|
|
/* now read the offsets of each font in the file */ |
|
|
if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) || |
|
|
FT_FRAME_ENTER( face->ttc_header.count * 4L ) ) |
|
|
goto Exit; |
|
|
|
|
|
for ( n = 0; n < face->ttc_header.count; n++ ) |
|
|
face->ttc_header.offsets[n] = FT_GET_ULONG(); |
|
367 |
|
|
368 |
FT_FRAME_EXIT(); |
if ( face_index < 0 ) |
369 |
|
face_index = 0; |
370 |
|
|
371 |
/* check face index */ |
if ( face_index >= face->ttc_header.count ) |
372 |
if ( face_index >= face->ttc_header.count ) |
return SFNT_Err_Bad_Argument; |
|
{ |
|
|
error = SFNT_Err_Bad_Argument; |
|
|
goto Exit; |
|
|
} |
|
373 |
|
|
374 |
/* seek to the appropriate TrueType file, then read tag */ |
sfnt->offset = face->ttc_header.offsets[face_index]; |
|
offset = face->ttc_header.offsets[face_index]; |
|
375 |
|
|
376 |
if ( FT_STREAM_SEEK( offset ) || |
if ( FT_STREAM_SEEK( sfnt->offset ) ) |
377 |
FT_READ_LONG( format_tag ) ) |
return error; |
|
goto Exit; |
|
|
} |
|
|
|
|
|
/* the format tag was read, now check the rest of the header */ |
|
|
sfnt->format_tag = format_tag; |
|
|
sfnt->offset = offset; |
|
378 |
|
|
379 |
if ( FT_STREAM_READ_FIELDS( sfnt_header_fields, sfnt ) ) |
/* read offset table */ |
380 |
goto Exit; |
if ( FT_READ_ULONG( sfnt->format_tag ) || |
381 |
|
FT_STREAM_READ_FIELDS( sfnt_header_fields, sfnt ) ) |
382 |
|
return error; |
383 |
|
|
384 |
/* now check the sfnt directory */ |
/* now check the sfnt directory */ |
385 |
error = sfnt_dir_check( stream, offset, sfnt->num_tables ); |
error = sfnt_dir_check( sfnt, stream ); |
386 |
if ( error ) |
if ( error ) |
387 |
{ |
FT_TRACE2(( "tt_face_load_sfnt_header: invalid SFNT!\n" )); |
|
FT_TRACE2(( "tt_face_load_sfnt_header: file is not SFNT!\n" )); |
|
|
error = SFNT_Err_Unknown_File_Format; |
|
|
goto Exit; |
|
|
} |
|
|
|
|
|
/* disallow face index values > 0 for non-TTC files */ |
|
|
if ( font_format_tag != TTAG_ttcf && face_index > 0 ) |
|
|
error = SFNT_Err_Bad_Argument; |
|
388 |
|
|
|
Exit: |
|
389 |
return error; |
return error; |
390 |
} |
} |
391 |
|
|