1/****************************************************************************
2 *
3 * ttload.c
4 *
5 * Load the basic TrueType tables, i.e., tables that can be either in
6 * TTF or OTF fonts (body).
7 *
8 * Copyright (C) 1996-2019 by
9 * David Turner, Robert Wilhelm, and Werner Lemberg.
10 *
11 * This file is part of the FreeType project, and may only be used,
12 * modified, and distributed under the terms of the FreeType project
13 * license, LICENSE.TXT. By continuing to use, modify, or distribute
14 * this file you indicate that you have read the license and
15 * understand and accept it fully.
16 *
17 */
18
19
20#include <ft2build.h>
21#include FT_INTERNAL_DEBUG_H
22#include FT_INTERNAL_STREAM_H
23#include FT_TRUETYPE_TAGS_H
24#include "ttload.h"
25
26#include "sferrors.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 ttload
37
38
39 /**************************************************************************
40 *
41 * @Function:
42 * tt_face_lookup_table
43 *
44 * @Description:
45 * Looks for a TrueType table by name.
46 *
47 * @Input:
48 * face ::
49 * A face object handle.
50 *
51 * tag ::
52 * The searched tag.
53 *
54 * @Return:
55 * A pointer to the table directory entry. 0 if not found.
56 */
57 FT_LOCAL_DEF( TT_Table )
58 tt_face_lookup_table( TT_Face face,
59 FT_ULong tag )
60 {
61 TT_Table entry;
62 TT_Table limit;
63#ifdef FT_DEBUG_LEVEL_TRACE
64 FT_Bool zero_length = FALSE;
65#endif
66
67
68 FT_TRACE4(( "tt_face_lookup_table: %08p, `%c%c%c%c' -- ",
69 face,
70 (FT_Char)( tag >> 24 ),
71 (FT_Char)( tag >> 16 ),
72 (FT_Char)( tag >> 8 ),
73 (FT_Char)( tag ) ));
74
75 entry = face->dir_tables;
76 limit = entry + face->num_tables;
77
78 for ( ; entry < limit; entry++ )
79 {
80 /* For compatibility with Windows, we consider */
81 /* zero-length tables the same as missing tables. */
82 if ( entry->Tag == tag )
83 {
84 if ( entry->Length != 0 )
85 {
86 FT_TRACE4(( "found table.\n" ));
87 return entry;
88 }
89#ifdef FT_DEBUG_LEVEL_TRACE
90 zero_length = TRUE;
91#endif
92 }
93 }
94
95#ifdef FT_DEBUG_LEVEL_TRACE
96 if ( zero_length )
97 FT_TRACE4(( "ignoring empty table\n" ));
98 else
99 FT_TRACE4(( "could not find table\n" ));
100#endif
101
102 return NULL;
103 }
104
105
106 /**************************************************************************
107 *
108 * @Function:
109 * tt_face_goto_table
110 *
111 * @Description:
112 * Looks for a TrueType table by name, then seek a stream to it.
113 *
114 * @Input:
115 * face ::
116 * A face object handle.
117 *
118 * tag ::
119 * The searched tag.
120 *
121 * stream ::
122 * The stream to seek when the table is found.
123 *
124 * @Output:
125 * length ::
126 * The length of the table if found, undefined otherwise.
127 *
128 * @Return:
129 * FreeType error code. 0 means success.
130 */
131 FT_LOCAL_DEF( FT_Error )
132 tt_face_goto_table( TT_Face face,
133 FT_ULong tag,
134 FT_Stream stream,
135 FT_ULong* length )
136 {
137 TT_Table table;
138 FT_Error error;
139
140
141 table = tt_face_lookup_table( face, tag );
142 if ( table )
143 {
144 if ( length )
145 *length = table->Length;
146
147 if ( FT_STREAM_SEEK( table->Offset ) )
148 goto Exit;
149 }
150 else
151 error = FT_THROW( Table_Missing );
152
153 Exit:
154 return error;
155 }
156
157
158 /* Here, we */
159 /* */
160 /* - check that `num_tables' is valid (and adjust it if necessary); */
161 /* also return the number of valid table entries */
162 /* */
163 /* - look for a `head' table, check its size, and parse it to check */
164 /* whether its `magic' field is correctly set */
165 /* */
166 /* - errors (except errors returned by stream handling) */
167 /* */
168 /* SFNT_Err_Unknown_File_Format: */
169 /* no table is defined in directory, it is not sfnt-wrapped */
170 /* data */
171 /* SFNT_Err_Table_Missing: */
172 /* table directory is valid, but essential tables */
173 /* (head/bhed/SING) are missing */
174 /* */
175 static FT_Error
176 check_table_dir( SFNT_Header sfnt,
177 FT_Stream stream,
178 FT_UShort* valid )
179 {
180 FT_Error error;
181 FT_UShort nn, valid_entries = 0;
182 FT_UInt has_head = 0, has_sing = 0, has_meta = 0;
183 FT_ULong offset = sfnt->offset + 12;
184
185 static const FT_Frame_Field table_dir_entry_fields[] =
186 {
187#undef FT_STRUCTURE
188#define FT_STRUCTURE TT_TableRec
189
190 FT_FRAME_START( 16 ),
191 FT_FRAME_ULONG( Tag ),
192 FT_FRAME_ULONG( CheckSum ),
193 FT_FRAME_ULONG( Offset ),
194 FT_FRAME_ULONG( Length ),
195 FT_FRAME_END
196 };
197
198
199 if ( FT_STREAM_SEEK( offset ) )
200 goto Exit;
201
202 for ( nn = 0; nn < sfnt->num_tables; nn++ )
203 {
204 TT_TableRec table;
205
206
207 if ( FT_STREAM_READ_FIELDS( table_dir_entry_fields, &table ) )
208 {
209 nn--;
210 FT_TRACE2(( "check_table_dir:"
211 " can read only %d table%s in font (instead of %d)\n",
212 nn, nn == 1 ? "" : "s", sfnt->num_tables ));
213 sfnt->num_tables = nn;
214 break;
215 }
216
217 /* we ignore invalid tables */
218
219 if ( table.Offset > stream->size )
220 {
221 FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn ));
222 continue;
223 }
224 else if ( table.Length > stream->size - table.Offset )
225 {
226 /* Some tables have such a simple structure that clipping its */
227 /* contents is harmless. This also makes FreeType less sensitive */
228 /* to invalid table lengths (which programs like Acroread seem to */
229 /* ignore in general). */
230
231 if ( table.Tag == TTAG_hmtx ||
232 table.Tag == TTAG_vmtx )
233 valid_entries++;
234 else
235 {
236 FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn ));
237 continue;
238 }
239 }
240 else
241 valid_entries++;
242
243 if ( table.Tag == TTAG_head || table.Tag == TTAG_bhed )
244 {
245 FT_UInt32 magic;
246
247
248#ifndef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
249 if ( table.Tag == TTAG_head )
250#endif
251 has_head = 1;
252
253 /*
254 * The table length should be 0x36, but certain font tools make it
255 * 0x38, so we will just check that it is greater.
256 *
257 * Note that according to the specification, the table must be
258 * padded to 32-bit lengths, but this doesn't apply to the value of
259 * its `Length' field!
260 *
261 */
262 if ( table.Length < 0x36 )
263 {
264 FT_TRACE2(( "check_table_dir:"
265 " `head' or `bhed' table too small\n" ));
266 error = FT_THROW( Table_Missing );
267 goto Exit;
268 }
269
270 if ( FT_STREAM_SEEK( table.Offset + 12 ) ||
271 FT_READ_ULONG( magic ) )
272 goto Exit;
273
274 if ( magic != 0x5F0F3CF5UL )
275 FT_TRACE2(( "check_table_dir:"
276 " invalid magic number in `head' or `bhed' table\n"));
277
278 if ( FT_STREAM_SEEK( offset + ( nn + 1 ) * 16 ) )
279 goto Exit;
280 }
281 else if ( table.Tag == TTAG_SING )
282 has_sing = 1;
283 else if ( table.Tag == TTAG_META )
284 has_meta = 1;
285 }
286
287 *valid = valid_entries;
288
289 if ( !valid_entries )
290 {
291 FT_TRACE2(( "check_table_dir: no valid tables found\n" ));
292 error = FT_THROW( Unknown_File_Format );
293 goto Exit;
294 }
295
296 /* if `sing' and `meta' tables are present, there is no `head' table */
297 if ( has_head || ( has_sing && has_meta ) )
298 {
299 error = FT_Err_Ok;
300 goto Exit;
301 }
302 else
303 {
304 FT_TRACE2(( "check_table_dir:" ));
305#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
306 FT_TRACE2(( " neither `head', `bhed', nor `sing' table found\n" ));
307#else
308 FT_TRACE2(( " neither `head' nor `sing' table found\n" ));
309#endif
310 error = FT_THROW( Table_Missing );
311 }
312
313 Exit:
314 return error;
315 }
316
317
318 /**************************************************************************
319 *
320 * @Function:
321 * tt_face_load_font_dir
322 *
323 * @Description:
324 * Loads the header of a SFNT font file.
325 *
326 * @Input:
327 * face ::
328 * A handle to the target face object.
329 *
330 * stream ::
331 * The input stream.
332 *
333 * @Output:
334 * sfnt ::
335 * The SFNT header.
336 *
337 * @Return:
338 * FreeType error code. 0 means success.
339 *
340 * @Note:
341 * The stream cursor must be at the beginning of the font directory.
342 */
343 FT_LOCAL_DEF( FT_Error )
344 tt_face_load_font_dir( TT_Face face,
345 FT_Stream stream )
346 {
347 SFNT_HeaderRec sfnt;
348 FT_Error error;
349 FT_Memory memory = stream->memory;
350 FT_UShort nn, valid_entries = 0;
351
352 static const FT_Frame_Field offset_table_fields[] =
353 {
354#undef FT_STRUCTURE
355#define FT_STRUCTURE SFNT_HeaderRec
356
357 FT_FRAME_START( 8 ),
358 FT_FRAME_USHORT( num_tables ),
359 FT_FRAME_USHORT( search_range ),
360 FT_FRAME_USHORT( entry_selector ),
361 FT_FRAME_USHORT( range_shift ),
362 FT_FRAME_END
363 };
364
365
366 FT_TRACE2(( "tt_face_load_font_dir: %08p\n", face ));
367
368 /* read the offset table */
369
370 sfnt.offset = FT_STREAM_POS();
371
372 if ( FT_READ_ULONG( sfnt.format_tag ) ||
373 FT_STREAM_READ_FIELDS( offset_table_fields, &sfnt ) )
374 goto Exit;
375
376 /* many fonts don't have these fields set correctly */
377#if 0
378 if ( sfnt.search_range != 1 << ( sfnt.entry_selector + 4 ) ||
379 sfnt.search_range + sfnt.range_shift != sfnt.num_tables << 4 )
380 return FT_THROW( Unknown_File_Format );
381#endif
382
383 /* load the table directory */
384
385 FT_TRACE2(( "-- Number of tables: %10u\n", sfnt.num_tables ));
386 FT_TRACE2(( "-- Format version: 0x%08lx\n", sfnt.format_tag ));
387
388 if ( sfnt.format_tag != TTAG_OTTO )
389 {
390 /* check first */
391 error = check_table_dir( &sfnt, stream, &valid_entries );
392 if ( error )
393 {
394 FT_TRACE2(( "tt_face_load_font_dir:"
395 " invalid table directory for TrueType\n" ));
396 goto Exit;
397 }
398 }
399 else
400 valid_entries = sfnt.num_tables;
401
402 face->num_tables = valid_entries;
403 face->format_tag = sfnt.format_tag;
404
405 if ( FT_QNEW_ARRAY( face->dir_tables, face->num_tables ) )
406 goto Exit;
407
408 if ( FT_STREAM_SEEK( sfnt.offset + 12 ) ||
409 FT_FRAME_ENTER( sfnt.num_tables * 16L ) )
410 goto Exit;
411
412 FT_TRACE2(( "\n"
413 " tag offset length checksum\n"
414 " ----------------------------------\n" ));
415
416 valid_entries = 0;
417 for ( nn = 0; nn < sfnt.num_tables; nn++ )
418 {
419 TT_TableRec entry;
420 FT_UShort i;
421 FT_Bool duplicate;
422
423
424 entry.Tag = FT_GET_TAG4();
425 entry.CheckSum = FT_GET_ULONG();
426 entry.Offset = FT_GET_ULONG();
427 entry.Length = FT_GET_ULONG();
428
429 /* ignore invalid tables that can't be sanitized */
430
431 if ( entry.Offset > stream->size )
432 continue;
433 else if ( entry.Length > stream->size - entry.Offset )
434 {
435 if ( entry.Tag == TTAG_hmtx ||
436 entry.Tag == TTAG_vmtx )
437 {
438#ifdef FT_DEBUG_LEVEL_TRACE
439 FT_ULong old_length = entry.Length;
440#endif
441
442
443 /* make metrics table length a multiple of 4 */
444 entry.Length = ( stream->size - entry.Offset ) & ~3U;
445
446 FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx"
447 " (sanitized; original length %08lx)",
448 (FT_Char)( entry.Tag >> 24 ),
449 (FT_Char)( entry.Tag >> 16 ),
450 (FT_Char)( entry.Tag >> 8 ),
451 (FT_Char)( entry.Tag ),
452 entry.Offset,
453 entry.Length,
454 entry.CheckSum,
455 old_length ));
456 }
457 else
458 continue;
459 }
460#ifdef FT_DEBUG_LEVEL_TRACE
461 else
462 FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx",
463 (FT_Char)( entry.Tag >> 24 ),
464 (FT_Char)( entry.Tag >> 16 ),
465 (FT_Char)( entry.Tag >> 8 ),
466 (FT_Char)( entry.Tag ),
467 entry.Offset,
468 entry.Length,
469 entry.CheckSum ));
470#endif
471
472 /* ignore duplicate tables – the first one wins */
473 duplicate = 0;
474 for ( i = 0; i < valid_entries; i++ )
475 {
476 if ( face->dir_tables[i].Tag == entry.Tag )
477 {
478 duplicate = 1;
479 break;
480 }
481 }
482 if ( duplicate )
483 {
484 FT_TRACE2(( " (duplicate, ignored)\n" ));
485 continue;
486 }
487 else
488 {
489 FT_TRACE2(( "\n" ));
490
491 /* we finally have a valid entry */
492 face->dir_tables[valid_entries++] = entry;
493 }
494 }
495
496 /* final adjustment to number of tables */
497 face->num_tables = valid_entries;
498
499 FT_FRAME_EXIT();
500
501 FT_TRACE2(( "table directory loaded\n\n" ));
502
503 Exit:
504 return error;
505 }
506
507
508 /**************************************************************************
509 *
510 * @Function:
511 * tt_face_load_any
512 *
513 * @Description:
514 * Loads any font table into client memory.
515 *
516 * @Input:
517 * face ::
518 * The face object to look for.
519 *
520 * tag ::
521 * The tag of table to load. Use the value 0 if you want
522 * to access the whole font file, else set this parameter
523 * to a valid TrueType table tag that you can forge with
524 * the MAKE_TT_TAG macro.
525 *
526 * offset ::
527 * The starting offset in the table (or the file if
528 * tag == 0).
529 *
530 * length ::
531 * The address of the decision variable:
532 *
533 * If length == NULL:
534 * Loads the whole table. Returns an error if
535 * `offset' == 0!
536 *
537 * If *length == 0:
538 * Exits immediately; returning the length of the given
539 * table or of the font file, depending on the value of
540 * `tag'.
541 *
542 * If *length != 0:
543 * Loads the next `length' bytes of table or font,
544 * starting at offset `offset' (in table or font too).
545 *
546 * @Output:
547 * buffer ::
548 * The address of target buffer.
549 *
550 * @Return:
551 * FreeType error code. 0 means success.
552 */
553 FT_LOCAL_DEF( FT_Error )
554 tt_face_load_any( TT_Face face,
555 FT_ULong tag,
556 FT_Long offset,
557 FT_Byte* buffer,
558 FT_ULong* length )
559 {
560 FT_Error error;
561 FT_Stream stream;
562 TT_Table table;
563 FT_ULong size;
564
565
566 if ( tag != 0 )
567 {
568 /* look for tag in font directory */
569 table = tt_face_lookup_table( face, tag );
570 if ( !table )
571 {
572 error = FT_THROW( Table_Missing );
573 goto Exit;
574 }
575
576 offset += table->Offset;
577 size = table->Length;
578 }
579 else
580 /* tag == 0 -- the user wants to access the font file directly */
581 size = face->root.stream->size;
582
583 if ( length && *length == 0 )
584 {
585 *length = size;
586
587 return FT_Err_Ok;
588 }
589
590 if ( length )
591 size = *length;
592
593 stream = face->root.stream;
594 /* the `if' is syntactic sugar for picky compilers */
595 if ( FT_STREAM_READ_AT( offset, buffer, size ) )
596 goto Exit;
597
598 Exit:
599 return error;
600 }
601
602
603 /**************************************************************************
604 *
605 * @Function:
606 * tt_face_load_generic_header
607 *
608 * @Description:
609 * Loads the TrueType table `head' or `bhed'.
610 *
611 * @Input:
612 * face ::
613 * A handle to the target face object.
614 *
615 * stream ::
616 * The input stream.
617 *
618 * @Return:
619 * FreeType error code. 0 means success.
620 */
621 static FT_Error
622 tt_face_load_generic_header( TT_Face face,
623 FT_Stream stream,
624 FT_ULong tag )
625 {
626 FT_Error error;
627 TT_Header* header;
628
629 static const FT_Frame_Field header_fields[] =
630 {
631#undef FT_STRUCTURE
632#define FT_STRUCTURE TT_Header
633
634 FT_FRAME_START( 54 ),
635 FT_FRAME_ULONG ( Table_Version ),
636 FT_FRAME_ULONG ( Font_Revision ),
637 FT_FRAME_LONG ( CheckSum_Adjust ),
638 FT_FRAME_LONG ( Magic_Number ),
639 FT_FRAME_USHORT( Flags ),
640 FT_FRAME_USHORT( Units_Per_EM ),
641 FT_FRAME_ULONG ( Created[0] ),
642 FT_FRAME_ULONG ( Created[1] ),
643 FT_FRAME_ULONG ( Modified[0] ),
644 FT_FRAME_ULONG ( Modified[1] ),
645 FT_FRAME_SHORT ( xMin ),
646 FT_FRAME_SHORT ( yMin ),
647 FT_FRAME_SHORT ( xMax ),
648 FT_FRAME_SHORT ( yMax ),
649 FT_FRAME_USHORT( Mac_Style ),
650 FT_FRAME_USHORT( Lowest_Rec_PPEM ),
651 FT_FRAME_SHORT ( Font_Direction ),
652 FT_FRAME_SHORT ( Index_To_Loc_Format ),
653 FT_FRAME_SHORT ( Glyph_Data_Format ),
654 FT_FRAME_END
655 };
656
657
658 error = face->goto_table( face, tag, stream, 0 );
659 if ( error )
660 goto Exit;
661
662 header = &face->header;
663
664 if ( FT_STREAM_READ_FIELDS( header_fields, header ) )
665 goto Exit;
666
667 FT_TRACE3(( "Units per EM: %4u\n", header->Units_Per_EM ));
668 FT_TRACE3(( "IndexToLoc: %4d\n", header->Index_To_Loc_Format ));
669
670 Exit:
671 return error;
672 }
673
674
675 FT_LOCAL_DEF( FT_Error )
676 tt_face_load_head( TT_Face face,
677 FT_Stream stream )
678 {
679 return tt_face_load_generic_header( face, stream, TTAG_head );
680 }
681
682
683#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
684
685 FT_LOCAL_DEF( FT_Error )
686 tt_face_load_bhed( TT_Face face,
687 FT_Stream stream )
688 {
689 return tt_face_load_generic_header( face, stream, TTAG_bhed );
690 }
691
692#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
693
694
695 /**************************************************************************
696 *
697 * @Function:
698 * tt_face_load_maxp
699 *
700 * @Description:
701 * Loads the maximum profile into a face object.
702 *
703 * @Input:
704 * face ::
705 * A handle to the target face object.
706 *
707 * stream ::
708 * The input stream.
709 *
710 * @Return:
711 * FreeType error code. 0 means success.
712 */
713 FT_LOCAL_DEF( FT_Error )
714 tt_face_load_maxp( TT_Face face,
715 FT_Stream stream )
716 {
717 FT_Error error;
718 TT_MaxProfile* maxProfile = &face->max_profile;
719
720 static const FT_Frame_Field maxp_fields[] =
721 {
722#undef FT_STRUCTURE
723#define FT_STRUCTURE TT_MaxProfile
724
725 FT_FRAME_START( 6 ),
726 FT_FRAME_LONG ( version ),
727 FT_FRAME_USHORT( numGlyphs ),
728 FT_FRAME_END
729 };
730
731 static const FT_Frame_Field maxp_fields_extra[] =
732 {
733 FT_FRAME_START( 26 ),
734 FT_FRAME_USHORT( maxPoints ),
735 FT_FRAME_USHORT( maxContours ),
736 FT_FRAME_USHORT( maxCompositePoints ),
737 FT_FRAME_USHORT( maxCompositeContours ),
738 FT_FRAME_USHORT( maxZones ),
739 FT_FRAME_USHORT( maxTwilightPoints ),
740 FT_FRAME_USHORT( maxStorage ),
741 FT_FRAME_USHORT( maxFunctionDefs ),
742 FT_FRAME_USHORT( maxInstructionDefs ),
743 FT_FRAME_USHORT( maxStackElements ),
744 FT_FRAME_USHORT( maxSizeOfInstructions ),
745 FT_FRAME_USHORT( maxComponentElements ),
746 FT_FRAME_USHORT( maxComponentDepth ),
747 FT_FRAME_END
748 };
749
750
751 error = face->goto_table( face, TTAG_maxp, stream, 0 );
752 if ( error )
753 goto Exit;
754
755 if ( FT_STREAM_READ_FIELDS( maxp_fields, maxProfile ) )
756 goto Exit;
757
758 maxProfile->maxPoints = 0;
759 maxProfile->maxContours = 0;
760 maxProfile->maxCompositePoints = 0;
761 maxProfile->maxCompositeContours = 0;
762 maxProfile->maxZones = 0;
763 maxProfile->maxTwilightPoints = 0;
764 maxProfile->maxStorage = 0;
765 maxProfile->maxFunctionDefs = 0;
766 maxProfile->maxInstructionDefs = 0;
767 maxProfile->maxStackElements = 0;
768 maxProfile->maxSizeOfInstructions = 0;
769 maxProfile->maxComponentElements = 0;
770 maxProfile->maxComponentDepth = 0;
771
772 if ( maxProfile->version >= 0x10000L )
773 {
774 if ( FT_STREAM_READ_FIELDS( maxp_fields_extra, maxProfile ) )
775 goto Exit;
776
777 /* XXX: an adjustment that is necessary to load certain */
778 /* broken fonts like `Keystrokes MT' :-( */
779 /* */
780 /* We allocate 64 function entries by default when */
781 /* the maxFunctionDefs value is smaller. */
782
783 if ( maxProfile->maxFunctionDefs < 64 )
784 maxProfile->maxFunctionDefs = 64;
785
786 /* we add 4 phantom points later */
787 if ( maxProfile->maxTwilightPoints > ( 0xFFFFU - 4 ) )
788 {
789 FT_TRACE0(( "tt_face_load_maxp:"
790 " too much twilight points in `maxp' table;\n"
791 " "
792 " some glyphs might be rendered incorrectly\n" ));
793
794 maxProfile->maxTwilightPoints = 0xFFFFU - 4;
795 }
796 }
797
798 FT_TRACE3(( "numGlyphs: %u\n", maxProfile->numGlyphs ));
799
800 Exit:
801 return error;
802 }
803
804
805 /**************************************************************************
806 *
807 * @Function:
808 * tt_face_load_name
809 *
810 * @Description:
811 * Loads the name records.
812 *
813 * @Input:
814 * face ::
815 * A handle to the target face object.
816 *
817 * stream ::
818 * The input stream.
819 *
820 * @Return:
821 * FreeType error code. 0 means success.
822 */
823 FT_LOCAL_DEF( FT_Error )
824 tt_face_load_name( TT_Face face,
825 FT_Stream stream )
826 {
827 FT_Error error;
828 FT_Memory memory = stream->memory;
829 FT_ULong table_pos, table_len;
830 FT_ULong storage_start, storage_limit;
831 TT_NameTable table;
832
833 static const FT_Frame_Field name_table_fields[] =
834 {
835#undef FT_STRUCTURE
836#define FT_STRUCTURE TT_NameTableRec
837
838 FT_FRAME_START( 6 ),
839 FT_FRAME_USHORT( format ),
840 FT_FRAME_USHORT( numNameRecords ),
841 FT_FRAME_USHORT( storageOffset ),
842 FT_FRAME_END
843 };
844
845 static const FT_Frame_Field name_record_fields[] =
846 {
847#undef FT_STRUCTURE
848#define FT_STRUCTURE TT_NameRec
849
850 /* no FT_FRAME_START */
851 FT_FRAME_USHORT( platformID ),
852 FT_FRAME_USHORT( encodingID ),
853 FT_FRAME_USHORT( languageID ),
854 FT_FRAME_USHORT( nameID ),
855 FT_FRAME_USHORT( stringLength ),
856 FT_FRAME_USHORT( stringOffset ),
857 FT_FRAME_END
858 };
859
860 static const FT_Frame_Field langTag_record_fields[] =
861 {
862#undef FT_STRUCTURE
863#define FT_STRUCTURE TT_LangTagRec
864
865 /* no FT_FRAME_START */
866 FT_FRAME_USHORT( stringLength ),
867 FT_FRAME_USHORT( stringOffset ),
868 FT_FRAME_END
869 };
870
871
872 table = &face->name_table;
873 table->stream = stream;
874
875 error = face->goto_table( face, TTAG_name, stream, &table_len );
876 if ( error )
877 goto Exit;
878
879 table_pos = FT_STREAM_POS();
880
881 if ( FT_STREAM_READ_FIELDS( name_table_fields, table ) )
882 goto Exit;
883
884 /* Some popular Asian fonts have an invalid `storageOffset' value (it */
885 /* should be at least `6 + 12*numNameRecords'). However, the string */
886 /* offsets, computed as `storageOffset + entry->stringOffset', are */
887 /* valid pointers within the name table... */
888 /* */
889 /* We thus can't check `storageOffset' right now. */
890 /* */
891 storage_start = table_pos + 6 + 12 * table->numNameRecords;
892 storage_limit = table_pos + table_len;
893
894 if ( storage_start > storage_limit )
895 {
896 FT_ERROR(( "tt_face_load_name: invalid `name' table\n" ));
897 error = FT_THROW( Name_Table_Missing );
898 goto Exit;
899 }
900
901 /* `name' format 1 contains additional language tag records, */
902 /* which we load first */
903 if ( table->format == 1 )
904 {
905 if ( FT_STREAM_SEEK( storage_start ) ||
906 FT_READ_USHORT( table->numLangTagRecords ) )
907 goto Exit;
908
909 storage_start += 2 + 4 * table->numLangTagRecords;
910
911 /* allocate language tag records array */
912 if ( FT_NEW_ARRAY( table->langTags, table->numLangTagRecords ) ||
913 FT_FRAME_ENTER( table->numLangTagRecords * 4 ) )
914 goto Exit;
915
916 /* load language tags */
917 {
918 TT_LangTag entry = table->langTags;
919 TT_LangTag limit = entry + table->numLangTagRecords;
920
921
922 for ( ; entry < limit; entry++ )
923 {
924 (void)FT_STREAM_READ_FIELDS( langTag_record_fields, entry );
925
926 /* check that the langTag string is within the table */
927 entry->stringOffset += table_pos + table->storageOffset;
928 if ( entry->stringOffset < storage_start ||
929 entry->stringOffset + entry->stringLength > storage_limit )
930 {
931 /* invalid entry; ignore it */
932 entry->stringLength = 0;
933 }
934 }
935 }
936
937 FT_FRAME_EXIT();
938
939 (void)FT_STREAM_SEEK( table_pos + 6 );
940 }
941
942 /* allocate name records array */
943 if ( FT_NEW_ARRAY( table->names, table->numNameRecords ) ||
944 FT_FRAME_ENTER( table->numNameRecords * 12 ) )
945 goto Exit;
946
947 /* load name records */
948 {
949 TT_Name entry = table->names;
950 FT_UInt count = table->numNameRecords;
951
952
953 for ( ; count > 0; count-- )
954 {
955 if ( FT_STREAM_READ_FIELDS( name_record_fields, entry ) )
956 continue;
957
958 /* check that the name is not empty */
959 if ( entry->stringLength == 0 )
960 continue;
961
962 /* check that the name string is within the table */
963 entry->stringOffset += table_pos + table->storageOffset;
964 if ( entry->stringOffset < storage_start ||
965 entry->stringOffset + entry->stringLength > storage_limit )
966 {
967 /* invalid entry; ignore it */
968 continue;
969 }
970
971 /* assure that we have a valid language tag ID, and */
972 /* that the corresponding langTag entry is valid, too */
973 if ( table->format == 1 && entry->languageID >= 0x8000U )
974 {
975 if ( entry->languageID - 0x8000U >= table->numLangTagRecords ||
976 !table->langTags[entry->languageID - 0x8000U].stringLength )
977 {
978 /* invalid entry; ignore it */
979 continue;
980 }
981 }
982
983 entry++;
984 }
985
986 /* reduce array size to the actually used elements */
987 count = (FT_UInt)( entry - table->names );
988 (void)FT_RENEW_ARRAY( table->names,
989 table->numNameRecords,
990 count );
991 table->numNameRecords = count;
992 }
993
994 FT_FRAME_EXIT();
995
996 /* everything went well, update face->num_names */
997 face->num_names = (FT_UShort)table->numNameRecords;
998
999 Exit:
1000 return error;
1001 }
1002
1003
1004 /**************************************************************************
1005 *
1006 * @Function:
1007 * tt_face_free_name
1008 *
1009 * @Description:
1010 * Frees the name records.
1011 *
1012 * @Input:
1013 * face ::
1014 * A handle to the target face object.
1015 */
1016 FT_LOCAL_DEF( void )
1017 tt_face_free_name( TT_Face face )
1018 {
1019 FT_Memory memory = face->root.driver->root.memory;
1020 TT_NameTable table = &face->name_table;
1021
1022
1023 if ( table->names )
1024 {
1025 TT_Name entry = table->names;
1026 TT_Name limit = entry + table->numNameRecords;
1027
1028
1029 for ( ; entry < limit; entry++ )
1030 FT_FREE( entry->string );
1031
1032 FT_FREE( table->names );
1033 }
1034
1035 if ( table->langTags )
1036 {
1037 TT_LangTag entry = table->langTags;
1038 TT_LangTag limit = entry + table->numLangTagRecords;
1039
1040
1041 for ( ; entry < limit; entry++ )
1042 FT_FREE( entry->string );
1043
1044 FT_FREE( table->langTags );
1045 }
1046
1047 table->numNameRecords = 0;
1048 table->numLangTagRecords = 0;
1049 table->format = 0;
1050 table->storageOffset = 0;
1051 }
1052
1053
1054 /**************************************************************************
1055 *
1056 * @Function:
1057 * tt_face_load_cmap
1058 *
1059 * @Description:
1060 * Loads the cmap directory in a face object. The cmaps themselves
1061 * are loaded on demand in the `ttcmap.c' module.
1062 *
1063 * @Input:
1064 * face ::
1065 * A handle to the target face object.
1066 *
1067 * stream ::
1068 * A handle to the input stream.
1069 *
1070 * @Return:
1071 * FreeType error code. 0 means success.
1072 */
1073
1074 FT_LOCAL_DEF( FT_Error )
1075 tt_face_load_cmap( TT_Face face,
1076 FT_Stream stream )
1077 {
1078 FT_Error error;
1079
1080
1081 error = face->goto_table( face, TTAG_cmap, stream, &face->cmap_size );
1082 if ( error )
1083 goto Exit;
1084
1085 if ( FT_FRAME_EXTRACT( face->cmap_size, face->cmap_table ) )
1086 face->cmap_size = 0;
1087
1088 Exit:
1089 return error;
1090 }
1091
1092
1093
1094 /**************************************************************************
1095 *
1096 * @Function:
1097 * tt_face_load_os2
1098 *
1099 * @Description:
1100 * Loads the OS2 table.
1101 *
1102 * @Input:
1103 * face ::
1104 * A handle to the target face object.
1105 *
1106 * stream ::
1107 * A handle to the input stream.
1108 *
1109 * @Return:
1110 * FreeType error code. 0 means success.
1111 */
1112 FT_LOCAL_DEF( FT_Error )
1113 tt_face_load_os2( TT_Face face,
1114 FT_Stream stream )
1115 {
1116 FT_Error error;
1117 TT_OS2* os2;
1118
1119 static const FT_Frame_Field os2_fields[] =
1120 {
1121#undef FT_STRUCTURE
1122#define FT_STRUCTURE TT_OS2
1123
1124 FT_FRAME_START( 78 ),
1125 FT_FRAME_USHORT( version ),
1126 FT_FRAME_SHORT ( xAvgCharWidth ),
1127 FT_FRAME_USHORT( usWeightClass ),
1128 FT_FRAME_USHORT( usWidthClass ),
1129 FT_FRAME_SHORT ( fsType ),
1130 FT_FRAME_SHORT ( ySubscriptXSize ),
1131 FT_FRAME_SHORT ( ySubscriptYSize ),
1132 FT_FRAME_SHORT ( ySubscriptXOffset ),
1133 FT_FRAME_SHORT ( ySubscriptYOffset ),
1134 FT_FRAME_SHORT ( ySuperscriptXSize ),
1135 FT_FRAME_SHORT ( ySuperscriptYSize ),
1136 FT_FRAME_SHORT ( ySuperscriptXOffset ),
1137 FT_FRAME_SHORT ( ySuperscriptYOffset ),
1138 FT_FRAME_SHORT ( yStrikeoutSize ),
1139 FT_FRAME_SHORT ( yStrikeoutPosition ),
1140 FT_FRAME_SHORT ( sFamilyClass ),
1141 FT_FRAME_BYTE ( panose[0] ),
1142 FT_FRAME_BYTE ( panose[1] ),
1143 FT_FRAME_BYTE ( panose[2] ),
1144 FT_FRAME_BYTE ( panose[3] ),
1145 FT_FRAME_BYTE ( panose[4] ),
1146 FT_FRAME_BYTE ( panose[5] ),
1147 FT_FRAME_BYTE ( panose[6] ),
1148 FT_FRAME_BYTE ( panose[7] ),
1149 FT_FRAME_BYTE ( panose[8] ),
1150 FT_FRAME_BYTE ( panose[9] ),
1151 FT_FRAME_ULONG ( ulUnicodeRange1 ),
1152 FT_FRAME_ULONG ( ulUnicodeRange2 ),
1153 FT_FRAME_ULONG ( ulUnicodeRange3 ),
1154 FT_FRAME_ULONG ( ulUnicodeRange4 ),
1155 FT_FRAME_BYTE ( achVendID[0] ),
1156 FT_FRAME_BYTE ( achVendID[1] ),
1157 FT_FRAME_BYTE ( achVendID[2] ),
1158 FT_FRAME_BYTE ( achVendID[3] ),
1159
1160 FT_FRAME_USHORT( fsSelection ),
1161 FT_FRAME_USHORT( usFirstCharIndex ),
1162 FT_FRAME_USHORT( usLastCharIndex ),
1163 FT_FRAME_SHORT ( sTypoAscender ),
1164 FT_FRAME_SHORT ( sTypoDescender ),
1165 FT_FRAME_SHORT ( sTypoLineGap ),
1166 FT_FRAME_USHORT( usWinAscent ),
1167 FT_FRAME_USHORT( usWinDescent ),
1168 FT_FRAME_END
1169 };
1170
1171 /* `OS/2' version 1 and newer */
1172 static const FT_Frame_Field os2_fields_extra1[] =
1173 {
1174 FT_FRAME_START( 8 ),
1175 FT_FRAME_ULONG( ulCodePageRange1 ),
1176 FT_FRAME_ULONG( ulCodePageRange2 ),
1177 FT_FRAME_END
1178 };
1179
1180 /* `OS/2' version 2 and newer */
1181 static const FT_Frame_Field os2_fields_extra2[] =
1182 {
1183 FT_FRAME_START( 10 ),
1184 FT_FRAME_SHORT ( sxHeight ),
1185 FT_FRAME_SHORT ( sCapHeight ),
1186 FT_FRAME_USHORT( usDefaultChar ),
1187 FT_FRAME_USHORT( usBreakChar ),
1188 FT_FRAME_USHORT( usMaxContext ),
1189 FT_FRAME_END
1190 };
1191
1192 /* `OS/2' version 5 and newer */
1193 static const FT_Frame_Field os2_fields_extra5[] =
1194 {
1195 FT_FRAME_START( 4 ),
1196 FT_FRAME_USHORT( usLowerOpticalPointSize ),
1197 FT_FRAME_USHORT( usUpperOpticalPointSize ),
1198 FT_FRAME_END
1199 };
1200
1201
1202 /* We now support old Mac fonts where the OS/2 table doesn't */
1203 /* exist. Simply put, we set the `version' field to 0xFFFF */
1204 /* and test this value each time we need to access the table. */
1205 error = face->goto_table( face, TTAG_OS2, stream, 0 );
1206 if ( error )
1207 goto Exit;
1208
1209 os2 = &face->os2;
1210
1211 if ( FT_STREAM_READ_FIELDS( os2_fields, os2 ) )
1212 goto Exit;
1213
1214 os2->ulCodePageRange1 = 0;
1215 os2->ulCodePageRange2 = 0;
1216 os2->sxHeight = 0;
1217 os2->sCapHeight = 0;
1218 os2->usDefaultChar = 0;
1219 os2->usBreakChar = 0;
1220 os2->usMaxContext = 0;
1221 os2->usLowerOpticalPointSize = 0;
1222 os2->usUpperOpticalPointSize = 0xFFFF;
1223
1224 if ( os2->version >= 0x0001 )
1225 {
1226 /* only version 1 tables */
1227 if ( FT_STREAM_READ_FIELDS( os2_fields_extra1, os2 ) )
1228 goto Exit;
1229
1230 if ( os2->version >= 0x0002 )
1231 {
1232 /* only version 2 tables */
1233 if ( FT_STREAM_READ_FIELDS( os2_fields_extra2, os2 ) )
1234 goto Exit;
1235
1236 if ( os2->version >= 0x0005 )
1237 {
1238 /* only version 5 tables */
1239 if ( FT_STREAM_READ_FIELDS( os2_fields_extra5, os2 ) )
1240 goto Exit;
1241 }
1242 }
1243 }
1244
1245 FT_TRACE3(( "sTypoAscender: %4d\n", os2->sTypoAscender ));
1246 FT_TRACE3(( "sTypoDescender: %4d\n", os2->sTypoDescender ));
1247 FT_TRACE3(( "usWinAscent: %4u\n", os2->usWinAscent ));
1248 FT_TRACE3(( "usWinDescent: %4u\n", os2->usWinDescent ));
1249 FT_TRACE3(( "fsSelection: 0x%2x\n", os2->fsSelection ));
1250
1251 Exit:
1252 return error;
1253 }
1254
1255
1256 /**************************************************************************
1257 *
1258 * @Function:
1259 * tt_face_load_postscript
1260 *
1261 * @Description:
1262 * Loads the Postscript table.
1263 *
1264 * @Input:
1265 * face ::
1266 * A handle to the target face object.
1267 *
1268 * stream ::
1269 * A handle to the input stream.
1270 *
1271 * @Return:
1272 * FreeType error code. 0 means success.
1273 */
1274 FT_LOCAL_DEF( FT_Error )
1275 tt_face_load_post( TT_Face face,
1276 FT_Stream stream )
1277 {
1278 FT_Error error;
1279 TT_Postscript* post = &face->postscript;
1280
1281 static const FT_Frame_Field post_fields[] =
1282 {
1283#undef FT_STRUCTURE
1284#define FT_STRUCTURE TT_Postscript
1285
1286 FT_FRAME_START( 32 ),
1287 FT_FRAME_LONG ( FormatType ),
1288 FT_FRAME_LONG ( italicAngle ),
1289 FT_FRAME_SHORT( underlinePosition ),
1290 FT_FRAME_SHORT( underlineThickness ),
1291 FT_FRAME_ULONG( isFixedPitch ),
1292 FT_FRAME_ULONG( minMemType42 ),
1293 FT_FRAME_ULONG( maxMemType42 ),
1294 FT_FRAME_ULONG( minMemType1 ),
1295 FT_FRAME_ULONG( maxMemType1 ),
1296 FT_FRAME_END
1297 };
1298
1299
1300 error = face->goto_table( face, TTAG_post, stream, 0 );
1301 if ( error )
1302 return error;
1303
1304 if ( FT_STREAM_READ_FIELDS( post_fields, post ) )
1305 return error;
1306
1307 /* we don't load the glyph names, we do that in another */
1308 /* module (ttpost). */
1309
1310 FT_TRACE3(( "FormatType: 0x%x\n", post->FormatType ));
1311 FT_TRACE3(( "isFixedPitch: %s\n", post->isFixedPitch
1312 ? " yes" : " no" ));
1313
1314 return FT_Err_Ok;
1315 }
1316
1317
1318 /**************************************************************************
1319 *
1320 * @Function:
1321 * tt_face_load_pclt
1322 *
1323 * @Description:
1324 * Loads the PCL 5 Table.
1325 *
1326 * @Input:
1327 * face ::
1328 * A handle to the target face object.
1329 *
1330 * stream ::
1331 * A handle to the input stream.
1332 *
1333 * @Return:
1334 * FreeType error code. 0 means success.
1335 */
1336 FT_LOCAL_DEF( FT_Error )
1337 tt_face_load_pclt( TT_Face face,
1338 FT_Stream stream )
1339 {
1340 static const FT_Frame_Field pclt_fields[] =
1341 {
1342#undef FT_STRUCTURE
1343#define FT_STRUCTURE TT_PCLT
1344
1345 FT_FRAME_START( 54 ),
1346 FT_FRAME_ULONG ( Version ),
1347 FT_FRAME_ULONG ( FontNumber ),
1348 FT_FRAME_USHORT( Pitch ),
1349 FT_FRAME_USHORT( xHeight ),
1350 FT_FRAME_USHORT( Style ),
1351 FT_FRAME_USHORT( TypeFamily ),
1352 FT_FRAME_USHORT( CapHeight ),
1353 FT_FRAME_USHORT( SymbolSet ),
1354 FT_FRAME_BYTES ( TypeFace, 16 ),
1355 FT_FRAME_BYTES ( CharacterComplement, 8 ),
1356 FT_FRAME_BYTES ( FileName, 6 ),
1357 FT_FRAME_CHAR ( StrokeWeight ),
1358 FT_FRAME_CHAR ( WidthType ),
1359 FT_FRAME_BYTE ( SerifStyle ),
1360 FT_FRAME_BYTE ( Reserved ),
1361 FT_FRAME_END
1362 };
1363
1364 FT_Error error;
1365 TT_PCLT* pclt = &face->pclt;
1366
1367
1368 /* optional table */
1369 error = face->goto_table( face, TTAG_PCLT, stream, 0 );
1370 if ( error )
1371 goto Exit;
1372
1373 if ( FT_STREAM_READ_FIELDS( pclt_fields, pclt ) )
1374 goto Exit;
1375
1376 Exit:
1377 return error;
1378 }
1379
1380
1381 /**************************************************************************
1382 *
1383 * @Function:
1384 * tt_face_load_gasp
1385 *
1386 * @Description:
1387 * Loads the `gasp' table into a face object.
1388 *
1389 * @Input:
1390 * face ::
1391 * A handle to the target face object.
1392 *
1393 * stream ::
1394 * The input stream.
1395 *
1396 * @Return:
1397 * FreeType error code. 0 means success.
1398 */
1399 FT_LOCAL_DEF( FT_Error )
1400 tt_face_load_gasp( TT_Face face,
1401 FT_Stream stream )
1402 {
1403 FT_Error error;
1404 FT_Memory memory = stream->memory;
1405
1406 FT_UInt j,num_ranges;
1407 TT_GaspRange gaspranges = NULL;
1408
1409
1410 /* the gasp table is optional */
1411 error = face->goto_table( face, TTAG_gasp, stream, 0 );
1412 if ( error )
1413 goto Exit;
1414
1415 if ( FT_FRAME_ENTER( 4L ) )
1416 goto Exit;
1417
1418 face->gasp.version = FT_GET_USHORT();
1419 face->gasp.numRanges = FT_GET_USHORT();
1420
1421 FT_FRAME_EXIT();
1422
1423 /* only support versions 0 and 1 of the table */
1424 if ( face->gasp.version >= 2 )
1425 {
1426 face->gasp.numRanges = 0;
1427 error = FT_THROW( Invalid_Table );
1428 goto Exit;
1429 }
1430
1431 num_ranges = face->gasp.numRanges;
1432 FT_TRACE3(( "numRanges: %u\n", num_ranges ));
1433
1434 if ( FT_QNEW_ARRAY( face->gasp.gaspRanges, num_ranges ) ||
1435 FT_FRAME_ENTER( num_ranges * 4L ) )
1436 goto Exit;
1437
1438 gaspranges = face->gasp.gaspRanges;
1439
1440 for ( j = 0; j < num_ranges; j++ )
1441 {
1442 gaspranges[j].maxPPEM = FT_GET_USHORT();
1443 gaspranges[j].gaspFlag = FT_GET_USHORT();
1444
1445 FT_TRACE3(( "gaspRange %d: rangeMaxPPEM %5d, rangeGaspBehavior 0x%x\n",
1446 j,
1447 gaspranges[j].maxPPEM,
1448 gaspranges[j].gaspFlag ));
1449 }
1450
1451 FT_FRAME_EXIT();
1452
1453 Exit:
1454 return error;
1455 }
1456
1457
1458/* END */
1459