xref: /inferno-os/libfreetype/psobjs.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1 /***************************************************************************/
2 /*                                                                         */
3 /*  psobjs.c                                                               */
4 /*                                                                         */
5 /*    Auxiliary functions for PostScript fonts (body).                     */
6 /*                                                                         */
7 /*  Copyright 1996-2001, 2002 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 
25 #include "psauxerr.h"
26 
27 
28   /*************************************************************************/
29   /*************************************************************************/
30   /*****                                                               *****/
31   /*****                             PS_TABLE                          *****/
32   /*****                                                               *****/
33   /*************************************************************************/
34   /*************************************************************************/
35 
36   /*************************************************************************/
37   /*                                                                       */
38   /* <Function>                                                            */
39   /*    ps_table_new                                                       */
40   /*                                                                       */
41   /* <Description>                                                         */
42   /*    Initializes a PS_Table.                                            */
43   /*                                                                       */
44   /* <InOut>                                                               */
45   /*    table  :: The address of the target table.                         */
46   /*                                                                       */
47   /* <Input>                                                               */
48   /*    count  :: The table size = the maximum number of elements.         */
49   /*                                                                       */
50   /*    memory :: The memory object to use for all subsequent              */
51   /*              reallocations.                                           */
52   /*                                                                       */
53   /* <Return>                                                              */
54   /*    FreeType error code.  0 means success.                             */
55   /*                                                                       */
56   FT_LOCAL_DEF( FT_Error )
ps_table_new(PS_Table table,FT_Int count,FT_Memory memory)57   ps_table_new( PS_Table   table,
58                 FT_Int     count,
59                 FT_Memory  memory )
60   {
61     FT_Error  error;
62 
63 
64     table->memory = memory;
65     if ( FT_NEW_ARRAY( table->elements, count ) ||
66          FT_NEW_ARRAY( table->lengths,  count ) )
67       goto Exit;
68 
69     table->max_elems = count;
70     table->init      = 0xDEADBEEFUL;
71     table->num_elems = 0;
72     table->block     = 0;
73     table->capacity  = 0;
74     table->cursor    = 0;
75 
76     *(PS_Table_FuncsRec*)&table->funcs = ps_table_funcs;
77 
78   Exit:
79     if ( error )
80       FT_FREE( table->elements );
81 
82     return error;
83   }
84 
85 
86   static void
shift_elements(PS_Table table,FT_Byte * old_base)87   shift_elements( PS_Table  table,
88                   FT_Byte*  old_base )
89   {
90     FT_Long    delta  = (FT_Long)( table->block - old_base );
91     FT_Byte**  offset = table->elements;
92     FT_Byte**  limit  = offset + table->max_elems;
93 
94 
95     for ( ; offset < limit; offset++ )
96     {
97       if ( offset[0] )
98         offset[0] += delta;
99     }
100   }
101 
102 
103   static FT_Error
reallocate_t1_table(PS_Table table,FT_Long new_size)104   reallocate_t1_table( PS_Table  table,
105                        FT_Long   new_size )
106   {
107     FT_Memory  memory   = table->memory;
108     FT_Byte*   old_base = table->block;
109     FT_Error   error;
110 
111 
112     /* allocate new base block */
113     if ( FT_ALLOC( table->block, new_size ) )
114       return error;
115 
116     /* copy elements and shift offsets */
117     if (old_base )
118     {
119       FT_MEM_COPY( table->block, old_base, table->capacity );
120       shift_elements( table, old_base );
121       FT_FREE( old_base );
122     }
123 
124     table->capacity = new_size;
125 
126     return PSaux_Err_Ok;
127   }
128 
129 
130   /*************************************************************************/
131   /*                                                                       */
132   /* <Function>                                                            */
133   /*    ps_table_add                                                       */
134   /*                                                                       */
135   /* <Description>                                                         */
136   /*    Adds an object to a PS_Table, possibly growing its memory block.   */
137   /*                                                                       */
138   /* <InOut>                                                               */
139   /*    table  :: The target table.                                        */
140   /*                                                                       */
141   /* <Input>                                                               */
142   /*    idx  :: The index of the object in the table.                      */
143   /*                                                                       */
144   /*    object :: The address of the object to copy in memory.             */
145   /*                                                                       */
146   /*    length :: The length in bytes of the source object.                */
147   /*                                                                       */
148   /* <Return>                                                              */
149   /*    FreeType error code.  0 means success.  An error is returned if a  */
150   /*    reallocation fails.                                                */
151   /*                                                                       */
152   FT_LOCAL_DEF( FT_Error )
ps_table_add(PS_Table table,FT_Int idx,void * object,FT_Int length)153   ps_table_add( PS_Table  table,
154                 FT_Int    idx,
155                 void*     object,
156                 FT_Int    length )
157   {
158     if ( idx < 0 || idx > table->max_elems )
159     {
160       FT_ERROR(( "ps_table_add: invalid index\n" ));
161       return PSaux_Err_Invalid_Argument;
162     }
163 
164     /* grow the base block if needed */
165     if ( table->cursor + length > table->capacity )
166     {
167       FT_Error   error;
168       FT_Offset  new_size  = table->capacity;
169       FT_Long    in_offset;
170 
171 
172       in_offset = (FT_Long)((FT_Byte*)object - table->block);
173       if ( (FT_ULong)in_offset >= table->capacity )
174         in_offset = -1;
175 
176       while ( new_size < table->cursor + length )
177       {
178         /* increase size by 25% and round up to the nearest multiple of 1024 */
179         new_size += (new_size >> 2) + 1;
180         new_size  = ( new_size + 1023 ) & -1024;
181       }
182 
183       error = reallocate_t1_table( table, new_size );
184       if ( error )
185         return error;
186 
187       if ( in_offset >= 0 )
188         object = table->block + in_offset;
189     }
190 
191     /* add the object to the base block and adjust offset */
192     table->elements[idx] = table->block + table->cursor;
193     table->lengths [idx] = length;
194     FT_MEM_COPY( table->block + table->cursor, object, length );
195 
196     table->cursor += length;
197     return PSaux_Err_Ok;
198   }
199 
200 
201   /*************************************************************************/
202   /*                                                                       */
203   /* <Function>                                                            */
204   /*    ps_table_done                                                      */
205   /*                                                                       */
206   /* <Description>                                                         */
207   /*    Finalizes a PS_TableRec (i.e., reallocate it to its current        */
208   /*    cursor).                                                           */
209   /*                                                                       */
210   /* <InOut>                                                               */
211   /*    table :: The target table.                                         */
212   /*                                                                       */
213   /* <Note>                                                                */
214   /*    This function does NOT release the heap's memory block.  It is up  */
215   /*    to the caller to clean it, or reference it in its own structures.  */
216   /*                                                                       */
217   FT_LOCAL_DEF( void )
ps_table_done(PS_Table table)218   ps_table_done( PS_Table  table )
219   {
220     FT_Memory  memory = table->memory;
221     FT_Error   error;
222     FT_Byte*   old_base = table->block;
223 
224 
225     /* should never fail, because rec.cursor <= rec.size */
226     if ( !old_base )
227       return;
228 
229     if ( FT_ALLOC( table->block, table->cursor ) )
230       return;
231     FT_MEM_COPY( table->block, old_base, table->cursor );
232     shift_elements( table, old_base );
233 
234     table->capacity = table->cursor;
235     FT_FREE( old_base );
236 
237     FT_UNUSED( error );
238   }
239 
240 
241   FT_LOCAL_DEF( void )
ps_table_release(PS_Table table)242   ps_table_release( PS_Table  table )
243   {
244     FT_Memory  memory = table->memory;
245 
246 
247     if ( (FT_ULong)table->init == 0xDEADBEEFUL )
248     {
249       FT_FREE( table->block );
250       FT_FREE( table->elements );
251       FT_FREE( table->lengths );
252       table->init = 0;
253     }
254   }
255 
256 
257   /*************************************************************************/
258   /*************************************************************************/
259   /*****                                                               *****/
260   /*****                            T1 PARSER                          *****/
261   /*****                                                               *****/
262   /*************************************************************************/
263   /*************************************************************************/
264 
265 
266 #define IS_T1_WHITESPACE( c )  ( (c) == ' '  || (c) == '\t' )
267 #define IS_T1_LINESPACE( c )   ( (c) == '\r' || (c) == '\n' )
268 
269 #define IS_T1_SPACE( c )  ( IS_T1_WHITESPACE( c ) || IS_T1_LINESPACE( c ) )
270 
271 
272   FT_LOCAL_DEF( void )
ps_parser_skip_spaces(PS_Parser parser)273   ps_parser_skip_spaces( PS_Parser  parser )
274   {
275     FT_Byte* cur   = parser->cursor;
276     FT_Byte* limit = parser->limit;
277 
278 
279     while ( cur < limit )
280     {
281       FT_Byte  c = *cur;
282 
283 
284       if ( !IS_T1_SPACE( c ) )
285         break;
286       cur++;
287     }
288     parser->cursor = cur;
289   }
290 
291 
292   FT_LOCAL_DEF( void )
ps_parser_skip_alpha(PS_Parser parser)293   ps_parser_skip_alpha( PS_Parser  parser )
294   {
295     FT_Byte* cur   = parser->cursor;
296     FT_Byte* limit = parser->limit;
297 
298 
299     while ( cur < limit )
300     {
301       FT_Byte  c = *cur;
302 
303 
304       if ( IS_T1_SPACE( c ) )
305         break;
306       cur++;
307     }
308     parser->cursor = cur;
309   }
310 
311 
312   FT_LOCAL_DEF( void )
ps_parser_to_token(PS_Parser parser,T1_Token token)313   ps_parser_to_token( PS_Parser  parser,
314                       T1_Token   token )
315   {
316     FT_Byte*  cur;
317     FT_Byte*  limit;
318     FT_Byte   starter, ender;
319     FT_Int    embed;
320 
321 
322     token->type  = T1_TOKEN_TYPE_NONE;
323     token->start = 0;
324     token->limit = 0;
325 
326     /* first of all, skip space */
327     ps_parser_skip_spaces( parser );
328 
329     cur   = parser->cursor;
330     limit = parser->limit;
331 
332     if ( cur < limit )
333     {
334       switch ( *cur )
335       {
336         /************* check for strings ***********************/
337       case '(':
338         token->type = T1_TOKEN_TYPE_STRING;
339         ender = ')';
340         goto Lookup_Ender;
341 
342         /************* check for programs/array ****************/
343       case '{':
344         token->type = T1_TOKEN_TYPE_ARRAY;
345         ender = '}';
346         goto Lookup_Ender;
347 
348         /************* check for table/array ******************/
349       case '[':
350         token->type = T1_TOKEN_TYPE_ARRAY;
351         ender = ']';
352 
353       Lookup_Ender:
354         embed   = 1;
355         starter = *cur++;
356         token->start = cur;
357         while ( cur < limit )
358         {
359           if ( *cur == starter )
360             embed++;
361           else if ( *cur == ender )
362           {
363             embed--;
364             if ( embed <= 0 )
365             {
366               token->limit = cur++;
367               break;
368             }
369           }
370           cur++;
371         }
372         break;
373 
374         /* **************** otherwise, it's any token **********/
375       default:
376         token->start = cur++;
377         token->type  = T1_TOKEN_TYPE_ANY;
378         while ( cur < limit && !IS_T1_SPACE( *cur ) )
379           cur++;
380 
381         token->limit = cur;
382       }
383 
384       if ( !token->limit )
385       {
386         token->start = 0;
387         token->type  = T1_TOKEN_TYPE_NONE;
388       }
389 
390       parser->cursor = cur;
391     }
392   }
393 
394 
395   FT_LOCAL_DEF( void )
ps_parser_to_token_array(PS_Parser parser,T1_Token tokens,FT_UInt max_tokens,FT_Int * pnum_tokens)396   ps_parser_to_token_array( PS_Parser  parser,
397                             T1_Token   tokens,
398                             FT_UInt    max_tokens,
399                             FT_Int*    pnum_tokens )
400   {
401     T1_TokenRec  master;
402 
403 
404     *pnum_tokens = -1;
405 
406     ps_parser_to_token( parser, &master );
407     if ( master.type == T1_TOKEN_TYPE_ARRAY )
408     {
409       FT_Byte*  old_cursor = parser->cursor;
410       FT_Byte*  old_limit  = parser->limit;
411       T1_Token  cur        = tokens;
412       T1_Token  limit      = cur + max_tokens;
413 
414 
415       parser->cursor = master.start;
416       parser->limit  = master.limit;
417 
418       while ( parser->cursor < parser->limit )
419       {
420         T1_TokenRec  token;
421 
422 
423         ps_parser_to_token( parser, &token );
424         if ( !token.type )
425           break;
426 
427         if ( cur < limit )
428           *cur = token;
429 
430         cur++;
431       }
432 
433       *pnum_tokens = (FT_Int)( cur - tokens );
434 
435       parser->cursor = old_cursor;
436       parser->limit  = old_limit;
437     }
438   }
439 
440 
441   static FT_Long
T1Radix(FT_Long radixBase,FT_Byte ** cur,FT_Byte * limit)442   T1Radix( FT_Long    radixBase,
443            FT_Byte**  cur,
444            FT_Byte*   limit )
445   {
446     FT_Long  result = 0;
447     FT_Byte  radixEndChar0 =
448                (FT_Byte)( radixBase > 10 ? '9' + 1 : '0' + radixBase );
449     FT_Byte  radixEndChar1 =
450                (FT_Byte)( 'A' + radixBase - 10 );
451     FT_Byte  radixEndChar2 =
452                (FT_Byte)( 'a' + radixBase - 10 );
453 
454 
455     while( *cur < limit )
456     {
457       if ( (*cur)[0] >= '0' && (*cur)[0] < radixEndChar0 )
458         result = result * radixBase + (*cur)[0] - '0';
459 
460       else if ( radixBase > 10 &&
461                 (*cur)[0] >= 'A' && (*cur)[0] < radixEndChar1 )
462         result = result * radixBase + ( (*cur)[0] - 'A' + 10 );
463 
464       else if ( radixBase > 10 &&
465                 (*cur)[0] >= 'a' && (*cur)[0] < radixEndChar2 )
466         result = result * radixBase + ( (*cur)[0] - 'a' + 10 );
467 
468       else
469         return result;
470 
471       (*cur)++;
472     }
473 
474     return result;
475   }
476 
477 
478   static FT_Long
t1_toint(FT_Byte ** cursor,FT_Byte * limit)479   t1_toint( FT_Byte**  cursor,
480             FT_Byte*   limit )
481   {
482     FT_Long   result = 0;
483     FT_Byte*  cur    = *cursor;
484     FT_Byte   c      = '\0', d;
485 
486 
487     for ( ; cur < limit; cur++ )
488     {
489       c = *cur;
490       d = (FT_Byte)( c - '0' );
491       if ( d < 10 )
492         break;
493 
494       if ( c == '-' )
495       {
496         cur++;
497         break;
498       }
499     }
500 
501     if ( cur < limit )
502     {
503       do
504       {
505         d = (FT_Byte)( cur[0] - '0' );
506         if ( d >= 10 )
507         {
508           if ( cur[0] == '#' )
509           {
510             cur++;
511             result = T1Radix( result, &cur, limit );
512           }
513           break;
514         }
515 
516         result = result * 10 + d;
517         cur++;
518 
519       } while ( cur < limit );
520 
521       if ( c == '-' )
522         result = -result;
523     }
524 
525     *cursor = cur;
526     return result;
527   }
528 
529 
530   static FT_Long
t1_tofixed(FT_Byte ** cursor,FT_Byte * limit,FT_Long power_ten)531   t1_tofixed( FT_Byte**  cursor,
532               FT_Byte*   limit,
533               FT_Long    power_ten )
534   {
535     FT_Byte*  cur  = *cursor;
536     FT_Long   num, divider, result;
537     FT_Int    sign = 0;
538     FT_Byte   d;
539 
540 
541     if ( cur >= limit )
542       return 0;
543 
544     /* first of all, check the sign */
545     if ( *cur == '-' )
546     {
547       sign = 1;
548       cur++;
549     }
550 
551     /* then, read the integer part, if any */
552     if ( *cur != '.' )
553       result = t1_toint( &cur, limit ) << 16;
554     else
555       result = 0;
556 
557     num     = 0;
558     divider = 1;
559 
560     if ( cur >= limit )
561       goto Exit;
562 
563     /* read decimal part, if any */
564     if ( *cur == '.' && cur + 1 < limit )
565     {
566       cur++;
567 
568       for (;;)
569       {
570         d = (FT_Byte)( *cur - '0' );
571         if ( d >= 10 )
572           break;
573 
574         if ( divider < 10000000L )
575         {
576           num      = num * 10 + d;
577           divider *= 10;
578         }
579 
580         cur++;
581         if ( cur >= limit )
582           break;
583       }
584     }
585 
586     /* read exponent, if any */
587     if ( cur + 1 < limit && ( *cur == 'e' || *cur == 'E' ) )
588     {
589       cur++;
590       power_ten += t1_toint( &cur, limit );
591     }
592 
593   Exit:
594     /* raise to power of ten if needed */
595     while ( power_ten > 0 )
596     {
597       result = result * 10;
598       num    = num * 10;
599       power_ten--;
600     }
601 
602     while ( power_ten < 0 )
603     {
604       result  = result / 10;
605       divider = divider * 10;
606       power_ten++;
607     }
608 
609     if ( num )
610       result += FT_DivFix( num, divider );
611 
612     if ( sign )
613       result = -result;
614 
615     *cursor = cur;
616     return result;
617   }
618 
619 
620   static FT_Int
t1_tocoordarray(FT_Byte ** cursor,FT_Byte * limit,FT_Int max_coords,FT_Short * coords)621   t1_tocoordarray( FT_Byte**  cursor,
622                    FT_Byte*   limit,
623                    FT_Int     max_coords,
624                    FT_Short*  coords )
625   {
626     FT_Byte*  cur   = *cursor;
627     FT_Int    count = 0;
628     FT_Byte   c, ender;
629 
630 
631     if ( cur >= limit )
632       goto Exit;
633 
634     /* check for the beginning of an array; if not, only one number will */
635     /* be read                                                           */
636     c     = *cur;
637     ender = 0;
638 
639     if ( c == '[' )
640       ender = ']';
641 
642     if ( c == '{' )
643       ender = '}';
644 
645     if ( ender )
646       cur++;
647 
648     /* now, read the coordinates */
649     for ( ; cur < limit; )
650     {
651       /* skip whitespace in front of data */
652       for (;;)
653       {
654         c = *cur;
655         if ( c != ' ' && c != '\t' )
656           break;
657 
658         cur++;
659         if ( cur >= limit )
660           goto Exit;
661       }
662 
663       if ( count >= max_coords || c == ender )
664         break;
665 
666       coords[count] = (FT_Short)( t1_tofixed( &cur, limit, 0 ) >> 16 );
667       count++;
668 
669       if ( !ender )
670         break;
671     }
672 
673   Exit:
674     *cursor = cur;
675     return count;
676   }
677 
678 
679   static FT_Int
t1_tofixedarray(FT_Byte ** cursor,FT_Byte * limit,FT_Int max_values,FT_Fixed * values,FT_Int power_ten)680   t1_tofixedarray( FT_Byte**  cursor,
681                    FT_Byte*   limit,
682                    FT_Int     max_values,
683                    FT_Fixed*  values,
684                    FT_Int     power_ten )
685   {
686     FT_Byte*  cur   = *cursor;
687     FT_Int    count = 0;
688     FT_Byte   c, ender;
689 
690 
691     if ( cur >= limit ) goto Exit;
692 
693     /* check for the beginning of an array. If not, only one number will */
694     /* be read                                                           */
695     c     = *cur;
696     ender = 0;
697 
698     if ( c == '[' )
699       ender = ']';
700 
701     if ( c == '{' )
702       ender = '}';
703 
704     if ( ender )
705       cur++;
706 
707     /* now, read the values */
708     for ( ; cur < limit; )
709     {
710       /* skip whitespace in front of data */
711       for (;;)
712       {
713         c = *cur;
714         if ( c != ' ' && c != '\t' )
715           break;
716 
717         cur++;
718         if ( cur >= limit )
719           goto Exit;
720       }
721 
722       if ( count >= max_values || c == ender )
723         break;
724 
725       values[count] = t1_tofixed( &cur, limit, power_ten );
726       count++;
727 
728       if ( !ender )
729         break;
730     }
731 
732   Exit:
733     *cursor = cur;
734     return count;
735   }
736 
737 
738 #if 0
739 
740   static FT_String*
741   t1_tostring( FT_Byte**  cursor,
742                FT_Byte*   limit,
743                FT_Memory  memory )
744   {
745     FT_Byte*    cur = *cursor;
746     FT_PtrDist  len = 0;
747     FT_Int      count;
748     FT_String*  result;
749     FT_Error    error;
750 
751 
752     /* XXX: some stupid fonts have a `Notice' or `Copyright' string     */
753     /*      that simply doesn't begin with an opening parenthesis, even */
754     /*      though they have a closing one!  E.g. "amuncial.pfb"        */
755     /*                                                                  */
756     /*      We must deal with these ill-fated cases there.  Note that   */
757     /*      these fonts didn't work with the old Type 1 driver as the   */
758     /*      notice/copyright was not recognized as a valid string token */
759     /*      and made the old token parser commit errors.                */
760 
761     while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) )
762       cur++;
763     if ( cur + 1 >= limit )
764       return 0;
765 
766     if ( *cur == '(' )
767       cur++;  /* skip the opening parenthesis, if there is one */
768 
769     *cursor = cur;
770     count   = 0;
771 
772     /* then, count its length */
773     for ( ; cur < limit; cur++ )
774     {
775       if ( *cur == '(' )
776         count++;
777 
778       else if ( *cur == ')' )
779       {
780         count--;
781         if ( count < 0 )
782           break;
783       }
784     }
785 
786     len = cur - *cursor;
787     if ( cur >= limit || FT_ALLOC( result, len + 1 ) )
788       return 0;
789 
790     /* now copy the string */
791     FT_MEM_COPY( result, *cursor, len );
792     result[len] = '\0';
793     *cursor = cur;
794     return result;
795   }
796 
797 #endif /* 0 */
798 
799 
800   static int
t1_tobool(FT_Byte ** cursor,FT_Byte * limit)801   t1_tobool( FT_Byte**  cursor,
802              FT_Byte*   limit )
803   {
804     FT_Byte*  cur    = *cursor;
805     FT_Bool   result = 0;
806 
807 
808     /* return 1 if we find `true', 0 otherwise */
809     if ( cur + 3 < limit &&
810          cur[0] == 't' &&
811          cur[1] == 'r' &&
812          cur[2] == 'u' &&
813          cur[3] == 'e' )
814     {
815       result = 1;
816       cur   += 5;
817     }
818     else if ( cur + 4 < limit &&
819               cur[0] == 'f' &&
820               cur[1] == 'a' &&
821               cur[2] == 'l' &&
822               cur[3] == 's' &&
823               cur[4] == 'e' )
824     {
825       result = 0;
826       cur   += 6;
827     }
828 
829     *cursor = cur;
830     return result;
831   }
832 
833 
834   /* Load a simple field (i.e. non-table) into the current list of objects */
835   FT_LOCAL_DEF( FT_Error )
ps_parser_load_field(PS_Parser parser,const T1_Field field,void ** objects,FT_UInt max_objects,FT_ULong * pflags)836   ps_parser_load_field( PS_Parser       parser,
837                         const T1_Field  field,
838                         void**          objects,
839                         FT_UInt         max_objects,
840                         FT_ULong*       pflags )
841   {
842     T1_TokenRec  token;
843     FT_Byte*     cur;
844     FT_Byte*     limit;
845     FT_UInt      count;
846     FT_UInt      idx;
847     FT_Error     error;
848 
849 
850     ps_parser_to_token( parser, &token );
851     if ( !token.type )
852       goto Fail;
853 
854     count = 1;
855     idx   = 0;
856     cur   = token.start;
857     limit = token.limit;
858 
859     /* we must detect arrays */
860     if ( field->type == T1_FIELD_TYPE_BBOX )
861     {
862       T1_TokenRec  token2;
863       FT_Byte*     old_cur   = parser->cursor;
864       FT_Byte*     old_limit = parser->limit;
865 
866 
867       parser->cursor = token.start;
868       parser->limit  = token.limit;
869 
870       ps_parser_to_token( parser, &token2 );
871       parser->cursor = old_cur;
872       parser->limit  = old_limit;
873 
874       if ( token2.type == T1_TOKEN_TYPE_ARRAY )
875         goto FieldArray;
876     }
877     else if ( token.type == T1_TOKEN_TYPE_ARRAY )
878     {
879     FieldArray:
880       /* if this is an array, and we have no blend, an error occurs */
881       if ( max_objects == 0 )
882         goto Fail;
883 
884       count = max_objects;
885       idx = 1;
886     }
887 
888     for ( ; count > 0; count--, idx++ )
889     {
890       FT_Byte*    q = (FT_Byte*)objects[idx] + field->offset;
891       FT_Long     val;
892       FT_String*  string;
893 
894 
895       switch ( field->type )
896       {
897       case T1_FIELD_TYPE_BOOL:
898         val = t1_tobool( &cur, limit );
899         goto Store_Integer;
900 
901       case T1_FIELD_TYPE_FIXED:
902         val = t1_tofixed( &cur, limit, 3 );
903         goto Store_Integer;
904 
905       case T1_FIELD_TYPE_INTEGER:
906         val = t1_toint( &cur, limit );
907 
908       Store_Integer:
909         switch ( field->size )
910         {
911         case 1:
912           *(FT_Byte*)q = (FT_Byte)val;
913           break;
914 
915         case 2:
916           *(FT_UShort*)q = (FT_UShort)val;
917           break;
918 
919         case 4:
920           *(FT_UInt32*)q = (FT_UInt32)val;
921           break;
922 
923         default:                /* for 64-bit systems */
924           *(FT_Long*)q = val;
925         }
926         break;
927 
928       case T1_FIELD_TYPE_STRING:
929         {
930           FT_Memory  memory = parser->memory;
931           FT_UInt    len    = (FT_UInt)( limit - cur );
932 
933 
934           if ( *(FT_String**)q )
935             /* with synthetic fonts, it's possible to find a field twice */
936             break;
937 
938           if ( FT_ALLOC( string, len + 1 ) )
939             goto Exit;
940 
941           FT_MEM_COPY( string, cur, len );
942           string[len] = 0;
943 
944           *(FT_String**)q = string;
945         }
946         break;
947 
948       case T1_FIELD_TYPE_BBOX:
949         {
950           FT_Fixed  temp[4];
951           FT_BBox*  bbox = (FT_BBox*)q;
952 
953 
954           /* we need the '[' and ']' delimiters */
955           token.start--;
956           token.limit++;
957           (void)t1_tofixedarray( &token.start, token.limit, 4, temp, 0 );
958 
959           bbox->xMin = FT_RoundFix( temp[0] );
960           bbox->yMin = FT_RoundFix( temp[1] );
961           bbox->xMax = FT_RoundFix( temp[2] );
962           bbox->yMax = FT_RoundFix( temp[3] );
963         }
964         break;
965 
966       default:
967         /* an error occured */
968         goto Fail;
969       }
970     }
971 
972 #if 0  /* obsolete - keep for reference */
973     if ( pflags )
974       *pflags |= 1L << field->flag_bit;
975 #else
976     FT_UNUSED( pflags );
977 #endif
978 
979     error = PSaux_Err_Ok;
980 
981   Exit:
982     return error;
983 
984   Fail:
985     error = PSaux_Err_Invalid_File_Format;
986     goto Exit;
987   }
988 
989 
990 #define T1_MAX_TABLE_ELEMENTS  32
991 
992 
993   FT_LOCAL_DEF( FT_Error )
ps_parser_load_field_table(PS_Parser parser,const T1_Field field,void ** objects,FT_UInt max_objects,FT_ULong * pflags)994   ps_parser_load_field_table( PS_Parser       parser,
995                               const T1_Field  field,
996                               void**          objects,
997                               FT_UInt         max_objects,
998                               FT_ULong*       pflags )
999   {
1000     T1_TokenRec  elements[T1_MAX_TABLE_ELEMENTS];
1001     T1_Token     token;
1002     FT_Int       num_elements;
1003     FT_Error     error = 0;
1004     FT_Byte*     old_cursor;
1005     FT_Byte*     old_limit;
1006     T1_FieldRec  fieldrec = *(T1_Field)field;
1007 
1008 
1009 #if 1
1010     fieldrec.type = T1_FIELD_TYPE_INTEGER;
1011     if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY )
1012       fieldrec.type = T1_FIELD_TYPE_FIXED;
1013 #endif
1014 
1015     ps_parser_to_token_array( parser, elements, 32, &num_elements );
1016     if ( num_elements < 0 )
1017       goto Fail;
1018 
1019     if ( num_elements > T1_MAX_TABLE_ELEMENTS )
1020       num_elements = T1_MAX_TABLE_ELEMENTS;
1021 
1022     old_cursor = parser->cursor;
1023     old_limit  = parser->limit;
1024 
1025     /* we store the elements count */
1026     *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) =
1027       (FT_Byte)num_elements;
1028 
1029     /* we now load each element, adjusting the field.offset on each one */
1030     token = elements;
1031     for ( ; num_elements > 0; num_elements--, token++ )
1032     {
1033       parser->cursor = token->start;
1034       parser->limit  = token->limit;
1035       ps_parser_load_field( parser, &fieldrec, objects, max_objects, 0 );
1036       fieldrec.offset += fieldrec.size;
1037     }
1038 
1039 #if 0  /* obsolete -- keep for reference */
1040     if ( pflags )
1041       *pflags |= 1L << field->flag_bit;
1042 #else
1043     FT_UNUSED( pflags );
1044 #endif
1045 
1046     parser->cursor = old_cursor;
1047     parser->limit  = old_limit;
1048 
1049   Exit:
1050     return error;
1051 
1052   Fail:
1053     error = PSaux_Err_Invalid_File_Format;
1054     goto Exit;
1055   }
1056 
1057 
1058   FT_LOCAL_DEF( FT_Long )
ps_parser_to_int(PS_Parser parser)1059   ps_parser_to_int( PS_Parser  parser )
1060   {
1061     return t1_toint( &parser->cursor, parser->limit );
1062   }
1063 
1064 
1065   FT_LOCAL_DEF( FT_Fixed )
ps_parser_to_fixed(PS_Parser parser,FT_Int power_ten)1066   ps_parser_to_fixed( PS_Parser  parser,
1067                       FT_Int     power_ten )
1068   {
1069     return t1_tofixed( &parser->cursor, parser->limit, power_ten );
1070   }
1071 
1072 
1073   FT_LOCAL_DEF( FT_Int )
ps_parser_to_coord_array(PS_Parser parser,FT_Int max_coords,FT_Short * coords)1074   ps_parser_to_coord_array( PS_Parser  parser,
1075                             FT_Int     max_coords,
1076                             FT_Short*  coords )
1077   {
1078     return t1_tocoordarray( &parser->cursor, parser->limit,
1079                             max_coords, coords );
1080   }
1081 
1082 
1083   FT_LOCAL_DEF( FT_Int )
ps_parser_to_fixed_array(PS_Parser parser,FT_Int max_values,FT_Fixed * values,FT_Int power_ten)1084   ps_parser_to_fixed_array( PS_Parser  parser,
1085                             FT_Int     max_values,
1086                             FT_Fixed*  values,
1087                             FT_Int     power_ten )
1088   {
1089     return t1_tofixedarray( &parser->cursor, parser->limit,
1090                             max_values, values, power_ten );
1091   }
1092 
1093 
1094 #if 0
1095 
1096   FT_LOCAL_DEF( FT_String* )
1097   T1_ToString( PS_Parser  parser )
1098   {
1099     return t1_tostring( &parser->cursor, parser->limit, parser->memory );
1100   }
1101 
1102 
1103   FT_LOCAL_DEF( FT_Bool )
1104   T1_ToBool( PS_Parser  parser )
1105   {
1106     return t1_tobool( &parser->cursor, parser->limit );
1107   }
1108 
1109 #endif /* 0 */
1110 
1111 
1112   FT_LOCAL_DEF( void )
ps_parser_init(PS_Parser parser,FT_Byte * base,FT_Byte * limit,FT_Memory memory)1113   ps_parser_init( PS_Parser  parser,
1114                   FT_Byte*   base,
1115                   FT_Byte*   limit,
1116                   FT_Memory  memory )
1117   {
1118     parser->error  = 0;
1119     parser->base   = base;
1120     parser->limit  = limit;
1121     parser->cursor = base;
1122     parser->memory = memory;
1123     parser->funcs  = ps_parser_funcs;
1124   }
1125 
1126 
1127   FT_LOCAL_DEF( void )
ps_parser_done(PS_Parser parser)1128   ps_parser_done( PS_Parser  parser )
1129   {
1130     FT_UNUSED( parser );
1131   }
1132 
1133 
1134   /*************************************************************************/
1135   /*************************************************************************/
1136   /*****                                                               *****/
1137   /*****                            T1 BUILDER                         *****/
1138   /*****                                                               *****/
1139   /*************************************************************************/
1140   /*************************************************************************/
1141 
1142   /*************************************************************************/
1143   /*                                                                       */
1144   /* <Function>                                                            */
1145   /*    t1_builder_init                                                    */
1146   /*                                                                       */
1147   /* <Description>                                                         */
1148   /*    Initializes a given glyph builder.                                 */
1149   /*                                                                       */
1150   /* <InOut>                                                               */
1151   /*    builder :: A pointer to the glyph builder to initialize.           */
1152   /*                                                                       */
1153   /* <Input>                                                               */
1154   /*    face    :: The current face object.                                */
1155   /*                                                                       */
1156   /*    size    :: The current size object.                                */
1157   /*                                                                       */
1158   /*    glyph   :: The current glyph object.                               */
1159   /*                                                                       */
1160   /*    hinting :: Whether hinting should be applied.                      */
1161   /*                                                                       */
1162   FT_LOCAL_DEF( void )
t1_builder_init(T1_Builder builder,FT_Face face,FT_Size size,FT_GlyphSlot glyph,FT_Bool hinting)1163   t1_builder_init( T1_Builder    builder,
1164                    FT_Face       face,
1165                    FT_Size       size,
1166                    FT_GlyphSlot  glyph,
1167                    FT_Bool       hinting )
1168   {
1169     builder->path_begun  = 0;
1170     builder->load_points = 1;
1171 
1172     builder->face   = face;
1173     builder->glyph  = glyph;
1174     builder->memory = face->memory;
1175 
1176     if ( glyph )
1177     {
1178       FT_GlyphLoader  loader = glyph->internal->loader;
1179 
1180 
1181       builder->loader  = loader;
1182       builder->base    = &loader->base.outline;
1183       builder->current = &loader->current.outline;
1184       FT_GlyphLoader_Rewind( loader );
1185 
1186       builder->hints_globals = size->internal;
1187       builder->hints_funcs   = 0;
1188 
1189       if ( hinting )
1190         builder->hints_funcs = glyph->internal->glyph_hints;
1191     }
1192 
1193     if ( size )
1194     {
1195       builder->scale_x = size->metrics.x_scale;
1196       builder->scale_y = size->metrics.y_scale;
1197     }
1198 
1199     builder->pos_x = 0;
1200     builder->pos_y = 0;
1201 
1202     builder->left_bearing.x = 0;
1203     builder->left_bearing.y = 0;
1204     builder->advance.x      = 0;
1205     builder->advance.y      = 0;
1206 
1207     builder->funcs = t1_builder_funcs;
1208   }
1209 
1210 
1211   /*************************************************************************/
1212   /*                                                                       */
1213   /* <Function>                                                            */
1214   /*    t1_builder_done                                                    */
1215   /*                                                                       */
1216   /* <Description>                                                         */
1217   /*    Finalizes a given glyph builder.  Its contents can still be used   */
1218   /*    after the call, but the function saves important information       */
1219   /*    within the corresponding glyph slot.                               */
1220   /*                                                                       */
1221   /* <Input>                                                               */
1222   /*    builder :: A pointer to the glyph builder to finalize.             */
1223   /*                                                                       */
1224   FT_LOCAL_DEF( void )
t1_builder_done(T1_Builder builder)1225   t1_builder_done( T1_Builder  builder )
1226   {
1227     FT_GlyphSlot  glyph = builder->glyph;
1228 
1229 
1230     if ( glyph )
1231       glyph->outline = *builder->base;
1232   }
1233 
1234 
1235   /* check that there is enough space for `count' more points */
1236   FT_LOCAL_DEF( FT_Error )
t1_builder_check_points(T1_Builder builder,FT_Int count)1237   t1_builder_check_points( T1_Builder  builder,
1238                            FT_Int      count )
1239   {
1240     return FT_GlyphLoader_CheckPoints( builder->loader, count, 0 );
1241   }
1242 
1243 
1244   /* add a new point, do not check space */
1245   FT_LOCAL_DEF( void )
t1_builder_add_point(T1_Builder builder,FT_Pos x,FT_Pos y,FT_Byte flag)1246   t1_builder_add_point( T1_Builder  builder,
1247                         FT_Pos      x,
1248                         FT_Pos      y,
1249                         FT_Byte     flag )
1250   {
1251     FT_Outline*  outline = builder->current;
1252 
1253 
1254     if ( builder->load_points )
1255     {
1256       FT_Vector*  point   = outline->points + outline->n_points;
1257       FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points;
1258 
1259 
1260       if ( builder->shift )
1261       {
1262         x >>= 16;
1263         y >>= 16;
1264       }
1265       point->x = x;
1266       point->y = y;
1267       *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
1268 
1269       builder->last = *point;
1270     }
1271     outline->n_points++;
1272   }
1273 
1274 
1275   /* check space for a new on-curve point, then add it */
1276   FT_LOCAL_DEF( FT_Error )
t1_builder_add_point1(T1_Builder builder,FT_Pos x,FT_Pos y)1277   t1_builder_add_point1( T1_Builder  builder,
1278                          FT_Pos      x,
1279                          FT_Pos      y )
1280   {
1281     FT_Error  error;
1282 
1283 
1284     error = t1_builder_check_points( builder, 1 );
1285     if ( !error )
1286       t1_builder_add_point( builder, x, y, 1 );
1287 
1288     return error;
1289   }
1290 
1291 
1292   /* check room for a new contour, then add it */
1293   FT_LOCAL_DEF( FT_Error )
t1_builder_add_contour(T1_Builder builder)1294   t1_builder_add_contour( T1_Builder  builder )
1295   {
1296     FT_Outline*  outline = builder->current;
1297     FT_Error     error;
1298 
1299 
1300     if ( !builder->load_points )
1301     {
1302       outline->n_contours++;
1303       return PSaux_Err_Ok;
1304     }
1305 
1306     error = FT_GlyphLoader_CheckPoints( builder->loader, 0, 1 );
1307     if ( !error )
1308     {
1309       if ( outline->n_contours > 0 )
1310         outline->contours[outline->n_contours - 1] =
1311           (short)( outline->n_points - 1 );
1312 
1313       outline->n_contours++;
1314     }
1315 
1316     return error;
1317   }
1318 
1319 
1320   /* if a path was begun, add its first on-curve point */
1321   FT_LOCAL_DEF( FT_Error )
t1_builder_start_point(T1_Builder builder,FT_Pos x,FT_Pos y)1322   t1_builder_start_point( T1_Builder  builder,
1323                           FT_Pos      x,
1324                           FT_Pos      y )
1325   {
1326     FT_Error  error = 0;
1327 
1328 
1329     /* test whether we are building a new contour */
1330     if ( !builder->path_begun )
1331     {
1332       builder->path_begun = 1;
1333       error = t1_builder_add_contour( builder );
1334       if ( !error )
1335         error = t1_builder_add_point1( builder, x, y );
1336     }
1337     return error;
1338   }
1339 
1340 
1341   /* close the current contour */
1342   FT_LOCAL_DEF( void )
t1_builder_close_contour(T1_Builder builder)1343   t1_builder_close_contour( T1_Builder  builder )
1344   {
1345     FT_Outline*  outline = builder->current;
1346 
1347 
1348     /* XXXX: We must not include the last point in the path if it */
1349     /*       is located on the first point.                       */
1350     if ( outline->n_points > 1 )
1351     {
1352       FT_Int      first   = 0;
1353       FT_Vector*  p1      = outline->points + first;
1354       FT_Vector*  p2      = outline->points + outline->n_points - 1;
1355       FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points - 1;
1356 
1357 
1358       if ( outline->n_contours > 1 )
1359       {
1360         first = outline->contours[outline->n_contours - 2] + 1;
1361         p1    = outline->points + first;
1362       }
1363 
1364       /* `delete' last point only if it coincides with the first */
1365       /* point and it is not a control point (which can happen). */
1366       if ( p1->x == p2->x && p1->y == p2->y )
1367         if ( *control == FT_CURVE_TAG_ON )
1368           outline->n_points--;
1369     }
1370 
1371     if ( outline->n_contours > 0 )
1372       outline->contours[outline->n_contours - 1] =
1373         (short)( outline->n_points - 1 );
1374   }
1375 
1376 
1377   /*************************************************************************/
1378   /*************************************************************************/
1379   /*****                                                               *****/
1380   /*****                            OTHER                              *****/
1381   /*****                                                               *****/
1382   /*************************************************************************/
1383   /*************************************************************************/
1384 
1385   FT_LOCAL_DEF( void )
t1_decrypt(FT_Byte * buffer,FT_Offset length,FT_UShort seed)1386   t1_decrypt( FT_Byte*   buffer,
1387               FT_Offset  length,
1388               FT_UShort  seed )
1389   {
1390     while ( length > 0 )
1391     {
1392       FT_Byte  plain;
1393 
1394 
1395       plain     = (FT_Byte)( *buffer ^ ( seed >> 8 ) );
1396       seed      = (FT_UShort)( ( *buffer + seed ) * 52845U + 22719 );
1397       *buffer++ = plain;
1398       length--;
1399     }
1400   }
1401 
1402 
1403 /* END */
1404