shithub: freetype+ttf2subf

Download patch

ref: c011f4cba1a0ff57a5abb400ad8b30dad7b38a88
parent: a2da05c2c539c603aa3587a1acb07bff8cdab599
author: Werner Lemberg <[email protected]>
date: Mon Jun 26 05:40:00 EDT 2006

The Type 1 parser now skips over top-level procedures as required
for a `Simplified Parser'.  This makes the parser more robust as it
doesn't poke around in PostScript code.  Additionally, it makes the
FontDirectory hackery in src/type1/t1load.c unnecessary.

* src/psaux/psobjs.c (IS_OCTAL_DIGIT): New macro.
(skip_literal_string): Add FT_Error as return value.
Handle escapes better.
(skip_string): Add FT_Error as return value.
Don't set `parser->error' but return error code directly.
(skip_procedure): New function.
(ps_parser_skip_PS_token): Handle procedures.
Update code.
(ps_parser_to_token): Update code.
(ps_parser_load_field_table): Handle bbox entries also.

* src/type1/t1load.c (parse_dict): Remove FontDirectory hackery.
Add commented-out code for synthetic fonts.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2006-06-25  Jens Claudius  <[email protected]>
+
+	The Type 1 parser now skips over top-level procedures as required
+	for a `Simplified Parser'.  This makes the parser more robust as it
+	doesn't poke around in PostScript code.  Additionally, it makes the
+	FontDirectory hackery in src/type1/t1load.c unnecessary.
+
+	* src/psaux/psobjs.c (IS_OCTAL_DIGIT): New macro.
+	(skip_literal_string): Add FT_Error as return value.
+	Handle escapes better.
+	(skip_string): Add FT_Error as return value.
+	Don't set `parser->error' but return error code directly.
+	(skip_procedure): New function.
+	(ps_parser_skip_PS_token): Handle procedures.
+	Update code.
+	(ps_parser_to_token): Update code.
+	(ps_parser_load_field_table): Handle bbox entries also.
+
+	* src/type1/t1load.c (parse_dict): Remove FontDirectory hackery.
+	Add commented-out code for synthetic fonts.
+
 2006-06-24  Eugeniy Meshcheryakov  <[email protected]>
 
 	Fix two hinting bugs as reported in
--- a/src/psaux/psobjs.c
+++ b/src/psaux/psobjs.c
@@ -312,45 +312,94 @@
   }
 
 
-  /* first character must be `(' */
+#define IS_OCTAL_DIGIT( c ) ( '0' <= (c) && (c) <= '7' )
 
-  static void
+
+  /* first character must be `(';                               */
+  /* *acur is positioned at the character after the closing `)' */
+
+  static FT_Error
   skip_literal_string( FT_Byte*  *acur,
                        FT_Byte*   limit )
   {
-    FT_Byte*  cur   = *acur;
-    FT_Int    embed = 0;
+    FT_Byte*      cur   = *acur;
+    FT_Int        embed = 0;
+    FT_Error      error = PSaux_Err_Invalid_File_Format;
+    unsigned int  i;
 
 
     while ( cur < limit )
     {
-      if ( *cur == '\\' )
-        cur++;
-      else if ( *cur == '(' )
+      FT_Byte  c = *cur;
+
+
+      ++cur;
+
+      if ( c == '\\' )
+      {
+        /* Red Book 3rd ed., section `Literal Text Strings', p. 29:     */
+        /* A backslash can introduce three different types              */
+        /* of escape sequences:                                         */
+        /*   - a special escaped char like \r, \n, etc.                 */
+        /*   - a one-, two-, or three-digit octal number                */
+        /*   - none of the above in which case the backslash is ignored */
+
+        if ( cur == limit )
+          /* error (or to be ignored?) */
+          break;
+
+        switch ( *cur )
+        {
+          /* skip `special' escape */
+        case 'n':
+        case 'r':
+        case 't':
+        case 'b':
+        case 'f':
+        case '\\':
+        case '(':
+        case ')':
+          ++cur;
+          break;
+
+        default:
+          /* skip octal escape or ignore backslash */
+          for ( i = 0; i < 3 && cur < limit; ++i )
+          {
+            if ( ! IS_OCTAL_DIGIT( *cur ) )
+              break;
+
+            ++cur;
+          }
+        }
+      }
+      else if ( c == '(' )
         embed++;
-      else if ( *cur == ')' )
+      else if ( c == ')' )
       {
         embed--;
         if ( embed == 0 )
         {
-          cur++;
+          error = PSaux_Err_Ok;
           break;
         }
       }
-      cur++;
     }
 
     *acur = cur;
+
+    return error;
   }
 
 
   /* first character must be `<' */
 
-  static void
-  skip_string( PS_Parser  parser )
+  static FT_Error
+  skip_string( FT_Byte*  *acur,
+               FT_Byte*   limit )
   {
-    FT_Byte*  cur   = parser->cursor;
-    FT_Byte*  limit = parser->limit;
+    FT_Byte*  cur = *acur;
+    FT_Error  err =  PSaux_Err_Ok;
 
 
     while ( ++cur < limit )
@@ -367,15 +416,75 @@
     if ( cur < limit && *cur != '>' )
     {
       FT_ERROR(( "skip_string: missing closing delimiter `>'\n" ));
-      parser->error = PSaux_Err_Invalid_File_Format;
+      err = PSaux_Err_Invalid_File_Format;
     }
     else
       cur++;
 
-    parser->cursor = cur;
+    *acur = cur;
+    return err;
   }
 
 
+  /* first character must be the opening brace that */
+  /* starts the procedure                           */
+
+  /* NB: [ and ] need not match:                    */
+  /* `/foo {[} def' is a valid PostScript fragment, */
+  /* even within a Type1 font                       */
+
+  static FT_Error
+  skip_procedure( FT_Byte*  *acur,
+                  FT_Byte*   limit )
+  {
+    FT_Byte*  cur;
+    FT_Int    embed = 0;
+    FT_Error  error = PSaux_Err_Ok;
+
+
+    FT_ASSERT( **acur == '{' );
+
+    for ( cur = *acur; cur < limit && error == PSaux_Err_Ok; ++cur )
+    {
+      switch ( *cur )
+      {
+      case '{':
+        ++embed;
+        break;
+
+      case '}':
+        --embed;
+        if ( embed == 0 )
+        {
+          ++cur;
+          goto end;
+        }
+        break;
+
+      case '(':
+        error = skip_literal_string( &cur, limit );
+        break;
+
+      case '<':
+        error = skip_string( &cur, limit );
+        break;
+
+      case '%':
+        skip_comment( &cur, limit );
+        break;
+      }
+    }
+
+  end:
+    if ( embed != 0 )
+      error = PSaux_Err_Invalid_File_Format;
+
+    *acur = cur;
+
+    return error;
+  }
+
+
   /***********************************************************************/
   /*                                                                     */
   /* All exported parsing routines handle leading whitespace and stop at */
@@ -393,6 +502,7 @@
 
     FT_Byte*  cur   = parser->cursor;
     FT_Byte*  limit = parser->limit;
+    FT_Error  error = PSaux_Err_Ok;
 
 
     skip_spaces( &cur, limit );             /* this also skips comments */
@@ -400,16 +510,23 @@
       goto Exit;
 
     /* self-delimiting, single-character tokens */
-    if ( *cur == '[' || *cur == ']' ||
-         *cur == '{' || *cur == '}' )
+    if ( *cur == '[' || *cur == ']' )
     {
       cur++;
       goto Exit;
     }
 
+    /* skip balanced expressions (procedures and strings) */
+
+    if ( *cur == '{' )                              /* {...} */
+    {
+      error = skip_procedure( &cur, limit );
+      goto Exit;
+    }
+
     if ( *cur == '(' )                              /* (...) */
     {
-      skip_literal_string( &cur, limit );
+      error = skip_literal_string( &cur, limit );
       goto Exit;
     }
 
@@ -419,11 +536,11 @@
       {
         cur++;
         cur++;
-        goto Exit;
       }
-      parser->cursor = cur;
-      skip_string( parser );
-      return;
+      else
+        error = skip_string( &cur, limit );
+
+      goto Exit;
     }
 
     if ( *cur == '>' )
@@ -433,7 +550,7 @@
       {
         FT_ERROR(( "ps_parser_skip_PS_token: "
                    "unexpected closing delimiter `>'\n" ));
-        parser->error = PSaux_Err_Invalid_File_Format;
+        error = PSaux_Err_Invalid_File_Format;
         goto Exit;
       }
       cur++;
@@ -446,14 +563,9 @@
     /* anything else */
     while ( cur < limit )
     {
-      if ( *cur == ')' )
-      {
-        FT_ERROR(( "ps_parser_skip_PS_token: "
-                   "unexpected closing delimiter `)'\n" ));
-        parser->error = PSaux_Err_Invalid_File_Format;
-        goto Exit;
-      }
-      else if ( IS_PS_DELIM( *cur ) )
+      /* `*cur' might be invalid (e.g., `)' or `}'), but this is handled */
+      /* by the caller which will see this when it continues parsing     */
+      if ( IS_PS_DELIM( *cur ) )
         break;
 
       cur++;
@@ -460,6 +572,8 @@
     }
 
   Exit:
+    FT_ASSERT( parser->error == PSaux_Err_Ok );
+    parser->error  = error;
     parser->cursor = cur;
   }
 
@@ -480,7 +594,6 @@
   {
     FT_Byte*  cur;
     FT_Byte*  limit;
-    FT_Byte   starter, ender;
     FT_Int    embed;
 
 
@@ -503,26 +616,27 @@
     case '(':
       token->type  = T1_TOKEN_TYPE_STRING;
       token->start = cur;
-      skip_literal_string( &cur, limit );
-      if ( cur < limit )
+
+      if ( skip_literal_string( &cur, limit ) == PSaux_Err_Ok )
         token->limit = cur;
       break;
 
       /************* check for programs/array *****************/
     case '{':
-      token->type = T1_TOKEN_TYPE_ARRAY;
-      ender = '}';
-      goto Lookup_Ender;
+      token->type  = T1_TOKEN_TYPE_ARRAY;
+      token->start = cur;
 
+      if ( skip_procedure( &cur, limit ) == PSaux_Err_Ok )
+        token->limit = cur;
+      break;
+
       /************* check for table/array ********************/
+      /* XXX: in theory we should also look for "<<"          */
+      /*      since this is semantically equivalent to "[";   */
+      /*      in practice it doesn't matter (?)               */
     case '[':
-      token->type = T1_TOKEN_TYPE_ARRAY;
-      ender = ']';
-      /* fall through */
-
-    Lookup_Ender:
+      token->type  = T1_TOKEN_TYPE_ARRAY;
       embed        = 1;
-      starter      = *cur;
       token->start = cur++;
 
       /* we need this to catch `[ ]' */
@@ -532,9 +646,11 @@
 
       while ( cur < limit && !parser->error )
       {
-        if ( *cur == starter )
+        /* XXX: this is wrong because it does not      */
+        /*      skip comments, procedures, and strings */
+        if ( *cur == '[' )
           embed++;
-        else if ( *cur == ender )
+        else if ( *cur == ']' )
         {
           embed--;
           if ( embed <= 0 )
@@ -1038,11 +1154,10 @@
     T1_FieldRec  fieldrec = *(T1_Field)field;
 
 
-#if 1
     fieldrec.type = T1_FIELD_TYPE_INTEGER;
-    if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY )
+    if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY ||
+         field->type == T1_FIELD_TYPE_BBOX        )
       fieldrec.type = T1_FIELD_TYPE_FIXED;
-#endif
 
     ps_parser_to_token_array( parser, elements,
                               T1_MAX_TABLE_ELEMENTS, &num_elements );
@@ -1057,9 +1172,10 @@
     old_cursor = parser->cursor;
     old_limit  = parser->limit;
 
-    /* we store the elements count */
-    *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) =
-      (FT_Byte)num_elements;
+    /* we store the elements count if necessary */
+    if ( field->type != T1_FIELD_TYPE_BBOX )
+      *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) =
+        (FT_Byte)num_elements;
 
     /* we now load each element, adjusting the field.offset on each one */
     token = elements;
--- a/src/type1/t1load.c
+++ b/src/type1/t1load.c
@@ -242,7 +242,7 @@
 
         return axismap->design_points[j - 1] +
                  FT_MulDiv( t,
-                            axismap->design_points[j] - 
+                            axismap->design_points[j] -
                               axismap->design_points[j - 1],
                             1L );
       }
@@ -732,7 +732,7 @@
     FT_Memory    memory = face->root.memory;
 
 
-    T1_ToTokenArray( parser, axis_tokens, 
+    T1_ToTokenArray( parser, axis_tokens,
                      T1_MAX_MM_AXIS, &num_axis );
     if ( num_axis < 0 )
     {
@@ -1724,59 +1724,32 @@
 
       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 )
-      {
-        FT_Byte*  cur2;
-
-
-        /* skip the `FontDirectory' keyword */
-        T1_Skip_PS_Token( parser );
-        T1_Skip_Spaces  ( parser );
-        cur = cur2 = parser->root.cursor;
-
-        /* 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 );
-          if ( parser->root.error )
-            goto Exit;
-          T1_Skip_Spaces( parser );
-          cur = parser->root.cursor;
-        }
-
-        if ( cur < limit )
-        {
-          T1_TokenRec  token;
-
-
-          /* skip the `known' keyword and the token following it */
-          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;
-        }
-        parser->root.cursor = cur2;
-        have_integer = 0;
-      }
-
-      /* look for `eexec' */
-      else if ( *cur == 'e' && cur + 5 < limit &&
-                ft_strncmp( (char*)cur, "eexec", 5 ) == 0 )
+      /* cur[5] must be a token delimiter;                 */
+      /* eexec encryption is optional, so look for `eexec' */
+      if ( *cur == 'e' && cur + 5 < limit            &&
+           ft_strncmp( (char*)cur, "eexec", 5 ) == 0 )
         break;
 
+      /* cur[9] must be a token delimiter;                 */
       /* look for `closefile' which ends the eexec section */
-      else if ( *cur == 'c' && cur + 9 < limit &&
+      else if ( *cur == 'c' && cur + 9 < limit                &&
                 ft_strncmp( (char*)cur, "closefile", 9 ) == 0 )
         break;
 
+#ifdef TO_BE_DONE
+      /* in a synthetic font the base font starts after a           */
+      /* `FontDictionary' token that is placed after a Private dict */
+
+      /* cur[13] must be a token delimiter */
+      else if ( *cur == 'F' && cur + 13 < limit                    &&
+                ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
+      {
+        if ( loader->private_encountered )
+          loader->fontdir_after_private = 1;
+        parser->root.cursor += 13;
+      }
+#endif
+
       /* check whether we have an integer */
       else if ( ft_isdigit( *cur ) )
       {
@@ -1969,8 +1942,8 @@
 
     {
       FT_UInt  n;
-      
 
+
       for ( n = 0; n < T1_FIELD_COUNT; n++ )
         keyword_flags[n] = 0;
     }
@@ -1989,7 +1962,7 @@
                         keyword_flags );
     if ( error )
       goto Exit;
- 
+
     /* ensure even-ness of `num_blue_values' */
     priv->num_blue_values &= ~1;