:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / subsys / win32k / freetype / src / type1 / t1parse.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  t1parse.c                                                              */
4 /*                                                                         */
5 /*    Type 1 parser (body).                                                */
6 /*                                                                         */
7 /*  Copyright 1996-2000 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 <freetype/internal/ftdebug.h>
20 #include <freetype/internal/t1types.h>
21
22
23 #ifdef FT_FLAT_COMPILE
24
25 #include "t1parse.h"
26
27 #else
28
29 #include <freetype/src/type1/t1parse.h>
30
31 #endif
32
33
34 #include <stdio.h>  /* for sscanf()  */
35 #include <string.h> /* for strncpy() */
36
37
38   /*************************************************************************/
39   /*                                                                       */
40   /* <Function>                                                            */
41   /*    T1_New_Table                                                       */
42   /*                                                                       */
43   /* <Description>                                                         */
44   /*    Initializes a T1_Table structure.                                  */
45   /*                                                                       */
46   /* <InOut>                                                               */
47   /*    table  :: The address of the target table.                         */
48   /*                                                                       */
49   /* <Input>                                                               */
50   /*    count  :: The table size (i.e. maximum number of elements).        */
51   /*    memory :: The memory object to use for all subsequent              */
52   /*              reallocations.                                           */
53   /*                                                                       */
54   /* <Return>                                                              */
55   /*    FreeType error code.  0 means success.                             */
56   /*                                                                       */
57   LOCAL_FUNC
58   FT_Error  T1_New_Table( T1_Table*  table,
59                           FT_Int     count,
60                           FT_Memory  memory )
61   {
62          FT_Error  error;
63
64
65          table->memory = memory;
66
67          if ( ALLOC_ARRAY( table->elements, count, FT_Byte* ) )
68                  return error;
69
70          if ( ALLOC_ARRAY( table->lengths, count, FT_Byte* ) )
71          {
72            FREE( table->elements );
73            return error;
74         }
75
76         table->max_elems = count;
77         table->num_elems = 0;
78
79         table->block        = 0;
80         table->capacity     = 0;
81         table->cursor       = 0;
82
83         return error;
84   }
85
86
87   static
88   FT_Error  reallocate_t1_table( T1_Table*  table,
89                                  FT_Int     new_size )
90   {
91     FT_Memory  memory   = table->memory;
92     FT_Byte*   old_base = table->block;
93     FT_Error   error;
94
95
96     /* reallocate the base block */
97     if ( REALLOC( table->block, table->capacity, new_size ) )
98       return error;
99     table->capacity = new_size;
100
101     /* shift all offsets if necessary */
102     if ( old_base )
103     {
104       FT_Long    delta  = table->block - old_base;
105       FT_Byte**  offset = table->elements;
106       FT_Byte**  limit  = offset + table->max_elems;
107
108
109       if ( delta )
110         for ( ; offset < limit; offset ++ )
111           if (offset[0])
112             offset[0] += delta;
113     }
114
115     return T1_Err_Ok;
116   }
117
118
119   /*************************************************************************/
120   /*                                                                       */
121   /* <Function>                                                            */
122   /*    T1_Add_Table                                                       */
123   /*                                                                       */
124   /* <Description>                                                         */
125   /*    Adds an object to a T1_Table, possibly growing its memory block.   */
126   /*                                                                       */
127   /* <InOut>                                                               */
128   /*    table  :: The target table.                                        */
129   /*                                                                       */
130   /* <Input>                                                               */
131   /*    index  :: The index of the object in the table.                    */
132   /*                                                                       */
133   /*    object :: The address of the object to copy in memory.             */
134   /*                                                                       */
135   /*    length :: The length in bytes of the source object.                */
136   /*                                                                       */
137   /* <Return>                                                              */
138   /*    FreeType error code.  0 means success.  An error is returned if a  */
139   /*    reallocation failed.                                               */
140   /*                                                                       */
141   LOCAL_FUNC
142   FT_Error  T1_Add_Table( T1_Table*  table,
143                           FT_Int     index,
144                           void*      object,
145                           FT_Int     length )
146   {
147         if ( index < 0 || index > table->max_elems )
148     {
149           FT_ERROR(( "T1_Add_Table: invalid index\n" ));
150           return T1_Err_Syntax_Error;
151     }
152
153     /* grow the base block if needed */
154     if ( table->cursor + length > table->capacity )
155     {
156       FT_Error  error;
157       FT_Int    new_size = table->capacity;
158
159
160       while ( new_size < table->cursor + length )
161         new_size += 1024;
162
163       error = reallocate_t1_table( table, new_size );
164       if ( error )
165         return error;
166     }
167
168     /* add the object to the base block and adjust offset */
169     table->elements[index] = table->block + table->cursor;
170     table->lengths [index] = length;
171     MEM_Copy( table->block + table->cursor, object, length );
172
173     table->cursor += length;
174
175     return T1_Err_Ok;
176   }
177
178
179   /*************************************************************************/
180   /*                                                                       */
181   /* <Function>                                                            */
182   /*    T1_Done_Table                                                      */
183   /*                                                                       */
184   /* <Description>                                                         */
185   /*    Finalize a T1_Table (reallocate it to its current cursor).         */
186   /*                                                                       */
187   /* <Input>                                                               */
188   /*    table :: The target table.                                         */
189   /*                                                                       */
190   /* <Note>                                                                */
191   /*    This function does NOT release the heap's memory block.  It is up  */
192   /*    to the caller to clean it, or reference it in its own structures.  */
193   /*                                                                       */
194   LOCAL_FUNC
195   void  T1_Done_Table( T1_Table*  table )
196   {
197     FT_Memory  memory = table->memory;
198     FT_Error   error;
199     FT_Byte*   old_base;
200
201
202     /* should never fail, as rec.cursor <= rec.size */
203     old_base = table->block;
204     if ( !old_base )
205       return;
206
207     (void)REALLOC( table->block, table->capacity, table->cursor );
208     table->capacity = table->cursor;
209
210     if ( old_base != table->block )
211     {
212       FT_Long    delta   = table->block - old_base;
213       FT_Byte**  element = table->elements;
214       FT_Byte**  limit   = element + table->max_elems;
215
216
217       for ( ; element < limit; element++ )
218         if ( element[0] )
219           element[0] += delta;
220     }
221   }
222
223
224   LOCAL_FUNC
225   FT_String*  CopyString( T1_Parser*  parser )
226   {
227     FT_String*  string = NULL;
228     T1_Token*   token  = parser->args++;
229     FT_Memory   memory = parser->tokenizer->memory;
230     FT_Error    error;
231
232
233     if ( token->kind == tok_string )
234     {
235       FT_Int  len = token->len - 2;
236
237
238       if ( ALLOC( string, len + 1 ) )
239       {
240         parser->error = error;
241         return 0;
242       }
243
244       MEM_Copy( string, parser->tokenizer->base + token->start + 1, len );
245       string[len] = '\0';
246
247       parser->error = T1_Err_Ok;
248     }
249     else
250     {
251       FT_ERROR(( "T1_CopyString: syntax error, string token expected!\n" ));
252       parser->error = T1_Err_Syntax_Error;
253     }
254
255     return string;
256   }
257
258
259   static
260   FT_Error  parse_int( FT_Byte*  base,
261                        FT_Byte*  limit,
262                        FT_Long*  result )
263   {
264     FT_Bool  sign = 0;
265     FT_Long  sum  = 0;
266
267
268     if ( base >= limit )
269       goto Fail;
270
271     /* check sign */
272     if ( *base == '+' )
273       base++;
274
275     else if ( *base == '-' )
276     {
277       sign++;
278       base++;
279     }
280
281     /* parse digits */
282     if ( base >= limit )
283       goto Fail;
284
285     do
286     {
287       sum = ( 10 * sum + ( *base++ - '0' ) );
288
289     } while ( base < limit );
290
291     if ( sign )
292       sum = -sum;
293
294     *result = sum;
295     return T1_Err_Ok;
296
297   Fail:
298     FT_ERROR(( "parse_int: integer expected\n" ));
299     *result = 0;
300     return T1_Err_Syntax_Error;
301   }
302
303
304   static
305   FT_Error  parse_float( FT_Byte*  base,
306                          FT_Byte*  limit,
307                          FT_Long   scale,
308                          FT_Long*  result )
309   {
310 #if 1
311
312     /* XXX: We are simply much too lazy to code this function   */
313     /*      properly for now.  We will do that when the rest of */
314     /*      the driver works properly.                          */
315     char    temp[32];
316     int     len = limit - base;
317     double  value;
318
319
320     if ( len > 31 )
321       goto Fail;
322
323     strncpy( temp, (char*)base, len );
324     temp[len] = '\0';
325     if ( sscanf( temp, "%lf", &value ) != 1 )
326       goto Fail;
327
328     *result = (FT_Long)( scale * value );
329     return 0;
330
331 #else
332
333     FT_Byte*  cur;
334     FT_Bool   sign        = 0;  /* sign                        */
335     FT_Long   number_int  = 0;  /* integer part                */
336     FT_Long   number_frac = 0;  /* fractional part             */
337     FT_Long   exponent    = 0;  /* exponent value              */
338     FT_Int    num_frac    = 0;  /* number of fractional digits */
339
340
341     /* check sign */
342     if ( *base == '+' )
343       base++;
344
345     else if ( *base == '-' )
346     {
347       sign++;
348       base++;
349     }
350
351     /* find integer part */
352     cur = base;
353     while ( cur < limit )
354     {
355       FT_Byte  c = *cur;
356
357
358       if ( c == '.' || c == 'e' || c == 'E' )
359         break;
360
361       cur++;
362     }
363
364     if ( cur > base )
365     {
366       error = parse_integer( base, cur, &number_int );
367       if ( error )
368         goto Fail;
369     }
370
371     /* read fractional part, if any */
372     if ( *cur == '.' )
373     {
374       cur++;
375       base = cur;
376       while ( cur < limit )
377       {
378         FT_Byte  c = *cur;
379
380
381         if ( c == 'e' || c == 'E' )
382           break;
383         cur++;
384       }
385
386       num_frac = cur - base;
387
388       if ( cur > base )
389       {
390         error = parse_integer( base, cur, &number_frac );
391         if ( error )
392           goto Fail;
393         base = cur;
394       }
395    }
396
397     /* read exponent, if any */
398     if ( *cur == 'e' || *cur == 'E' )
399     {
400       cur++;
401       base = cur;
402       error = parse_integer( base, limit, &exponent );
403       if ( error )
404         goto Fail;
405
406       /* now check that exponent is within `correct bounds' */
407       /* i.e. between -6 and 6                              */
408       if ( exponent < -6 || exponent > 6 )
409         goto Fail;
410     }
411
412     /* now adjust integer value and exponent for fractional part */
413     while ( num_frac > 0 )
414     {
415       number_int *= 10;
416       exponent--;
417       num_frac--;
418     }
419
420     number_int += num_frac;
421
422     /* skip point if any, read fractional part */
423     if ( cur + 1 < limit )
424     {
425       if (*cur..
426     }
427
428     /* now compute scaled float value */
429     /* XXX: incomplete!               */
430
431 #endif /* 1 */
432
433   Fail:
434     FT_ERROR(( "parse_float: syntax error!\n" ));
435     return T1_Err_Syntax_Error;
436   }
437
438
439   static
440   FT_Error  parse_integer( FT_Byte*  base,
441                            FT_Byte*  limit,
442                            FT_Long*  result )
443   {
444     FT_Byte*  cur;
445
446
447     /* the lexical analyser accepts floats as well as integers */
448     /* now; check that we really have an int in this token     */
449     cur = base;
450     while ( cur < limit )
451     {
452       FT_Byte  c = *cur++;
453
454
455       if ( c == '.' || c == 'e' || c == 'E' )
456         goto Float_Number;
457     }
458
459     /* now read the number's value */
460     return parse_int( base, limit, result );
461
462   Float_Number:
463     /* we really have a float there; simply call parse_float in this */
464     /* case with a scale of `10' to perform round                    */
465     {
466       FT_Error error;
467
468
469       error = parse_float( base, limit, 10, result );
470       if ( !error )
471       {
472         if ( *result >= 0 )
473           *result = ( *result + 5 ) / 10;      /* round value */
474         else
475           *result = -( ( 5 - *result ) / 10 );
476       }
477       return error;
478     }
479   }
480
481
482   LOCAL_FUNC
483   FT_Long  CopyInteger( T1_Parser*  parser )
484   {
485     FT_Long    sum   = 0;
486     T1_Token*  token = parser->args++;
487
488
489     if ( token->kind == tok_number )
490     {
491       FT_Byte*  base  = parser->tokenizer->base + token->start;
492       FT_Byte*  limit = base + token->len;
493
494
495       /* now read the number's value */
496       parser->error = parse_integer( base, limit, &sum );
497       return sum;
498     }
499
500     FT_ERROR(( "CopyInteger: number expected\n" ));
501     parser->args--;
502     parser->error = T1_Err_Syntax_Error;
503     return 0;
504   }
505
506
507   LOCAL_FUNC
508   FT_Bool   CopyBoolean( T1_Parser*  parser )
509   {
510     FT_Error   error  = T1_Err_Ok;
511     FT_Bool    result = 0;
512     T1_Token*  token  = parser->args++;
513
514
515     if ( token->kind == tok_keyword )
516     {
517       if ( token->kind2 == key_false )
518         result = 0;
519
520       else if ( token->kind2 == key_true )
521         result = !0;
522
523       else
524         goto Fail;
525     }
526     else
527     {
528       Fail:
529         FT_ERROR(( "CopyBoolean:" ));
530         FT_ERROR(( " syntax error; `false' or `true' expected\n" ));
531         error = T1_Err_Syntax_Error;
532     }
533     parser->error = error;
534     return result;
535   }
536
537
538   LOCAL_FUNC
539   FT_Long   CopyFloat( T1_Parser*  parser,
540                        FT_Int      scale )
541   {
542     FT_Error   error;
543     FT_Long    sum = 0;
544     T1_Token*  token = parser->args++;
545
546
547     if ( token->kind == tok_number )
548     {
549       FT_Byte*  base  = parser->tokenizer->base + token->start;
550       FT_Byte*  limit = base + token->len;
551
552
553       error = parser->error = parse_float( base, limit, scale, &sum );
554       if ( error )
555         goto Fail;
556
557       return sum;
558     }
559
560   Fail:
561     FT_ERROR(( "CopyFloat: syntax error!\n" ));
562     parser->error = T1_Err_Syntax_Error;
563     return 0;
564   }
565
566
567   LOCAL_FUNC
568   void  CopyBBox( T1_Parser*  parser,
569                   FT_BBox*    bbox )
570   {
571     T1_Token*  token = parser->args++;
572     FT_Int     n;
573     FT_Error   error;
574
575
576     if ( token->kind == tok_program ||
577          token->kind == tok_array   )
578     {
579       /* get rid of `['/`]', or `{'/`}' */
580       FT_Byte*  base  = parser->tokenizer->base + token->start + 1;
581       FT_Byte*  limit = base + token->len - 2;
582       FT_Byte*  cur;
583       FT_Byte*  start;
584
585
586       /* read each parameter independently */
587       cur = base;
588       for ( n = 0; n < 4; n++ )
589       {
590         FT_Long*  result;
591
592
593         /* skip whitespace */
594         while ( cur < limit && *cur == ' ' )
595           cur++;
596
597         /* skip numbers */
598         start = cur;
599         while ( cur < limit && *cur != ' ' )
600           cur++;
601
602         /* compute result address */
603         switch ( n )
604         {
605         case 0:
606           result = &bbox->xMin;
607           break;
608         case 1:
609           result = &bbox->yMin;
610           break;
611         case 2:
612           result = &bbox->xMax;
613           break;
614         default:
615           result = &bbox->yMax;
616         }
617
618         error = parse_integer( start, cur, result );
619         if ( error )
620           goto Fail;
621       }
622       parser->error = 0;
623       return;
624     }
625
626   Fail:
627     FT_ERROR(( "CopyBBox: syntax error!\n" ));
628     parser->error = T1_Err_Syntax_Error;
629   }
630
631
632   LOCAL_FUNC
633   void  CopyMatrix( T1_Parser*  parser,
634                     FT_Matrix*  matrix )
635   {
636     T1_Token* token = parser->args++;
637     FT_Error  error;
638
639
640     if ( token->kind == tok_array )
641     {
642       /* get rid of `[' and `]' */
643       FT_Byte*  base  = parser->tokenizer->base + token->start + 1;
644       FT_Byte*  limit = base + token->len - 2;
645       FT_Byte*  cur;
646       FT_Byte*  start;
647       FT_Int    n;
648
649
650       /* read each parameter independently */
651       cur = base;
652       for ( n = 0; n < 4; n++ )
653       {
654         FT_Long*  result;
655
656
657         /* skip whitespace */
658         while ( cur < limit && *cur == ' ' )
659           cur++;
660
661         /* skip numbers */
662         start = cur;
663         while ( cur < limit && *cur != ' ')
664           cur++;
665
666         /* compute result address */
667         switch ( n )
668         {
669         case 0:
670           result = &matrix->xx;
671           break;
672         case 1:
673           result = &matrix->yx;
674           break;
675         case 2:
676           result = &matrix->xy;
677           break;
678         default:
679           result = &matrix->yy;
680         }
681
682         error = parse_float( start, cur, 65536000L, result );
683         if ( error )
684           goto Fail;
685       }
686       parser->error = 0;
687       return;
688     }
689
690   Fail:
691     FT_ERROR(( "CopyMatrix: syntax error!\n" ));
692     parser->error = T1_Err_Syntax_Error;
693   }
694
695
696   LOCAL_FUNC
697   void  CopyArray( T1_Parser*  parser,
698                    FT_Byte*    num_elements,
699                    FT_Short*   elements,
700                    FT_Int      max_elements )
701   {
702     T1_Token* token = parser->args++;
703     FT_Error  error;
704
705
706     if ( token->kind == tok_array   ||
707          token->kind == tok_program )   /* in the case of MinFeature */
708     {
709       /* get rid of `['/`]', or `{'/`}' */
710       FT_Byte*  base  = parser->tokenizer->base + token->start + 1;
711       FT_Byte*  limit = base + token->len - 2;
712       FT_Byte*  cur;
713       FT_Byte*  start;
714       FT_Int    n;
715
716
717       /* read each parameter independently */
718       cur = base;
719       for ( n = 0; n < max_elements; n++ )
720       {
721         FT_Long  result;
722
723
724         /* test end of string */
725         if ( cur >= limit )
726           break;
727
728         /* skip whitespace */
729         while ( cur < limit && *cur == ' ' )
730           cur++;
731
732         /* end of list? */
733         if ( cur >= limit )
734           break;
735
736         /* skip numbers */
737         start = cur;
738         while ( cur < limit && *cur != ' ' )
739           cur++;
740
741         error = parse_integer( start, cur, &result );
742         if ( error )
743           goto Fail;
744
745         *elements++ = (FT_Short)result;
746       }
747
748       if ( num_elements )
749         *num_elements = (FT_Byte)n;
750
751       parser->error = 0;
752       return;
753     }
754
755   Fail:
756     FT_ERROR(( "CopyArray: syntax error!\n" ));
757     parser->error = T1_Err_Syntax_Error;
758   }
759
760
761 /* END */