1ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/***************************************************************************/
2ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
3ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  cidparse.c                                                             */
4ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
5ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*    CID-keyed Type1 parser (body).                                       */
6ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
7ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann/*  Copyright 1996-2015 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_INTERNAL_OBJECTS_H
22e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include FT_INTERNAL_STREAM_H
23ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
24ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "cidparse.h"
25ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
26ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "ciderrs.h"
27ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
28ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
29ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
30ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
31ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
32ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
33ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* messages during execution.                                            */
34ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
35ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#undef  FT_COMPONENT
36ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define FT_COMPONENT  trace_cidparse
37ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
38ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
39ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
40ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
41ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
42ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
43ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                    INPUT STREAM PARSER                        *****/
44ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
45ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
46ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
47ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
48ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
49ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
50ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL_DEF( FT_Error )
51ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cid_parser_new( CID_Parser*    parser,
52ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                  FT_Stream      stream,
53ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                  FT_Memory      memory,
54ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                  PSAux_Service  psaux )
55ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
56ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Error  error;
57ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong  base_offset, offset, ps_len;
58ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte   *cur, *limit;
59ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte   *arg1, *arg2;
60ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
61ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
62ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MEM_ZERO( parser, sizeof ( *parser ) );
63ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory );
64ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
65ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->stream = stream;
66ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
67ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    base_offset = FT_STREAM_POS();
68ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
69ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* first of all, check the font format in the header */
70ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( FT_FRAME_ENTER( 31 ) )
71ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      goto Exit;
72ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
73ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( ft_strncmp( (char *)stream->cursor,
74ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     "%!PS-Adobe-3.0 Resource-CIDFont", 31 ) )
75ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
76ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_TRACE2(( "  not a CID-keyed font\n" ));
77ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      error = FT_THROW( Unknown_File_Format );
78ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
79ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
80ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_FRAME_EXIT();
81ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( error )
82ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      goto Exit;
83ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
84ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Again:
85ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* now, read the rest of the file until we find */
86ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* `StartData' or `/sfnts'                      */
87ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
88ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte   buffer[256 + 10];
89ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      FT_ULong  read_len = 256 + 10;
90ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*  p        = buffer;
91ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
92ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
93ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for ( offset = FT_STREAM_POS(); ; offset += 256 )
94ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
95ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        FT_ULong  stream_len;
96ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
97ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
98ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        stream_len = stream->size - FT_STREAM_POS();
99ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( stream_len == 0 )
100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE2(( "cid_parser_new: no `StartData' keyword found\n" ));
102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          error = FT_THROW( Invalid_File_Format );
103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          goto Exit;
104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        read_len = FT_MIN( read_len, stream_len );
107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( FT_STREAM_READ( p, read_len ) )
108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          goto Exit;
109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( read_len < 256 )
111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          p[read_len]  = '\0';
112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        limit = p + read_len - 10;
114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for ( p = buffer; p < limit; p++ )
116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( p[0] == 'S' && ft_strncmp( (char*)p, "StartData", 9 ) == 0 )
118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* save offset of binary data after `StartData' */
120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            offset += (FT_ULong)( p - buffer + 10 );
121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            goto Found;
122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          else if ( p[1] == 's' && ft_strncmp( (char*)p, "/sfnts", 6 ) == 0 )
124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            offset += (FT_ULong)( p - buffer + 7 );
126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            goto Found;
127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_MEM_MOVE( buffer, p, 10 );
131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        read_len = 256;
132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p = buffer + 10;
133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Found:
137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* We have found the start of the binary data or the `/sfnts' token. */
138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* Now rewind and extract the frame corresponding to this PostScript */
139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* section.                                                          */
140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ps_len = offset - base_offset;
142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( FT_STREAM_SEEK( base_offset )                  ||
143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov         FT_FRAME_EXTRACT( ps_len, parser->postscript ) )
144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      goto Exit;
145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->data_offset    = offset;
147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->postscript_len = ps_len;
148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->root.base      = parser->postscript;
149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->root.cursor    = parser->postscript;
150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->root.limit     = parser->root.cursor + ps_len;
151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->num_dict       = -1;
152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* Finally, we check whether `StartData' or `/sfnts' was real --  */
154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* it could be in a comment or string.  We also get the arguments */
155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* of `StartData' to find out whether the data is represented in  */
156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* binary or hex format.                                          */
157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    arg1 = parser->root.cursor;
159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cid_parser_skip_PS_token( parser );
160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cid_parser_skip_spaces  ( parser );
161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    arg2 = parser->root.cursor;
162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cid_parser_skip_PS_token( parser );
163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cid_parser_skip_spaces  ( parser );
164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    limit = parser->root.limit;
166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cur   = parser->root.cursor;
167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    while ( cur < limit )
169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( parser->root.error )
171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        error = parser->root.error;
173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        goto Exit;
174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( cur[0] == 'S' && ft_strncmp( (char*)cur, "StartData", 9 ) == 0 )
177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( ft_strncmp( (char*)arg1, "(Hex)", 5 ) == 0 )
179ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        {
180ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          FT_Long  tmp = ft_atol( (const char *)arg2 );
181ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
182ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
183ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          if ( tmp < 0 )
184ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          {
185ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            FT_ERROR(( "cid_parser_new: invalid length of hex data\n" ));
186ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            error = FT_THROW( Invalid_File_Format );
187ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          }
188ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          else
189ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            parser->binary_length = (FT_ULong)tmp;
190ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        }
191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        goto Exit;
193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else if ( cur[1] == 's' && ft_strncmp( (char*)cur, "/sfnts", 6 ) == 0 )
195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_TRACE2(( "cid_parser_new: cannot handle Type 11 fonts\n" ));
197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        error = FT_THROW( Unknown_File_Format );
198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        goto Exit;
199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cid_parser_skip_PS_token( parser );
202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cid_parser_skip_spaces  ( parser );
203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      arg1 = arg2;
204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      arg2 = cur;
205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cur  = parser->root.cursor;
206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* we haven't found the correct `StartData'; go back and continue */
209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* searching                                                      */
210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_FRAME_RELEASE( parser->postscript );
211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !FT_STREAM_SEEK( offset ) )
212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      goto Again;
213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Exit:
215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return error;
216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL_DEF( void )
220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cid_parser_done( CID_Parser*  parser )
221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* always free the private dictionary */
223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( parser->postscript )
224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Stream  stream = parser->stream;
226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_FRAME_RELEASE( parser->postscript );
229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    parser->root.funcs.done( &parser->root );
231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* END */
235