예제 #1
0
  tt_face_load_gasp( TT_Face    face,
                     FT_Stream  stream )
  {
    FT_Error   error;
    FT_Memory  memory = stream->memory;

    FT_UInt        j,num_ranges;
    TT_GaspRange   gaspranges;


    /* the gasp table is optional */
    error = face->goto_table( face, TTAG_gasp, stream, 0 );
    if ( error )
      goto Exit;

    if ( FT_FRAME_ENTER( 4L ) )
      goto Exit;

    face->gasp.version   = FT_GET_USHORT();
    face->gasp.numRanges = FT_GET_USHORT();

    FT_FRAME_EXIT();

    /* only support versions 0 and 1 of the table */
    if ( face->gasp.version >= 2 )
    {
      face->gasp.numRanges = 0;
      error = SFNT_Err_Invalid_Table;
      goto Exit;
    }

    num_ranges = face->gasp.numRanges;
    FT_TRACE3(( "numRanges: %u\n", num_ranges ));

    if ( FT_QNEW_ARRAY( gaspranges, num_ranges ) ||
         FT_FRAME_ENTER( num_ranges * 4L )      )
      goto Exit;

    face->gasp.gaspRanges = gaspranges;

    for ( j = 0; j < num_ranges; j++ )
    {
      gaspranges[j].maxPPEM  = FT_GET_USHORT();
      gaspranges[j].gaspFlag = FT_GET_USHORT();

      FT_TRACE3(( "gaspRange %d: rangeMaxPPEM %5d, rangeGaspBehavior 0x%x\n",
                  j,
                  gaspranges[j].maxPPEM,
                  gaspranges[j].gaspFlag ));
    }

    FT_FRAME_EXIT();

  Exit:
    return error;
  }
예제 #2
0
파일: cffload.c 프로젝트: Ali-il/gamekit
  static FT_Error
  cff_charset_load( CFF_Charset  charset,
                    FT_UInt      num_glyphs,
                    FT_Stream    stream,
                    FT_ULong     base_offset,
                    FT_ULong     offset,
                    FT_Bool      invert )
  {
    FT_Memory  memory = stream->memory;
    FT_Error   error  = CFF_Err_Ok;
    FT_UShort  glyph_sid;


    /* If the the offset is greater than 2, we have to parse the */
    /* charset table.                                            */
    if ( offset > 2 )
    {
      FT_UInt  j;


      charset->offset = base_offset + offset;

      /* Get the format of the table. */
      if ( FT_STREAM_SEEK( charset->offset ) ||
           FT_READ_BYTE( charset->format )   )
        goto Exit;

      /* Allocate memory for sids. */
      if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) )
        goto Exit;

      /* assign the .notdef glyph */
      charset->sids[0] = 0;

      switch ( charset->format )
      {
      case 0:
        if ( num_glyphs > 0 )
        {
          if ( FT_FRAME_ENTER( ( num_glyphs - 1 ) * 2 ) )
            goto Exit;

          for ( j = 1; j < num_glyphs; j++ )
            charset->sids[j] = FT_GET_USHORT();

          FT_FRAME_EXIT();
        }
        break;

      case 1:
      case 2:
        {
          FT_UInt  nleft;
          FT_UInt  i;


          j = 1;

          while ( j < num_glyphs )
          {
            /* Read the first glyph sid of the range. */
            if ( FT_READ_USHORT( glyph_sid ) )
              goto Exit;

            /* Read the number of glyphs in the range.  */
            if ( charset->format == 2 )
            {
              if ( FT_READ_USHORT( nleft ) )
                goto Exit;
            }
            else
            {
              if ( FT_READ_BYTE( nleft ) )
                goto Exit;
            }

            /* Fill in the range of sids -- `nleft + 1' glyphs. */
            for ( i = 0; j < num_glyphs && i <= nleft; i++, j++, glyph_sid++ )
              charset->sids[j] = glyph_sid;
          }
        }
        break;

      default:
        FT_ERROR(( "cff_charset_load: invalid table format!\n" ));
        error = CFF_Err_Invalid_File_Format;
        goto Exit;
      }
    }
    else
    {
      /* Parse default tables corresponding to offset == 0, 1, or 2.  */
      /* CFF specification intimates the following:                   */
      /*                                                              */
      /* In order to use a predefined charset, the following must be  */
      /* true: The charset constructed for the glyphs in the font's   */
      /* charstrings dictionary must match the predefined charset in  */
      /* the first num_glyphs.                                        */

      charset->offset = offset;  /* record charset type */

      switch ( (FT_UInt)offset )
      {
      case 0:
        if ( num_glyphs > 229 )
        {
          FT_ERROR(( "cff_charset_load: implicit charset larger than\n"
                     "predefined charset (Adobe ISO-Latin)!\n" ));
          error = CFF_Err_Invalid_File_Format;
          goto Exit;
        }

        /* Allocate memory for sids. */
        if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) )
          goto Exit;

        /* Copy the predefined charset into the allocated memory. */
        FT_ARRAY_COPY( charset->sids, cff_isoadobe_charset, num_glyphs );

        break;

      case 1:
        if ( num_glyphs > 166 )
        {
          FT_ERROR(( "cff_charset_load: implicit charset larger than\n"
                     "predefined charset (Adobe Expert)!\n" ));
          error = CFF_Err_Invalid_File_Format;
          goto Exit;
        }

        /* Allocate memory for sids. */
        if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) )
          goto Exit;

        /* Copy the predefined charset into the allocated memory.     */
        FT_ARRAY_COPY( charset->sids, cff_expert_charset, num_glyphs );

        break;

      case 2:
        if ( num_glyphs > 87 )
        {
          FT_ERROR(( "cff_charset_load: implicit charset larger than\n"
                     "predefined charset (Adobe Expert Subset)!\n" ));
          error = CFF_Err_Invalid_File_Format;
          goto Exit;
        }

        /* Allocate memory for sids. */
        if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) )
          goto Exit;

        /* Copy the predefined charset into the allocated memory.     */
        FT_ARRAY_COPY( charset->sids, cff_expertsubset_charset, num_glyphs );

        break;

      default:
        error = CFF_Err_Invalid_File_Format;
        goto Exit;
      }
    }

    /* we have to invert the `sids' array for subsetted CID-keyed fonts */
    if ( invert )
      error = cff_charset_compute_cids( charset, num_glyphs, memory );

  Exit:
    /* Clean up if there was an error. */
    if ( error )
    {
      FT_FREE( charset->sids );
      FT_FREE( charset->cids );
      charset->format = 0;
      charset->offset = 0;
      charset->sids   = 0;
    }

    return error;
  }
예제 #3
0
파일: ttpost.c 프로젝트: hsmith/freetype
  static FT_Error
  load_format_20( TT_Face    face,
                  FT_Stream  stream,
                  FT_ULong   post_limit )
  {
    FT_Memory   memory = stream->memory;
    FT_Error    error;

    FT_Int      num_glyphs;
    FT_UShort   num_names;

    FT_UShort*  glyph_indices = NULL;
    FT_Char**   name_strings  = NULL;


    if ( FT_READ_USHORT( num_glyphs ) )
      goto Exit;

    /* UNDOCUMENTED!  The number of glyphs in this table can be smaller */
    /* than the value in the maxp table (cf. cyberbit.ttf).             */

    /* There already exist fonts which have more than 32768 glyph names */
    /* in this table, so the test for this threshold has been dropped.  */

    if ( num_glyphs > face->max_profile.numGlyphs )
    {
      error = FT_THROW( Invalid_File_Format );
      goto Exit;
    }

    /* load the indices */
    {
      FT_Int  n;


      if ( FT_NEW_ARRAY ( glyph_indices, num_glyphs ) ||
           FT_FRAME_ENTER( num_glyphs * 2L )          )
        goto Fail;

      for ( n = 0; n < num_glyphs; n++ )
        glyph_indices[n] = FT_GET_USHORT();

      FT_FRAME_EXIT();
    }

    /* compute number of names stored in table */
    {
      FT_Int  n;


      num_names = 0;

      for ( n = 0; n < num_glyphs; n++ )
      {
        FT_Int  idx;


        idx = glyph_indices[n];
        if ( idx >= 258 )
        {
          idx -= 257;
          if ( idx > num_names )
            num_names = (FT_UShort)idx;
        }
      }
    }

    /* now load the name strings */
    {
      FT_UShort  n;


      if ( FT_NEW_ARRAY( name_strings, num_names ) )
        goto Fail;

      for ( n = 0; n < num_names; n++ )
      {
        FT_UInt  len;


        if ( FT_STREAM_POS() >= post_limit )
          break;
        else
        {
          FT_TRACE6(( "load_format_20: %d byte left in post table\n",
                      post_limit - FT_STREAM_POS() ));

          if ( FT_READ_BYTE( len ) )
            goto Fail1;
        }

        if ( len > post_limit                   ||
             FT_STREAM_POS() > post_limit - len )
        {
          FT_Int  d = (FT_Int)post_limit - (FT_Int)FT_STREAM_POS();


          FT_ERROR(( "load_format_20:"
                     " exceeding string length (%d),"
                     " truncating at end of post table (%d byte left)\n",
                     len, d ));
          len = (FT_UInt)FT_MAX( 0, d );
        }

        if ( FT_NEW_ARRAY( name_strings[n], len + 1 ) ||
             FT_STREAM_READ( name_strings[n], len   ) )
          goto Fail1;

        name_strings[n][len] = '\0';
      }

      if ( n < num_names )
      {
        FT_ERROR(( "load_format_20:"
                   " all entries in post table are already parsed,"
                   " using NULL names for gid %d - %d\n",
                    n, num_names - 1 ));
        for ( ; n < num_names; n++ )
          if ( FT_NEW_ARRAY( name_strings[n], 1 ) )
            goto Fail1;
          else
            name_strings[n][0] = '\0';
      }
    }

    /* all right, set table fields and exit successfully */
    {
      TT_Post_20  table = &face->postscript_names.names.format_20;


      table->num_glyphs    = (FT_UShort)num_glyphs;
      table->num_names     = (FT_UShort)num_names;
      table->glyph_indices = glyph_indices;
      table->glyph_names   = name_strings;
    }
    return FT_Err_Ok;

  Fail1:
    {
      FT_UShort  n;


      for ( n = 0; n < num_names; n++ )
        FT_FREE( name_strings[n] );
    }

  Fail:
    FT_FREE( name_strings );
    FT_FREE( glyph_indices );

  Exit:
    return error;
  }
예제 #4
0
  tt_face_load_hmtx( TT_Face    face,
                     FT_Stream  stream,
                     FT_Bool    vertical )
  {
    FT_Error   error;
    FT_Memory  memory = stream->memory;

    FT_ULong   table_len;
    FT_Long    num_shorts, num_longs, num_shorts_checked;

    TT_LongMetrics *   longs;
    TT_ShortMetrics**  shorts;


    if ( vertical )
    {
      error = face->goto_table( face, TTAG_vmtx, stream, &table_len );
      if ( error )
        goto Fail;

      num_longs = face->vertical.number_Of_VMetrics;
      if ( (FT_ULong)num_longs > table_len / 4 )
        num_longs = (FT_Long)(table_len / 4);

      face->vertical.number_Of_VMetrics = 0;

      longs  = (TT_LongMetrics *)&face->vertical.long_metrics;
      shorts = (TT_ShortMetrics**)&face->vertical.short_metrics;
    }
    else
    {
      error = face->goto_table( face, TTAG_hmtx, stream, &table_len );
      if ( error )
        goto Fail;

      num_longs = face->horizontal.number_Of_HMetrics;
      if ( (FT_ULong)num_longs > table_len / 4 )
        num_longs = (FT_Long)(table_len / 4);

      face->horizontal.number_Of_HMetrics = 0;

      longs  = (TT_LongMetrics *)&face->horizontal.long_metrics;
      shorts = (TT_ShortMetrics**)&face->horizontal.short_metrics;
    }

    /* never trust derived values */

    num_shorts         = face->max_profile.numGlyphs - num_longs;
    num_shorts_checked = ( table_len - num_longs * 4L ) / 2;

    if ( num_shorts < 0 )
    {
      FT_ERROR(( "%cmtx has more metrics than glyphs.\n" ));

      /* Adobe simply ignores this problem.  So we shall do the same. */
#if 0
      error = vertical ? SFNT_Err_Invalid_Vert_Metrics
                       : SFNT_Err_Invalid_Horiz_Metrics;
      goto Exit;
#else
      num_shorts = 0;
#endif
    }

    if ( FT_QNEW_ARRAY( *longs,  num_longs  ) ||
         FT_QNEW_ARRAY( *shorts, num_shorts ) )
      goto Fail;

    if ( FT_FRAME_ENTER( table_len ) )
      goto Fail;

    {
      TT_LongMetrics  cur   = *longs;
      TT_LongMetrics  limit = cur + num_longs;


      for ( ; cur < limit; cur++ )
      {
        cur->advance = FT_GET_USHORT();
        cur->bearing = FT_GET_SHORT();
      }
    }

    /* do we have an inconsistent number of metric values? */
    {
      TT_ShortMetrics*  cur   = *shorts;
      TT_ShortMetrics*  limit = cur +
                                FT_MIN( num_shorts, num_shorts_checked );


      for ( ; cur < limit; cur++ )
        *cur = FT_GET_SHORT();

      /* We fill up the missing left side bearings with the     */
      /* last valid value.  Since this will occur for buggy CJK */
      /* fonts usually only, nothing serious will happen.       */
      if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
      {
        FT_Short  val = (*shorts)[num_shorts_checked - 1];


        limit = *shorts + num_shorts;
        for ( ; cur < limit; cur++ )
          *cur = val;
      }
    }

    FT_FRAME_EXIT();

    if ( vertical )
      face->vertical.number_Of_VMetrics = (FT_UShort)num_longs;
    else
      face->horizontal.number_Of_HMetrics = (FT_UShort)num_longs;

  Fail:
    return error;
  }
예제 #5
0
파일: ttpost.c 프로젝트: 1tgr/mobius
  static FT_Error
  load_format_20( TT_Face    face,
                  FT_Stream  stream )
  {
    FT_Memory   memory = stream->memory;
    FT_Error    error;

    FT_Int      num_glyphs;
    FT_UShort   num_names;

    FT_UShort*  glyph_indices = 0;
    FT_Char**   name_strings  = 0;


    if ( FT_READ_USHORT( num_glyphs ) )
      goto Exit;

    /* UNDOCUMENTED!  The number of glyphs in this table can be smaller */
    /* than the value in the maxp table (cf. cyberbit.ttf).             */

    /* There already exist fonts which have more than 32768 glyph names */
    /* in this table, so the test for this threshold has been dropped.  */

    if ( num_glyphs > face->root.num_glyphs )
    {
      error = SFNT_Err_Invalid_File_Format;
      goto Exit;
    }

    /* load the indices */
    {
      FT_Int  n;


      if ( FT_NEW_ARRAY ( glyph_indices, num_glyphs ) ||
           FT_FRAME_ENTER( num_glyphs * 2L )          )
        goto Fail;

      for ( n = 0; n < num_glyphs; n++ )
        glyph_indices[n] = FT_GET_USHORT();

      FT_FRAME_EXIT();
    }

    /* compute number of names stored in table */
    {
      FT_Int  n;


      num_names = 0;

      for ( n = 0; n < num_glyphs; n++ )
      {
        FT_Int  idx;


        idx = glyph_indices[n];
        if ( idx >= 258 )
        {
          idx -= 257;
          if ( idx > num_names )
            num_names = (FT_UShort)idx;
        }
      }
    }

    /* now load the name strings */
    {
      FT_UShort  n;


      if ( FT_NEW_ARRAY( name_strings, num_names ) )
        goto Fail;

      for ( n = 0; n < num_names; n++ )
      {
        FT_UInt  len;


        if ( FT_READ_BYTE  ( len )                    ||
             FT_NEW_ARRAY( name_strings[n], len + 1 ) ||
             FT_STREAM_READ  ( name_strings[n], len ) )
          goto Fail1;

        name_strings[n][len] = '\0';
      }
    }

    /* all right, set table fields and exit successfuly */
    {
      TT_Post_20  table = &face->postscript_names.names.format_20;


      table->num_glyphs    = (FT_UShort)num_glyphs;
      table->num_names     = (FT_UShort)num_names;
      table->glyph_indices = glyph_indices;
      table->glyph_names   = name_strings;
    }
    return SFNT_Err_Ok;

  Fail1:
    {
      FT_UShort  n;


      for ( n = 0; n < num_names; n++ )
        FT_FREE( name_strings[n] );
    }

  Fail:
    FT_FREE( name_strings );
    FT_FREE( glyph_indices );

  Exit:
    return error;
  }
예제 #6
0
  TT_CharMap_Load( TT_Face       face,
                   TT_CMapTable  cmap,
                   FT_Stream     stream )
  {
    FT_Error     error;
    FT_Memory    memory;
    FT_UShort    num_SH, num_Seg, i;
    FT_ULong     j, n;

    FT_UShort    u, l;

    TT_CMap0     cmap0;
    TT_CMap2     cmap2;
    TT_CMap4     cmap4;
    TT_CMap6     cmap6;
    TT_CMap8_12  cmap8_12;
    TT_CMap10    cmap10;

    TT_CMap2SubHeader  cmap2sub;
    TT_CMap4Segment    segments;
    TT_CMapGroup       groups;


    if ( cmap->loaded )
      return SFNT_Err_Ok;

    memory = stream->memory;

    if ( FT_STREAM_SEEK( cmap->offset ) )
      return error;

    switch ( cmap->format )
    {
    case 0:
      cmap0 = &cmap->c.cmap0;

      if ( FT_READ_USHORT( cmap0->language )           ||
           FT_ALLOC( cmap0->glyphIdArray, 256L )       ||
           FT_STREAM_READ( cmap0->glyphIdArray, 256L ) )
        goto Fail;

      cmap->get_index     = code_to_index0;
      cmap->get_next_char = code_to_next0;
      break;

    case 2:
      num_SH = 0;
      cmap2  = &cmap->c.cmap2;

      /* allocate subheader keys */

      if ( FT_NEW_ARRAY( cmap2->subHeaderKeys, 256 ) ||
           FT_FRAME_ENTER( 2L + 512L )               )
        goto Fail;

      cmap2->language = FT_GET_USHORT();

      for ( i = 0; i < 256; i++ )
      {
        u = (FT_UShort)( FT_GET_USHORT() / 8 );
        cmap2->subHeaderKeys[i] = u;

        if ( num_SH < u )
          num_SH = u;
      }

      FT_FRAME_EXIT();

      /* load subheaders */

      cmap2->numGlyphId = l = (FT_UShort)(
        ( ( cmap->length - 2L * ( 256 + 3 ) - num_SH * 8L ) & 0xFFFFU ) / 2 );

      if ( FT_NEW_ARRAY( cmap2->subHeaders, num_SH + 1 ) ||
           FT_FRAME_ENTER( ( num_SH + 1 ) * 8L )         )
      {
        FT_FREE( cmap2->subHeaderKeys );
        goto Fail;
      }

      cmap2sub = cmap2->subHeaders;

      for ( i = 0; i <= num_SH; i++ )
      {
        cmap2sub->firstCode     = FT_GET_USHORT();
        cmap2sub->entryCount    = FT_GET_USHORT();
        cmap2sub->idDelta       = FT_GET_SHORT();
        /* we apply the location offset immediately */
        cmap2sub->idRangeOffset = (FT_UShort)(
          FT_GET_USHORT() - ( num_SH - i ) * 8 - 2 );

        cmap2sub++;
      }

      FT_FRAME_EXIT();

      /* load glyph IDs */

      if ( FT_NEW_ARRAY( cmap2->glyphIdArray, l ) ||
           FT_FRAME_ENTER( l * 2L )               )
      {
        FT_FREE( cmap2->subHeaders );
        FT_FREE( cmap2->subHeaderKeys );
        goto Fail;
      }

      for ( i = 0; i < l; i++ )
        cmap2->glyphIdArray[i] = FT_GET_USHORT();

      FT_FRAME_EXIT();

      cmap->get_index = code_to_index2;
      cmap->get_next_char = code_to_next2;
      break;

    case 4:
      cmap4 = &cmap->c.cmap4;

      /* load header */

      if ( FT_FRAME_ENTER( 10L ) )
        goto Fail;

      cmap4->language      = FT_GET_USHORT();
      cmap4->segCountX2    = FT_GET_USHORT();
      cmap4->searchRange   = FT_GET_USHORT();
      cmap4->entrySelector = FT_GET_USHORT();
      cmap4->rangeShift    = FT_GET_USHORT();

      num_Seg = (FT_UShort)( cmap4->segCountX2 / 2 );

      FT_FRAME_EXIT();

      /* load segments */

      if ( FT_NEW_ARRAY( cmap4->segments, num_Seg )   ||
           FT_FRAME_ENTER( ( num_Seg * 4 + 1 ) * 2L ) )
        goto Fail;

      segments = cmap4->segments;

      for ( i = 0; i < num_Seg; i++ )
        segments[i].endCount = FT_GET_USHORT();

      (void)FT_GET_USHORT();

      for ( i = 0; i < num_Seg; i++ )
        segments[i].startCount = FT_GET_USHORT();

      for ( i = 0; i < num_Seg; i++ )
        segments[i].idDelta = FT_GET_SHORT();

      for ( i = 0; i < num_Seg; i++ )
        segments[i].idRangeOffset = FT_GET_USHORT();

      FT_FRAME_EXIT();

      cmap4->numGlyphId = l = (FT_UShort)(
        ( ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xFFFFU ) / 2 );

      /* load IDs */

      if ( FT_NEW_ARRAY( cmap4->glyphIdArray, l ) ||
           FT_FRAME_ENTER( l * 2L )               )
      {
        FT_FREE( cmap4->segments );
        goto Fail;
      }

      for ( i = 0; i < l; i++ )
        cmap4->glyphIdArray[i] = FT_GET_USHORT();

      FT_FRAME_EXIT();

      cmap4->last_segment = cmap4->segments;

      cmap->get_index     = code_to_index4;
      cmap->get_next_char = code_to_next4;
      break;

    case 6:
      cmap6 = &cmap->c.cmap6;

      if ( FT_FRAME_ENTER( 6L ) )
        goto Fail;

      cmap6->language   = FT_GET_USHORT();
      cmap6->firstCode  = FT_GET_USHORT();
      cmap6->entryCount = FT_GET_USHORT();

      FT_FRAME_EXIT();

      l = cmap6->entryCount;

      if ( FT_NEW_ARRAY( cmap6->glyphIdArray, l ) ||
           FT_FRAME_ENTER( l * 2L )               )
        goto Fail;

      for ( i = 0; i < l; i++ )
        cmap6->glyphIdArray[i] = FT_GET_USHORT();

      FT_FRAME_EXIT();
      cmap->get_index     = code_to_index6;
      cmap->get_next_char = code_to_next6;
      break;

    case 8:
    case 12:
      cmap8_12 = &cmap->c.cmap8_12;

      if ( FT_FRAME_ENTER( 8L ) )
        goto Fail;

      cmap->length       = FT_GET_ULONG();
      cmap8_12->language = FT_GET_ULONG();

      FT_FRAME_EXIT();

      if ( cmap->format == 8 )
        if ( FT_STREAM_SKIP( 8192L ) )
          goto Fail;

      if ( FT_READ_ULONG( cmap8_12->nGroups ) )
        goto Fail;

      n = cmap8_12->nGroups;

      if ( FT_NEW_ARRAY( cmap8_12->groups, n ) ||
           FT_FRAME_ENTER( n * 3 * 4L )        )
        goto Fail;

      groups = cmap8_12->groups;

      for ( j = 0; j < n; j++ )
      {
        groups[j].startCharCode = FT_GET_ULONG();
        groups[j].endCharCode   = FT_GET_ULONG();
        groups[j].startGlyphID  = FT_GET_ULONG();
      }

      FT_FRAME_EXIT();

      cmap8_12->last_group = cmap8_12->groups;

      cmap->get_index     = code_to_index8_12;
      cmap->get_next_char = code_to_next8_12;
      break;

    case 10:
      cmap10 = &cmap->c.cmap10;

      if ( FT_FRAME_ENTER( 16L ) )
        goto Fail;

      cmap->length          = FT_GET_ULONG();
      cmap10->language      = FT_GET_ULONG();
      cmap10->startCharCode = FT_GET_ULONG();
      cmap10->numChars      = FT_GET_ULONG();

      FT_FRAME_EXIT();

      n = cmap10->numChars;

      if ( FT_NEW_ARRAY( cmap10->glyphs, n ) ||
           FT_FRAME_ENTER( n * 2L )          )
        goto Fail;

      for ( j = 0; j < n; j++ )
        cmap10->glyphs[j] = FT_GET_USHORT();

      FT_FRAME_EXIT();
      cmap->get_index     = code_to_index10;
      cmap->get_next_char = code_to_next10;
      break;

    default:   /* corrupt character mapping table */
      return SFNT_Err_Invalid_CharMap_Format;

    }

    return SFNT_Err_Ok;

  Fail:
    TT_CharMap_Free( face, cmap );
    return error;
  }