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