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