Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /***************************************************************************/
  2. /*                                                                         */
  3. /*  t1parse.c                                                              */
  4. /*                                                                         */
  5. /*    Type 1 parser (body).                                                */
  6. /*                                                                         */
  7. /*  Copyright 1996-2005, 2008, 2009, 2012, 2013 by                         */
  8. /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
  9. /*                                                                         */
  10. /*  This file is part of the FreeType project, and may only be used,       */
  11. /*  modified, and distributed under the terms of the FreeType project      */
  12. /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
  13. /*  this file you indicate that you have read the license and              */
  14. /*  understand and accept it fully.                                        */
  15. /*                                                                         */
  16. /***************************************************************************/
  17.  
  18.  
  19.   /*************************************************************************/
  20.   /*                                                                       */
  21.   /* The Type 1 parser is in charge of the following:                      */
  22.   /*                                                                       */
  23.   /*  - provide an implementation of a growing sequence of objects called  */
  24.   /*    a `T1_Table' (used to build various tables needed by the loader).  */
  25.   /*                                                                       */
  26.   /*  - opening .pfb and .pfa files to extract their top-level and private */
  27.   /*    dictionaries.                                                      */
  28.   /*                                                                       */
  29.   /*  - read numbers, arrays & strings from any dictionary.                */
  30.   /*                                                                       */
  31.   /* See `t1load.c' to see how data is loaded from the font file.          */
  32.   /*                                                                       */
  33.   /*************************************************************************/
  34.  
  35.  
  36. #include <ft2build.h>
  37. #include FT_INTERNAL_DEBUG_H
  38. #include FT_INTERNAL_STREAM_H
  39. #include FT_INTERNAL_POSTSCRIPT_AUX_H
  40.  
  41. #include "t1parse.h"
  42.  
  43. #include "t1errors.h"
  44.  
  45.  
  46.   /*************************************************************************/
  47.   /*                                                                       */
  48.   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  49.   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  50.   /* messages during execution.                                            */
  51.   /*                                                                       */
  52. #undef  FT_COMPONENT
  53. #define FT_COMPONENT  trace_t1parse
  54.  
  55.  
  56.   /*************************************************************************/
  57.   /*************************************************************************/
  58.   /*************************************************************************/
  59.   /*****                                                               *****/
  60.   /*****                   INPUT STREAM PARSER                         *****/
  61.   /*****                                                               *****/
  62.   /*************************************************************************/
  63.   /*************************************************************************/
  64.   /*************************************************************************/
  65.  
  66.  
  67.   /* see Adobe Technical Note 5040.Download_Fonts.pdf */
  68.  
  69.   static FT_Error
  70.   read_pfb_tag( FT_Stream   stream,
  71.                 FT_UShort  *atag,
  72.                 FT_ULong   *asize )
  73.   {
  74.     FT_Error   error;
  75.     FT_UShort  tag;
  76.     FT_ULong   size;
  77.  
  78.  
  79.     *atag  = 0;
  80.     *asize = 0;
  81.  
  82.     if ( !FT_READ_USHORT( tag ) )
  83.     {
  84.       if ( tag == 0x8001U || tag == 0x8002U )
  85.       {
  86.         if ( !FT_READ_ULONG_LE( size ) )
  87.           *asize = size;
  88.       }
  89.  
  90.       *atag = tag;
  91.     }
  92.  
  93.     return error;
  94.   }
  95.  
  96.  
  97.   static FT_Error
  98.   check_type1_format( FT_Stream    stream,
  99.                       const char*  header_string,
  100.                       size_t       header_length )
  101.   {
  102.     FT_Error   error;
  103.     FT_UShort  tag;
  104.     FT_ULong   dummy;
  105.  
  106.  
  107.     if ( FT_STREAM_SEEK( 0 ) )
  108.       goto Exit;
  109.  
  110.     error = read_pfb_tag( stream, &tag, &dummy );
  111.     if ( error )
  112.       goto Exit;
  113.  
  114.     /* We assume that the first segment in a PFB is always encoded as   */
  115.     /* text.  This might be wrong (and the specification doesn't insist */
  116.     /* on that), but we have never seen a counterexample.               */
  117.     if ( tag != 0x8001U && FT_STREAM_SEEK( 0 ) )
  118.       goto Exit;
  119.  
  120.     if ( !FT_FRAME_ENTER( header_length ) )
  121.     {
  122.       error = FT_Err_Ok;
  123.  
  124.       if ( ft_memcmp( stream->cursor, header_string, header_length ) != 0 )
  125.         error = FT_THROW( Unknown_File_Format );
  126.  
  127.       FT_FRAME_EXIT();
  128.     }
  129.  
  130.   Exit:
  131.     return error;
  132.   }
  133.  
  134.  
  135.   FT_LOCAL_DEF( FT_Error )
  136.   T1_New_Parser( T1_Parser      parser,
  137.                  FT_Stream      stream,
  138.                  FT_Memory      memory,
  139.                  PSAux_Service  psaux )
  140.   {
  141.     FT_Error   error;
  142.     FT_UShort  tag;
  143.     FT_ULong   size;
  144.  
  145.  
  146.     psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory );
  147.  
  148.     parser->stream       = stream;
  149.     parser->base_len     = 0;
  150.     parser->base_dict    = 0;
  151.     parser->private_len  = 0;
  152.     parser->private_dict = 0;
  153.     parser->in_pfb       = 0;
  154.     parser->in_memory    = 0;
  155.     parser->single_block = 0;
  156.  
  157.     /* check the header format */
  158.     error = check_type1_format( stream, "%!PS-AdobeFont", 14 );
  159.     if ( error )
  160.     {
  161.       if ( FT_ERR_NEQ( error, Unknown_File_Format ) )
  162.         goto Exit;
  163.  
  164.       error = check_type1_format( stream, "%!FontType", 10 );
  165.       if ( error )
  166.       {
  167.         FT_TRACE2(( "  not a Type 1 font\n" ));
  168.         goto Exit;
  169.       }
  170.     }
  171.  
  172.     /******************************************************************/
  173.     /*                                                                */
  174.     /* Here a short summary of what is going on:                      */
  175.     /*                                                                */
  176.     /*   When creating a new Type 1 parser, we try to locate and load */
  177.     /*   the base dictionary if this is possible (i.e., for PFB       */
  178.     /*   files).  Otherwise, we load the whole font into memory.      */
  179.     /*                                                                */
  180.     /*   When `loading' the base dictionary, we only setup pointers   */
  181.     /*   in the case of a memory-based stream.  Otherwise, we         */
  182.     /*   allocate and load the base dictionary in it.                 */
  183.     /*                                                                */
  184.     /*   parser->in_pfb is set if we are in a binary (`.pfb') font.   */
  185.     /*   parser->in_memory is set if we have a memory stream.         */
  186.     /*                                                                */
  187.  
  188.     /* try to compute the size of the base dictionary;     */
  189.     /* look for a Postscript binary file tag, i.e., 0x8001 */
  190.     if ( FT_STREAM_SEEK( 0L ) )
  191.       goto Exit;
  192.  
  193.     error = read_pfb_tag( stream, &tag, &size );
  194.     if ( error )
  195.       goto Exit;
  196.  
  197.     if ( tag != 0x8001U )
  198.     {
  199.       /* assume that this is a PFA file for now; an error will */
  200.       /* be produced later when more things are checked        */
  201.       if ( FT_STREAM_SEEK( 0L ) )
  202.         goto Exit;
  203.       size = stream->size;
  204.     }
  205.     else
  206.       parser->in_pfb = 1;
  207.  
  208.     /* now, try to load `size' bytes of the `base' dictionary we */
  209.     /* found previously                                          */
  210.  
  211.     /* if it is a memory-based resource, set up pointers */
  212.     if ( !stream->read )
  213.     {
  214.       parser->base_dict = (FT_Byte*)stream->base + stream->pos;
  215.       parser->base_len  = size;
  216.       parser->in_memory = 1;
  217.  
  218.       /* check that the `size' field is valid */
  219.       if ( FT_STREAM_SKIP( size ) )
  220.         goto Exit;
  221.     }
  222.     else
  223.     {
  224.       /* read segment in memory -- this is clumsy, but so does the format */
  225.       if ( FT_ALLOC( parser->base_dict, size )       ||
  226.            FT_STREAM_READ( parser->base_dict, size ) )
  227.         goto Exit;
  228.       parser->base_len = size;
  229.     }
  230.  
  231.     parser->root.base   = parser->base_dict;
  232.     parser->root.cursor = parser->base_dict;
  233.     parser->root.limit  = parser->root.cursor + parser->base_len;
  234.  
  235.   Exit:
  236.     if ( error && !parser->in_memory )
  237.       FT_FREE( parser->base_dict );
  238.  
  239.     return error;
  240.   }
  241.  
  242.  
  243.   FT_LOCAL_DEF( void )
  244.   T1_Finalize_Parser( T1_Parser  parser )
  245.   {
  246.     FT_Memory  memory = parser->root.memory;
  247.  
  248.  
  249.     /* always free the private dictionary */
  250.     FT_FREE( parser->private_dict );
  251.  
  252.     /* free the base dictionary only when we have a disk stream */
  253.     if ( !parser->in_memory )
  254.       FT_FREE( parser->base_dict );
  255.  
  256.     parser->root.funcs.done( &parser->root );
  257.   }
  258.  
  259.  
  260.   FT_LOCAL_DEF( FT_Error )
  261.   T1_Get_Private_Dict( T1_Parser      parser,
  262.                        PSAux_Service  psaux )
  263.   {
  264.     FT_Stream  stream = parser->stream;
  265.     FT_Memory  memory = parser->root.memory;
  266.     FT_Error   error  = FT_Err_Ok;
  267.     FT_ULong   size;
  268.  
  269.  
  270.     if ( parser->in_pfb )
  271.     {
  272.       /* in the case of the PFB format, the private dictionary can be  */
  273.       /* made of several segments.  We thus first read the number of   */
  274.       /* segments to compute the total size of the private dictionary  */
  275.       /* then re-read them into memory.                                */
  276.       FT_Long    start_pos = FT_STREAM_POS();
  277.       FT_UShort  tag;
  278.  
  279.  
  280.       parser->private_len = 0;
  281.       for (;;)
  282.       {
  283.         error = read_pfb_tag( stream, &tag, &size );
  284.         if ( error )
  285.           goto Fail;
  286.  
  287.         if ( tag != 0x8002U )
  288.           break;
  289.  
  290.         parser->private_len += size;
  291.  
  292.         if ( FT_STREAM_SKIP( size ) )
  293.           goto Fail;
  294.       }
  295.  
  296.       /* Check that we have a private dictionary there */
  297.       /* and allocate private dictionary buffer        */
  298.       if ( parser->private_len == 0 )
  299.       {
  300.         FT_ERROR(( "T1_Get_Private_Dict:"
  301.                    " invalid private dictionary section\n" ));
  302.         error = FT_THROW( Invalid_File_Format );
  303.         goto Fail;
  304.       }
  305.  
  306.       if ( FT_STREAM_SEEK( start_pos )                           ||
  307.            FT_ALLOC( parser->private_dict, parser->private_len ) )
  308.         goto Fail;
  309.  
  310.       parser->private_len = 0;
  311.       for (;;)
  312.       {
  313.         error = read_pfb_tag( stream, &tag, &size );
  314.         if ( error || tag != 0x8002U )
  315.         {
  316.           error = FT_Err_Ok;
  317.           break;
  318.         }
  319.  
  320.         if ( FT_STREAM_READ( parser->private_dict + parser->private_len,
  321.                              size ) )
  322.           goto Fail;
  323.  
  324.         parser->private_len += size;
  325.       }
  326.     }
  327.     else
  328.     {
  329.       /* We have already `loaded' the whole PFA font file into memory; */
  330.       /* if this is a memory resource, allocate a new block to hold    */
  331.       /* the private dict.  Otherwise, simply overwrite into the base  */
  332.       /* dictionary block in the heap.                                 */
  333.  
  334.       /* first of all, look at the `eexec' keyword */
  335.       FT_Byte*  cur   = parser->base_dict;
  336.       FT_Byte*  limit = cur + parser->base_len;
  337.       FT_Byte   c;
  338.  
  339.  
  340.     Again:
  341.       for (;;)
  342.       {
  343.         c = cur[0];
  344.         if ( c == 'e' && cur + 9 < limit )  /* 9 = 5 letters for `eexec' + */
  345.                                             /* whitespace + 4 chars        */
  346.         {
  347.           if ( cur[1] == 'e' &&
  348.                cur[2] == 'x' &&
  349.                cur[3] == 'e' &&
  350.                cur[4] == 'c' )
  351.             break;
  352.         }
  353.         cur++;
  354.         if ( cur >= limit )
  355.         {
  356.           FT_ERROR(( "T1_Get_Private_Dict:"
  357.                      " could not find `eexec' keyword\n" ));
  358.           error = FT_THROW( Invalid_File_Format );
  359.           goto Exit;
  360.         }
  361.       }
  362.  
  363.       /* check whether `eexec' was real -- it could be in a comment */
  364.       /* or string (as e.g. in u003043t.gsf from ghostscript)       */
  365.  
  366.       parser->root.cursor = parser->base_dict;
  367.       /* set limit to `eexec' + whitespace + 4 characters */
  368.       parser->root.limit  = cur + 10;
  369.  
  370.       cur   = parser->root.cursor;
  371.       limit = parser->root.limit;
  372.  
  373.       while ( cur < limit )
  374.       {
  375.         if ( *cur == 'e' && ft_strncmp( (char*)cur, "eexec", 5 ) == 0 )
  376.           goto Found;
  377.  
  378.         T1_Skip_PS_Token( parser );
  379.         if ( parser->root.error )
  380.           break;
  381.         T1_Skip_Spaces  ( parser );
  382.         cur = parser->root.cursor;
  383.       }
  384.  
  385.       /* we haven't found the correct `eexec'; go back and continue */
  386.       /* searching                                                  */
  387.  
  388.       cur   = limit;
  389.       limit = parser->base_dict + parser->base_len;
  390.       goto Again;
  391.  
  392.       /* now determine where to write the _encrypted_ binary private  */
  393.       /* dictionary.  We overwrite the base dictionary for disk-based */
  394.       /* resources and allocate a new block otherwise                 */
  395.  
  396.     Found:
  397.       parser->root.limit = parser->base_dict + parser->base_len;
  398.  
  399.       T1_Skip_PS_Token( parser );
  400.       cur   = parser->root.cursor;
  401.       limit = parser->root.limit;
  402.  
  403.       /* according to the Type1 spec, the first cipher byte must not be  */
  404.       /* an ASCII whitespace character code (blank, tab, carriage return */
  405.       /* or line feed).  We have seen Type 1 fonts with two line feed    */
  406.       /* characters...  So skip now all whitespace character codes.      */
  407.       while ( cur < limit       &&
  408.               ( *cur == ' '  ||
  409.                 *cur == '\t' ||
  410.                 *cur == '\r' ||
  411.                 *cur == '\n' ) )
  412.         ++cur;
  413.       if ( cur >= limit )
  414.       {
  415.         FT_ERROR(( "T1_Get_Private_Dict:"
  416.                    " `eexec' not properly terminated\n" ));
  417.         error = FT_THROW( Invalid_File_Format );
  418.         goto Exit;
  419.       }
  420.  
  421.       size = (FT_ULong)( parser->base_len - ( cur - parser->base_dict ) );
  422.  
  423.       if ( parser->in_memory )
  424.       {
  425.         /* note that we allocate one more byte to put a terminating `0' */
  426.         if ( FT_ALLOC( parser->private_dict, size + 1 ) )
  427.           goto Fail;
  428.         parser->private_len = size;
  429.       }
  430.       else
  431.       {
  432.         parser->single_block = 1;
  433.         parser->private_dict = parser->base_dict;
  434.         parser->private_len  = size;
  435.         parser->base_dict    = 0;
  436.         parser->base_len     = 0;
  437.       }
  438.  
  439.       /* now determine whether the private dictionary is encoded in binary */
  440.       /* or hexadecimal ASCII format -- decode it accordingly              */
  441.  
  442.       /* we need to access the next 4 bytes (after the final whitespace */
  443.       /* following the `eexec' keyword); if they all are hexadecimal    */
  444.       /* digits, then we have a case of ASCII storage                   */
  445.  
  446.       if ( cur + 3 < limit                                &&
  447.            ft_isxdigit( cur[0] ) && ft_isxdigit( cur[1] ) &&
  448.            ft_isxdigit( cur[2] ) && ft_isxdigit( cur[3] ) )
  449.       {
  450.         /* ASCII hexadecimal encoding */
  451.         FT_Long  len;
  452.  
  453.  
  454.         parser->root.cursor = cur;
  455.         (void)psaux->ps_parser_funcs->to_bytes( &parser->root,
  456.                                                 parser->private_dict,
  457.                                                 parser->private_len,
  458.                                                 &len,
  459.                                                 0 );
  460.         parser->private_len = len;
  461.  
  462.         /* put a safeguard */
  463.         parser->private_dict[len] = '\0';
  464.       }
  465.       else
  466.         /* binary encoding -- copy the private dict */
  467.         FT_MEM_MOVE( parser->private_dict, cur, size );
  468.     }
  469.  
  470.     /* we now decrypt the encoded binary private dictionary */
  471.     psaux->t1_decrypt( parser->private_dict, parser->private_len, 55665U );
  472.  
  473.     if ( parser->private_len < 4 )
  474.     {
  475.       FT_ERROR(( "T1_Get_Private_Dict:"
  476.                  " invalid private dictionary section\n" ));
  477.       error = FT_THROW( Invalid_File_Format );
  478.       goto Fail;
  479.     }
  480.  
  481.     /* replace the four random bytes at the beginning with whitespace */
  482.     parser->private_dict[0] = ' ';
  483.     parser->private_dict[1] = ' ';
  484.     parser->private_dict[2] = ' ';
  485.     parser->private_dict[3] = ' ';
  486.  
  487.     parser->root.base   = parser->private_dict;
  488.     parser->root.cursor = parser->private_dict;
  489.     parser->root.limit  = parser->root.cursor + parser->private_len;
  490.  
  491.   Fail:
  492.   Exit:
  493.     return error;
  494.   }
  495.  
  496.  
  497. /* END */
  498.