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