1ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/***************************************************************************/
2ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
3ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  t1parse.c                                                              */
4ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
5ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*    Type 1 parser (body).                                                */
6ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
7e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov/*  Copyright 1996-2005, 2008, 2009, 2012-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
19ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
20ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
21ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* The Type 1 parser is in charge of the following:                      */
22ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
23ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*  - provide an implementation of a growing sequence of objects called  */
24ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    a `T1_Table' (used to build various tables needed by the loader).  */
25ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
26ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*  - opening .pfb and .pfa files to extract their top-level and private */
27ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    dictionaries.                                                      */
28ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
29ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*  - read numbers, arrays & strings from any dictionary.                */
30ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
31ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* See `t1load.c' to see how data is loaded from the font file.          */
32ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
33ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
34ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
35ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
36e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include <ft2build.h>
37e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include FT_INTERNAL_DEBUG_H
38e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include FT_INTERNAL_STREAM_H
39e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include FT_INTERNAL_POSTSCRIPT_AUX_H
40ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
41ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "t1parse.h"
42ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
43ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "t1errors.h"
44ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
45ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
46ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
47ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
48ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
49ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
50ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* messages during execution.                                            */
51ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
52ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#undef  FT_COMPONENT
53ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define FT_COMPONENT  trace_t1parse
54ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
55ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
56ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
57ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
58ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
59ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
60ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                   INPUT STREAM PARSER                         *****/
61ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
62ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
63ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
64ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
65ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
66ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
67ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* see Adobe Technical Note 5040.Download_Fonts.pdf */
68ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
69ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_Error
70ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  read_pfb_tag( FT_Stream   stream,
71ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FT_UShort  *atag,
72ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FT_ULong   *asize )
73ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
74ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Error   error;
75ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UShort  tag;
76ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong   size;
77ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
78ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
79ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    *atag  = 0;
80ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    *asize = 0;
81ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
82ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !FT_READ_USHORT( tag ) )
83ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
84ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( tag == 0x8001U || tag == 0x8002U )
85ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
86ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( !FT_READ_ULONG_LE( size ) )
87ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          *asize = size;
88ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
89ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
90ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      *atag = tag;
91ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
92ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
93ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return error;
94ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
95ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
96ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
97ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_Error
98ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  check_type1_format( FT_Stream    stream,
99ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      const char*  header_string,
100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      size_t       header_length )
101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Error   error;
103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UShort  tag;
104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong   dummy;
105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( FT_STREAM_SEEK( 0 ) )
108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      goto Exit;
109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    error = read_pfb_tag( stream, &tag, &dummy );
111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( error )
112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      goto Exit;
113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* We assume that the first segment in a PFB is always encoded as   */
115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* text.  This might be wrong (and the specification doesn't insist */
116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* on that), but we have never seen a counterexample.               */
117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( tag != 0x8001U && FT_STREAM_SEEK( 0 ) )
118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      goto Exit;
119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !FT_FRAME_ENTER( header_length ) )
121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      error = FT_Err_Ok;
123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( ft_memcmp( stream->cursor, header_string, header_length ) != 0 )
125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        error = FT_THROW( Unknown_File_Format );
126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_FRAME_EXIT();
128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Exit:
131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return error;
132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL_DEF( FT_Error )
136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  T1_New_Parser( T1_Parser      parser,
137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 FT_Stream      stream,
138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 FT_Memory      memory,
139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 PSAux_Service  psaux )
140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Error   error;
142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UShort  tag;
143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong   size;
144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory );
147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->stream       = stream;
149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->base_len     = 0;
150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->base_dict    = 0;
151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->private_len  = 0;
152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->private_dict = 0;
153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->in_pfb       = 0;
154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->in_memory    = 0;
155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->single_block = 0;
156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* check the header format */
158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    error = check_type1_format( stream, "%!PS-AdobeFont", 14 );
159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( error )
160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( FT_ERR_NEQ( error, Unknown_File_Format ) )
162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        goto Exit;
163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      error = check_type1_format( stream, "%!FontType", 10 );
165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( error )
166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_TRACE2(( "  not a Type 1 font\n" ));
168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        goto Exit;
169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /******************************************************************/
173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /*                                                                */
174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* Here a short summary of what is going on:                      */
175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /*                                                                */
176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /*   When creating a new Type 1 parser, we try to locate and load */
177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /*   the base dictionary if this is possible (i.e., for PFB       */
178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /*   files).  Otherwise, we load the whole font into memory.      */
179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /*                                                                */
180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /*   When `loading' the base dictionary, we only setup pointers   */
181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /*   in the case of a memory-based stream.  Otherwise, we         */
182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /*   allocate and load the base dictionary in it.                 */
183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /*                                                                */
184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /*   parser->in_pfb is set if we are in a binary (`.pfb') font.   */
185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /*   parser->in_memory is set if we have a memory stream.         */
186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /*                                                                */
187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* try to compute the size of the base dictionary;     */
189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* look for a Postscript binary file tag, i.e., 0x8001 */
190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( FT_STREAM_SEEK( 0L ) )
191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      goto Exit;
192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    error = read_pfb_tag( stream, &tag, &size );
194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( error )
195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      goto Exit;
196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( tag != 0x8001U )
198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* assume that this is a PFA file for now; an error will */
200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* be produced later when more things are checked        */
201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( FT_STREAM_SEEK( 0L ) )
202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        goto Exit;
203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      size = stream->size;
204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      parser->in_pfb = 1;
207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* now, try to load `size' bytes of the `base' dictionary we */
209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* found previously                                          */
210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* if it is a memory-based resource, set up pointers */
212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !stream->read )
213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      parser->base_dict = (FT_Byte*)stream->base + stream->pos;
215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      parser->base_len  = size;
216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      parser->in_memory = 1;
217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* check that the `size' field is valid */
219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( FT_STREAM_SKIP( size ) )
220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        goto Exit;
221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* read segment in memory -- this is clumsy, but so does the format */
225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( FT_ALLOC( parser->base_dict, size )       ||
226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov           FT_STREAM_READ( parser->base_dict, size ) )
227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        goto Exit;
228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      parser->base_len = size;
229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->root.base   = parser->base_dict;
232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->root.cursor = parser->base_dict;
233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->root.limit  = parser->root.cursor + parser->base_len;
234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Exit:
236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( error && !parser->in_memory )
237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_FREE( parser->base_dict );
238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return error;
240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL_DEF( void )
244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  T1_Finalize_Parser( T1_Parser  parser )
245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Memory  memory = parser->root.memory;
247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* always free the private dictionary */
250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_FREE( parser->private_dict );
251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* free the base dictionary only when we have a disk stream */
253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !parser->in_memory )
254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_FREE( parser->base_dict );
255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->root.funcs.done( &parser->root );
257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL_DEF( FT_Error )
261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  T1_Get_Private_Dict( T1_Parser      parser,
262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       PSAux_Service  psaux )
263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Stream  stream = parser->stream;
265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Memory  memory = parser->root.memory;
266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Error   error  = FT_Err_Ok;
267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong   size;
268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( parser->in_pfb )
271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* in the case of the PFB format, the private dictionary can be  */
273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* made of several segments.  We thus first read the number of   */
274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* segments to compute the total size of the private dictionary  */
275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* then re-read them into memory.                                */
276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Long    start_pos = FT_STREAM_POS();
277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UShort  tag;
278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      parser->private_len = 0;
281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for (;;)
282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        error = read_pfb_tag( stream, &tag, &size );
284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( error )
285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          goto Fail;
286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( tag != 0x8002U )
288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        parser->private_len += size;
291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( FT_STREAM_SKIP( size ) )
293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          goto Fail;
294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* Check that we have a private dictionary there */
297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* and allocate private dictionary buffer        */
298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( parser->private_len == 0 )
299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_ERROR(( "T1_Get_Private_Dict:"
301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                   " invalid private dictionary section\n" ));
302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        error = FT_THROW( Invalid_File_Format );
303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        goto Fail;
304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( FT_STREAM_SEEK( start_pos )                           ||
307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov           FT_ALLOC( parser->private_dict, parser->private_len ) )
308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        goto Fail;
309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      parser->private_len = 0;
311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for (;;)
312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        error = read_pfb_tag( stream, &tag, &size );
314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( error || tag != 0x8002U )
315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          error = FT_Err_Ok;
317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( FT_STREAM_READ( parser->private_dict + parser->private_len,
321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                             size ) )
322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          goto Fail;
323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        parser->private_len += size;
325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* We have already `loaded' the whole PFA font file into memory; */
330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* if this is a memory resource, allocate a new block to hold    */
331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* the private dict.  Otherwise, simply overwrite into the base  */
332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* dictionary block in the heap.                                 */
333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* first of all, look at the `eexec' keyword */
335e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      FT_Byte*    cur   = parser->base_dict;
336e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      FT_Byte*    limit = cur + parser->base_len;
337e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      FT_Byte     c;
338e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      FT_Pointer  pos_lf;
339e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      FT_Bool     test_cr;
340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    Again:
343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for (;;)
344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        c = cur[0];
346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( c == 'e' && cur + 9 < limit )  /* 9 = 5 letters for `eexec' + */
347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                            /* whitespace + 4 chars        */
348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( cur[1] == 'e' &&
350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov               cur[2] == 'x' &&
351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov               cur[3] == 'e' &&
352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov               cur[4] == 'c' )
353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cur++;
356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( cur >= limit )
357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_ERROR(( "T1_Get_Private_Dict:"
359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     " could not find `eexec' keyword\n" ));
360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          error = FT_THROW( Invalid_File_Format );
361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          goto Exit;
362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* check whether `eexec' was real -- it could be in a comment */
366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* or string (as e.g. in u003043t.gsf from ghostscript)       */
367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      parser->root.cursor = parser->base_dict;
369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* set limit to `eexec' + whitespace + 4 characters */
370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      parser->root.limit  = cur + 10;
371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cur   = parser->root.cursor;
373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      limit = parser->root.limit;
374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      while ( cur < limit )
376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( *cur == 'e' && ft_strncmp( (char*)cur, "eexec", 5 ) == 0 )
378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          goto Found;
379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        T1_Skip_PS_Token( parser );
381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( parser->root.error )
382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        T1_Skip_Spaces  ( parser );
384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cur = parser->root.cursor;
385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* we haven't found the correct `eexec'; go back and continue */
388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* searching                                                  */
389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cur   = limit;
391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      limit = parser->base_dict + parser->base_len;
392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      goto Again;
393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* now determine where to write the _encrypted_ binary private  */
395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* dictionary.  We overwrite the base dictionary for disk-based */
396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* resources and allocate a new block otherwise                 */
397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    Found:
399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      parser->root.limit = parser->base_dict + parser->base_len;
400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      T1_Skip_PS_Token( parser );
402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cur   = parser->root.cursor;
403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      limit = parser->root.limit;
404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
405e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      /* According to the Type 1 spec, the first cipher byte must not be */
406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* an ASCII whitespace character code (blank, tab, carriage return */
407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* or line feed).  We have seen Type 1 fonts with two line feed    */
408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* characters...  So skip now all whitespace character codes.      */
409e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      /*                                                                 */
410e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      /* On the other hand, Adobe's Type 1 parser handles fonts just     */
411e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      /* fine that are violating this limitation, so we add a heuristic  */
412e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      /* test to stop at \r only if it is not used for EOL.              */
413e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
414e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      pos_lf  = ft_memchr( cur, '\n', limit - cur );
415e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      test_cr = FT_BOOL( !pos_lf                                      ||
416e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                         pos_lf > ft_memchr( cur, '\r', limit - cur ) );
417e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
418e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      while ( cur < limit                    &&
419e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov              ( *cur == ' '                ||
420e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                *cur == '\t'               ||
421e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                (test_cr && *cur == '\r' ) ||
422e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov                *cur == '\n'               ) )
423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        ++cur;
424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( cur >= limit )
425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_ERROR(( "T1_Get_Private_Dict:"
427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                   " `eexec' not properly terminated\n" ));
428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        error = FT_THROW( Invalid_File_Format );
429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        goto Exit;
430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      size = (FT_ULong)( parser->base_len - ( cur - parser->base_dict ) );
433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( parser->in_memory )
435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* note that we allocate one more byte to put a terminating `0' */
437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( FT_ALLOC( parser->private_dict, size + 1 ) )
438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          goto Fail;
439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        parser->private_len = size;
440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        parser->single_block = 1;
444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        parser->private_dict = parser->base_dict;
445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        parser->private_len  = size;
446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        parser->base_dict    = 0;
447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        parser->base_len     = 0;
448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* now determine whether the private dictionary is encoded in binary */
451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* or hexadecimal ASCII format -- decode it accordingly              */
452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* we need to access the next 4 bytes (after the final whitespace */
454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* following the `eexec' keyword); if they all are hexadecimal    */
455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* digits, then we have a case of ASCII storage                   */
456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( cur + 3 < limit                                &&
458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov           ft_isxdigit( cur[0] ) && ft_isxdigit( cur[1] ) &&
459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov           ft_isxdigit( cur[2] ) && ft_isxdigit( cur[3] ) )
460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* ASCII hexadecimal encoding */
462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Long  len;
463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        parser->root.cursor = cur;
466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        (void)psaux->ps_parser_funcs->to_bytes( &parser->root,
467ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                parser->private_dict,
468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                parser->private_len,
469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                &len,
470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                0 );
471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        parser->private_len = len;
472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* put a safeguard */
474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        parser->private_dict[len] = '\0';
475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* binary encoding -- copy the private dict */
478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_MEM_MOVE( parser->private_dict, cur, size );
479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* we now decrypt the encoded binary private dictionary */
482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    psaux->t1_decrypt( parser->private_dict, parser->private_len, 55665U );
483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( parser->private_len < 4 )
485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_ERROR(( "T1_Get_Private_Dict:"
487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 " invalid private dictionary section\n" ));
488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      error = FT_THROW( Invalid_File_Format );
489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      goto Fail;
490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* replace the four random bytes at the beginning with whitespace */
493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->private_dict[0] = ' ';
494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->private_dict[1] = ' ';
495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->private_dict[2] = ' ';
496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->private_dict[3] = ' ';
497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->root.base   = parser->private_dict;
499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->root.cursor = parser->private_dict;
500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->root.limit  = parser->root.cursor + parser->private_len;
501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Fail:
503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Exit:
504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return error;
505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* END */
509