shithub: freetype+ttf2subf

Download patch

ref: e3f41982a2391d2fcb61b8883af98aa4e5b82df1
parent: 15ee9b5542f22ee85325889414e657aa2c1fc4cd
author: Werner Lemberg <[email protected]>
date: Thu Oct 16 11:48:39 EDT 2003

Completely revised Type 42 parser.  It now handles both fonts
produced with ttftot42 (tested version 0.3.1) and
TrueTypeToType42.ps (tested version May 2001; it is necessary to
fix the broken header comment to be `%!PS-TrueTypeFont...').

* src/type42/t42objs.c (T42_GlyphSlot_Load): Change fourth
parameter to `FT_UInt'.
* src/type42/t42objs.h: Updated.

* src/type42/t42parse.h (T42_ParserRec): Change type of `in_memory'
to FT_Bool.
(T42_Loader): Change type of `num_chars' and `num_glyphs' to
FT_UInt.
Add `swap_table' element.
* src/type42/t42parse.c (T42_KEYWORD_COUNT, T1_ToFixed,
T1_ToCoordArray, T1_ToTokenArray): Removed.
(T1_ToBytes): New macro.
(t42_is_alpha, t42_hexval): Removed.
(t42_is_space): Handle `\0'.
(t42_parse_encoding): Updated to use new PostScript parser routines
from psaux.
Handle `/Encoding [ ... ]' also.
(T42_Load_Status): New enumeration.
(t42_parse_sfnts): Updated to use new PostScript parser routines
from psaux.
(t42_parse_charstrings): Updated to use new PostScript parser
routines from psaux.
Handle `/CharStrings << ... >>' also.
Don't expect that /.notdef is the first element in dictionary.  Copy
code from type1 module to handle this.
(t42_parse_dict): Updated to use new PostScript parser routines
from psaux.
Remove code for synthetic fonts (which can't occur in Type 42
fonts).
(t42_loader_done): Release `swap_table'.

* src/psaux/psobjs.c (skip_string): Increase `cur' properly.

* src/type1/t1load.c (parse_charstrings): Make test for `.notdef'
faster.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,47 @@
-2003-10-15:  Graham Asher  <[email protected]>
+2003-10-16  Werner Lemberg  <[email protected]>
+
+	Completely revised Type 42 parser.  It now handles both fonts
+	produced with ttftot42 (tested version 0.3.1) and
+	TrueTypeToType42.ps (tested version May 2001; it is necessary to
+	fix the broken header comment to be `%!PS-TrueTypeFont...').
+
+	* src/type42/t42objs.c (T42_GlyphSlot_Load): Change fourth
+	parameter to `FT_UInt'.
+	* src/type42/t42objs.h: Updated.
+
+	* src/type42/t42parse.h (T42_ParserRec): Change type of `in_memory'
+	to FT_Bool.
+	(T42_Loader): Change type of `num_chars' and `num_glyphs' to
+	FT_UInt.
+	Add `swap_table' element.
+	* src/type42/t42parse.c (T42_KEYWORD_COUNT, T1_ToFixed,
+	T1_ToCoordArray, T1_ToTokenArray): Removed.
+	(T1_ToBytes): New macro.
+	(t42_is_alpha, t42_hexval): Removed.
+	(t42_is_space): Handle `\0'.
+	(t42_parse_encoding): Updated to use new PostScript parser routines
+	from psaux.
+	Handle `/Encoding [ ... ]' also.
+	(T42_Load_Status): New enumeration.
+	(t42_parse_sfnts): Updated to use new PostScript parser routines
+	from psaux.
+	(t42_parse_charstrings): Updated to use new PostScript parser
+	routines from psaux.
+	Handle `/CharStrings << ... >>' also.
+	Don't expect that /.notdef is the first element in dictionary.  Copy
+	code from type1 module to handle this.
+	(t42_parse_dict): Updated to use new PostScript parser routines
+	from psaux.
+	Remove code for synthetic fonts (which can't occur in Type 42
+	fonts).
+	(t42_loader_done): Release `swap_table'.
+
+	* src/psaux/psobjs.c (skip_string): Increase `cur' properly.
+
+	* src/type1/t1load.c (parse_charstrings): Make test for `.notdef'
+	faster.
+
+2003-10-15  Graham Asher  <[email protected]>
 
 	* src/autohint/ahglobal.c (blue_chars), src/winfonts/winfnt.c
 	(fnt_cmap_class_rec, fnt_cmap_class), src/bdf/bdflib.c (empty,
--- a/src/psaux/psobjs.c
+++ b/src/psaux/psobjs.c
@@ -410,9 +410,7 @@
     FT_Byte*  limit = parser->limit;
 
 
-    cur++;
-
-    while ( cur < limit )
+    while ( ++cur < limit )
     {
       int  d;
 
--- a/src/type1/t1load.c
+++ b/src/type1/t1load.c
@@ -1190,9 +1190,7 @@
 
       /* the format is simple:                    */
       /*   `/glyphname' + binary data             */
-      /*                                          */
-      /* note that we stop when we find a `def'   */
-      /*                                          */
+
       T1_Skip_Spaces( parser );
 
       cur = parser->root.cursor;
@@ -1236,8 +1234,9 @@
         /* add a trailing zero to the name table */
         name_table->elements[n][len] = '\0';
 
-        /* record index of /.notdef              */
-        if ( ft_strcmp( (const char*)".notdef",
+        /* record index of /.notdef */
+        if ( *cur == '.'                                              &&
+             ft_strcmp( ".notdef",
                         (const char*)(name_table->elements[n]) ) == 0 )
         {
           notdef_index = n;
@@ -1274,7 +1273,7 @@
 
     loader->num_glyphs = n;
 
-    /* if /.notdef is found but does not occupy index 0, do our magic.      */
+    /* if /.notdef is found but does not occupy index 0, do our magic. */
     if ( ft_strcmp( (const char*)".notdef",
                     (const char*)name_table->elements[0] ) &&
          notdef_found                                      )
--- a/src/type42/t42drivr.c
+++ b/src/type42/t42drivr.c
@@ -24,10 +24,9 @@
   /* 2) Incremental fonts making use of the GlyphDirectory keyword         */
   /*    will be loaded, but the rendering will be using the TrueType       */
   /*    tables.                                                            */
-  /* 3) The sfnts array is expected to be ASCII, not binary.               */
-  /* 4) As for Type1 fonts, CDevProc is not supported.                     */
-  /* 5) The Metrics dictionary is not supported.                           */
-  /* 6) AFM metrics are not supported.                                     */
+  /* 3) As for Type1 fonts, CDevProc is not supported.                     */
+  /* 4) The Metrics dictionary is not supported.                           */
+  /* 5) AFM metrics are not supported.                                     */
   /*                                                                       */
   /* In other words, this driver supports Type42 fonts derived from        */
   /* TrueType fonts in a non-CID manner, as done by usual conversion       */
--- a/src/type42/t42objs.c
+++ b/src/type42/t42objs.c
@@ -53,7 +53,8 @@
     if ( error )
       goto Exit;
 
-    error = t42_parse_dict( face, &loader, parser->base_dict, parser->base_len );
+    error = t42_parse_dict( face, &loader,
+                            parser->base_dict, parser->base_len );
 
     if ( type1->font_type != 42 )
     {
@@ -65,7 +66,8 @@
     /* to the Type1 data                                    */
     type1->num_glyphs = loader.num_glyphs;
 
-    if ( !loader.charstrings.init ) {
+    if ( !loader.charstrings.init )
+    {
       FT_ERROR(( "T42_Open_Face: no charstrings array in face!\n" ));
       error = T42_Err_Invalid_File_Format;
     }
@@ -121,8 +123,10 @@
               if ( ft_strcmp( (const char*)".notdef",
                               (const char*)glyph_name ) != 0 )
               {
-                if ( charcode < min_char ) min_char = charcode;
-                if ( charcode > max_char ) max_char = charcode;
+                if ( charcode < min_char )
+                  min_char = charcode;
+                if ( charcode > max_char )
+                  max_char = charcode;
               }
               break;
             }
@@ -149,12 +153,12 @@
                  FT_Int         num_params,
                  FT_Parameter*  params )
   {
-    FT_Error         error;
+    FT_Error            error;
     FT_Service_PsNames  psnames;
-    PSAux_Service    psaux;
-    FT_Face          root  = (FT_Face)&face->root;
-    T1_Font          type1 = &face->type1;
-    PS_FontInfo      info  = &type1->font_info;
+    PSAux_Service       psaux;
+    FT_Face             root  = (FT_Face)&face->root;
+    T1_Font             type1 = &face->type1;
+    PS_FontInfo         info  = &type1->font_info;
 
     FT_UNUSED( num_params );
     FT_UNUSED( params );
@@ -189,7 +193,7 @@
       goto Exit;
     }
 
-    /* Now, load the font program into the face object */
+    /* Now load the font program into the face object */
 
     /* Init the face object fields */
     /* Now set up root face fields */
@@ -350,7 +354,7 @@
 
 #if 0
         /* Select default charmap */
-        if (root->num_charmaps)
+        if ( root->num_charmaps )
           root->charmap = root->charmaps[0];
 #endif
       }
@@ -452,8 +456,6 @@
   }
 
 
-
-
   FT_LOCAL_DEF( FT_Error )
   T42_Size_Init( T42_Size  size )
   {
@@ -601,7 +603,7 @@
   FT_LOCAL_DEF( FT_Error )
   T42_GlyphSlot_Load( FT_GlyphSlot  glyph,
                       FT_Size       size,
-                      FT_Int        glyph_index,
+                      FT_UInt       glyph_index,
                       FT_Int32      load_flags )
   {
     FT_Error         error;
--- a/src/type42/t42objs.h
+++ b/src/type42/t42objs.h
@@ -102,7 +102,7 @@
   FT_LOCAL( FT_Error )
   T42_GlyphSlot_Load( FT_GlyphSlot  glyph,
                       FT_Size       size,
-                      FT_Int        glyph_index,
+                      FT_UInt       glyph_index,
                       FT_Int32      load_flags );
 
   FT_LOCAL( void )
--- a/src/type42/t42parse.c
+++ b/src/type42/t42parse.c
@@ -93,10 +93,6 @@
   };
 
 
-#define T42_KEYWORD_COUNT                                          \
-          ( sizeof ( t42_keywords ) / sizeof ( t42_keywords[0] ) )
-
-
 #define T1_Add_Table( p, i, o, l )  (p)->funcs.add( (p), i, o, l )
 #define T1_Done_Table( p )          \
           do                        \
@@ -114,17 +110,15 @@
 #define T1_Skip_Spaces( p )    (p)->root.funcs.skip_spaces( &(p)->root )
 #define T1_Skip_PS_Token( p )  (p)->root.funcs.skip_PS_token( &(p)->root )
 
-#define T1_ToInt( p )       (p)->root.funcs.to_int( &(p)->root )
-#define T1_ToFixed( p, t )  (p)->root.funcs.to_fixed( &(p)->root, t )
+#define T1_ToInt( p )                          \
+          (p)->root.funcs.to_int( &(p)->root )
+#define T1_ToBytes( p, b, m, n, d )                          \
+          (p)->root.funcs.to_bytes( &(p)->root, b, m, n, d )
 
-#define T1_ToCoordArray( p, m, c )                           \
-          (p)->root.funcs.to_coord_array( &(p)->root, m, c )
 #define T1_ToFixedArray( p, m, f, t )                           \
           (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
 #define T1_ToToken( p, t )                          \
           (p)->root.funcs.to_token( &(p)->root, t )
-#define T1_ToTokenArray( p, t, m, c )                           \
-          (p)->root.funcs.to_token_array( &(p)->root, t, m, c )
 
 #define T1_Load_Field( p, f, o, m, pf )                         \
           (p)->root.funcs.load_field( &(p)->root, f, o, m, pf )
@@ -195,9 +189,9 @@
     }
 
     /* Now check font format; we must see `%!PS-TrueTypeFont' */
-    if (size <= 17                                    ||
-        ( ft_strncmp( (const char*)parser->base_dict,
-                      "%!PS-TrueTypeFont", 17) )      )
+    if ( size <= 17                                    ||
+         ( ft_strncmp( (const char*)parser->base_dict,
+                       "%!PS-TrueTypeFont", 17 ) )     )
       error = T42_Err_Unknown_File_Format;
     else
     {
@@ -229,23 +223,11 @@
 
 
   static int
-  t42_is_alpha( FT_Byte  c )
-  {
-    /* Note: we must accept "+" as a valid character, as it is used in */
-    /*       embedded type1 fonts in PDF documents.                    */
-    /*                                                                 */
-    return ( ft_isalnum( c ) ||
-             c == '.'        ||
-             c == '_'        ||
-             c == '-'        ||
-             c == '+'        );
-  }
-
-
-  static int
   t42_is_space( FT_Byte  c )
   {
-    return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' );
+    return ( c == ' '  || c == '\t'              ||
+             c == '\r' || c == '\n' || c == '\f' ||
+             c == '\0'                           );
   }
 
 
@@ -288,8 +270,8 @@
     matrix->yy = temp[3];
 
     /* note that the offsets must be expressed in integer font units */
-    offset->x  = temp[4] >> 16;
-    offset->y  = temp[5] >> 16;
+    offset->x = temp[4] >> 16;
+    offset->y = temp[5] >> 16;
   }
 
 
@@ -297,49 +279,53 @@
   t42_parse_encoding( T42_Face    face,
                       T42_Loader  loader )
   {
-    T42_Parser     parser = &loader->parser;
-    FT_Byte*       cur    = parser->root.cursor;
-    FT_Byte*       limit  = parser->root.limit;
+    T42_Parser  parser = &loader->parser;
+    FT_Byte*    cur;
+    FT_Byte*    limit  = parser->root.limit;
 
     PSAux_Service  psaux  = (PSAux_Service)face->psaux;
 
 
-    /* skip whitespace */
-    while ( t42_is_space( *cur ) )
+    T1_Skip_Spaces( parser );
+    cur = parser->root.cursor;
+
+    if ( cur >= limit )
     {
-      cur++;
-      if ( cur >= limit )
-      {
-        FT_ERROR(( "t42_parse_encoding: out of bounds!\n" ));
-        parser->root.error = T42_Err_Invalid_File_Format;
-        return;
-      }
+      FT_ERROR(( "t42_parse_encoding: out of bounds!\n" ));
+      parser->root.error = T42_Err_Invalid_File_Format;
+      return;
     }
 
-    /* if we have a number, then the encoding is an array, */
-    /* and we must load it now                             */
-    if ( ft_isdigit( *cur ) )
+    /* if we have a number or `[', the encoding is an array, */
+    /* and we must load it now                               */
+    if ( ft_isdigit( *cur ) || *cur == '[' )
     {
-      T1_Encoding  encode     = &face->type1.encoding;
-      FT_Int       count, n;
-      PS_Table     char_table = &loader->encoding_table;
-      FT_Memory    memory     = parser->root.memory;
+      T1_Encoding  encode          = &face->type1.encoding;
+      FT_UInt      count, n;
+      PS_Table     char_table      = &loader->encoding_table;
+      FT_Memory    memory          = parser->root.memory;
       FT_Error     error;
+      FT_Bool      only_immediates = 0;
 
 
-      if ( encode->char_index )
-        /*  with synthetic fonts, it's possible we get here twice  */
-        return;
+      /* read the number of entries in the encoding; should be 256 */
+      if ( *cur == '[' )
+      {
+        count           = 256;
+        only_immediates = 1;
+        parser->root.cursor++;
+      }
+      else
+        count = (FT_UInt)T1_ToInt( parser );
 
-      /* read the number of entries in the encoding, should be 256 */
-      count = (FT_Int)T1_ToInt( parser );
-      if ( parser->root.error )
+      T1_Skip_Spaces( parser );
+      if ( parser->root.cursor >= limit )
         return;
 
       /* we use a T1_Table to store our charnames */
       loader->num_chars = encode->num_chars = count;
-      if ( FT_NEW_ARRAY( encode->char_index, count ) ||
-           FT_NEW_ARRAY( encode->char_name,  count ) ||
+      if ( FT_NEW_ARRAY( encode->char_index, count )     ||
+           FT_NEW_ARRAY( encode->char_name,  count )     ||
            FT_SET_ERROR( psaux->ps_table_funcs->init(
                            char_table, count, memory ) ) )
       {
@@ -356,86 +342,97 @@
         T1_Add_Table( char_table, n, notdef, 8 );
       }
 
-      /* Now, we will need to read a record of the form         */
-      /* ... charcode /charname ... for each entry in our table */
+      /* Now we need to read records of the form                */
       /*                                                        */
+      /*   ... charcode /charname ...                           */
+      /*                                                        */
+      /* for each entry in our table.                           */
+      /*                                                        */
       /* We simply look for a number followed by an immediate   */
       /* name.  Note that this ignores correctly the sequence   */
-      /* that is often seen in type1 fonts:                     */
+      /* that is often seen in type42 fonts:                    */
       /*                                                        */
       /*   0 1 255 { 1 index exch /.notdef put } for dup        */
       /*                                                        */
       /* used to clean the encoding array before anything else. */
       /*                                                        */
-      /* We stop when we encounter a `def'.                     */
+      /* Alternatively, if the array is directly given as       */
+      /*                                                        */
+      /*   /Encoding [ ... ]                                    */
+      /*                                                        */
+      /* we only read immediates.                               */
 
-      cur   = parser->root.cursor;
-      limit = parser->root.limit;
-      n     = 0;
+      n = 0;
 
-      for ( ; cur < limit; )
+      while ( parser->root.cursor < limit )
       {
-        FT_Byte  c;
+        T1_Skip_Spaces( parser );
+        cur = parser->root.cursor;
 
-
-        c = *cur;
-
-        /* we stop when we encounter a `def' */
-        if ( c == 'd' && cur + 3 < limit )
+        /* we stop when we encounter `def' or `]' */
+        if ( *cur == 'd' && cur + 3 < limit )
         {
-          if ( cur[1] == 'e'       &&
-               cur[2] == 'f'       &&
-               t42_is_space( cur[-1] ) &&
-               t42_is_space( cur[3] )  )
+          if ( cur[1] == 'e'          &&
+               cur[2] == 'f'          &&
+               t42_is_space( cur[3] ) )
           {
             FT_TRACE6(( "encoding end\n" ));
+            cur += 3;
             break;
           }
         }
+        if ( *cur == ']' )
+        {
+          FT_TRACE6(( "encoding end\n" ));
+          cur++;
+          break;
+        }
 
-        /* otherwise, we must find a number before anything else */
-        if ( ft_isdigit( c ) )
+        /* check whether we've found an entry */
+        if ( ft_isdigit( *cur ) || only_immediates )
         {
           FT_Int  charcode;
 
 
-          parser->root.cursor = cur;
-          charcode = (FT_Int)T1_ToInt( parser );
-          cur      = parser->root.cursor;
+          if ( only_immediates )
+            charcode = n;
+          else
+          {
+            charcode = (FT_Int)T1_ToInt( parser );
+            T1_Skip_Spaces( parser );
+          }
 
-          /* skip whitespace */
-          while ( cur < limit && t42_is_space( *cur ) )
-            cur++;
+          cur = parser->root.cursor;
 
-          if ( cur < limit && *cur == '/' )
+          if ( *cur == '/' && cur + 2 < limit && n < count )
           {
-            /* bingo, we have an immediate name -- it must be a */
-            /* character name                                   */
-            FT_Byte*    cur2 = cur + 1;
             FT_PtrDist  len;
 
 
-            while ( cur2 < limit && t42_is_alpha( *cur2 ) )
-              cur2++;
+            cur++;
 
-            len = cur2 - cur - 1;
+            parser->root.cursor = cur;
+            T1_Skip_PS_Token( parser );
 
+            len = parser->root.cursor - cur;
+
             parser->root.error = T1_Add_Table( char_table, charcode,
-                                               cur + 1, len + 1 );
+                                               cur, len + 1 );
             char_table->elements[charcode][len] = '\0';
             if ( parser->root.error )
               return;
 
-            cur = cur2;
+            n++;
           }
         }
         else
-          cur++;
+          T1_Skip_PS_Token( parser );
       }
 
       face->type1.encoding_type  = T1_ENCODING_TYPE_ARRAY;
       parser->root.cursor        = cur;
     }
+
     /* Otherwise, we should have either `StandardEncoding', */
     /* `ExpertEncoding', or `ISOLatin1Encoding'             */
     else
@@ -452,7 +449,8 @@
                 ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
         face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
 
-      else {
+      else
+      {
         FT_ERROR(( "t42_parse_encoding: invalid token!\n" ));
         parser->root.error = T42_Err_Invalid_File_Format;
       }
@@ -460,36 +458,15 @@
   }
 
 
-  static FT_UInt
-  t42_hexval( FT_Byte  v )
+  typedef enum
   {
-    FT_UInt  d;
+    BEFORE_START,
+    BEFORE_TABLE_DIR,
+    OTHER_TABLES
 
-    d = (FT_UInt)( v - 'A' );
-    if ( d < 6 )
-    {
-      d += 10;
-      goto Exit;
-    }
+  } T42_Load_Status;
 
-    d = (FT_UInt)( v - 'a' );
-    if ( d < 6 )
-    {
-      d += 10;
-      goto Exit;
-    }
 
-    d = (FT_UInt)( v - '0' );
-    if ( d < 10 )
-      goto Exit;
-
-    d = 0;
-
-  Exit:
-    return d;
-  }
-
-
   static void
   t42_parse_sfnts( T42_Face    face,
                    T42_Loader  loader )
@@ -496,154 +473,176 @@
   {
     T42_Parser  parser = &loader->parser;
     FT_Memory   memory = parser->root.memory;
-    FT_Byte*    cur    = parser->root.cursor;
+    FT_Byte*    cur;
     FT_Byte*    limit  = parser->root.limit;
     FT_Error    error;
-    FT_Int      num_tables = 0, status;
-    FT_ULong    count, ttf_size = 0, string_size = 0;
-    FT_Bool     in_string  = 0;
-    FT_Byte     v = 0;
+    FT_Int      num_tables = 0;
+    FT_ULong    count, ttf_size = 0;
 
+    FT_Long     n, string_size, old_string_size, real_size;
+    FT_Byte*    string_buf = NULL;
+    FT_Bool     alloc      = 0;
 
-    /* The format is `/sfnts [ <...> <...> ... ] def' */
+    T42_Load_Status  status;
 
-    while ( t42_is_space( *cur ) )
-      cur++;
 
-    if (*cur++ == '[')
+    /* The format is                                */
+    /*                                              */
+    /*   /sfnts [ <hexstring> <hexstring> ... ] def */
+    /*                                              */
+    /* or                                           */
+    /*                                              */
+    /*   /sfnts [                                   */
+    /*      <num_bin_bytes> RD <binary data>        */
+    /*      <num_bin_bytes> RD <binary data>        */
+    /*      ...                                     */
+    /*   ] def                                      */
+    /*                                              */
+    /* with exactly one space after the `RD' token. */
+
+    T1_Skip_Spaces( parser );
+
+    if ( parser->root.cursor >= limit || *parser->root.cursor++ != '[' )
     {
-      status = 0;
-      count = 0;
-    }
-    else
-    {
       FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector!\n" ));
       error = T42_Err_Invalid_File_Format;
       goto Fail;
     }
 
-    while ( cur < limit - 2 )
+    T1_Skip_Spaces( parser );
+    status          = BEFORE_START;
+    old_string_size = 0;
+    count           = 0;
+
+    while ( parser->root.cursor < limit )
     {
-      while ( t42_is_space( *cur ) )
-        cur++;
+      cur = parser->root.cursor;
 
-      switch ( *cur )
+      if ( *cur == ']' )
       {
-      case ']':
-        parser->root.cursor = cur++;
-        return;
+        parser->root.cursor++;
+        goto Exit;
+      }
 
-      case '<':
-        in_string   = 1;
-        string_size = 0;
-        cur++;
-        continue;
+      else if ( *cur == '<' )
+      {
+        T1_Skip_PS_Token( parser );
+        if ( parser->root.error )
+          goto Exit;
 
-      case '>':
-        if ( !in_string )
-        {
-          FT_ERROR(( "t42_parse_sfnts: found unpaired `>'!\n" ));
-          error = T42_Err_Invalid_File_Format;
+        /* don't include delimiters */
+        string_size = (FT_Long)( ( parser->root.cursor - cur - 2 + 1 ) / 2 );
+        if ( FT_REALLOC( string_buf, old_string_size, string_size ) )
           goto Fail;
-        }
 
-        /* A string can have, as a last byte,         */
-        /* a zero byte for padding.  If so, ignore it */
-        if ( ( v == 0 ) && ( string_size % 2 == 1 ) )
-          count--;
-        in_string = 0;
-        cur++;
-        continue;
+        alloc = 1;
 
-      case '%':
-        if ( !in_string )
-        {
-          /* Comment found; skip till end of line */
-          while ( *cur != '\n' )
-            cur++;
-          continue;
-        }
-        else
-        {
-          FT_ERROR(( "t42_parse_sfnts: found `%' in string!\n" ));
-          error = T42_Err_Invalid_File_Format;
-          goto Fail;
-        }
+        parser->root.cursor = cur;
+        (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 );
+        old_string_size = string_size;
+        string_size = real_size;
+      }
 
-      default:
-        if ( !ft_isxdigit( *cur ) || !ft_isxdigit( *(cur + 1) ) )
+      else if ( ft_isdigit( *cur ) )
+      {
+        string_size = T1_ToInt( parser );
+
+        T1_Skip_PS_Token( parser );             /* `RD' */
+
+        string_buf = parser->root.cursor + 1;   /* one space after `RD' */
+
+        parser->root.cursor += string_size + 1;
+        if ( parser->root.cursor >= limit )
         {
-          FT_ERROR(( "t42_parse_sfnts: found non-hex characters in string" ));
+          FT_ERROR(( "t42_parse_sfnts: too many binary data!\n" ));
           error = T42_Err_Invalid_File_Format;
           goto Fail;
         }
-
-        v = (FT_Byte)( 16 * t42_hexval( cur[0] ) + t42_hexval( cur[1] ) );
-        cur += 2;
-        string_size++;
       }
 
-      switch ( status )
+      /* A string can have a trailing zero byte for padding.  Ignore it. */
+      if ( string_buf[string_size - 1] == 0 && ( string_size % 2 == 1 ) )
+        string_size--;
+
+      for ( n = 0; n < string_size; n++ )
       {
-      case 0: /* The '[' was read, so load offset table, 12 bytes */
-        if ( count < 12 )
+        switch ( status )
         {
-          face->ttf_data[count++] = v;
-          continue;
-        }
-        else
-        {
-          num_tables = 16 * face->ttf_data[4] + face->ttf_data[5];
-          status     = 1;
-          ttf_size   = 12 + 16 * num_tables;
+        case BEFORE_START:
+          /* load offset table, 12 bytes */
+          if ( count < 12 )
+          {
+            face->ttf_data[count++] = string_buf[n];
+            continue;
+          }
+          else
+          {
+            num_tables = 16 * face->ttf_data[4] + face->ttf_data[5];
+            status     = BEFORE_TABLE_DIR;
+            ttf_size   = 12 + 16 * num_tables;
 
-          if ( FT_REALLOC( face->ttf_data, 12, ttf_size ) )
-            goto Fail;
-        }
-        /* No break, fall-through */
+            if ( FT_REALLOC( face->ttf_data, 12, ttf_size ) )
+              goto Fail;
+          }
+          /* fall through */
 
-      case 1: /* The offset table is read; read now the table directory */
-        if ( count < ttf_size )
-        {
-          face->ttf_data[count++] = v;
-          continue;
-        }
-        else
-        {
-          int      i;
-          FT_ULong len;
+        case BEFORE_TABLE_DIR:
+          /* the offset table is read; read the table directory */
+          if ( count < ttf_size )
+          {
+            face->ttf_data[count++] = string_buf[n];
+            continue;
+          }
+          else
+          {
+            int       i;
+            FT_ULong  len;
 
 
-          for ( i = 0; i < num_tables; i++ )
-          {
-            FT_Byte*  p = face->ttf_data + 12 + 16*i + 12;
+            for ( i = 0; i < num_tables; i++ )
+            {
+              FT_Byte*  p = face->ttf_data + 12 + 16 * i + 12;
 
-            len = FT_PEEK_ULONG( p );
 
-            /* Pad to a 4-byte boundary length */
-            ttf_size += ( len + 3 ) & ~3;
-          }
+              len = FT_PEEK_ULONG( p );
 
-          status         = 2;
-          face->ttf_size = ttf_size;
+              /* Pad to a 4-byte boundary length */
+              ttf_size += ( len + 3 ) & ~3;
+            }
 
-          if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables,
-                           ttf_size + 1 ) )
-            goto Fail;
-        }
-        /* No break, fall-through */
+            status         = OTHER_TABLES;
+            face->ttf_size = ttf_size;
 
-      case 2: /* We are reading normal tables; just swallow them */
-        face->ttf_data[count++] = v;
+            if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables,
+                             ttf_size + 1 ) )
+              goto Fail;
+          }
+          /* fall through */
 
+        case OTHER_TABLES:
+          /* all other tables are just copied */
+          if ( count >= ttf_size )
+          {
+            FT_ERROR(( "t42_parse_sfnts: too many binary data!\n" ));
+            error = T42_Err_Invalid_File_Format;
+            goto Fail;
+          }
+          face->ttf_data[count++] = string_buf[n];
+        }
       }
+
+      T1_Skip_Spaces( parser );
     }
 
-    /* If control reaches this point, the format was not valid */
+    /* if control reaches this point, the format was not valid */
     error = T42_Err_Invalid_File_Format;
 
   Fail:
     parser->root.error = error;
+
+  Exit:
+    if ( alloc )
+      FT_FREE( string_buf );
   }
 
 
@@ -651,23 +650,76 @@
   t42_parse_charstrings( T42_Face    face,
                          T42_Loader  loader )
   {
-    T42_Parser     parser     = &loader->parser;
-    PS_Table       code_table = &loader->charstrings;
-    PS_Table       name_table = &loader->glyph_names;
-    FT_Memory      memory     = parser->root.memory;
+    T42_Parser     parser       = &loader->parser;
+    PS_Table       code_table   = &loader->charstrings;
+    PS_Table       name_table   = &loader->glyph_names;
+    PS_Table       swap_table   = &loader->swap_table;
+    FT_Memory      memory       = parser->root.memory;
     FT_Error       error;
 
-    PSAux_Service  psaux      = (PSAux_Service)face->psaux;
+    PSAux_Service  psaux        = (PSAux_Service)face->psaux;
 
     FT_Byte*       cur;
-    FT_Byte*       limit      = parser->root.limit;
-    FT_Int         n;
+    FT_Byte*       limit        = parser->root.limit;
+    FT_UInt        n;
+    FT_UInt        notdef_index = 0;
+    FT_Byte        notdef_found = 0;
 
 
-    loader->num_glyphs = (FT_Int)T1_ToInt( parser );
-    if ( parser->root.error )
-      return;
+    T1_Skip_Spaces( parser );
 
+    if ( parser->root.cursor >= limit )
+    {
+      FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" ));
+      error = T42_Err_Invalid_File_Format;
+      goto Fail;
+    }
+
+    if ( ft_isdigit( *parser->root.cursor ) )
+    {
+      loader->num_glyphs = (FT_UInt)T1_ToInt( parser );
+      if ( parser->root.error )
+        return;
+    }
+    else if ( *parser->root.cursor == '<' )
+    {
+      /* We have `<< ... >>'.  Count the number of `/' in the dictionary */
+      /* to get its size.                                                */
+      FT_UInt  count = 0;
+
+
+      T1_Skip_PS_Token( parser );
+      T1_Skip_Spaces( parser );
+      cur = parser->root.cursor;
+
+      while ( parser->root.cursor < limit )
+      {
+        if ( *parser->root.cursor == '/' )
+          count++;
+        else if ( *parser->root.cursor == '>' )
+        {
+          loader->num_glyphs  = count;
+          parser->root.cursor = cur;        /* rewind */
+          break;
+        }
+        T1_Skip_PS_Token( parser );
+        T1_Skip_Spaces( parser );
+      }
+    }
+    else
+    {
+      FT_ERROR(( "t42_parse_charstrings: invalid token!\n" ));
+      error = T42_Err_Invalid_File_Format;
+      goto Fail;
+    }
+
+    if ( parser->root.cursor >= limit )
+    {
+      FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" ));
+      error = T42_Err_Invalid_File_Format;
+      goto Fail;
+    }
+
     /* initialize tables */
 
     error = psaux->ps_table_funcs->init( code_table,
@@ -682,15 +734,20 @@
     if ( error )
       goto Fail;
 
+    /* Initialize table for swapping index notdef_index and */
+    /* index 0 names and codes (if necessary).              */
+
+    error = psaux->ps_table_funcs->init( swap_table, 4, memory );
+    if ( error )
+      goto Fail;
+
     n = 0;
 
     for (;;)
     {
-      /* the format is simple:                    */
-      /*   `/glyphname' + index + def             */
-      /*                                          */
-      /* note that we stop when we find an `end'  */
-      /*                                          */
+      /* The format is simple:                   */
+      /*   `/glyphname' + index [+ def]          */
+
       T1_Skip_Spaces( parser );
 
       cur = parser->root.cursor;
@@ -697,26 +754,34 @@
       if ( cur >= limit )
         break;
 
-      /* we stop when we find an `end' keyword */
-      if ( *cur   == 'e'   &&
-           cur + 3 < limit &&
-           cur[1] == 'n'   &&
-           cur[2] == 'd'   )
+      /* We stop when we find an `end' keyword or '>' */
+      if ( *cur   == 'e'          &&
+           cur + 3 < limit        &&
+           cur[1] == 'n'          &&
+           cur[2] == 'd'          &&
+           t42_is_space( cur[3] ) )
         break;
+      if ( *cur == '>' )
+        break;
 
-      if ( *cur != '/' )
-        T1_Skip_PS_Token( parser );
-      else
+      T1_Skip_PS_Token( parser );
+
+      if ( *cur == '/' )
       {
-        FT_Byte*  cur2 = cur + 1;
-        FT_Int    len;
+        FT_PtrDist  len;
 
 
-        while ( cur2 < limit && t42_is_alpha( *cur2 ) )
-          cur2++;
-        len = (FT_Int)( cur2 - cur - 1 );
+        if ( cur + 1 >= limit )
+        {
+          FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" ));
+          error = T42_Err_Invalid_File_Format;
+          goto Fail;
+        }
 
-        error = T1_Add_Table( name_table, n, cur + 1, len + 1 );
+        cur++;                              /* skip `/' */
+        len = parser->root.cursor - cur;
+
+        error = T1_Add_Table( name_table, n, cur, len + 1 );
         if ( error )
           goto Fail;
 
@@ -723,17 +788,29 @@
         /* add a trailing zero to the name table */
         name_table->elements[n][len] = '\0';
 
-        parser->root.cursor = cur2;
+        /* record index of /.notdef */
+        if ( *cur == '.'                                              &&
+             ft_strcmp( ".notdef",
+                        (const char*)(name_table->elements[n]) ) == 0 )
+        {
+          notdef_index = n;
+          notdef_found = 1;
+        }
+
         T1_Skip_Spaces( parser );
 
-        cur2 = cur = parser->root.cursor;
-        if ( cur >= limit )
-          break;
+        cur = parser->root.cursor;
 
-        while ( cur2 < limit && t42_is_alpha( *cur2 ) )
-          cur2++;
-        len = (FT_Int)( cur2 - cur );
+        (void)T1_ToInt( parser );
+        if ( parser->root.cursor >= limit )
+        {
+          FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" ));
+          error = T42_Err_Invalid_File_Format;
+          goto Fail;
+        }
 
+        len = parser->root.cursor - cur;
+
         error = T1_Add_Table( code_table, n, cur, len + 1 );
         if ( error )
           goto Fail;
@@ -746,15 +823,79 @@
       }
     }
 
-    /* Index 0 must be a .notdef element */
-    if ( ft_strcmp( (char *)name_table->elements[0], ".notdef" ) )
+    loader->num_glyphs = n;
+
+    if ( !notdef_found )
     {
-      FT_ERROR(( "t42_parse_charstrings: Index 0 is not `.notdef'!\n" ));
+      FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph!\n" ));
       error = T42_Err_Invalid_File_Format;
       goto Fail;
     }
 
-    loader->num_glyphs = n;
+    /* if /.notdef does not occupy index 0, do our magic. */
+    if ( ft_strcmp( (const char*)".notdef",
+                    (const char*)name_table->elements[0] ) )
+    {
+      /* Swap glyph in index 0 with /.notdef glyph.  First, add index 0  */
+      /* name and code entries to swap_table.  Then place notdef_index   */
+      /* name and code entries into swap_table.  Then swap name and code */
+      /* entries at indices notdef_index and 0 using values stored in    */
+      /* swap_table.                                                     */
+
+      /* Index 0 name */
+      error = T1_Add_Table( swap_table, 0,
+                            name_table->elements[0],
+                            name_table->lengths [0] );
+      if ( error )
+        goto Fail;
+
+      /* Index 0 code */
+      error = T1_Add_Table( swap_table, 1,
+                            code_table->elements[0],
+                            code_table->lengths [0] );
+      if ( error )
+        goto Fail;
+
+      /* Index notdef_index name */
+      error = T1_Add_Table( swap_table, 2,
+                            name_table->elements[notdef_index],
+                            name_table->lengths [notdef_index] );
+      if ( error )
+        goto Fail;
+
+      /* Index notdef_index code */
+      error = T1_Add_Table( swap_table, 3,
+                            code_table->elements[notdef_index],
+                            code_table->lengths [notdef_index] );
+      if ( error )
+        goto Fail;
+
+      error = T1_Add_Table( name_table, notdef_index,
+                            swap_table->elements[0],
+                            swap_table->lengths [0] );
+      if ( error )
+        goto Fail;
+
+      error = T1_Add_Table( code_table, notdef_index,
+                            swap_table->elements[1],
+                            swap_table->lengths [1] );
+      if ( error )
+        goto Fail;
+
+      error = T1_Add_Table( name_table, 0,
+                            swap_table->elements[2],
+                            swap_table->lengths [2] );
+      if ( error )
+        goto Fail;
+
+      error = T1_Add_Table( code_table, 0,
+                            swap_table->elements[3],
+                            swap_table->lengths [3] );
+      if ( error )
+        goto Fail;
+
+    }
+
     return;
 
   Fail:
@@ -774,14 +915,16 @@
 
 
     /* if the keyword has a dedicated callback, call it */
-    if ( field->type == T1_FIELD_TYPE_CALLBACK ) {
+    if ( field->type == T1_FIELD_TYPE_CALLBACK )
+    {
       field->reader( (FT_Face)face, loader );
       error = loader->parser.root.error;
       goto Exit;
     }
 
-    /* now, the keyword is either a simple field, or a table of fields; */
-    /* we are now going to take care of it                              */
+    /* now the keyword is either a simple field or a table of fields; */
+    /* we are now going to take care of it                            */
+
     switch ( field->location )
     {
     case T1_FIELD_LOCATION_FONT_INFO:
@@ -818,28 +961,27 @@
                   FT_Long     size )
   {
     T42_Parser  parser     = &loader->parser;
-    FT_Byte*    cur        = base;
-    FT_Byte*    limit      = cur + size;
-    FT_UInt     n_keywords = (FT_UInt)( sizeof ( t42_keywords ) /
-                                        sizeof ( t42_keywords[0] ) );
+    FT_Byte*    limit;
+    int         n_keywords = sizeof ( t42_keywords ) /
+                               sizeof ( t42_keywords[0] );
 
-    FT_Byte     keyword_flags[T42_KEYWORD_COUNT];
 
-    {
-      FT_UInt  n;
-
-
-      for ( n = 0; n < T42_KEYWORD_COUNT; n++ )
-        keyword_flags[n] = 0;
-    }
-
     parser->root.cursor = base;
     parser->root.limit  = base + size;
-    parser->root.error  = 0;
+    parser->root.error  = T42_Err_Ok;
 
-    for ( ; cur < limit; cur++ )
+    limit = parser->root.limit;
+
+    T1_Skip_Spaces( parser );
+
+    while ( parser->root.cursor < limit )
     {
-      /* look for `FontDirectory', which causes problems on some fonts */
+      FT_Byte*  cur;
+
+
+      cur = parser->root.cursor;
+
+      /* look for `FontDirectory' which causes problems for some fonts */
       if ( *cur == 'F' && cur + 25 < limit                    &&
            ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
       {
@@ -847,14 +989,22 @@
 
 
         /* skip the `FontDirectory' keyword */
-        cur += 13;
-        cur2 = cur;
+        T1_Skip_PS_Token( parser );
+        T1_Skip_Spaces  ( parser );
+        cur = cur2 = parser->root.cursor;
 
-        /* lookup the `known' keyword */
-        while ( cur < limit && *cur != 'k'           &&
-                ft_strncmp( (char*)cur, "known", 5 ) )
-          cur++;
+        /* look up the `known' keyword */
+        while ( cur < limit )
+        {
+          if ( *cur == 'k' && cur + 5 < limit             &&
+                ft_strncmp( (char*)cur, "known", 5 ) == 0 )
+            break;
 
+          T1_Skip_PS_Token( parser );
+          T1_Skip_Spaces  ( parser );
+          cur = parser->root.cursor;
+        }
+
         if ( cur < limit )
         {
           T1_TokenRec  token;
@@ -861,34 +1011,37 @@
 
 
           /* skip the `known' keyword and the token following it */
-          cur += 5;
-          loader->parser.root.cursor = cur;
-          T1_ToToken( &loader->parser, &token );
+          T1_Skip_PS_Token( parser );
+          T1_ToToken( parser, &token );
 
           /* if the last token was an array, skip it! */
           if ( token.type == T1_TOKEN_TYPE_ARRAY )
             cur2 = parser->root.cursor;
         }
-        cur = cur2;
+        parser->root.cursor = cur2;
       }
+
       /* look for immediates */
       else if ( *cur == '/' && cur + 2 < limit )
       {
-        FT_Byte*  cur2;
-        FT_UInt    i, len;
+        FT_PtrDist  len;
 
 
         cur++;
-        cur2 = cur;
-        while ( cur2 < limit && t42_is_alpha( *cur2 ) )
-          cur2++;
 
-        len  = (FT_UInt)( cur2 - cur );
-        if ( len > 0 && len < 22 ) /* XXX What shall it this 22? */
+        parser->root.cursor = cur;
+        T1_Skip_PS_Token( parser );
+
+        len = parser->root.cursor - cur;
+
+        if ( len > 0 && len < 22 && parser->root.cursor < limit )
         {
-          /* now, compare the immediate name to the keyword table */
+          int  i;
 
-          /* Loop through all known keywords */
+
+          /* now compare the immediate name to the keyword table */
+
+          /* loop through all known keywords */
           for ( i = 0; i < n_keywords; i++ )
           {
             T1_Field  keyword = (T1_Field)&t42_keywords[i];
@@ -898,32 +1051,27 @@
             if ( !name )
               continue;
 
-            if ( ( len == ft_strlen( (const char *)name ) ) &&
-                 ( ft_memcmp( cur, name, len ) == 0 )       )
+            if ( cur[0] == name[0]                      && 
+                 len == ft_strlen( (const char *)name ) &&
+                 ft_memcmp( cur, name, len ) == 0       )
             {
               /* we found it -- run the parsing callback! */
-              parser->root.cursor = cur2;
-              T1_Skip_Spaces( parser );
-
-              /* only record the first instance of each field/keyword */
-              /* to deal with synthetic fonts correctly               */
-              if ( keyword_flags[i] == 0 )
-              {
-                parser->root.error = t42_load_keyword(face,
-                                                      loader,
-                                                      keyword );
-                if ( parser->root.error )
-                  return parser->root.error;
-              }
-              keyword_flags[i] = 1;
-
-              cur = parser->root.cursor;
+              parser->root.error = t42_load_keyword( face,
+                                                     loader,
+                                                     keyword );
+              if ( parser->root.error )
+                return parser->root.error;
               break;
             }
           }
         }
       }
+      else
+        T1_Skip_PS_Token( parser );
+
+      T1_Skip_Spaces( parser );
     }
+
     return parser->root.error;
   }
 
@@ -955,6 +1103,7 @@
     T1_Release_Table( &loader->encoding_table );
     T1_Release_Table( &loader->charstrings );
     T1_Release_Table( &loader->glyph_names );
+    T1_Release_Table( &loader->swap_table );
 
     /* finalize parser */
     t42_parser_done( parser );
--- a/src/type42/t42parse.h
+++ b/src/type42/t42parse.h
@@ -33,7 +33,7 @@
     FT_Byte*      base_dict;
     FT_Long       base_len;
 
-    FT_Byte       in_memory;
+    FT_Bool       in_memory;
 
   } T42_ParserRec, *T42_Parser;
 
@@ -42,13 +42,14 @@
   {
     T42_ParserRec  parser;          /* parser used to read the stream */
 
-    FT_Int         num_chars;       /* number of characters in encoding */
+    FT_UInt        num_chars;       /* number of characters in encoding */
     PS_TableRec    encoding_table;  /* PS_Table used to store the       */
                                     /* encoding character names         */
 
-    FT_Int         num_glyphs;
+    FT_UInt        num_glyphs;
     PS_TableRec    glyph_names;
     PS_TableRec    charstrings;
+    PS_TableRec    swap_table;      /* For moving .notdef glyph to index 0. */
 
   } T42_LoaderRec, *T42_Loader;