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