source: trunk/poppler/freetype2/src/psaux/psobjs.c @ 165

Last change on this file since 165 was 165, checked in by Eugene Romanenko, 15 years ago

update to latest freetype cvs, (closes #76)

File size: 47.5 KB
Line 
1/***************************************************************************/
2/*                                                                         */
3/*  psobjs.c                                                               */
4/*                                                                         */
5/*    Auxiliary functions for PostScript fonts (body).                     */
6/*                                                                         */
7/*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006 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#include <ft2build.h>
20#include FT_INTERNAL_POSTSCRIPT_AUX_H
21#include FT_INTERNAL_DEBUG_H
22
23#include "psobjs.h"
24#include "psconv.h"
25
26#include "psauxerr.h"
27
28
29  /*************************************************************************/
30  /*                                                                       */
31  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
32  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
33  /* messages during execution.                                            */
34  /*                                                                       */
35#undef  FT_COMPONENT
36#define FT_COMPONENT  trace_psobjs
37
38
39  /*************************************************************************/
40  /*************************************************************************/
41  /*****                                                               *****/
42  /*****                             PS_TABLE                          *****/
43  /*****                                                               *****/
44  /*************************************************************************/
45  /*************************************************************************/
46
47  /*************************************************************************/
48  /*                                                                       */
49  /* <Function>                                                            */
50  /*    ps_table_new                                                       */
51  /*                                                                       */
52  /* <Description>                                                         */
53  /*    Initializes a PS_Table.                                            */
54  /*                                                                       */
55  /* <InOut>                                                               */
56  /*    table  :: The address of the target table.                         */
57  /*                                                                       */
58  /* <Input>                                                               */
59  /*    count  :: The table size = the maximum number of elements.         */
60  /*                                                                       */
61  /*    memory :: The memory object to use for all subsequent              */
62  /*              reallocations.                                           */
63  /*                                                                       */
64  /* <Return>                                                              */
65  /*    FreeType error code.  0 means success.                             */
66  /*                                                                       */
67  FT_LOCAL_DEF( FT_Error )
68  ps_table_new( PS_Table   table,
69                FT_Int     count,
70                FT_Memory  memory )
71  {
72    FT_Error  error;
73
74
75    table->memory = memory;
76    if ( FT_NEW_ARRAY( table->elements, count ) ||
77         FT_NEW_ARRAY( table->lengths,  count ) )
78      goto Exit;
79
80    table->max_elems = count;
81    table->init      = 0xDEADBEEFUL;
82    table->num_elems = 0;
83    table->block     = 0;
84    table->capacity  = 0;
85    table->cursor    = 0;
86
87    *(PS_Table_FuncsRec*)&table->funcs = ps_table_funcs;
88
89  Exit:
90    if ( error )
91      FT_FREE( table->elements );
92
93    return error;
94  }
95
96
97  static void
98  shift_elements( PS_Table  table,
99                  FT_Byte*  old_base )
100  {
101    FT_PtrDist  delta  = table->block - old_base;
102    FT_Byte**   offset = table->elements;
103    FT_Byte**   limit  = offset + table->max_elems;
104
105
106    for ( ; offset < limit; offset++ )
107    {
108      if ( offset[0] )
109        offset[0] += delta;
110    }
111  }
112
113
114  static FT_Error
115  reallocate_t1_table( PS_Table  table,
116                       FT_Long   new_size )
117  {
118    FT_Memory  memory   = table->memory;
119    FT_Byte*   old_base = table->block;
120    FT_Error   error;
121
122
123    /* allocate new base block */
124    if ( FT_ALLOC( table->block, new_size ) )
125    {
126      table->block = old_base;
127      return error;
128    }
129
130    /* copy elements and shift offsets */
131    if ( old_base )
132    {
133      FT_MEM_COPY( table->block, old_base, table->capacity );
134      shift_elements( table, old_base );
135      FT_FREE( old_base );
136    }
137
138    table->capacity = new_size;
139
140    return PSaux_Err_Ok;
141  }
142
143
144  /*************************************************************************/
145  /*                                                                       */
146  /* <Function>                                                            */
147  /*    ps_table_add                                                       */
148  /*                                                                       */
149  /* <Description>                                                         */
150  /*    Adds an object to a PS_Table, possibly growing its memory block.   */
151  /*                                                                       */
152  /* <InOut>                                                               */
153  /*    table  :: The target table.                                        */
154  /*                                                                       */
155  /* <Input>                                                               */
156  /*    idx    :: The index of the object in the table.                    */
157  /*                                                                       */
158  /*    object :: The address of the object to copy in memory.             */
159  /*                                                                       */
160  /*    length :: The length in bytes of the source object.                */
161  /*                                                                       */
162  /* <Return>                                                              */
163  /*    FreeType error code.  0 means success.  An error is returned if a  */
164  /*    reallocation fails.                                                */
165  /*                                                                       */
166  FT_LOCAL_DEF( FT_Error )
167  ps_table_add( PS_Table    table,
168                FT_Int      idx,
169                void*       object,
170                FT_PtrDist  length )
171  {
172    if ( idx < 0 || idx > table->max_elems )
173    {
174      FT_ERROR(( "ps_table_add: invalid index\n" ));
175      return PSaux_Err_Invalid_Argument;
176    }
177
178    /* grow the base block if needed */
179    if ( table->cursor + length > table->capacity )
180    {
181      FT_Error   error;
182      FT_Offset  new_size  = table->capacity;
183      FT_Long    in_offset;
184
185
186      in_offset = (FT_Long)((FT_Byte*)object - table->block);
187      if ( (FT_ULong)in_offset >= table->capacity )
188        in_offset = -1;
189
190      while ( new_size < table->cursor + length )
191      {
192        /* increase size by 25% and round up to the nearest multiple
193           of 1024 */
194        new_size += ( new_size >> 2 ) + 1;
195        new_size  = FT_PAD_CEIL( new_size, 1024 );
196      }
197
198      error = reallocate_t1_table( table, new_size );
199      if ( error )
200        return error;
201
202      if ( in_offset >= 0 )
203        object = table->block + in_offset;
204    }
205
206    /* add the object to the base block and adjust offset */
207    table->elements[idx] = table->block + table->cursor;
208    table->lengths [idx] = length;
209    FT_MEM_COPY( table->block + table->cursor, object, length );
210
211    table->cursor += length;
212    return PSaux_Err_Ok;
213  }
214
215
216  /*************************************************************************/
217  /*                                                                       */
218  /* <Function>                                                            */
219  /*    ps_table_done                                                      */
220  /*                                                                       */
221  /* <Description>                                                         */
222  /*    Finalizes a PS_TableRec (i.e., reallocate it to its current        */
223  /*    cursor).                                                           */
224  /*                                                                       */
225  /* <InOut>                                                               */
226  /*    table :: The target table.                                         */
227  /*                                                                       */
228  /* <Note>                                                                */
229  /*    This function does NOT release the heap's memory block.  It is up  */
230  /*    to the caller to clean it, or reference it in its own structures.  */
231  /*                                                                       */
232  FT_LOCAL_DEF( void )
233  ps_table_done( PS_Table  table )
234  {
235    FT_Memory  memory = table->memory;
236    FT_Error   error;
237    FT_Byte*   old_base = table->block;
238
239
240    /* should never fail, because rec.cursor <= rec.size */
241    if ( !old_base )
242      return;
243
244    if ( FT_ALLOC( table->block, table->cursor ) )
245      return;
246    FT_MEM_COPY( table->block, old_base, table->cursor );
247    shift_elements( table, old_base );
248
249    table->capacity = table->cursor;
250    FT_FREE( old_base );
251
252    FT_UNUSED( error );
253  }
254
255
256  FT_LOCAL_DEF( void )
257  ps_table_release( PS_Table  table )
258  {
259    FT_Memory  memory = table->memory;
260
261
262    if ( (FT_ULong)table->init == 0xDEADBEEFUL )
263    {
264      FT_FREE( table->block );
265      FT_FREE( table->elements );
266      FT_FREE( table->lengths );
267      table->init = 0;
268    }
269  }
270
271
272  /*************************************************************************/
273  /*************************************************************************/
274  /*****                                                               *****/
275  /*****                            T1 PARSER                          *****/
276  /*****                                                               *****/
277  /*************************************************************************/
278  /*************************************************************************/
279
280
281  /* first character must be already part of the comment */
282
283  static void
284  skip_comment( FT_Byte*  *acur,
285                FT_Byte*   limit )
286  {
287    FT_Byte*  cur = *acur;
288
289
290    while ( cur < limit )
291    {
292      if ( IS_PS_NEWLINE( *cur ) )
293        break;
294      cur++;
295    }
296
297    *acur = cur;
298  }
299
300
301  static void
302  skip_spaces( FT_Byte*  *acur,
303               FT_Byte*   limit )
304  {
305    FT_Byte*  cur = *acur;
306
307
308    while ( cur < limit )
309    {
310      if ( !IS_PS_SPACE( *cur ) )
311      {
312        if ( *cur == '%' )
313          /* According to the PLRM, a comment is equal to a space. */
314          skip_comment( &cur, limit );
315        else
316          break;
317      }
318      cur++;
319    }
320
321    *acur = cur;
322  }
323
324
325#define IS_OCTAL_DIGIT( c ) ( '0' <= (c) && (c) <= '7' )
326
327
328  /* first character must be `(';                               */
329  /* *acur is positioned at the character after the closing `)' */
330
331  static FT_Error
332  skip_literal_string( FT_Byte*  *acur,
333                       FT_Byte*   limit )
334  {
335    FT_Byte*      cur   = *acur;
336    FT_Int        embed = 0;
337    FT_Error      error = PSaux_Err_Invalid_File_Format;
338    unsigned int  i;
339
340
341    while ( cur < limit )
342    {
343      FT_Byte  c = *cur;
344
345
346      ++cur;
347
348      if ( c == '\\' )
349      {
350        /* Red Book 3rd ed., section `Literal Text Strings', p. 29:     */
351        /* A backslash can introduce three different types              */
352        /* of escape sequences:                                         */
353        /*   - a special escaped char like \r, \n, etc.                 */
354        /*   - a one-, two-, or three-digit octal number                */
355        /*   - none of the above in which case the backslash is ignored */
356
357        if ( cur == limit )
358          /* error (or to be ignored?) */
359          break;
360
361        switch ( *cur )
362        {
363          /* skip `special' escape */
364        case 'n':
365        case 'r':
366        case 't':
367        case 'b':
368        case 'f':
369        case '\\':
370        case '(':
371        case ')':
372          ++cur;
373          break;
374
375        default:
376          /* skip octal escape or ignore backslash */
377          for ( i = 0; i < 3 && cur < limit; ++i )
378          {
379            if ( ! IS_OCTAL_DIGIT( *cur ) )
380              break;
381
382            ++cur;
383          }
384        }
385      }
386      else if ( c == '(' )
387        embed++;
388      else if ( c == ')' )
389      {
390        embed--;
391        if ( embed == 0 )
392        {
393          error = PSaux_Err_Ok;
394          break;
395        }
396      }
397    }
398
399    *acur = cur;
400
401    return error;
402  }
403
404
405  /* first character must be `<' */
406
407  static FT_Error
408  skip_string( FT_Byte*  *acur,
409               FT_Byte*   limit )
410  {
411    FT_Byte*  cur = *acur;
412    FT_Error  err =  PSaux_Err_Ok;
413
414
415    while ( ++cur < limit )
416    {
417      /* All whitespace characters are ignored. */
418      skip_spaces( &cur, limit );
419      if ( cur >= limit )
420        break;
421
422      if ( !IS_PS_XDIGIT( *cur ) )
423        break;
424    }
425
426    if ( cur < limit && *cur != '>' )
427    {
428      FT_ERROR(( "skip_string: missing closing delimiter `>'\n" ));
429      err = PSaux_Err_Invalid_File_Format;
430    }
431    else
432      cur++;
433
434    *acur = cur;
435    return err;
436  }
437
438
439  /* first character must be the opening brace that */
440  /* starts the procedure                           */
441
442  /* NB: [ and ] need not match:                    */
443  /* `/foo {[} def' is a valid PostScript fragment, */
444  /* even within a Type1 font                       */
445
446  static FT_Error
447  skip_procedure( FT_Byte*  *acur,
448                  FT_Byte*   limit )
449  {
450    FT_Byte*  cur;
451    FT_Int    embed = 0;
452    FT_Error  error = PSaux_Err_Ok;
453
454
455    FT_ASSERT( **acur == '{' );
456
457    for ( cur = *acur; cur < limit && error == PSaux_Err_Ok; ++cur )
458    {
459      switch ( *cur )
460      {
461      case '{':
462        ++embed;
463        break;
464
465      case '}':
466        --embed;
467        if ( embed == 0 )
468        {
469          ++cur;
470          goto end;
471        }
472        break;
473
474      case '(':
475        error = skip_literal_string( &cur, limit );
476        break;
477
478      case '<':
479        error = skip_string( &cur, limit );
480        break;
481
482      case '%':
483        skip_comment( &cur, limit );
484        break;
485      }
486    }
487
488  end:
489    if ( embed != 0 )
490      error = PSaux_Err_Invalid_File_Format;
491
492    *acur = cur;
493
494    return error;
495  }
496
497
498  /***********************************************************************/
499  /*                                                                     */
500  /* All exported parsing routines handle leading whitespace and stop at */
501  /* the first character which isn't part of the just handled token.     */
502  /*                                                                     */
503  /***********************************************************************/
504
505
506  FT_LOCAL_DEF( void )
507  ps_parser_skip_PS_token( PS_Parser  parser )
508  {
509    /* Note: PostScript allows any non-delimiting, non-whitespace        */
510    /*       character in a name (PS Ref Manual, 3rd ed, p31).           */
511    /*       PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */
512
513    FT_Byte*  cur   = parser->cursor;
514    FT_Byte*  limit = parser->limit;
515    FT_Error  error = PSaux_Err_Ok;
516
517
518    skip_spaces( &cur, limit );             /* this also skips comments */
519    if ( cur >= limit )
520      goto Exit;
521
522    /* self-delimiting, single-character tokens */
523    if ( *cur == '[' || *cur == ']' )
524    {
525      cur++;
526      goto Exit;
527    }
528
529    /* skip balanced expressions (procedures and strings) */
530
531    if ( *cur == '{' )                              /* {...} */
532    {
533      error = skip_procedure( &cur, limit );
534      goto Exit;
535    }
536
537    if ( *cur == '(' )                              /* (...) */
538    {
539      error = skip_literal_string( &cur, limit );
540      goto Exit;
541    }
542
543    if ( *cur == '<' )                              /* <...> */
544    {
545      if ( cur + 1 < limit && *(cur + 1) == '<' )   /* << */
546      {
547        cur++;
548        cur++;
549      }
550      else
551        error = skip_string( &cur, limit );
552
553      goto Exit;
554    }
555
556    if ( *cur == '>' )
557    {
558      cur++;
559      if ( cur >= limit || *cur != '>' )             /* >> */
560      {
561        FT_ERROR(( "ps_parser_skip_PS_token: "
562                   "unexpected closing delimiter `>'\n" ));
563        error = PSaux_Err_Invalid_File_Format;
564        goto Exit;
565      }
566      cur++;
567      goto Exit;
568    }
569
570    if ( *cur == '/' )
571      cur++;
572
573    /* anything else */
574    while ( cur < limit )
575    {
576      /* *cur might be invalid (e.g., ')' or '}'), but this   */
577      /* is handled by the test `cur == parser->cursor' below */
578      if ( IS_PS_DELIM( *cur ) )
579        break;
580
581      cur++;
582    }
583
584  Exit:
585    if ( cur == parser->cursor )
586    {
587      FT_ERROR(( "ps_parser_skip_PS_token: "
588                 "current token is `%c', which is self-delimiting "
589                 "but invalid at this point\n",
590                 *cur ));
591     
592      error = PSaux_Err_Invalid_File_Format;
593    }
594
595    FT_ASSERT( parser->error == PSaux_Err_Ok );
596    parser->error  = error;
597    parser->cursor = cur;
598  }
599
600
601  FT_LOCAL_DEF( void )
602  ps_parser_skip_spaces( PS_Parser  parser )
603  {
604    skip_spaces( &parser->cursor, parser->limit );
605  }
606
607
608  /* `token' here means either something between balanced delimiters */
609  /* or the next token; the delimiters are not removed.              */
610
611  FT_LOCAL_DEF( void )
612  ps_parser_to_token( PS_Parser  parser,
613                      T1_Token   token )
614  {
615    FT_Byte*  cur;
616    FT_Byte*  limit;
617    FT_Int    embed;
618
619
620    token->type  = T1_TOKEN_TYPE_NONE;
621    token->start = 0;
622    token->limit = 0;
623
624    /* first of all, skip leading whitespace */
625    ps_parser_skip_spaces( parser );
626
627    cur   = parser->cursor;
628    limit = parser->limit;
629
630    if ( cur >= limit )
631      return;
632
633    switch ( *cur )
634    {
635      /************* check for literal string *****************/
636    case '(':
637      token->type  = T1_TOKEN_TYPE_STRING;
638      token->start = cur;
639
640      if ( skip_literal_string( &cur, limit ) == PSaux_Err_Ok )
641        token->limit = cur;
642      break;
643
644      /************* check for programs/array *****************/
645    case '{':
646      token->type  = T1_TOKEN_TYPE_ARRAY;
647      token->start = cur;
648
649      if ( skip_procedure( &cur, limit ) == PSaux_Err_Ok )
650        token->limit = cur;
651      break;
652
653      /************* check for table/array ********************/
654      /* XXX: in theory we should also look for "<<"          */
655      /*      since this is semantically equivalent to "[";   */
656      /*      in practice it doesn't matter (?)               */
657    case '[':
658      token->type  = T1_TOKEN_TYPE_ARRAY;
659      embed        = 1;
660      token->start = cur++;
661
662      /* we need this to catch `[ ]' */
663      parser->cursor = cur;
664      ps_parser_skip_spaces( parser );
665      cur = parser->cursor;
666
667      while ( cur < limit && !parser->error )
668      {
669        /* XXX: this is wrong because it does not      */
670        /*      skip comments, procedures, and strings */
671        if ( *cur == '[' )
672          embed++;
673        else if ( *cur == ']' )
674        {
675          embed--;
676          if ( embed <= 0 )
677          {
678            token->limit = ++cur;
679            break;
680          }
681        }
682
683        parser->cursor = cur;
684        ps_parser_skip_PS_token( parser );
685        /* we need this to catch `[XXX ]' */
686        ps_parser_skip_spaces  ( parser );
687        cur = parser->cursor;
688      }
689      break;
690
691      /* ************ otherwise, it is any token **************/
692    default:
693      token->start = cur;
694      token->type  = ( *cur == '/' ? T1_TOKEN_TYPE_KEY : T1_TOKEN_TYPE_ANY );
695      ps_parser_skip_PS_token( parser );
696      cur = parser->cursor;
697      if ( !parser->error )
698        token->limit = cur;
699    }
700
701    if ( !token->limit )
702    {
703      token->start = 0;
704      token->type  = T1_TOKEN_TYPE_NONE;
705    }
706
707    parser->cursor = cur;
708  }
709
710
711  /* NB: `tokens' can be NULL if we only want to count */
712  /* the number of array elements                      */
713
714  FT_LOCAL_DEF( void )
715  ps_parser_to_token_array( PS_Parser  parser,
716                            T1_Token   tokens,
717                            FT_UInt    max_tokens,
718                            FT_Int*    pnum_tokens )
719  {
720    T1_TokenRec  master;
721
722
723    *pnum_tokens = -1;
724
725    /* this also handles leading whitespace */
726    ps_parser_to_token( parser, &master );
727
728    if ( master.type == T1_TOKEN_TYPE_ARRAY )
729    {
730      FT_Byte*  old_cursor = parser->cursor;
731      FT_Byte*  old_limit  = parser->limit;
732      T1_Token  cur        = tokens;
733      T1_Token  limit      = cur + max_tokens;
734
735
736      /* don't include outermost delimiters */
737      parser->cursor = master.start + 1;
738      parser->limit  = master.limit - 1;
739
740      while ( parser->cursor < parser->limit )
741      {
742        T1_TokenRec  token;
743
744
745        ps_parser_to_token( parser, &token );
746        if ( !token.type )
747          break;
748
749        if ( tokens != NULL && cur < limit )
750          *cur = token;
751
752        cur++;
753      }
754
755      *pnum_tokens = (FT_Int)( cur - tokens );
756
757      parser->cursor = old_cursor;
758      parser->limit  = old_limit;
759    }
760  }
761
762
763  /* first character must be a delimiter or a part of a number */
764  /* NB: `coords' can be NULL if we just want to skip the      */
765  /*     array; in this case we ignore `max_coords'            */
766
767  static FT_Int
768  ps_tocoordarray( FT_Byte*  *acur,
769                   FT_Byte*   limit,
770                   FT_Int     max_coords,
771                   FT_Short*  coords )
772  {
773    FT_Byte*  cur   = *acur;
774    FT_Int    count = 0;
775    FT_Byte   c, ender;
776
777
778    if ( cur >= limit )
779      goto Exit;
780
781    /* check for the beginning of an array; otherwise, only one number */
782    /* will be read                                                    */
783    c     = *cur;
784    ender = 0;
785
786    if ( c == '[' )
787      ender = ']';
788
789    if ( c == '{' )
790      ender = '}';
791
792    if ( ender )
793      cur++;
794
795    /* now, read the coordinates */
796    while ( cur < limit )
797    {
798      FT_Short dummy;
799
800
801      /* skip whitespace in front of data */
802      skip_spaces( &cur, limit );
803      if ( cur >= limit )
804        goto Exit;
805
806      if ( coords != NULL && count >= max_coords )
807        break;
808
809      if ( *cur == ender )
810      {
811        cur++;
812        break;
813      }
814
815      /* call PS_Conv_ToFixed() even if coords == NULL */
816      /* to properly parse number at `cur'             */
817      *( coords != NULL ? &coords[count] : &dummy ) =
818        (FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 );
819      count++;
820
821      if ( !ender )
822        break;
823    }
824
825  Exit:
826    *acur = cur;
827    return count;
828  }
829
830
831  /* first character must be a delimiter or a part of a number */
832  /* NB: `values' can be NULL if we just want to skip the      */
833  /*     array in this case we ignore `max_values'             */
834
835  static FT_Int
836  ps_tofixedarray( FT_Byte*  *acur,
837                   FT_Byte*   limit,
838                   FT_Int     max_values,
839                   FT_Fixed*  values,
840                   FT_Int     power_ten )
841  {
842    FT_Byte*  cur   = *acur;
843    FT_Int    count = 0;
844    FT_Byte   c, ender;
845
846
847    if ( cur >= limit )
848      goto Exit;
849
850    /* Check for the beginning of an array.  Otherwise, only one number */
851    /* will be read.                                                    */
852    c     = *cur;
853    ender = 0;
854
855    if ( c == '[' )
856      ender = ']';
857
858    if ( c == '{' )
859      ender = '}';
860
861    if ( ender )
862      cur++;
863
864    /* now, read the values */
865    while ( cur < limit )
866    {
867      FT_Fixed dummy;
868
869
870      /* skip whitespace in front of data */
871      skip_spaces( &cur, limit );
872      if ( cur >= limit )
873        goto Exit;
874
875      if ( values != NULL && count >= max_values )
876        break;
877
878      if ( *cur == ender )
879      {
880        cur++;
881        break;
882      }
883
884      /* call PS_Conv_ToFixed() even if coords == NULL */
885      /* to properly parse number at `cur'             */
886      *( values != NULL ? &values[count] : &dummy ) =
887        PS_Conv_ToFixed( &cur, limit, power_ten );
888      count++;
889
890      if ( !ender )
891        break;
892    }
893
894  Exit:
895    *acur = cur;
896    return count;
897  }
898
899
900#if 0
901
902  static FT_String*
903  ps_tostring( FT_Byte**  cursor,
904               FT_Byte*   limit,
905               FT_Memory  memory )
906  {
907    FT_Byte*    cur = *cursor;
908    FT_PtrDist  len = 0;
909    FT_Int      count;
910    FT_String*  result;
911    FT_Error    error;
912
913
914    /* XXX: some stupid fonts have a `Notice' or `Copyright' string     */
915    /*      that simply doesn't begin with an opening parenthesis, even */
916    /*      though they have a closing one!  E.g. "amuncial.pfb"        */
917    /*                                                                  */
918    /*      We must deal with these ill-fated cases there.  Note that   */
919    /*      these fonts didn't work with the old Type 1 driver as the   */
920    /*      notice/copyright was not recognized as a valid string token */
921    /*      and made the old token parser commit errors.                */
922
923    while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) )
924      cur++;
925    if ( cur + 1 >= limit )
926      return 0;
927
928    if ( *cur == '(' )
929      cur++;  /* skip the opening parenthesis, if there is one */
930
931    *cursor = cur;
932    count   = 0;
933
934    /* then, count its length */
935    for ( ; cur < limit; cur++ )
936    {
937      if ( *cur == '(' )
938        count++;
939
940      else if ( *cur == ')' )
941      {
942        count--;
943        if ( count < 0 )
944          break;
945      }
946    }
947
948    len = cur - *cursor;
949    if ( cur >= limit || FT_ALLOC( result, len + 1 ) )
950      return 0;
951
952    /* now copy the string */
953    FT_MEM_COPY( result, *cursor, len );
954    result[len] = '\0';
955    *cursor = cur;
956    return result;
957  }
958
959#endif /* 0 */
960
961
962  static int
963  ps_tobool( FT_Byte*  *acur,
964             FT_Byte*   limit )
965  {
966    FT_Byte*  cur    = *acur;
967    FT_Bool   result = 0;
968
969
970    /* return 1 if we find `true', 0 otherwise */
971    if ( cur + 3 < limit &&
972         cur[0] == 't'   &&
973         cur[1] == 'r'   &&
974         cur[2] == 'u'   &&
975         cur[3] == 'e'   )
976    {
977      result = 1;
978      cur   += 5;
979    }
980    else if ( cur + 4 < limit &&
981              cur[0] == 'f'   &&
982              cur[1] == 'a'   &&
983              cur[2] == 'l'   &&
984              cur[3] == 's'   &&
985              cur[4] == 'e'   )
986    {
987      result = 0;
988      cur   += 6;
989    }
990
991    *acur = cur;
992    return result;
993  }
994
995
996  /* load a simple field (i.e. non-table) into the current list of objects */
997
998  FT_LOCAL_DEF( FT_Error )
999  ps_parser_load_field( PS_Parser       parser,
1000                        const T1_Field  field,
1001                        void**          objects,
1002                        FT_UInt         max_objects,
1003                        FT_ULong*       pflags )
1004  {
1005    T1_TokenRec  token;
1006    FT_Byte*     cur;
1007    FT_Byte*     limit;
1008    FT_UInt      count;
1009    FT_UInt      idx;
1010    FT_Error     error;
1011
1012
1013    /* this also skips leading whitespace */
1014    ps_parser_to_token( parser, &token );
1015    if ( !token.type )
1016      goto Fail;
1017
1018    count = 1;
1019    idx   = 0;
1020    cur   = token.start;
1021    limit = token.limit;
1022
1023    /* we must detect arrays in /FontBBox */
1024    if ( field->type == T1_FIELD_TYPE_BBOX )
1025    {
1026      T1_TokenRec  token2;
1027      FT_Byte*     old_cur   = parser->cursor;
1028      FT_Byte*     old_limit = parser->limit;
1029
1030
1031      /* don't include delimiters */
1032      parser->cursor = token.start + 1;
1033      parser->limit  = token.limit - 1;
1034
1035      ps_parser_to_token( parser, &token2 );
1036      parser->cursor = old_cur;
1037      parser->limit  = old_limit;
1038
1039      if ( token2.type == T1_TOKEN_TYPE_ARRAY )
1040        goto FieldArray;
1041    }
1042    else if ( token.type == T1_TOKEN_TYPE_ARRAY )
1043    {
1044    FieldArray:
1045      /* if this is an array and we have no blend, an error occurs */
1046      if ( max_objects == 0 )
1047        goto Fail;
1048
1049      count = max_objects;
1050      idx   = 1;
1051
1052      /* don't include delimiters */
1053      cur++;
1054      limit--;
1055    }
1056
1057    for ( ; count > 0; count--, idx++ )
1058    {
1059      FT_Byte*    q = (FT_Byte*)objects[idx] + field->offset;
1060      FT_Long     val;
1061      FT_String*  string;
1062
1063
1064      skip_spaces( &cur, limit );
1065
1066      switch ( field->type )
1067      {
1068      case T1_FIELD_TYPE_BOOL:
1069        val = ps_tobool( &cur, limit );
1070        goto Store_Integer;
1071
1072      case T1_FIELD_TYPE_FIXED:
1073        val = PS_Conv_ToFixed( &cur, limit, 0 );
1074        goto Store_Integer;
1075
1076      case T1_FIELD_TYPE_FIXED_1000:
1077        val = PS_Conv_ToFixed( &cur, limit, 3 );
1078        goto Store_Integer;
1079
1080      case T1_FIELD_TYPE_INTEGER:
1081        val = PS_Conv_ToInt( &cur, limit );
1082        /* fall through */
1083
1084      Store_Integer:
1085        switch ( field->size )
1086        {
1087        case (8 / FT_CHAR_BIT):
1088          *(FT_Byte*)q = (FT_Byte)val;
1089          break;
1090
1091        case (16 / FT_CHAR_BIT):
1092          *(FT_UShort*)q = (FT_UShort)val;
1093          break;
1094
1095        case (32 / FT_CHAR_BIT):
1096          *(FT_UInt32*)q = (FT_UInt32)val;
1097          break;
1098
1099        default:                /* for 64-bit systems */
1100          *(FT_Long*)q = val;
1101        }
1102        break;
1103
1104      case T1_FIELD_TYPE_STRING:
1105      case T1_FIELD_TYPE_KEY:
1106        {
1107          FT_Memory  memory = parser->memory;
1108          FT_UInt    len    = (FT_UInt)( limit - cur );
1109
1110
1111          if ( cur >= limit )
1112            break;
1113
1114          /* we allow both a string or a name   */
1115          /* for cases like /FontName (foo) def */
1116          if ( token.type == T1_TOKEN_TYPE_KEY )
1117          {
1118            /* don't include leading `/' */
1119            len--;
1120            cur++;
1121          }
1122          else if ( token.type == T1_TOKEN_TYPE_STRING )
1123          {
1124            /* don't include delimiting parentheses    */
1125            /* XXX we don't handle <<...>> here        */
1126            /* XXX should we convert octal escapes?    */
1127            /*     if so, what encoding should we use? */
1128            cur++;
1129            len -= 2;
1130          }
1131          else
1132          {
1133            FT_ERROR(( "ps_parser_load_field: expected a name or string "
1134                       "but found token of type %d instead\n",
1135                       token.type ));
1136            error = PSaux_Err_Invalid_File_Format;
1137            goto Exit;
1138          }
1139
1140          /* for this to work (FT_String**)q must have been */
1141          /* initialized to NULL                            */
1142          if ( *(FT_String**)q != NULL )
1143          {
1144            FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n",
1145                        field->ident ));
1146            FT_FREE( *(FT_String**)q );
1147            *(FT_String**)q = NULL;
1148          }
1149
1150          if ( FT_ALLOC( string, len + 1 ) )
1151            goto Exit;
1152
1153          FT_MEM_COPY( string, cur, len );
1154          string[len] = 0;
1155
1156          *(FT_String**)q = string;
1157        }
1158        break;
1159
1160      case T1_FIELD_TYPE_BBOX:
1161        {
1162          FT_Fixed  temp[4];
1163          FT_BBox*  bbox = (FT_BBox*)q;
1164
1165
1166          (void)ps_tofixedarray( &token.start, token.limit, 4, temp, 0 );
1167
1168          bbox->xMin = FT_RoundFix( temp[0] );
1169          bbox->yMin = FT_RoundFix( temp[1] );
1170          bbox->xMax = FT_RoundFix( temp[2] );
1171          bbox->yMax = FT_RoundFix( temp[3] );
1172        }
1173        break;
1174
1175      default:
1176        /* an error occured */
1177        goto Fail;
1178      }
1179    }
1180
1181#if 0  /* obsolete -- keep for reference */
1182    if ( pflags )
1183      *pflags |= 1L << field->flag_bit;
1184#else
1185    FT_UNUSED( pflags );
1186#endif
1187
1188    error = PSaux_Err_Ok;
1189
1190  Exit:
1191    return error;
1192
1193  Fail:
1194    error = PSaux_Err_Invalid_File_Format;
1195    goto Exit;
1196  }
1197
1198
1199#define T1_MAX_TABLE_ELEMENTS  32
1200
1201
1202  FT_LOCAL_DEF( FT_Error )
1203  ps_parser_load_field_table( PS_Parser       parser,
1204                              const T1_Field  field,
1205                              void**          objects,
1206                              FT_UInt         max_objects,
1207                              FT_ULong*       pflags )
1208  {
1209    T1_TokenRec  elements[T1_MAX_TABLE_ELEMENTS];
1210    T1_Token     token;
1211    FT_Int       num_elements;
1212    FT_Error     error = PSaux_Err_Ok;
1213    FT_Byte*     old_cursor;
1214    FT_Byte*     old_limit;
1215    T1_FieldRec  fieldrec = *(T1_Field)field;
1216
1217
1218    fieldrec.type = T1_FIELD_TYPE_INTEGER;
1219    if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY ||
1220         field->type == T1_FIELD_TYPE_BBOX        )
1221      fieldrec.type = T1_FIELD_TYPE_FIXED;
1222
1223    ps_parser_to_token_array( parser, elements,
1224                              T1_MAX_TABLE_ELEMENTS, &num_elements );
1225    if ( num_elements < 0 )
1226    {
1227      error = PSaux_Err_Ignore;
1228      goto Exit;
1229    }
1230    if ( num_elements > T1_MAX_TABLE_ELEMENTS )
1231      num_elements = T1_MAX_TABLE_ELEMENTS;
1232
1233    old_cursor = parser->cursor;
1234    old_limit  = parser->limit;
1235
1236    /* we store the elements count if necessary */
1237    if ( field->type != T1_FIELD_TYPE_BBOX )
1238      *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) =
1239        (FT_Byte)num_elements;
1240
1241    /* we now load each element, adjusting the field.offset on each one */
1242    token = elements;
1243    for ( ; num_elements > 0; num_elements--, token++ )
1244    {
1245      parser->cursor = token->start;
1246      parser->limit  = token->limit;
1247      ps_parser_load_field( parser, &fieldrec, objects, max_objects, 0 );
1248      fieldrec.offset += fieldrec.size;
1249    }
1250
1251#if 0  /* obsolete -- keep for reference */
1252    if ( pflags )
1253      *pflags |= 1L << field->flag_bit;
1254#else
1255    FT_UNUSED( pflags );
1256#endif
1257
1258    parser->cursor = old_cursor;
1259    parser->limit  = old_limit;
1260
1261  Exit:
1262    return error;
1263  }
1264
1265
1266  FT_LOCAL_DEF( FT_Long )
1267  ps_parser_to_int( PS_Parser  parser )
1268  {
1269    ps_parser_skip_spaces( parser );
1270    return PS_Conv_ToInt( &parser->cursor, parser->limit );
1271  }
1272
1273
1274  /* first character must be `<' if `delimiters' is non-zero */
1275
1276  FT_LOCAL_DEF( FT_Error )
1277  ps_parser_to_bytes( PS_Parser  parser,
1278                      FT_Byte*   bytes,
1279                      FT_Long    max_bytes,
1280                      FT_Long*   pnum_bytes,
1281                      FT_Bool    delimiters )
1282  {
1283    FT_Error  error = PSaux_Err_Ok;
1284    FT_Byte*  cur;
1285   
1286   
1287    ps_parser_skip_spaces( parser );
1288    cur = parser->cursor;
1289
1290    if ( cur >= parser->limit )
1291      goto Exit;
1292
1293    if ( delimiters )
1294    {
1295      if ( *cur != '<' )
1296      {
1297        FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" ));
1298        error = PSaux_Err_Invalid_File_Format;
1299        goto Exit;
1300      }
1301
1302      cur++;
1303    }
1304
1305    *pnum_bytes = PS_Conv_ASCIIHexDecode( &cur,
1306                                          parser->limit,
1307                                          bytes,
1308                                          max_bytes );
1309
1310    if ( delimiters )
1311    {
1312      if ( cur < parser->limit && *cur != '>' )
1313      {
1314        FT_ERROR(( "ps_tobytes: Missing closing delimiter `>'\n" ));
1315        error = PSaux_Err_Invalid_File_Format;
1316        goto Exit;
1317      }
1318
1319      cur++;
1320    }
1321
1322    parser->cursor = cur;
1323
1324  Exit:
1325    return error;
1326  }
1327
1328
1329  FT_LOCAL_DEF( FT_Fixed )
1330  ps_parser_to_fixed( PS_Parser  parser,
1331                      FT_Int     power_ten )
1332  {
1333    ps_parser_skip_spaces( parser );
1334    return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten );
1335  }
1336
1337
1338  FT_LOCAL_DEF( FT_Int )
1339  ps_parser_to_coord_array( PS_Parser  parser,
1340                            FT_Int     max_coords,
1341                            FT_Short*  coords )
1342  {
1343    ps_parser_skip_spaces( parser );
1344    return ps_tocoordarray( &parser->cursor, parser->limit,
1345                            max_coords, coords );
1346  }
1347
1348
1349  FT_LOCAL_DEF( FT_Int )
1350  ps_parser_to_fixed_array( PS_Parser  parser,
1351                            FT_Int     max_values,
1352                            FT_Fixed*  values,
1353                            FT_Int     power_ten )
1354  {
1355    ps_parser_skip_spaces( parser );
1356    return ps_tofixedarray( &parser->cursor, parser->limit,
1357                            max_values, values, power_ten );
1358  }
1359
1360
1361#if 0
1362
1363  FT_LOCAL_DEF( FT_String* )
1364  T1_ToString( PS_Parser  parser )
1365  {
1366    return ps_tostring( &parser->cursor, parser->limit, parser->memory );
1367  }
1368
1369
1370  FT_LOCAL_DEF( FT_Bool )
1371  T1_ToBool( PS_Parser  parser )
1372  {
1373    return ps_tobool( &parser->cursor, parser->limit );
1374  }
1375
1376#endif /* 0 */
1377
1378
1379  FT_LOCAL_DEF( void )
1380  ps_parser_init( PS_Parser  parser,
1381                  FT_Byte*   base,
1382                  FT_Byte*   limit,
1383                  FT_Memory  memory )
1384  {
1385    parser->error  = PSaux_Err_Ok;
1386    parser->base   = base;
1387    parser->limit  = limit;
1388    parser->cursor = base;
1389    parser->memory = memory;
1390    parser->funcs  = ps_parser_funcs;
1391  }
1392
1393
1394  FT_LOCAL_DEF( void )
1395  ps_parser_done( PS_Parser  parser )
1396  {
1397    FT_UNUSED( parser );
1398  }
1399
1400
1401  /*************************************************************************/
1402  /*************************************************************************/
1403  /*****                                                               *****/
1404  /*****                            T1 BUILDER                         *****/
1405  /*****                                                               *****/
1406  /*************************************************************************/
1407  /*************************************************************************/
1408
1409  /*************************************************************************/
1410  /*                                                                       */
1411  /* <Function>                                                            */
1412  /*    t1_builder_init                                                    */
1413  /*                                                                       */
1414  /* <Description>                                                         */
1415  /*    Initializes a given glyph builder.                                 */
1416  /*                                                                       */
1417  /* <InOut>                                                               */
1418  /*    builder :: A pointer to the glyph builder to initialize.           */
1419  /*                                                                       */
1420  /* <Input>                                                               */
1421  /*    face    :: The current face object.                                */
1422  /*                                                                       */
1423  /*    size    :: The current size object.                                */
1424  /*                                                                       */
1425  /*    glyph   :: The current glyph object.                               */
1426  /*                                                                       */
1427  /*    hinting :: Whether hinting should be applied.                      */
1428  /*                                                                       */
1429  FT_LOCAL_DEF( void )
1430  t1_builder_init( T1_Builder    builder,
1431                   FT_Face       face,
1432                   FT_Size       size,
1433                   FT_GlyphSlot  glyph,
1434                   FT_Bool       hinting )
1435  {
1436    builder->parse_state = T1_Parse_Start;
1437    builder->load_points = 1;
1438
1439    builder->face   = face;
1440    builder->glyph  = glyph;
1441    builder->memory = face->memory;
1442
1443    if ( glyph )
1444    {
1445      FT_GlyphLoader  loader = glyph->internal->loader;
1446
1447
1448      builder->loader  = loader;
1449      builder->base    = &loader->base.outline;
1450      builder->current = &loader->current.outline;
1451      FT_GlyphLoader_Rewind( loader );
1452
1453      builder->hints_globals = size->internal;
1454      builder->hints_funcs   = 0;
1455
1456      if ( hinting )
1457        builder->hints_funcs = glyph->internal->glyph_hints;
1458    }
1459
1460    if ( size )
1461    {
1462      builder->scale_x = size->metrics.x_scale;
1463      builder->scale_y = size->metrics.y_scale;
1464    }
1465
1466    builder->pos_x = 0;
1467    builder->pos_y = 0;
1468
1469    builder->left_bearing.x = 0;
1470    builder->left_bearing.y = 0;
1471    builder->advance.x      = 0;
1472    builder->advance.y      = 0;
1473
1474    builder->funcs = t1_builder_funcs;
1475  }
1476
1477
1478  /*************************************************************************/
1479  /*                                                                       */
1480  /* <Function>                                                            */
1481  /*    t1_builder_done                                                    */
1482  /*                                                                       */
1483  /* <Description>                                                         */
1484  /*    Finalizes a given glyph builder.  Its contents can still be used   */
1485  /*    after the call, but the function saves important information       */
1486  /*    within the corresponding glyph slot.                               */
1487  /*                                                                       */
1488  /* <Input>                                                               */
1489  /*    builder :: A pointer to the glyph builder to finalize.             */
1490  /*                                                                       */
1491  FT_LOCAL_DEF( void )
1492  t1_builder_done( T1_Builder  builder )
1493  {
1494    FT_GlyphSlot  glyph = builder->glyph;
1495
1496
1497    if ( glyph )
1498      glyph->outline = *builder->base;
1499  }
1500
1501
1502  /* check that there is enough space for `count' more points */
1503  FT_LOCAL_DEF( FT_Error )
1504  t1_builder_check_points( T1_Builder  builder,
1505                           FT_Int      count )
1506  {
1507    return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 );
1508  }
1509
1510
1511  /* add a new point, do not check space */
1512  FT_LOCAL_DEF( void )
1513  t1_builder_add_point( T1_Builder  builder,
1514                        FT_Pos      x,
1515                        FT_Pos      y,
1516                        FT_Byte     flag )
1517  {
1518    FT_Outline*  outline = builder->current;
1519
1520
1521    if ( builder->load_points )
1522    {
1523      FT_Vector*  point   = outline->points + outline->n_points;
1524      FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points;
1525
1526
1527      if ( builder->shift )
1528      {
1529        x >>= 16;
1530        y >>= 16;
1531      }
1532      point->x = x;
1533      point->y = y;
1534      *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
1535
1536      builder->last = *point;
1537    }
1538    outline->n_points++;
1539  }
1540
1541
1542  /* check space for a new on-curve point, then add it */
1543  FT_LOCAL_DEF( FT_Error )
1544  t1_builder_add_point1( T1_Builder  builder,
1545                         FT_Pos      x,
1546                         FT_Pos      y )
1547  {
1548    FT_Error  error;
1549
1550
1551    error = t1_builder_check_points( builder, 1 );
1552    if ( !error )
1553      t1_builder_add_point( builder, x, y, 1 );
1554
1555    return error;
1556  }
1557
1558
1559  /* check space for a new contour, then add it */
1560  FT_LOCAL_DEF( FT_Error )
1561  t1_builder_add_contour( T1_Builder  builder )
1562  {
1563    FT_Outline*  outline = builder->current;
1564    FT_Error     error;
1565
1566
1567    if ( !builder->load_points )
1568    {
1569      outline->n_contours++;
1570      return PSaux_Err_Ok;
1571    }
1572
1573    error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 );
1574    if ( !error )
1575    {
1576      if ( outline->n_contours > 0 )
1577        outline->contours[outline->n_contours - 1] =
1578          (short)( outline->n_points - 1 );
1579
1580      outline->n_contours++;
1581    }
1582
1583    return error;
1584  }
1585
1586
1587  /* if a path was begun, add its first on-curve point */
1588  FT_LOCAL_DEF( FT_Error )
1589  t1_builder_start_point( T1_Builder  builder,
1590                          FT_Pos      x,
1591                          FT_Pos      y )
1592  {
1593    FT_Error  error = PSaux_Err_Invalid_File_Format;
1594
1595
1596    /* test whether we are building a new contour */
1597
1598    if ( builder->parse_state == T1_Parse_Have_Path )
1599      error = PSaux_Err_Ok;
1600    else if ( builder->parse_state == T1_Parse_Have_Moveto )
1601    {
1602      builder->parse_state = T1_Parse_Have_Path;
1603      error = t1_builder_add_contour( builder );
1604      if ( !error )
1605        error = t1_builder_add_point1( builder, x, y );
1606    }
1607
1608    return error;
1609  }
1610
1611
1612  /* close the current contour */
1613  FT_LOCAL_DEF( void )
1614  t1_builder_close_contour( T1_Builder  builder )
1615  {
1616    FT_Outline*  outline = builder->current;
1617
1618
1619    if ( !outline )
1620      return;
1621
1622    /* XXXX: We must not include the last point in the path if it */
1623    /*       is located on the first point.                       */
1624    if ( outline->n_points > 1 )
1625    {
1626      FT_Int      first   = 0;
1627      FT_Vector*  p1      = outline->points + first;
1628      FT_Vector*  p2      = outline->points + outline->n_points - 1;
1629      FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points - 1;
1630
1631
1632      if ( outline->n_contours > 1 )
1633      {
1634        first = outline->contours[outline->n_contours - 2] + 1;
1635        p1    = outline->points + first;
1636      }
1637
1638      /* `delete' last point only if it coincides with the first */
1639      /* point and it is not a control point (which can happen). */
1640      if ( p1->x == p2->x && p1->y == p2->y )
1641        if ( *control == FT_CURVE_TAG_ON )
1642          outline->n_points--;
1643    }
1644
1645    if ( outline->n_contours > 0 )
1646      outline->contours[outline->n_contours - 1] =
1647        (short)( outline->n_points - 1 );
1648  }
1649
1650
1651  /*************************************************************************/
1652  /*************************************************************************/
1653  /*****                                                               *****/
1654  /*****                            OTHER                              *****/
1655  /*****                                                               *****/
1656  /*************************************************************************/
1657  /*************************************************************************/
1658
1659  FT_LOCAL_DEF( void )
1660  t1_decrypt( FT_Byte*   buffer,
1661              FT_Offset  length,
1662              FT_UShort  seed )
1663  {
1664    PS_Conv_EexecDecode( &buffer,
1665                         buffer + length,
1666                         buffer,
1667                         length,
1668                         &seed );
1669  }
1670
1671
1672/* END */
Note: See TracBrowser for help on using the repository browser.