]> git.saurik.com Git - wxWidgets.git/blobdiff - src/freetype/type1/t1load.c
Added FreeType II beta 8.
[wxWidgets.git] / src / freetype / type1 / t1load.c
diff --git a/src/freetype/type1/t1load.c b/src/freetype/type1/t1load.c
new file mode 100644 (file)
index 0000000..00a56a2
--- /dev/null
@@ -0,0 +1,1594 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t1load.c                                                               */
+/*                                                                         */
+/*    Type 1 font loader (body).                                           */
+/*                                                                         */
+/*  Copyright 1996-2000 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <freetype/config/ftconfig.h>
+#include <freetype/internal/ftdebug.h>
+#include <freetype/internal/t1types.h>
+
+
+#ifdef FT_FLAT_COMPILE
+
+#include "t1tokens.h"
+#include "t1parse.h"
+
+#else
+
+#include <type1/t1tokens.h>
+#include <type1/t1parse.h>
+
+#endif
+
+
+#include <stdio.h>
+
+#include <string.h>     /* for strncpy(), strncmp(), strlen() */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_t1load
+
+
+  typedef FT_Error  (*T1_Parse_Func)( T1_Parser*  parser );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Init_T1_Parser                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Initializes a given parser object to build a given T1_Face.        */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    parser    :: A handle to the newly built parser object.            */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face      :: A handle to the target Type 1 face object.            */
+  /*                                                                       */
+  /*    tokenizer :: A handle to the target Type 1 token manager.          */
+  /*                                                                       */
+  LOCAL_FUNC
+  void  Init_T1_Parser( T1_Parser*    parser,
+                        T1_Face       face,
+                        T1_Tokenizer  tokenizer )
+  {
+    parser->error     = 0;
+    parser->face      = face;
+    parser->tokenizer = tokenizer;
+    parser->top       = parser->stack;
+    parser->limit     = parser->stack + T1_MAX_STACK_DEPTH;
+
+    parser->state_index    = 0;
+    parser->state_stack[0] = dict_none;
+
+    parser->encoding_type    = t1_encoding_none;
+    parser->encoding_names   = 0;
+    parser->encoding_offsets = 0;
+    parser->encoding_lengths = 0;
+
+    parser->dump_tokens            = 0;
+    face->type1.private_dict.lenIV = 4;  /* XXX : is it sure? */
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Next_T1_Token                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Grabs the next significant token from a parser's input stream.     */
+  /*    This function ignores a number of tokens, and translates           */
+  /*    alternate forms into their common ones.                            */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    parser :: A handle to the source parser.                           */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    token  :: The extracted token descriptor.                          */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeTyoe error code.  0 means success.                             */
+  /*                                                                       */
+  LOCAL_FUNC
+  FT_Error  Next_T1_Token( T1_Parser*  parser,
+                           T1_Token*   token )
+  {
+    FT_Error      error;
+    T1_Tokenizer  tokzer = parser->tokenizer;
+
+
+  L1:
+    error = Read_Token( tokzer );
+    if ( error )
+      return error;
+
+    /* we now must ignore a number of tokens like `dup', `executeonly', */
+    /* `readonly', etc.                                                 */
+    *token = tokzer->token;
+    if ( token->kind == tok_keyword )
+      switch( token->kind2 )
+      {
+      case key_dup:
+      case key_execonly:
+      case key_readonly:
+      case key_noaccess:
+      case key_userdict:
+        /* do nothing - loop */
+        goto L1;
+
+        /* we also translate some other keywords from their alternative */
+        /* to their `normal' form                                       */
+
+      case key_NP_alternate:
+        token->kind2 = key_NP;
+        break;
+
+      case key_RD_alternate:
+        token->kind2 = key_RD;
+        break;
+
+      case key_ND_alternate:
+        token->kind2 = key_ND;
+        break;
+
+      default:
+        ;
+      }
+
+#if defined( FT_DEBUG_LEVEL_ERROR ) || defined( FT_DEBUG_LEVEL_TRACE )
+
+    /* Dump the token when requested.  This feature is only available */
+    /* in the `error' and `trace' debug levels.                       */
+    if ( parser->dump_tokens )
+    {
+      FT_String  temp_string[128];
+      FT_Int     len;
+
+
+      len = token->len;
+      if ( len > 127 )
+        len = 127;
+      strncpy( temp_string,
+               (FT_String*)tokzer->base + token->start,
+               len );
+      temp_string[len] = '\0';
+      FT_ERROR(( "%s\n", temp_string ));
+    }
+
+#endif /* FT_DEBUG_LEVEL_ERROR or FT_DEBUG_LEVEL_TRACE */
+
+    return T1_Err_Ok;
+  }
+
+
+  static
+  FT_Error  Expect_Keyword( T1_Parser*    parser,
+                            T1_TokenType  keyword )
+  {
+    T1_Token  token;
+    FT_Error  error;
+
+
+    error = Next_T1_Token( parser, &token );
+    if ( error )
+      goto Exit;
+
+    if ( token.kind  != tok_keyword ||
+         token.kind2 != keyword     )
+    {
+      error = T1_Err_Syntax_Error;
+      FT_ERROR(( "Expect_Keyword: keyword `%s' expected.\n",
+                 t1_keywords[keyword - key_first_] ));
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  static
+  FT_Error  Expect_Keyword2( T1_Parser*    parser,
+                             T1_TokenType  keyword1,
+                             T1_TokenType  keyword2 )
+  {
+    T1_Token  token;
+    FT_Error  error;
+
+
+    error = Next_T1_Token( parser, &token );
+    if ( error )
+      goto Exit;
+
+    if ( token.kind  != tok_keyword  ||
+         ( token.kind2 != keyword1 &&
+           token.kind2 != keyword2 ) )
+    {
+      error = T1_Err_Syntax_Error;
+      FT_ERROR(( "Expect_Keyword2: keyword `%s' or `%s' expected.\n",
+                 t1_keywords[keyword1 - key_first_],
+                 t1_keywords[keyword2 - key_first_] ));
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  static
+  void  Parse_Encoding( T1_Parser*  parser )
+  {
+    T1_Token*     token  = parser->top+1;
+    FT_Memory     memory = parser->face->root.memory;
+    T1_Encoding*  encode = &parser->face->type1.encoding;
+    FT_Error      error  = 0;
+
+
+    if ( token->kind  == tok_keyword              &&
+         ( token->kind2 == key_StandardEncoding ||
+           token->kind2 == key_ExpertEncoding   ) )
+    {
+      encode->num_chars  = 256;
+      encode->code_first = 32;
+      encode->code_last  = 255;
+
+      if ( ALLOC_ARRAY( encode->char_index, 256, FT_Short ) )
+        goto Exit;
+
+      encode->char_name = 0;  /* no need to store glyph names */
+
+      /* Now copy the encoding */
+      switch ( token->kind2 )
+      {
+      case key_ExpertEncoding:
+        parser->encoding_type = t1_encoding_expert;
+        break;
+
+      default:
+        parser->encoding_type = t1_encoding_standard;
+        break;
+      }
+    }
+    else
+    {
+      FT_ERROR(( "Parse_Encoding: invalid encoding type\n" ));
+      error = T1_Err_Syntax_Error;
+    }
+
+  Exit:
+    parser->error = error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                                                                       */
+  /*           IMPLEMENTATION OF THE `DEF' KEYWORD DEPENDING ON            */
+  /*                        CURRENT DICTIONARY STATE                       */
+  /*                                                                       */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Do_Def_Font                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    This function performs a `def' if in the Font dictionary.  Its     */
+  /*    purpose is to build the T1_Face attributes directly from the       */
+  /*    stream.                                                            */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    parser :: A handle to the current parser.                          */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  static
+  FT_Error  Do_Def_Font( T1_Parser*  parser )
+  {
+    T1_Token*  top   = parser->top;
+    T1_Face    face  = parser->face;
+    T1_Font*   type1 = &face->type1;
+
+
+    switch ( top[0].kind2 )
+    {
+    case imm_FontName:
+      /* in some cases, the /FontName is an immediate like */
+      /* /TimesNewRoman.  In this case, we simply copy the */
+      /* token string (without the /).                     */
+      if ( top[1].kind == tok_immediate )
+      {
+        FT_Memory  memory = parser->tokenizer->memory;
+        FT_Error   error;
+        FT_Int     len = top[1].len;
+
+
+        if ( ALLOC( type1->font_name, len + 1 ) )
+        {
+          parser->error = error;
+          return error;
+        }
+
+        MEM_Copy( type1->font_name,
+                  parser->tokenizer->base + top[1].start,
+                  len );
+        type1->font_name[len] = '\0';
+      }
+      else
+        type1->font_name = CopyString( parser );
+      break;
+
+    case imm_Encoding:
+      Parse_Encoding( parser );
+      break;
+
+    case imm_PaintType:
+      type1->paint_type = (FT_Byte)CopyInteger( parser );
+      break;
+
+    case imm_FontType:
+      type1->font_type = (FT_Byte)CopyInteger( parser );
+      break;
+
+    case imm_FontMatrix:
+      CopyMatrix( parser, &type1->font_matrix );
+      break;
+
+    case imm_FontBBox:
+      CopyBBox( parser, &type1->font_bbox );
+      break;
+
+    case imm_UniqueID:
+      type1->private_dict.unique_id = CopyInteger( parser );
+      break;
+
+    case imm_StrokeWidth:
+      type1->stroke_width = CopyInteger( parser );
+      break;
+
+    case imm_FontID:
+      type1->font_id = CopyInteger( parser );
+      break;
+
+    default:
+      /* ignore all other things */
+      parser->error = T1_Err_Ok;
+    }
+
+    return parser->error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Do_Def_FontInfo                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    This function performs a `def' if in the FontInfo dictionary. Its  */
+  /*    purpose is to build the T1_FontInfo structure directly from the    */
+  /*    stream.                                                            */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    parser :: A handle to the current parser.                          */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeTyoe error code.  0 means success.                             */
+  /*                                                                       */
+  static
+  FT_Error  Do_Def_FontInfo( T1_Parser*  parser )
+  {
+    T1_Token*     top  = parser->top;
+    T1_FontInfo*  info = &parser->face->type1.font_info;
+
+
+    switch ( top[0].kind2 )
+    {
+    case imm_version:
+      info->version = CopyString( parser );
+      break;
+
+    case imm_Notice:
+      info->notice = CopyString( parser );
+      break;
+
+    case imm_FullName:
+      info->full_name = CopyString( parser );
+      break;
+
+    case imm_FamilyName:
+      info->family_name = CopyString( parser );
+      break;
+
+    case imm_Weight:
+      info->weight = CopyString( parser );
+      break;
+
+    case imm_ItalicAngle:
+      info->italic_angle = CopyInteger( parser );
+      break;
+
+    case imm_isFixedPitch:
+      info->is_fixed_pitch = CopyBoolean( parser );
+      break;
+
+    case imm_UnderlinePosition:
+      info->underline_position = (FT_Short)CopyInteger( parser );
+      break;
+
+    case imm_UnderlineThickness:
+      info->underline_thickness = (FT_Short)CopyInteger( parser );
+      break;
+
+    default:
+      /* ignore all other things */
+      parser->error = T1_Err_Ok;
+    }
+
+    return parser->error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Do_Def_Private                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    This function performs a `def' if in the Private dictionary.  Its  */
+  /*    purpose is to build the T1_Private structure directly from the     */
+  /*    stream.                                                            */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    parser :: A handle to the current parser.                          */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeTyoe error code.  0 means success.                             */
+  /*                                                                       */
+  static
+  FT_Error  Do_Def_Private( T1_Parser*  parser )
+  {
+    T1_Token*   top   = parser->top;
+    T1_Private* priv  = &parser->face->type1.private_dict;
+
+
+    switch ( top[0].kind2 )
+    {
+      /* Ignore the definitions of RD, NP, ND, and their alternate forms */
+    case imm_RD:
+    case imm_RD_alternate:
+    case imm_ND:
+    case imm_ND_alternate:
+    case imm_NP:
+    case imm_NP_alternate:
+      parser->error = T1_Err_Ok;
+      break;
+
+    case imm_BlueValues:
+      CopyArray( parser, &priv->num_blue_values,
+                 priv->blue_values, 14 );
+      break;
+
+    case imm_OtherBlues:
+      CopyArray( parser, &priv->num_other_blues,
+                 priv->other_blues, 10 );
+      break;
+
+    case imm_FamilyBlues:
+      CopyArray( parser, &priv->num_family_blues,
+                 priv->family_blues, 14 );
+      break;
+
+    case imm_FamilyOtherBlues:
+      CopyArray( parser, &priv->num_family_other_blues,
+                 priv->family_other_blues, 10 );
+      break;
+
+    case imm_BlueScale:
+      priv->blue_scale = CopyFloat( parser, 0x10000L );
+      break;
+
+    case imm_BlueShift:
+      priv->blue_shift = CopyInteger( parser );
+      break;
+
+    case imm_BlueFuzz:
+      priv->blue_fuzz = CopyInteger( parser );
+      break;
+
+    case imm_StdHW:
+      CopyArray( parser, 0, (FT_Short*)&priv->standard_width, 1 );
+      break;
+
+    case imm_StdVW:
+      CopyArray( parser, 0, (FT_Short*)&priv->standard_height, 1 );
+      break;
+
+    case imm_StemSnapH:
+      CopyArray( parser, &priv->num_snap_widths,
+                 priv->snap_widths, 12 );
+      break;
+
+    case imm_StemSnapV:
+      CopyArray( parser, &priv->num_snap_heights,
+                 priv->snap_heights, 12 );
+      break;
+
+    case imm_ForceBold:
+      priv->force_bold = CopyBoolean( parser );
+      break;
+
+    case imm_LanguageGroup:
+      priv->language_group = CopyInteger( parser );
+      break;
+
+    case imm_password:
+      priv->password = CopyInteger( parser );
+      break;
+
+    case imm_UniqueID:
+      priv->unique_id = CopyInteger( parser );
+      break;
+
+    case imm_lenIV:
+      priv->lenIV = CopyInteger( parser );
+      break;
+
+    case imm_MinFeature:
+      CopyArray( parser, 0, priv->min_feature, 2 );
+      break;
+
+    default:
+      /* ignore all other things */
+      parser->error = T1_Err_Ok;
+    }
+
+    return parser->error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Do_Def_Error                                                       */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    This function returns a simple syntax error when invoked.  It is   */
+  /*    used for the `def' keyword if in the `encoding', `subrs',          */
+  /*    `othersubrs', and `charstrings' dictionary states.                 */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    parser :: A handle to the current parser.                          */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  static
+  FT_Error  Do_Def_Error( T1_Parser*  parser )
+  {
+    FT_ERROR(( "Do_Def_Error:" ));
+    FT_ERROR(( " `def' keyword encountered in bad dictionary/array\n" ));
+
+    parser->error = T1_Err_Syntax_Error;
+
+    return parser->error;
+  }
+
+
+  static
+  FT_Error  Do_Def_Ignore( T1_Parser*  parser )
+  {
+    FT_UNUSED( parser );
+    return T1_Err_Ok;
+  }
+
+
+  static
+  T1_Parse_Func  def_funcs[dict_max] =
+  {
+    Do_Def_Error,
+    Do_Def_Font,
+    Do_Def_FontInfo,
+    Do_Def_Ignore,
+    Do_Def_Private,
+    Do_Def_Ignore,
+    Do_Def_Ignore,
+    Do_Def_Ignore,
+    Do_Def_Ignore,
+    Do_Def_Ignore,
+    Do_Def_Ignore,
+  };
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                                                                       */
+  /*           IMPLEMENTATION OF THE `PUT' KEYWORD DEPENDING ON            */
+  /*                        CURRENT DICTIONARY STATE                       */
+  /*                                                                       */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Do_Put_Encoding                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    This function performs a `put' if in the Encoding array.  The      */
+  /*    glyph name is copied into the T1 recorder, and the charcode and    */
+  /*    glyph name pointer are written into the face object encoding.      */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    parser :: A handle to the current parser.                          */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  static
+  FT_Error  Do_Put_Encoding( T1_Parser*  parser )
+  {
+    FT_Error      error  = T1_Err_Ok;
+    T1_Face       face   = parser->face;
+    T1_Token*     top    = parser->top;
+    T1_Encoding*  encode = &face->type1.encoding;
+    FT_Int        index;
+
+
+    /* record and check the character code */
+    if ( top[0].kind != tok_number )
+    {
+      FT_TRACE4(( "Do_Put_Encoding: number expected\n" ));
+      goto Syntax_Error;
+    }
+    index = (FT_Int)CopyInteger( parser );
+    if ( parser->error )
+      return parser->error;
+
+    if ( index < 0 || index >= encode->num_chars )
+    {
+      FT_TRACE4(( "Do_Put_Encoding: invalid character code\n" ));
+      goto Syntax_Error;
+    }
+
+    /* record the immediate name */
+    if ( top[1].kind != tok_immediate )
+    {
+      FT_TRACE4(( "Do_Put_Encoding: immediate name expected\n" ));
+      goto Syntax_Error;
+    }
+
+    /* if the glyph name is `.notdef', store a NULL char name; */
+    /* otherwise, record the glyph name                        */
+    if ( top[1].kind == imm_notdef )
+    {
+      parser->table.elements[index] = 0;
+      parser->table.lengths [index] = 0;
+    }
+    else
+    {
+      FT_String  temp_name[128];
+      T1_Token*  token = top + 1;
+      FT_Int     len   = token->len - 1;
+
+
+      /* copy immediate name */
+      if ( len > 127 )
+        len = 127;
+      MEM_Copy( temp_name, parser->tokenizer->base + token->start + 1, len );
+      temp_name[len] = '\0';
+
+      error = T1_Add_Table( &parser->table, index,
+                            (FT_Byte*)temp_name, len + 1 );
+
+      /* adjust code_first and code_last */
+      if ( index < encode->code_first ) encode->code_first = index;
+      if ( index > encode->code_last  ) encode->code_last  = index;
+    }
+    return error;
+
+  Syntax_Error:
+    /* ignore the error, and simply clear the stack */
+    FT_TRACE4(( "Do_Put_Encoding: invalid syntax encountered\n" ));
+    parser->top = parser->stack;
+
+    return T1_Err_Ok;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                                                                       */
+  /*           IMPLEMENTATION OF THE "RD" KEYWORD DEPENDING ON             */
+  /*                        CURRENT DICTIONARY STATE                       */
+  /*                                                                       */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Do_RD_Subrs                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    This function performs an `RD' if in the Subrs dictionary.  It     */
+  /*    simply records the array of bytecodes/charstrings corresponding to */
+  /*    the sub-routine.                                                   */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    parser :: A handle to the current parser.                          */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  static
+  FT_Error  Do_RD_Subrs( T1_Parser*  parser )
+  {
+    FT_Error      error  = T1_Err_Ok;
+    T1_Face       face   = parser->face;
+    T1_Token*     top    = parser->top;
+    T1_Tokenizer  tokzer = parser->tokenizer;
+    FT_Int        index, count;
+
+
+    /* record and check the character code */
+    if ( top[0].kind != tok_number ||
+         top[1].kind != tok_number )
+    {
+      FT_ERROR(( "Do_RD_Subrs: number expected\n" ));
+      goto Syntax_Error;
+    }
+    index = (FT_Int)CopyInteger( parser );
+    error = parser->error;
+    if ( error )
+      goto Exit;
+
+    count = (FT_Int)CopyInteger( parser );
+    error = parser->error;
+    if ( error )
+      goto Exit;
+
+    if ( index < 0 || index >= face->type1.num_subrs )
+    {
+      FT_ERROR(( "Do_RD_Subrs: invalid character code\n" ));
+      goto Syntax_Error;
+    }
+
+    /* decrypt charstring and skip it */
+    {
+      FT_Byte*  base = tokzer->base + tokzer->cursor;
+
+
+      tokzer->cursor += count;
+
+      /* some fonts use a value of -1 for lenIV to indicate that */
+      /* the charstrings are unencoded.                          */
+      /*                                                         */
+      /* Thanks to Tom Kacvinsky for pointing this out.          */
+      /*                                                         */
+      if ( face->type1.private_dict.lenIV >= 0 )
+      {
+        t1_decrypt( base, count, 4330 );
+
+        base  += face->type1.private_dict.lenIV;
+        count -= face->type1.private_dict.lenIV;
+      }
+
+      error = T1_Add_Table( &parser->table, index, base, count );
+    }
+
+    /* consume the closing NP or `put' */
+    error = Expect_Keyword2( parser, key_NP, key_put );
+
+  Exit:
+    return error;
+
+  Syntax_Error:
+    return T1_Err_Syntax_Error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Do_RD_CharStrings                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    This function performs an `RD' if in the CharStrings dictionary.   */
+  /*    It simply records the array of bytecodes/charstrings corresponding */
+  /*    to the glyph program string.                                       */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    parser :: A handle to the current parser.                          */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  static
+  FT_Error  Do_RD_Charstrings( T1_Parser*  parser )
+  {
+    FT_Error      error = T1_Err_Ok;
+    T1_Face       face  = parser->face;
+    T1_Token*     top   = parser->top;
+    T1_Tokenizer  tokzer = parser->tokenizer;
+    FT_Int        index, count;
+
+
+    /* check the character name argument */
+    if ( top[0].kind != tok_immediate )
+    {
+      FT_ERROR(( "Do_RD_Charstrings: immediate character name expected\n" ));
+      goto Syntax_Error;
+    }
+
+    /* check the count argument */
+    if ( top[1].kind != tok_number )
+    {
+      FT_ERROR(( "Do_RD_Charstrings: number expected\n" ));
+      goto Syntax_Error;
+    }
+
+    parser->args++;
+    count = (FT_Int)CopyInteger( parser );
+    error = parser->error;
+    if ( error )
+      goto Exit;
+
+    /* record the glyph name and get the corresponding glyph index */
+    if ( top[0].kind2 == imm_notdef )
+      index = 0;
+    else
+    {
+      FT_String  temp_name[128];
+      T1_Token*  token = top;
+      FT_Int     len   = token->len - 1;
+
+
+      /* copy immediate name */
+      if ( len > 127 )
+        len = 127;
+      MEM_Copy( temp_name, parser->tokenizer->base + token->start + 1, len );
+      temp_name[len] = '\0';
+
+      index = parser->cur_name++;
+      error = T1_Add_Table( &parser->table, index * 2,
+                            (FT_Byte*)temp_name, len + 1 );
+      if ( error )
+        goto Exit;
+    }
+
+    /* decrypt and record charstring, then skip them */
+    {
+      FT_Byte*  base = tokzer->base + tokzer->cursor;
+
+
+      tokzer->cursor += count;  /* skip */
+
+      if ( face->type1.private_dict.lenIV >= 0 )
+      {
+        t1_decrypt( base, count, 4330 );
+
+        base  += face->type1.private_dict.lenIV;
+        count -= face->type1.private_dict.lenIV;
+      }
+
+      error = T1_Add_Table( &parser->table, index * 2 + 1, base, count );
+    }
+
+    /* consume the closing `ND' */
+    if ( !error )
+      error = Expect_Keyword( parser, key_ND );
+
+  Exit:
+    return error;
+
+  Syntax_Error:
+    return T1_Err_Syntax_Error;
+  }
+
+
+  static
+  FT_Error  Expect_Dict_Arguments( T1_Parser*    parser,
+                                   FT_Int        num_args,
+                                   T1_TokenType  immediate,
+                                   T1_DictState  new_state,
+                                   FT_Int*       count )
+  {
+    /* check that we have enough arguments in the stack, including */
+    /* the `dict' keyword                                          */
+    if ( parser->top - parser->stack < num_args )
+    {
+      FT_ERROR(( "Expect_Dict_Arguments: expecting at least %d arguments",
+                 num_args ));
+      goto Syntax_Error;
+    }
+
+    /* check that we have the correct immediate, if needed */
+    if ( num_args == 2 )
+    {
+      if ( parser->top[-2].kind  != tok_immediate ||
+           parser->top[-2].kind2 != immediate     )
+      {
+        FT_ERROR(( "Expect_Dict_Arguments: expecting `/%s' dictionary\n",
+                   t1_immediates[immediate - imm_first_] ));
+        goto Syntax_Error;
+      }
+    }
+
+    parser->args = parser->top-1;
+
+    /* check that the count argument is a number */
+    if ( parser->args->kind != tok_number )
+    {
+      FT_ERROR(( "Expect_Dict_Arguments:" ));
+      FT_ERROR(( " expecting numerical count argument for `dict'\n" ));
+      goto Syntax_Error;
+    }
+
+    if ( count )
+    {
+      *count = CopyInteger( parser );
+      if ( parser->error )
+        return parser->error;
+    }
+
+    /* save the dictionary state */
+    parser->state_stack[++parser->state_index] = new_state;
+
+    /* consume the `begin' keyword and clear the stack */
+    parser->top -= num_args;
+    return Expect_Keyword( parser, key_begin );
+
+  Syntax_Error:
+    return T1_Err_Syntax_Error;
+  }
+
+
+  static
+  FT_Error  Expect_Array_Arguments( T1_Parser*  parser )
+  {
+    T1_Token*     top   = parser->top;
+    FT_Error      error = T1_Err_Ok;
+    T1_DictState  new_state;
+    FT_Int        count;
+    T1_Face       face   = parser->face;
+    FT_Memory     memory = face->root.memory;
+
+
+    /* Check arguments format */
+    if ( top - parser->stack < 2 )
+    {
+      FT_ERROR(( "Expect_Array_Arguments: two arguments expected\n" ));
+      error = T1_Err_Stack_Underflow;
+      goto Exit;
+    }
+
+    parser->top -= 2;
+    top         -= 2;
+    parser->args = top + 1;
+
+    if ( top[0].kind != tok_immediate )
+    {
+      FT_ERROR(( "Expect_Array_Arguments:" ));
+      FT_ERROR(( " first argument must be an immediate name\n" ));
+      goto Syntax_Error;
+    }
+
+    if ( top[1].kind != tok_number )
+    {
+      FT_ERROR(( "Expect_Array_Arguments:" ));
+      FT_ERROR(( " second argument must be a number\n" ));
+      goto Syntax_Error;
+    }
+
+    count = (FT_Int)CopyInteger( parser );
+
+    /* Is this an array we know about? */
+    switch ( top[0].kind2 )
+    {
+    case imm_Encoding:
+      {
+        T1_Encoding*  encode = &face->type1.encoding;
+
+
+        new_state = dict_encoding;
+
+        encode->code_first = count;
+        encode->code_last  = 0;
+        encode->num_chars  = count;
+
+        /* Allocate the table of character indices.  The table of   */
+        /* character names is allocated through init_t1_recorder(). */
+        if ( ALLOC_ARRAY( encode->char_index, count, FT_Short ) )
+          return error;
+
+        error = T1_New_Table( &parser->table, count, memory );
+        if ( error )
+          goto Exit;
+
+        parser->encoding_type = t1_encoding_array;
+      }
+      break;
+
+    case imm_Subrs:
+      new_state             = dict_subrs;
+      face->type1.num_subrs = count;
+
+      error = T1_New_Table( &parser->table, count, memory );
+      if ( error )
+        goto Exit;
+      break;
+
+    case imm_CharStrings:
+      new_state = dict_charstrings;
+      break;
+
+    default:
+      new_state = dict_unknown_array;
+    }
+
+    parser->state_stack[++parser->state_index] = new_state;
+
+  Exit:
+    return error;
+
+  Syntax_Error:
+    return T1_Err_Syntax_Error;
+  }
+
+
+  static
+  FT_Error  Finalize_Parsing( T1_Parser*  parser )
+  {
+    T1_Face             face    = parser->face;
+    T1_Font*            type1   = &face->type1;
+    FT_Memory           memory  = face->root.memory;
+    T1_Table*           strings = &parser->table;
+    PSNames_Interface*  psnames = (PSNames_Interface*)face->psnames;
+
+    FT_Int              num_glyphs;
+    FT_Int              n;
+    FT_Error            error;
+
+
+    num_glyphs = type1->num_glyphs = parser->cur_name;
+
+    /* allocate glyph names and charstrings arrays */
+    if ( ALLOC_ARRAY( type1->glyph_names,     num_glyphs, FT_String* ) ||
+         ALLOC_ARRAY( type1->charstrings,     num_glyphs, FT_Byte* )   ||
+         ALLOC_ARRAY( type1->charstrings_len, num_glyphs, FT_Int*  )   )
+      return error;
+
+    /* copy glyph names and charstrings offsets and lengths */
+    type1->charstrings_block = strings->block;
+    for ( n = 0; n < num_glyphs; n++ )
+    {
+      type1->glyph_names[n]     = (FT_String*)strings->elements[2 * n];
+      type1->charstrings[n]     = strings->elements[2 * n + 1];
+      type1->charstrings_len[n] = strings->lengths [2 * n + 1];
+    }
+
+    /* now free the old tables */
+    FREE( strings->elements );
+    FREE( strings->lengths );
+
+    if ( !psnames )
+    {
+      FT_ERROR(( "Finalize_Parsing: `PSNames' module missing!\n" ));
+      return T1_Err_Unimplemented_Feature;
+    }
+
+    /* compute encoding if required */
+    if ( parser->encoding_type == t1_encoding_none )
+    {
+      FT_ERROR(( "Finalize_Parsing: no encoding specified in font file\n" ));
+      return T1_Err_Syntax_Error;
+    }
+
+    {
+      FT_Int        n;
+      T1_Encoding*  encode = &type1->encoding;
+
+
+      encode->code_first = encode->num_chars - 1;
+      encode->code_last  = 0;
+
+      for ( n = 0; n < encode->num_chars; n++ )
+      {
+        FT_String** names;
+        FT_Int      index;
+        FT_Int      m;
+
+
+        switch ( parser->encoding_type )
+        {
+        case t1_encoding_standard:
+          index = psnames->adobe_std_encoding[n];
+          names = 0;
+          break;
+
+        case t1_encoding_expert:
+          index = psnames->adobe_expert_encoding[n];
+          names = 0;
+          break;
+
+        default:
+          index = n;
+          names = (FT_String**)parser->encoding_offsets;
+        }
+
+        encode->char_index[n] = 0;
+
+        if ( index )
+        {
+          FT_String*  name;
+
+
+          if ( names )
+            name = names[index];
+          else
+            name = (FT_String*)psnames->adobe_std_strings(index);
+
+          if ( name )
+          {
+            FT_Int  len = strlen( name );
+
+
+            /* lookup glyph index from name */
+            for ( m = 0; m < num_glyphs; m++ )
+            {
+              if ( strncmp( type1->glyph_names[m], name, len ) == 0 )
+              {
+                encode->char_index[n] = m;
+                break;
+              }
+            }
+
+            if ( n < encode->code_first ) encode->code_first = n;
+            if ( n > encode->code_last  ) encode->code_last  = n;
+          }
+        }
+      }
+
+      parser->encoding_type = t1_encoding_none;
+
+      FREE( parser->encoding_names );
+      FREE( parser->encoding_lengths );
+      FREE( parser->encoding_offsets );
+    }
+
+    return T1_Err_Ok;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Parse_T1_FontProgram                                               */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Parses a given Type 1 font file and builds its face object.        */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    parser :: A handle to the target parser object.                    */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    The parser contains a handle to the target face object.            */
+  /*                                                                       */
+  LOCAL_FUNC
+  FT_Error  Parse_T1_FontProgram( T1_Parser*  parser )
+  {
+    FT_Error  error;
+    T1_Font*  type1 = &parser->face->type1;
+
+
+    for (;;)
+    {
+      T1_Token      token;
+      T1_Token*     top;
+      T1_DictState  dict_state;
+      FT_Int        dict_index;
+
+
+      error      = Next_T1_Token( parser, &token );
+      top        = parser->top;
+      dict_index = parser->state_index;
+      dict_state = parser->state_stack[dict_index];
+
+      switch ( token.kind )
+      {
+        /* a keyword has been detected */
+      case tok_keyword:
+        switch ( token.kind2 )
+        {
+        case key_dict:
+          switch ( dict_state )
+          {
+          case dict_none:
+            /* All right, we are beginning the font dictionary.  */
+            /* Check that we only have one number argument, then */
+            /* consume the `begin' and change to `dict_font'     */
+            /* state.                                            */
+            error = Expect_Dict_Arguments( parser, 1, tok_error,
+                                           dict_font, 0 );
+            if ( error )
+              goto Exit;
+
+            /* clear stack from all the previous content.  This */
+            /* could be some stupid Postscript code.            */
+            parser->top = parser->stack;
+            break;
+
+          case dict_font:
+            /* This must be the /FontInfo dictionary, so check */
+            /* that we have at least two arguments, that they  */
+            /* are `/FontInfo' and a number, then change the   */
+            /* dictionary state.                               */
+            error = Expect_Dict_Arguments( parser, 2, imm_FontInfo,
+                                           dict_fontinfo, 0 );
+            if ( error )
+              goto Exit;
+            break;
+
+          case dict_none2:
+            error = Expect_Dict_Arguments( parser, 2, imm_Private,
+                                           dict_private, 0 );
+            if ( error )
+              goto Exit;
+            break;
+
+          case dict_private:
+            {
+              T1_Face  face = parser->face;
+              FT_Int   count;
+
+
+              error = Expect_Dict_Arguments( parser, 2, imm_CharStrings,
+                                             dict_charstrings, &count );
+              if ( error )
+                goto Exit;
+
+              type1->num_glyphs = count;
+              error = T1_New_Table( &parser->table, count * 2,
+                                    face->root.memory );
+              if ( error )
+                goto Exit;
+
+              /* record `.notdef' as the first glyph in the font */
+              error = T1_Add_Table( &parser->table, 0,
+                                    (FT_Byte*)".notdef", 8 );
+              parser->cur_name = 1;
+              /* XXX: DO SOMETHING HERE */
+            }
+            break;
+
+          default:
+            /* All other uses are invalid */
+            FT_ERROR(( "Parse_T1_FontProgram:" ));
+            FT_ERROR(( " invalid use of `dict' keyword\n" ));
+            goto Syntax_Error;
+          }
+          break;
+
+        case key_array:
+          /* Are we in an array yet?  If so, raise an error */
+          switch ( dict_state )
+          {
+          case dict_encoding:
+          case dict_subrs:
+          case dict_othersubrs:
+          case dict_charstrings:
+          case dict_unknown_array:
+            FT_ERROR(( "Parse_T1_FontProgram: nested array definitions\n" ));
+            goto Syntax_Error;
+
+          default:
+            ;
+          }
+          error = Expect_Array_Arguments( parser );
+          if ( error )
+            goto Exit;
+          break;
+
+        case key_ND:
+        case key_NP:
+        case key_def:
+          /* Are we in an array? If so, finalize it. */
+          switch ( dict_state )
+          {
+          case dict_encoding:    /* finish encoding array */
+            /* copy table names to the face object */
+            T1_Done_Table( &parser->table );
+
+            parser->encoding_names   = parser->table.block;
+            parser->encoding_lengths = parser->table.lengths;
+            parser->encoding_offsets = parser->table.elements;
+
+            parser->state_index--;
+            break;
+
+          case dict_subrs:
+            /* copy recorder sub-routines */
+            T1_Done_Table( &parser->table );
+
+            parser->subrs      = parser->table.block;
+            type1->subrs       = parser->table.elements;
+            type1->subrs_len   = parser->table.lengths;
+            type1->subrs_block = parser->table.block;
+
+            parser->state_index--;
+            break;
+
+          case dict_charstrings:
+          case dict_othersubrs:
+          case dict_unknown_array:
+            FT_ERROR(( "Parse_T1_FontProgram: unsupported array\n" ));
+            goto Syntax_Error;
+            break;
+
+          default:   /* normal `def' processing */
+            /* Check that we have sufficient operands in the stack */
+            if ( top >= parser->stack + 2 )
+            {
+              /* Now check that the first operand is an immediate. */
+              /* If so, call the appropriate `def' routine based   */
+              /* on the current parser state.                      */
+              if ( top[-2].kind == tok_immediate )
+              {
+                parser->top -= 2;
+                parser->args = parser->top + 1;
+                error = def_funcs[dict_state](parser);
+              }
+              else
+              {
+                /* This is an error, but some fonts contain  */
+                /* stupid Postscript code.  We simply ignore */
+                /* an invalid `def' by clearing the stack.   */
+#if 0
+                FT_ERROR(( "Parse_T1_FontProgram: immediate expected\n" ));
+                goto Syntax_Error;
+#else
+                parser->top = parser->stack;
+#endif
+              }
+            }
+            else
+            {
+              FT_ERROR(( "Parse_T1_FontProgram: not enough arguments\n" ));
+              goto Stack_Underflow;
+            }
+          }
+          break;
+
+        case key_index:
+          if ( top <= parser->stack )
+          {
+            FT_ERROR(( "Parse_T1_FontProgram: not enough arguments\n" ));
+            goto Stack_Underflow;
+          }
+
+          /* simply ignore? */
+          parser->top --;
+          break;
+
+        case key_put:
+          /* Check that we have sufficient operands in stack */
+          if ( top < parser->stack + 2 )
+          {
+            FT_ERROR(( "Parse_T1_FontProgram: not enough arguments\n" ));
+            goto Stack_Underflow;
+          }
+
+          parser->top -= 2;
+          parser->args = parser->top;
+
+          switch ( dict_state )
+          {
+          case dict_encoding:
+            error = Do_Put_Encoding( parser );
+            if ( error )
+              goto Exit;
+            break;
+
+          case dict_unknown_array:   /* ignore the `put' */
+            break;
+
+          default:
+#if 0
+            FT_ERROR(( "Parse_T1_FontProgram: invalid context\n" ));
+            goto Syntax_Error;
+#else
+            /* invalid context; simply ignore the `put' and */
+            /* clear the stack (stupid Postscript code)     */
+            FT_TRACE4(( "Parse_T1_FontProgram: invalid context ignored.\n" ));
+            parser->top = parser->stack;
+#endif
+          }
+          break;
+
+        case key_RD:
+          /* Check that we have sufficient operands in stack */
+          if ( top < parser->stack + 2 )
+          {
+            FT_ERROR(( "Parse_T1_FontProgram: not enough arguments\n" ));
+            goto Stack_Underflow;
+          }
+
+          parser->top -= 2;
+          parser->args = parser->top;
+          switch ( dict_state )
+          {
+          case dict_subrs:
+            error = Do_RD_Subrs( parser );
+            if ( error )
+              goto Exit;
+            break;
+
+          case dict_charstrings:
+            error = Do_RD_Charstrings( parser );
+            if ( error )
+              goto Exit;
+            break;
+
+          default:
+            FT_ERROR(( "Parse_T1_FontProgram: invalid context\n" ));
+            goto Syntax_Error;
+          }
+          break;
+
+        case key_end:
+          /* Were we in a dictionary or in an array? */
+          if ( dict_index <= 0 )
+          {
+            FT_ERROR(( "Parse_T1_FontProgram: no dictionary defined\n" ));
+            goto Syntax_Error;
+          }
+
+          switch ( dict_state )
+          {
+            /* jump to the private dictionary if we are closing the */
+            /* `/Font' dictionary                                   */
+          case dict_font:
+            goto Open_Private;
+
+            /* exit the parser when closing the CharStrings dictionary */
+          case dict_charstrings:
+            return Finalize_Parsing( parser );
+
+          default:
+            /* Pop the current dictionary state and return to previous */
+            /* one.  Consume the `def'.                                */
+
+            /* Because some buggy fonts (BitStream) have incorrect     */
+            /* syntax, we never escape from the private dictionary     */
+            if ( dict_state != dict_private )
+              parser->state_index--;
+
+            /* many fonts use `NP' instead of `def' or `put', so */
+            /* we simply ignore the next token                   */
+#if 0
+            error = Expect_Keyword2( parser, key_def, key_put );
+            if ( error )
+              goto Exit;
+#else
+            (void)Expect_Keyword2( parser, key_def, key_put );
+#endif
+          }
+          break;
+
+        case key_for:
+          /* check that we have four arguments and simply */
+          /* ignore them                                  */
+          if ( top - parser->stack < 4 )
+          {
+            FT_ERROR(( "Parse_T1_FontProgram: not enough arguments\n" ));
+            goto Stack_Underflow;
+          }
+
+          parser->top -= 4;
+          break;
+
+        case key_currentdict:
+        Open_Private:
+          parser->state_index    = 0;
+          parser->state_stack[0] = dict_none2;
+          error = Open_PrivateDict( parser->tokenizer );
+          if ( error )
+            goto Exit;
+          break;
+
+        case key_true:
+        case key_false:
+        case key_StandardEncoding:
+        case key_ExpertEncoding:
+          goto Push_Element;
+
+        default:
+          FT_ERROR(( "Parse_T1_FontProgram:" ));
+          FT_ERROR(( " invalid keyword in context\n" ));
+          error = T1_Err_Syntax_Error;
+        }
+        break;
+
+        /* check for the presence of `/BlendAxisTypes' -- we cannot deal */
+        /* with multiple master fonts, so we must return a correct error */
+        /* code to allow another driver to load them                     */
+      case tok_immediate:
+        if ( token.kind2 == imm_BlendAxisTypes )
+        {
+          error = FT_Err_Unknown_File_Format;
+          goto Exit;
+        }
+        /* fallthrough */
+
+        /* A number was detected */
+      case tok_string:
+      case tok_program:
+      case tok_array:
+      case tok_hexarray:
+      case tok_any:
+      case tok_number:                        /* push number on stack */
+
+      Push_Element:
+        if ( top >= parser->limit )
+        {
+          error = T1_Err_Stack_Overflow;
+          goto Exit;
+        }
+        else
+          *parser->top++ = token;
+        break;
+
+        /* anything else is an error per se the spec, but we     */
+        /* frequently encounter stupid postscript code in fonts, */
+        /* so just ignore them                                   */
+      default:
+        error = T1_Err_Ok;  /* ignore token */
+      }
+
+      if ( error )
+        return error;
+    }
+
+  Exit:
+    return error;
+
+  Syntax_Error:
+    return T1_Err_Syntax_Error;
+
+  Stack_Underflow:
+    return T1_Err_Stack_Underflow;
+  }
+
+
+/* END */