22e8cf2d147dd9292c9c8e3ce0b6f978dccfed89
[framework/graphics/freetype.git] / src / psaux / psconv.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  psconv.c                                                               */
4 /*                                                                         */
5 /*    Some convenience conversions (body).                                 */
6 /*                                                                         */
7 /*  Copyright 2006, 2008, 2009, 2012-2013 by                               */
8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9 /*                                                                         */
10 /*  This file is part of the FreeType project, and may only be used,       */
11 /*  modified, and distributed under the terms of the FreeType project      */
12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13 /*  this file you indicate that you have read the license and              */
14 /*  understand and accept it fully.                                        */
15 /*                                                                         */
16 /***************************************************************************/
17
18
19 #include <ft2build.h>
20 #include FT_INTERNAL_POSTSCRIPT_AUX_H
21 #include FT_INTERNAL_DEBUG_H
22
23 #include "psconv.h"
24 #include "psauxerr.h"
25
26
27   /*************************************************************************/
28   /*                                                                       */
29   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
30   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
31   /* messages during execution.                                            */
32   /*                                                                       */
33 #undef  FT_COMPONENT
34 #define FT_COMPONENT  trace_psconv
35
36
37   /* The following array is used by various functions to quickly convert */
38   /* digits (both decimal and non-decimal) into numbers.                 */
39
40 #if 'A' == 65
41   /* ASCII */
42
43   static const FT_Char  ft_char_table[128] =
44   {
45     /* 0x00 */
46     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
47     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
48     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
49      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
50     -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
51     25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
52     -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
53     25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
54   };
55
56   /* no character >= 0x80 can represent a valid number */
57 #define OP  >=
58
59 #endif /* 'A' == 65 */
60
61 #if 'A' == 193
62   /* EBCDIC */
63
64   static const FT_Char  ft_char_table[128] =
65   {
66     /* 0x80 */
67     -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1,
68     -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1,
69     -1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1,
70     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
71     -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1,
72     -1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1,
73     -1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1,
74      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
75   };
76
77   /* no character < 0x80 can represent a valid number */
78 #define OP  <
79
80 #endif /* 'A' == 193 */
81
82
83   FT_LOCAL_DEF( FT_Long )
84   PS_Conv_Strtol( FT_Byte**  cursor,
85                   FT_Byte*   limit,
86                   FT_Long    base )
87   {
88     FT_Byte*  p = *cursor;
89
90     FT_Long   num           = 0;
91     FT_Bool   sign          = 0;
92     FT_Bool   have_overflow = 0;
93
94     FT_Long   num_limit;
95     FT_Char   c_limit;
96
97
98     if ( p >= limit )
99       goto Bad;
100
101     if ( base < 2 || base > 36 )
102     {
103       FT_TRACE4(( "!!!INVALID BASE:!!!" ));
104       return 0;
105     }
106
107     if ( *p == '-' || *p == '+' )
108     {
109       sign = FT_BOOL( *p == '-' );
110
111       p++;
112       if ( p == limit )
113         goto Bad;
114     }
115
116     num_limit = 0x7FFFFFFFL / base;
117     c_limit   = (FT_Char)( 0x7FFFFFFFL % base );
118
119     for ( ; p < limit; p++ )
120     {
121       FT_Char  c;
122
123
124       if ( IS_PS_SPACE( *p ) || *p OP 0x80 )
125         break;
126
127       c = ft_char_table[*p & 0x7F];
128
129       if ( c < 0 || c >= base )
130         break;
131
132       if ( num > num_limit || ( num == num_limit && c > c_limit ) )
133         have_overflow = 1;
134       else
135         num = num * base + c;
136     }
137
138     *cursor = p;
139
140     if ( have_overflow )
141     {
142       num = 0x7FFFFFFFL;
143       FT_TRACE4(( "!!!OVERFLOW:!!!" ));
144     }
145
146     if ( sign )
147       num = -num;
148
149     return num;
150
151   Bad:
152     FT_TRACE4(( "!!!END OF DATA:!!!" ));
153     return 0;
154   }
155
156
157   FT_LOCAL_DEF( FT_Long )
158   PS_Conv_ToInt( FT_Byte**  cursor,
159                  FT_Byte*   limit )
160
161   {
162     FT_Byte*  p = *cursor;
163     FT_Byte*  curp;
164
165     FT_Long   num;
166
167
168     curp = p;
169     num  = PS_Conv_Strtol( &p, limit, 10 );
170
171     if ( p == curp )
172       return 0;
173
174     if ( p < limit && *p == '#' )
175     {
176       p++;
177
178       curp = p;
179       num  = PS_Conv_Strtol( &p, limit, num );
180
181       if ( p == curp )
182         return 0;
183     }
184
185     *cursor = p;
186
187     return num;
188   }
189
190
191   FT_LOCAL_DEF( FT_Fixed )
192   PS_Conv_ToFixed( FT_Byte**  cursor,
193                    FT_Byte*   limit,
194                    FT_Long    power_ten )
195   {
196     FT_Byte*  p = *cursor;
197     FT_Byte*  curp;
198
199     FT_Fixed  integral = 0;
200     FT_Long   decimal  = 0;
201     FT_Long   divider  = 1;
202
203     FT_Bool   sign           = 0;
204     FT_Bool   have_overflow  = 0;
205     FT_Bool   have_underflow = 0;
206
207
208     if ( p >= limit )
209       goto Bad;
210
211     if ( *p == '-' || *p == '+' )
212     {
213       sign = FT_BOOL( *p == '-' );
214
215       p++;
216       if ( p == limit )
217         goto Bad;
218     }
219
220     /* read the integer part */
221     if ( *p != '.' )
222     {
223       curp     = p;
224       integral = PS_Conv_ToInt( &p, limit );
225
226       if ( p == curp )
227         return 0;
228
229       if ( integral > 0x7FFF )
230         have_overflow = 1;
231       else
232         integral = (FT_Fixed)( (FT_UInt32)integral << 16 );
233     }
234
235     /* read the decimal part */
236     if ( p < limit && *p == '.' )
237     {
238       p++;
239
240       for ( ; p < limit; p++ )
241       {
242         FT_Char  c;
243
244
245         if ( IS_PS_SPACE( *p ) || *p OP 0x80 )
246           break;
247
248         c = ft_char_table[*p & 0x7F];
249
250         if ( c < 0 || c >= 10 )
251           break;
252
253         /* only add digit if we don't overflow */
254         if ( divider < 0xCCCCCCCL && decimal < 0xCCCCCCCL )
255         {
256           decimal = decimal * 10 + c;
257
258           if ( !integral && power_ten > 0 )
259             power_ten--;
260           else
261             divider *= 10;
262         }
263       }
264     }
265
266     /* read exponent, if any */
267     if ( p + 1 < limit && ( *p == 'e' || *p == 'E' ) )
268     {
269       FT_Long  exponent;
270
271
272       p++;
273
274       curp     = p;
275       exponent = PS_Conv_ToInt( &p, limit );
276
277       if ( curp == p )
278         return 0;
279
280       /* arbitrarily limit exponent */
281       if ( exponent > 1000 )
282         have_overflow = 1;
283       else if ( exponent < -1000 )
284         have_underflow = 1;
285       else
286         power_ten += exponent;
287     }
288
289     *cursor = p;
290
291     if ( !integral && !decimal )
292       return 0;
293
294     if ( have_overflow )
295       goto Overflow;
296     if ( have_underflow )
297       goto Underflow;
298
299     while ( power_ten > 0 )
300     {
301       if ( integral >= 0xCCCCCCCL )
302         goto Overflow;
303       integral *= 10;
304
305       if ( decimal >= 0xCCCCCCCL )
306       {
307         if ( divider == 1 )
308           goto Overflow;
309         divider /= 10;
310       }
311       else
312         decimal *= 10;
313
314       power_ten--;
315     }
316
317     while ( power_ten < 0 )
318     {
319       integral /= 10;
320       if ( divider < 0xCCCCCCCL )
321         divider *= 10;
322       else
323         decimal /= 10;
324
325       if ( !integral && !decimal )
326         goto Underflow;
327
328       power_ten++;
329     }
330
331     if ( decimal )
332     {
333       decimal = FT_DivFix( decimal, divider );
334       /* it's not necessary to check this addition for overflow */
335       /* due to the structure of the real number representation */
336       integral += decimal;
337     }
338
339   Exit:
340     if ( sign )
341       integral = -integral;
342
343     return integral;
344
345   Bad:
346     FT_TRACE4(( "!!!END OF DATA:!!!" ));
347     return 0;
348
349   Overflow:
350     integral = 0x7FFFFFFFL;
351     FT_TRACE4(( "!!!OVERFLOW:!!!" ));
352     goto Exit;
353
354   Underflow:
355     FT_TRACE4(( "!!!UNDERFLOW:!!!" ));
356     return 0;
357   }
358
359
360 #if 0
361   FT_LOCAL_DEF( FT_UInt )
362   PS_Conv_StringDecode( FT_Byte**  cursor,
363                         FT_Byte*   limit,
364                         FT_Byte*   buffer,
365                         FT_Offset  n )
366   {
367     FT_Byte*  p;
368     FT_UInt   r = 0;
369
370
371     for ( p = *cursor; r < n && p < limit; p++ )
372     {
373       FT_Byte  b;
374
375
376       if ( *p != '\\' )
377       {
378         buffer[r++] = *p;
379
380         continue;
381       }
382
383       p++;
384
385       switch ( *p )
386       {
387       case 'n':
388         b = '\n';
389         break;
390       case 'r':
391         b = '\r';
392         break;
393       case 't':
394         b = '\t';
395         break;
396       case 'b':
397         b = '\b';
398         break;
399       case 'f':
400         b = '\f';
401         break;
402       case '\r':
403         p++;
404         if ( *p != '\n' )
405         {
406           b = *p;
407
408           break;
409         }
410         /* no break */
411       case '\n':
412         continue;
413         break;
414       default:
415         if ( IS_PS_DIGIT( *p ) )
416         {
417           b = *p - '0';
418
419           p++;
420
421           if ( IS_PS_DIGIT( *p ) )
422           {
423             b = b * 8 + *p - '0';
424
425             p++;
426
427             if ( IS_PS_DIGIT( *p ) )
428               b = b * 8 + *p - '0';
429             else
430             {
431               buffer[r++] = b;
432               b = *p;
433             }
434           }
435           else
436           {
437             buffer[r++] = b;
438             b = *p;
439           }
440         }
441         else
442           b = *p;
443         break;
444       }
445
446       buffer[r++] = b;
447     }
448
449     *cursor = p;
450
451     return r;
452   }
453 #endif /* 0 */
454
455
456   FT_LOCAL_DEF( FT_UInt )
457   PS_Conv_ASCIIHexDecode( FT_Byte**  cursor,
458                           FT_Byte*   limit,
459                           FT_Byte*   buffer,
460                           FT_Offset  n )
461   {
462     FT_Byte*  p;
463     FT_UInt   r   = 0;
464     FT_UInt   w   = 0;
465     FT_UInt   pad = 0x01;
466
467
468     n *= 2;
469
470 #if 1
471
472     p = *cursor;
473
474     if ( p >= limit )
475       return 0;
476
477     if ( n > (FT_UInt)( limit - p ) )
478       n = (FT_UInt)( limit - p );
479
480     /* we try to process two nibbles at a time to be as fast as possible */
481     for ( ; r < n; r++ )
482     {
483       FT_UInt  c = p[r];
484
485
486       if ( IS_PS_SPACE( c ) )
487         continue;
488
489       if ( c OP 0x80 )
490         break;
491
492       c = ft_char_table[c & 0x7F];
493       if ( (unsigned)c >= 16 )
494         break;
495
496       pad = ( pad << 4 ) | c;
497       if ( pad & 0x100 )
498       {
499         buffer[w++] = (FT_Byte)pad;
500         pad         = 0x01;
501       }
502     }
503
504     if ( pad != 0x01 )
505       buffer[w++] = (FT_Byte)( pad << 4 );
506
507     *cursor = p + r;
508
509     return w;
510
511 #else /* 0 */
512
513     for ( r = 0; r < n; r++ )
514     {
515       FT_Char  c;
516
517
518       if ( IS_PS_SPACE( *p ) )
519         continue;
520
521       if ( *p OP 0x80 )
522         break;
523
524       c = ft_char_table[*p & 0x7F];
525
526       if ( (unsigned)c >= 16 )
527         break;
528
529       if ( r & 1 )
530       {
531         *buffer = (FT_Byte)(*buffer + c);
532         buffer++;
533       }
534       else
535         *buffer = (FT_Byte)(c << 4);
536
537       r++;
538     }
539
540     *cursor = p;
541
542     return ( r + 1 ) / 2;
543
544 #endif /* 0 */
545
546   }
547
548
549   FT_LOCAL_DEF( FT_UInt )
550   PS_Conv_EexecDecode( FT_Byte**   cursor,
551                        FT_Byte*    limit,
552                        FT_Byte*    buffer,
553                        FT_Offset   n,
554                        FT_UShort*  seed )
555   {
556     FT_Byte*  p;
557     FT_UInt   r;
558     FT_UInt   s = *seed;
559
560
561 #if 1
562
563     p = *cursor;
564
565     if ( p >= limit )
566       return 0;
567
568     if ( n > (FT_UInt)(limit - p) )
569       n = (FT_UInt)(limit - p);
570
571     for ( r = 0; r < n; r++ )
572     {
573       FT_UInt  val = p[r];
574       FT_UInt  b   = ( val ^ ( s >> 8 ) );
575
576
577       s         = ( (val + s)*52845U + 22719 ) & 0xFFFFU;
578       buffer[r] = (FT_Byte) b;
579     }
580
581     *cursor = p + n;
582     *seed   = (FT_UShort)s;
583
584 #else /* 0 */
585
586     for ( r = 0, p = *cursor; r < n && p < limit; r++, p++ )
587     {
588       FT_Byte  b = (FT_Byte)( *p ^ ( s >> 8 ) );
589
590
591       s = (FT_UShort)( ( *p + s ) * 52845U + 22719 );
592       *buffer++ = b;
593     }
594     *cursor = p;
595     *seed   = s;
596
597 #endif /* 0 */
598
599     return r;
600   }
601
602
603 /* END */