misc/libfreetype/src/cid/cidload.c
changeset 9372 915436ff64ab
parent 9371 f3840de881bd
child 9373 b769a8e38cbd
equal deleted inserted replaced
9371:f3840de881bd 9372:915436ff64ab
     1 /***************************************************************************/
       
     2 /*                                                                         */
       
     3 /*  cidload.c                                                              */
       
     4 /*                                                                         */
       
     5 /*    CID-keyed Type1 font loader (body).                                  */
       
     6 /*                                                                         */
       
     7 /*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2009 by             */
       
     8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
       
     9 /*                                                                         */
       
    10 /*  This file is part of the FreeType project, and may only be used,       */
       
    11 /*  modified, and distributed under the terms of the FreeType project      */
       
    12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
       
    13 /*  this file you indicate that you have read the license and              */
       
    14 /*  understand and accept it fully.                                        */
       
    15 /*                                                                         */
       
    16 /***************************************************************************/
       
    17 
       
    18 
       
    19 #include <ft2build.h>
       
    20 #include FT_INTERNAL_DEBUG_H
       
    21 #include FT_CONFIG_CONFIG_H
       
    22 #include FT_MULTIPLE_MASTERS_H
       
    23 #include FT_INTERNAL_TYPE1_TYPES_H
       
    24 
       
    25 #include "cidload.h"
       
    26 
       
    27 #include "ciderrs.h"
       
    28 
       
    29 
       
    30   /*************************************************************************/
       
    31   /*                                                                       */
       
    32   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
       
    33   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
       
    34   /* messages during execution.                                            */
       
    35   /*                                                                       */
       
    36 #undef  FT_COMPONENT
       
    37 #define FT_COMPONENT  trace_cidload
       
    38 
       
    39 
       
    40   /* read a single offset */
       
    41   FT_LOCAL_DEF( FT_Long )
       
    42   cid_get_offset( FT_Byte*  *start,
       
    43                   FT_Byte    offsize )
       
    44   {
       
    45     FT_Long   result;
       
    46     FT_Byte*  p = *start;
       
    47 
       
    48 
       
    49     for ( result = 0; offsize > 0; offsize-- )
       
    50     {
       
    51       result <<= 8;
       
    52       result  |= *p++;
       
    53     }
       
    54 
       
    55     *start = p;
       
    56     return result;
       
    57   }
       
    58 
       
    59 
       
    60   /*************************************************************************/
       
    61   /*************************************************************************/
       
    62   /*****                                                               *****/
       
    63   /*****                    TYPE 1 SYMBOL PARSING                      *****/
       
    64   /*****                                                               *****/
       
    65   /*************************************************************************/
       
    66   /*************************************************************************/
       
    67 
       
    68 
       
    69   static FT_Error
       
    70   cid_load_keyword( CID_Face        face,
       
    71                     CID_Loader*     loader,
       
    72                     const T1_Field  keyword )
       
    73   {
       
    74     FT_Error      error;
       
    75     CID_Parser*   parser = &loader->parser;
       
    76     FT_Byte*      object;
       
    77     void*         dummy_object;
       
    78     CID_FaceInfo  cid = &face->cid;
       
    79 
       
    80 
       
    81     /* if the keyword has a dedicated callback, call it */
       
    82     if ( keyword->type == T1_FIELD_TYPE_CALLBACK )
       
    83     {
       
    84       keyword->reader( (FT_Face)face, parser );
       
    85       error = parser->root.error;
       
    86       goto Exit;
       
    87     }
       
    88 
       
    89     /* we must now compute the address of our target object */
       
    90     switch ( keyword->location )
       
    91     {
       
    92     case T1_FIELD_LOCATION_CID_INFO:
       
    93       object = (FT_Byte*)cid;
       
    94       break;
       
    95 
       
    96     case T1_FIELD_LOCATION_FONT_INFO:
       
    97       object = (FT_Byte*)&cid->font_info;
       
    98       break;
       
    99 
       
   100     case T1_FIELD_LOCATION_FONT_EXTRA:
       
   101       object = (FT_Byte*)&face->font_extra;
       
   102       break;
       
   103 
       
   104     case T1_FIELD_LOCATION_BBOX:
       
   105       object = (FT_Byte*)&cid->font_bbox;
       
   106       break;
       
   107 
       
   108     default:
       
   109       {
       
   110         CID_FaceDict  dict;
       
   111 
       
   112 
       
   113         if ( parser->num_dict < 0 )
       
   114         {
       
   115           FT_ERROR(( "cid_load_keyword: invalid use of `%s'\n",
       
   116                      keyword->ident ));
       
   117           error = CID_Err_Syntax_Error;
       
   118           goto Exit;
       
   119         }
       
   120 
       
   121         dict = cid->font_dicts + parser->num_dict;
       
   122         switch ( keyword->location )
       
   123         {
       
   124         case T1_FIELD_LOCATION_PRIVATE:
       
   125           object = (FT_Byte*)&dict->private_dict;
       
   126           break;
       
   127 
       
   128         default:
       
   129           object = (FT_Byte*)dict;
       
   130         }
       
   131       }
       
   132     }
       
   133 
       
   134     dummy_object = object;
       
   135 
       
   136     /* now, load the keyword data in the object's field(s) */
       
   137     if ( keyword->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
       
   138          keyword->type == T1_FIELD_TYPE_FIXED_ARRAY   )
       
   139       error = cid_parser_load_field_table( &loader->parser, keyword,
       
   140                                            &dummy_object );
       
   141     else
       
   142       error = cid_parser_load_field( &loader->parser,
       
   143                                      keyword, &dummy_object );
       
   144   Exit:
       
   145     return error;
       
   146   }
       
   147 
       
   148 
       
   149   FT_CALLBACK_DEF( FT_Error )
       
   150   parse_font_matrix( CID_Face     face,
       
   151                      CID_Parser*  parser )
       
   152   {
       
   153     FT_Matrix*    matrix;
       
   154     FT_Vector*    offset;
       
   155     CID_FaceDict  dict;
       
   156     FT_Face       root = (FT_Face)&face->root;
       
   157     FT_Fixed      temp[6];
       
   158     FT_Fixed      temp_scale;
       
   159 
       
   160 
       
   161     if ( parser->num_dict >= 0 )
       
   162     {
       
   163       dict   = face->cid.font_dicts + parser->num_dict;
       
   164       matrix = &dict->font_matrix;
       
   165       offset = &dict->font_offset;
       
   166 
       
   167       (void)cid_parser_to_fixed_array( parser, 6, temp, 3 );
       
   168 
       
   169       temp_scale = FT_ABS( temp[3] );
       
   170 
       
   171       /* Set units per EM based on FontMatrix values.  We set the value to */
       
   172       /* `1000/temp_scale', because temp_scale was already multiplied by   */
       
   173       /* 1000 (in `t1_tofixed', from psobjs.c).                            */
       
   174       root->units_per_EM = (FT_UShort)( FT_DivFix( 0x10000L,
       
   175                                         FT_DivFix( temp_scale, 1000 ) ) );
       
   176 
       
   177       /* we need to scale the values by 1.0/temp[3] */
       
   178       if ( temp_scale != 0x10000L )
       
   179       {
       
   180         temp[0] = FT_DivFix( temp[0], temp_scale );
       
   181         temp[1] = FT_DivFix( temp[1], temp_scale );
       
   182         temp[2] = FT_DivFix( temp[2], temp_scale );
       
   183         temp[4] = FT_DivFix( temp[4], temp_scale );
       
   184         temp[5] = FT_DivFix( temp[5], temp_scale );
       
   185         temp[3] = 0x10000L;
       
   186       }
       
   187 
       
   188       matrix->xx = temp[0];
       
   189       matrix->yx = temp[1];
       
   190       matrix->xy = temp[2];
       
   191       matrix->yy = temp[3];
       
   192 
       
   193       /* note that the font offsets are expressed in integer font units */
       
   194       offset->x  = temp[4] >> 16;
       
   195       offset->y  = temp[5] >> 16;
       
   196     }
       
   197 
       
   198     return CID_Err_Ok;      /* this is a callback function; */
       
   199                             /* we must return an error code */
       
   200   }
       
   201 
       
   202 
       
   203   FT_CALLBACK_DEF( FT_Error )
       
   204   parse_fd_array( CID_Face     face,
       
   205                   CID_Parser*  parser )
       
   206   {
       
   207     CID_FaceInfo  cid    = &face->cid;
       
   208     FT_Memory     memory = face->root.memory;
       
   209     FT_Error      error  = CID_Err_Ok;
       
   210     FT_Long       num_dicts;
       
   211 
       
   212 
       
   213     num_dicts = cid_parser_to_int( parser );
       
   214 
       
   215     if ( !cid->font_dicts )
       
   216     {
       
   217       FT_Int  n;
       
   218 
       
   219 
       
   220       if ( FT_NEW_ARRAY( cid->font_dicts, num_dicts ) )
       
   221         goto Exit;
       
   222 
       
   223       cid->num_dicts = (FT_UInt)num_dicts;
       
   224 
       
   225       /* don't forget to set a few defaults */
       
   226       for ( n = 0; n < cid->num_dicts; n++ )
       
   227       {
       
   228         CID_FaceDict  dict = cid->font_dicts + n;
       
   229 
       
   230 
       
   231         /* default value for lenIV */
       
   232         dict->private_dict.lenIV = 4;
       
   233       }
       
   234     }
       
   235 
       
   236   Exit:
       
   237     return error;
       
   238   }
       
   239 
       
   240 
       
   241   /* by mistake, `expansion_factor' appears both in PS_PrivateRec */
       
   242   /* and CID_FaceDictRec (both are public header files and can't  */
       
   243   /* changed); we simply copy the value                           */
       
   244 
       
   245   FT_CALLBACK_DEF( FT_Error )
       
   246   parse_expansion_factor( CID_Face     face,
       
   247                           CID_Parser*  parser )
       
   248   {
       
   249     CID_FaceDict  dict;
       
   250 
       
   251 
       
   252     if ( parser->num_dict >= 0 )
       
   253     {
       
   254       dict = face->cid.font_dicts + parser->num_dict;
       
   255 
       
   256       dict->expansion_factor              = cid_parser_to_fixed( parser, 0 );
       
   257       dict->private_dict.expansion_factor = dict->expansion_factor;
       
   258     }
       
   259 
       
   260     return CID_Err_Ok;
       
   261   }
       
   262 
       
   263 
       
   264   static
       
   265   const T1_FieldRec  cid_field_records[] =
       
   266   {
       
   267 
       
   268 #include "cidtoken.h"
       
   269 
       
   270     T1_FIELD_CALLBACK( "FDArray",         parse_fd_array, 0 )
       
   271     T1_FIELD_CALLBACK( "FontMatrix",      parse_font_matrix, 0 )
       
   272     T1_FIELD_CALLBACK( "ExpansionFactor", parse_expansion_factor, 0 )
       
   273 
       
   274     { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 }
       
   275   };
       
   276 
       
   277 
       
   278   static FT_Error
       
   279   cid_parse_dict( CID_Face     face,
       
   280                   CID_Loader*  loader,
       
   281                   FT_Byte*     base,
       
   282                   FT_Long      size )
       
   283   {
       
   284     CID_Parser*  parser = &loader->parser;
       
   285 
       
   286 
       
   287     parser->root.cursor = base;
       
   288     parser->root.limit  = base + size;
       
   289     parser->root.error  = CID_Err_Ok;
       
   290 
       
   291     {
       
   292       FT_Byte*  cur   = base;
       
   293       FT_Byte*  limit = cur + size;
       
   294 
       
   295 
       
   296       for (;;)
       
   297       {
       
   298         FT_Byte*  newlimit;
       
   299 
       
   300 
       
   301         parser->root.cursor = cur;
       
   302         cid_parser_skip_spaces( parser );
       
   303 
       
   304         if ( parser->root.cursor >= limit )
       
   305           newlimit = limit - 1 - 17;
       
   306         else
       
   307           newlimit = parser->root.cursor - 17;
       
   308 
       
   309         /* look for `%ADOBeginFontDict' */
       
   310         for ( ; cur < newlimit; cur++ )
       
   311         {
       
   312           if ( *cur == '%'                                            &&
       
   313                ft_strncmp( (char*)cur, "%ADOBeginFontDict", 17 ) == 0 )
       
   314           {
       
   315             /* if /FDArray was found, then cid->num_dicts is > 0, and */
       
   316             /* we can start increasing parser->num_dict               */
       
   317             if ( face->cid.num_dicts > 0 )
       
   318               parser->num_dict++;
       
   319           }
       
   320         }
       
   321 
       
   322         cur = parser->root.cursor;
       
   323         /* no error can occur in cid_parser_skip_spaces */
       
   324         if ( cur >= limit )
       
   325           break;
       
   326 
       
   327         cid_parser_skip_PS_token( parser );
       
   328         if ( parser->root.cursor >= limit || parser->root.error )
       
   329           break;
       
   330 
       
   331         /* look for immediates */
       
   332         if ( *cur == '/' && cur + 2 < limit )
       
   333         {
       
   334           FT_PtrDist  len;
       
   335 
       
   336 
       
   337           cur++;
       
   338           len = parser->root.cursor - cur;
       
   339 
       
   340           if ( len > 0 && len < 22 )
       
   341           {
       
   342             /* now compare the immediate name to the keyword table */
       
   343             T1_Field  keyword = (T1_Field)cid_field_records;
       
   344 
       
   345 
       
   346             for (;;)
       
   347             {
       
   348               FT_Byte*  name;
       
   349 
       
   350 
       
   351               name = (FT_Byte*)keyword->ident;
       
   352               if ( !name )
       
   353                 break;
       
   354 
       
   355               if ( cur[0] == name[0]                                 &&
       
   356                    len == (FT_PtrDist)ft_strlen( (const char*)name ) )
       
   357               {
       
   358                 FT_PtrDist  n;
       
   359 
       
   360 
       
   361                 for ( n = 1; n < len; n++ )
       
   362                   if ( cur[n] != name[n] )
       
   363                     break;
       
   364 
       
   365                 if ( n >= len )
       
   366                 {
       
   367                   /* we found it - run the parsing callback */
       
   368                   parser->root.error = cid_load_keyword( face,
       
   369                                                          loader,
       
   370                                                          keyword );
       
   371                   if ( parser->root.error )
       
   372                     return parser->root.error;
       
   373                   break;
       
   374                 }
       
   375               }
       
   376               keyword++;
       
   377             }
       
   378           }
       
   379         }
       
   380 
       
   381         cur = parser->root.cursor;
       
   382       }
       
   383     }
       
   384     return parser->root.error;
       
   385   }
       
   386 
       
   387 
       
   388   /* read the subrmap and the subrs of each font dict */
       
   389   static FT_Error
       
   390   cid_read_subrs( CID_Face  face )
       
   391   {
       
   392     CID_FaceInfo   cid    = &face->cid;
       
   393     FT_Memory      memory = face->root.memory;
       
   394     FT_Stream      stream = face->cid_stream;
       
   395     FT_Error       error;
       
   396     FT_Int         n;
       
   397     CID_Subrs      subr;
       
   398     FT_UInt        max_offsets = 0;
       
   399     FT_ULong*      offsets = 0;
       
   400     PSAux_Service  psaux = (PSAux_Service)face->psaux;
       
   401 
       
   402 
       
   403     if ( FT_NEW_ARRAY( face->subrs, cid->num_dicts ) )
       
   404       goto Exit;
       
   405 
       
   406     subr = face->subrs;
       
   407     for ( n = 0; n < cid->num_dicts; n++, subr++ )
       
   408     {
       
   409       CID_FaceDict  dict  = cid->font_dicts + n;
       
   410       FT_Int        lenIV = dict->private_dict.lenIV;
       
   411       FT_UInt       count, num_subrs = dict->num_subrs;
       
   412       FT_ULong      data_len;
       
   413       FT_Byte*      p;
       
   414 
       
   415 
       
   416       /* reallocate offsets array if needed */
       
   417       if ( num_subrs + 1 > max_offsets )
       
   418       {
       
   419         FT_UInt  new_max = FT_PAD_CEIL( num_subrs + 1, 4 );
       
   420 
       
   421 
       
   422         if ( FT_RENEW_ARRAY( offsets, max_offsets, new_max ) )
       
   423           goto Fail;
       
   424 
       
   425         max_offsets = new_max;
       
   426       }
       
   427 
       
   428       /* read the subrmap's offsets */
       
   429       if ( FT_STREAM_SEEK( cid->data_offset + dict->subrmap_offset ) ||
       
   430            FT_FRAME_ENTER( ( num_subrs + 1 ) * dict->sd_bytes )      )
       
   431         goto Fail;
       
   432 
       
   433       p = (FT_Byte*)stream->cursor;
       
   434       for ( count = 0; count <= num_subrs; count++ )
       
   435         offsets[count] = cid_get_offset( &p, (FT_Byte)dict->sd_bytes );
       
   436 
       
   437       FT_FRAME_EXIT();
       
   438 
       
   439       /* now, compute the size of subrs charstrings, */
       
   440       /* allocate, and read them                     */
       
   441       data_len = offsets[num_subrs] - offsets[0];
       
   442 
       
   443       if ( FT_NEW_ARRAY( subr->code, num_subrs + 1 ) ||
       
   444                FT_ALLOC( subr->code[0], data_len )   )
       
   445         goto Fail;
       
   446 
       
   447       if ( FT_STREAM_SEEK( cid->data_offset + offsets[0] ) ||
       
   448            FT_STREAM_READ( subr->code[0], data_len )  )
       
   449         goto Fail;
       
   450 
       
   451       /* set up pointers */
       
   452       for ( count = 1; count <= num_subrs; count++ )
       
   453       {
       
   454         FT_ULong  len;
       
   455 
       
   456 
       
   457         len               = offsets[count] - offsets[count - 1];
       
   458         subr->code[count] = subr->code[count - 1] + len;
       
   459       }
       
   460 
       
   461       /* decrypt subroutines, but only if lenIV >= 0 */
       
   462       if ( lenIV >= 0 )
       
   463       {
       
   464         for ( count = 0; count < num_subrs; count++ )
       
   465         {
       
   466           FT_ULong  len;
       
   467 
       
   468 
       
   469           len = offsets[count + 1] - offsets[count];
       
   470           psaux->t1_decrypt( subr->code[count], len, 4330 );
       
   471         }
       
   472       }
       
   473 
       
   474       subr->num_subrs = num_subrs;
       
   475     }
       
   476 
       
   477   Exit:
       
   478     FT_FREE( offsets );
       
   479     return error;
       
   480 
       
   481   Fail:
       
   482     if ( face->subrs )
       
   483     {
       
   484       for ( n = 0; n < cid->num_dicts; n++ )
       
   485       {
       
   486         if ( face->subrs[n].code )
       
   487           FT_FREE( face->subrs[n].code[0] );
       
   488 
       
   489         FT_FREE( face->subrs[n].code );
       
   490       }
       
   491       FT_FREE( face->subrs );
       
   492     }
       
   493     goto Exit;
       
   494   }
       
   495 
       
   496 
       
   497   static void
       
   498   t1_init_loader( CID_Loader*  loader,
       
   499                   CID_Face     face )
       
   500   {
       
   501     FT_UNUSED( face );
       
   502 
       
   503     FT_MEM_ZERO( loader, sizeof ( *loader ) );
       
   504   }
       
   505 
       
   506 
       
   507   static void
       
   508   t1_done_loader( CID_Loader*  loader )
       
   509   {
       
   510     CID_Parser*  parser = &loader->parser;
       
   511 
       
   512 
       
   513     /* finalize parser */
       
   514     cid_parser_done( parser );
       
   515   }
       
   516 
       
   517 
       
   518   static FT_Error
       
   519   cid_hex_to_binary( FT_Byte*  data,
       
   520                      FT_Long   data_len,
       
   521                      FT_ULong  offset,
       
   522                      CID_Face  face )
       
   523   {
       
   524     FT_Stream  stream = face->root.stream;
       
   525     FT_Error   error;
       
   526 
       
   527     FT_Byte    buffer[256];
       
   528     FT_Byte   *p, *plimit;
       
   529     FT_Byte   *d, *dlimit;
       
   530     FT_Byte    val;
       
   531 
       
   532     FT_Bool    upper_nibble, done;
       
   533 
       
   534 
       
   535     if ( FT_STREAM_SEEK( offset ) )
       
   536       goto Exit;
       
   537 
       
   538     d      = data;
       
   539     dlimit = d + data_len;
       
   540     p      = buffer;
       
   541     plimit = p;
       
   542 
       
   543     upper_nibble = 1;
       
   544     done         = 0;
       
   545 
       
   546     while ( d < dlimit )
       
   547     {
       
   548       if ( p >= plimit )
       
   549       {
       
   550         FT_ULong  oldpos = FT_STREAM_POS();
       
   551         FT_ULong  size   = stream->size - oldpos;
       
   552 
       
   553 
       
   554         if ( size == 0 )
       
   555         {
       
   556           error = CID_Err_Syntax_Error;
       
   557           goto Exit;
       
   558         }
       
   559 
       
   560         if ( FT_STREAM_READ( buffer, 256 > size ? size : 256 ) )
       
   561           goto Exit;
       
   562         p      = buffer;
       
   563         plimit = p + FT_STREAM_POS() - oldpos;
       
   564       }
       
   565 
       
   566       if ( ft_isdigit( *p ) )
       
   567         val = (FT_Byte)( *p - '0' );
       
   568       else if ( *p >= 'a' && *p <= 'f' )
       
   569         val = (FT_Byte)( *p - 'a' );
       
   570       else if ( *p >= 'A' && *p <= 'F' )
       
   571         val = (FT_Byte)( *p - 'A' + 10 );
       
   572       else if ( *p == ' '  ||
       
   573                 *p == '\t' ||
       
   574                 *p == '\r' ||
       
   575                 *p == '\n' ||
       
   576                 *p == '\f' ||
       
   577                 *p == '\0' )
       
   578       {
       
   579         p++;
       
   580         continue;
       
   581       }
       
   582       else if ( *p == '>' )
       
   583       {
       
   584         val  = 0;
       
   585         done = 1;
       
   586       }
       
   587       else
       
   588       {
       
   589         error = CID_Err_Syntax_Error;
       
   590         goto Exit;
       
   591       }
       
   592 
       
   593       if ( upper_nibble )
       
   594         *d = (FT_Byte)( val << 4 );
       
   595       else
       
   596       {
       
   597         *d = (FT_Byte)( *d + val );
       
   598         d++;
       
   599       }
       
   600 
       
   601       upper_nibble = (FT_Byte)( 1 - upper_nibble );
       
   602 
       
   603       if ( done )
       
   604         break;
       
   605 
       
   606       p++;
       
   607     }
       
   608 
       
   609     error = CID_Err_Ok;
       
   610 
       
   611   Exit:
       
   612     return error;
       
   613   }
       
   614 
       
   615 
       
   616   FT_LOCAL_DEF( FT_Error )
       
   617   cid_face_open( CID_Face  face,
       
   618                  FT_Int    face_index )
       
   619   {
       
   620     CID_Loader   loader;
       
   621     CID_Parser*  parser;
       
   622     FT_Memory    memory = face->root.memory;
       
   623     FT_Error     error;
       
   624 
       
   625 
       
   626     t1_init_loader( &loader, face );
       
   627 
       
   628     parser = &loader.parser;
       
   629     error = cid_parser_new( parser, face->root.stream, face->root.memory,
       
   630                             (PSAux_Service)face->psaux );
       
   631     if ( error )
       
   632       goto Exit;
       
   633 
       
   634     error = cid_parse_dict( face, &loader,
       
   635                             parser->postscript,
       
   636                             parser->postscript_len );
       
   637     if ( error )
       
   638       goto Exit;
       
   639 
       
   640     if ( face_index < 0 )
       
   641       goto Exit;
       
   642 
       
   643     if ( FT_NEW( face->cid_stream ) )
       
   644       goto Exit;
       
   645 
       
   646     if ( parser->binary_length )
       
   647     {
       
   648       /* we must convert the data section from hexadecimal to binary */
       
   649       if ( FT_ALLOC( face->binary_data, parser->binary_length )         ||
       
   650            cid_hex_to_binary( face->binary_data, parser->binary_length,
       
   651                               parser->data_offset, face )               )
       
   652         goto Exit;
       
   653 
       
   654       FT_Stream_OpenMemory( face->cid_stream,
       
   655                             face->binary_data, parser->binary_length );
       
   656       face->cid.data_offset = 0;
       
   657     }
       
   658     else
       
   659     {
       
   660       *face->cid_stream     = *face->root.stream;
       
   661       face->cid.data_offset = loader.parser.data_offset;
       
   662     }
       
   663 
       
   664     error = cid_read_subrs( face );
       
   665 
       
   666   Exit:
       
   667     t1_done_loader( &loader );
       
   668     return error;
       
   669   }
       
   670 
       
   671 
       
   672 /* END */