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