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