]> git.saurik.com Git - wxWidgets.git/blame - src/freetype/cid/cidparse.c
Unicode complation fixes
[wxWidgets.git] / src / freetype / cid / cidparse.c
CommitLineData
cabec872
RR
1/***************************************************************************/
2/* */
3/* cidparse.c */
4/* */
5/* CID-keyed Type1 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/ftcalc.h>
21#include <freetype/internal/ftobjs.h>
22#include <freetype/internal/ftstream.h>
23#include <freetype/internal/t1errors.h>
24
25
26#ifdef FT_FLAT_COMPILE
27
28#include "cidparse.h"
29
30#else
31
32#include <cid/cidparse.h>
33
34#endif
35
36
37#include <string.h> /* for strncmp() */
38
39
40 /*************************************************************************/
41 /* */
42 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
43 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
44 /* messages during execution. */
45 /* */
46#undef FT_COMPONENT
47#define FT_COMPONENT trace_cidparse
48
49
50#if 0
51
52 /*************************************************************************/
53 /*************************************************************************/
54 /*************************************************************************/
55 /***** *****/
56 /***** IMPLEMENTATION OF CID_TABLE OBJECT *****/
57 /***** *****/
58 /*************************************************************************/
59 /*************************************************************************/
60 /*************************************************************************/
61
62
63 /*************************************************************************/
64 /* */
65 /* <Function> */
66 /* CID_New_Table */
67 /* */
68 /* <Description> */
69 /* Initializes a CID_Table. */
70 /* */
71 /* <InOut> */
72 /* table :: The address of the target table. */
73 /* */
74 /* <Input> */
75 /* count :: The table size, i.e., the maximal number of elements. */
76 /* */
77 /* memory :: The memory object to be used for all subsequent */
78 /* reallocations. */
79 /* */
80 /* <Return> */
81 /* FreeType error code. 0 means success. */
82 /* */
83 LOCAL_FUNC
84 FT_Error CID_New_Table( CID_Table* table,
85 FT_Int count,
86 FT_Memory memory )
87 {
88 FT_Error error;
89
90
91 table->memory = memory;
92 if ( ALLOC_ARRAY( table->elements, count, FT_Byte* ) ||
93 ALLOC_ARRAY( table->lengths, count, FT_Byte* ) )
94 goto Exit;
95
96 table->max_elems = count;
97 table->init = 0xDEADBEEFL;
98 table->num_elems = 0;
99 table->block = 0;
100 table->capacity = 0;
101 table->cursor = 0;
102
103 Exit:
104 if ( error )
105 FREE( table->elements );
106
107 return error;
108 }
109
110
111 static
112 void shift_elements( CID_Table* table,
113 FT_Byte* old_base )
114 {
115 FT_Long delta = table->block - old_base;
116 FT_Byte** offset = table->elements;
117 FT_Byte** limit = offset + table->max_elems;
118
119
120 if ( delta )
121 for ( ; offset < limit; offset++ )
122 {
123 if ( offset[0] )
124 offset[0] += delta;
125 }
126 }
127
128
129 static
130 FT_Error reallocate_t1_table( CID_Table* table,
131 FT_Int new_size )
132 {
133 FT_Memory memory = table->memory;
134 FT_Byte* old_base = table->block;
135 FT_Error error;
136
137
138 /* realloc the base block */
139 if ( REALLOC( table->block, table->capacity, new_size ) )
140 return error;
141
142 table->capacity = new_size;
143
144 /* shift all offsets when needed */
145 if ( old_base )
146 shift_elements( table, old_base );
147
148 return T1_Err_Ok;
149 }
150
151
152 /*************************************************************************/
153 /* */
154 /* <Function> */
155 /* CID_Add_Table */
156 /* */
157 /* <Description> */
158 /* Adds an object to a CID_Table, possibly growing its memory block. */
159 /* */
160 /* <InOut> */
161 /* table :: The target table. */
162 /* */
163 /* <Input> */
164 /* index :: The index of the object in the table. */
165 /* */
166 /* object :: The address of the object to copy in the memory. */
167 /* */
168 /* length :: The length in bytes of the source object. */
169 /* */
170 /* <Return> */
171 /* FreeType error code. 0 means success. An error is returned if */
172 /* reallocation fails. */
173 /* */
174 LOCAL_FUNC
175 FT_Error CID_Add_Table( CID_Table* table,
176 FT_Int index,
177 void* object,
178 FT_Int length )
179 {
180 if ( index < 0 || index > table->max_elems )
181 {
182 FT_ERROR(( "CID_Add_Table: invalid index\n" ));
183 return T1_Err_Syntax_Error;
184 }
185
186 /* grow the base block if needed */
187 if ( table->cursor + length > table->capacity )
188 {
189 FT_Error error;
190 FT_Int new_size = table->capacity;
191
192
193 while ( new_size < table->cursor + length )
194 new_size += 1024;
195
196 error = reallocate_t1_table( table, new_size );
197 if ( error )
198 return error;
199 }
200
201 /* add the object to the base block and adjust offset */
202 table->elements[index] = table->block + table->cursor;
203 table->lengths [index] = length;
204
205 MEM_Copy( table->block + table->cursor, object, length );
206
207 table->cursor += length;
208
209 return T1_Err_Ok;
210 }
211
212
213 /*************************************************************************/
214 /* */
215 /* <Function> */
216 /* CID_Done_Table */
217 /* */
218 /* <Description> */
219 /* Finalizes a CID_Table (reallocate it to its current cursor). */
220 /* */
221 /* <InOut> */
222 /* table :: The target table. */
223 /* */
224 /* <Note> */
225 /* This function does NOT release the heap's memory block. It is up */
226 /* to the caller to clean it, or reference it in its own structures. */
227 /* */
228 LOCAL_FUNC
229 void CID_Done_Table( CID_Table* table )
230 {
231 FT_Memory memory = table->memory;
232 FT_Error error;
233 FT_Byte* old_base;
234
235
236 /* should never fail, as rec.cursor <= rec.size */
237 old_base = table->block;
238 if ( !old_base )
239 return;
240
241 (void)REALLOC( table->block, table->capacity, table->cursor );
242 table->capacity = table->cursor;
243
244 if ( old_base != table->block )
245 shift_elements( table, old_base );
246 }
247
248
249 LOCAL_FUNC
250 void CID_Release_Table( CID_Table* table )
251 {
252 FT_Memory memory = table->memory;
253
254
255 if ( table->init == 0xDEADBEEFL )
256 {
257 FREE( table->block );
258 FREE( table->elements );
259 FREE( table->lengths );
260 table->init = 0;
261 }
262 }
263
264#endif /* 0 */
265
266
267 /*************************************************************************/
268 /*************************************************************************/
269 /*************************************************************************/
270 /***** *****/
271 /***** INPUT STREAM PARSER *****/
272 /***** *****/
273 /*************************************************************************/
274 /*************************************************************************/
275 /*************************************************************************/
276
277
278#define IS_CID_WHITESPACE( c ) ( (c) == ' ' || (c) == '\t' )
279#define IS_CID_LINESPACE( c ) ( (c) == '\r' || (c) == '\n' )
280
281#define IS_CID_SPACE( c ) ( IS_CID_WHITESPACE( c ) || IS_CID_LINESPACE( c ) )
282
283
284 LOCAL_FUNC
285 void CID_Skip_Spaces( CID_Parser* parser )
286 {
287 FT_Byte* cur = parser->cursor;
288 FT_Byte* limit = parser->limit;
289
290
291 while ( cur < limit )
292 {
293 FT_Byte c = *cur;
294
295
296 if ( !IS_CID_SPACE( c ) )
297 break;
298 cur++;
299 }
300
301 parser->cursor = cur;
302 }
303
304
305 LOCAL_FUNC
306 void CID_ToToken( CID_Parser* parser,
307 CID_Token_Rec* token )
308 {
309 FT_Byte* cur;
310 FT_Byte* limit;
311 FT_Byte starter, ender;
312 FT_Int embed;
313
314
315 token->type = t1_token_none;
316 token->start = 0;
317 token->limit = 0;
318
319 /* first of all, skip space */
320 CID_Skip_Spaces( parser );
321
322 cur = parser->cursor;
323 limit = parser->limit;
324
325 if ( cur < limit )
326 {
327 switch ( *cur )
328 {
329 /************* check for strings ***********************/
330 case '(':
331 token->type = t1_token_string;
332 ender = ')';
333 goto Lookup_Ender;
334
335 /************* check for programs/array ****************/
336 case '{':
337 token->type = t1_token_array;
338 ender = '}';
339 goto Lookup_Ender;
340
341 /************* check for table/array ******************/
342 case '[':
343 token->type = t1_token_array;
344 ender = ']';
345
346 Lookup_Ender:
347 embed = 1;
348 starter = *cur++;
349 token->start = cur;
350
351 while ( cur < limit )
352 {
353 if ( *cur == starter )
354 embed++;
355 else if ( *cur == ender )
356 {
357 embed--;
358 if ( embed <= 0 )
359 {
360 token->limit = cur++;
361 break;
362 }
363 }
364 cur++;
365 }
366 break;
367
368 /* **************** otherwise, it is any token **********/
369 default:
370 token->start = cur++;
371 token->type = t1_token_any;
372 while ( cur < limit && !IS_CID_SPACE( *cur ) )
373 cur++;
374
375 token->limit = cur;
376 }
377
378 if ( !token->limit )
379 {
380 token->start = 0;
381 token->type = t1_token_none;
382 }
383
384 parser->cursor = cur;
385 }
386 }
387
388
389 LOCAL_FUNC
390 void CID_ToTokenArray( CID_Parser* parser,
391 CID_Token_Rec* tokens,
392 FT_UInt max_tokens,
393 FT_Int* pnum_tokens )
394 {
395 CID_Token_Rec master;
396
397
398 *pnum_tokens = -1;
399
400 CID_ToToken( parser, &master );
401
402 if ( master.type == t1_token_array )
403 {
404 FT_Byte* old_cursor = parser->cursor;
405 FT_Byte* old_limit = parser->limit;
406 CID_Token_Rec* cur = tokens;
407 CID_Token_Rec* limit = cur + max_tokens;
408
409
410 parser->cursor = master.start;
411 parser->limit = master.limit;
412
413 while ( parser->cursor < parser->limit )
414 {
415 CID_Token_Rec token;
416
417
418 CID_ToToken( parser, &token );
419 if ( !token.type )
420 break;
421
422 if ( cur < limit )
423 *cur = token;
424
425 cur++;
426 }
427
428 *pnum_tokens = cur - tokens;
429
430 parser->cursor = old_cursor;
431 parser->limit = old_limit;
432 }
433 }
434
435
436 static
437 FT_Long t1_toint( FT_Byte** cursor,
438 FT_Byte* limit )
439 {
440 FT_Long result = 0;
441 FT_Byte* cur = *cursor;
442 FT_Byte c, d;
443
444
445 for ( ; cur < limit; cur++ )
446 {
447 c = *cur;
448 d = (FT_Byte)( c - '0' );
449 if ( d < 10 )
450 break;
451
452 if ( c == '-' )
453 {
454 cur++;
455 break;
456 }
457 }
458
459 if ( cur < limit )
460 {
461 do
462 {
463 d = (FT_Byte)( cur[0] - '0' );
464 if ( d >= 10 )
465 break;
466
467 result = result * 10 + d;
468 cur++;
469
470 } while ( cur < limit );
471
472 if ( c == '-' )
473 result = -result;
474 }
475
476 *cursor = cur;
477
478 return result;
479 }
480
481
482 static
483 FT_Long t1_tofixed( FT_Byte** cursor,
484 FT_Byte* limit,
485 FT_Long power_ten )
486 {
487 FT_Byte* cur = *cursor;
488 FT_Long num, divider, result;
489 FT_Int sign = 0;
490 FT_Byte d;
491
492
493 if ( cur >= limit )
494 return 0;
495
496 /* first of all, read the integer part */
497 result = t1_toint( &cur, limit ) << 16;
498 num = 0;
499 divider = 1;
500
501 if ( result < 0 )
502 {
503 sign = 1;
504 result = -result;
505 }
506
507 if ( cur >= limit )
508 goto Exit;
509
510 /* read decimal part, if any */
511 if ( *cur == '.' && cur + 1 < limit )
512 {
513 cur++;
514
515 for (;;)
516 {
517 d = (FT_Byte)( *cur - '0' );
518 if ( d >= 10 )
519 break;
520
521 if ( divider < 10000000L )
522 {
523 num = num * 10 + d;
524 divider *= 10;
525 }
526
527 cur++;
528 if ( cur >= limit )
529 break;
530 }
531 }
532
533 /* read exponent, if any */
534 if ( cur + 1 < limit && ( *cur == 'e' || *cur == 'E' ) )
535 {
536 cur++;
537 power_ten += t1_toint( &cur, limit );
538 }
539
540 Exit:
541 /* raise to power of ten if needed */
542 while ( power_ten > 0 )
543 {
544 result = result * 10;
545 num = num * 10;
546 power_ten--;
547 }
548
549 while ( power_ten < 0 )
550 {
551 result = result / 10;
552 divider = divider * 10;
553 power_ten++;
554 }
555
556 if ( num )
557 result += FT_DivFix( num, divider );
558
559 if ( sign )
560 result = -result;
561
562 *cursor = cur;
563
564 return result;
565 }
566
567
568 static
569 int t1_tobool( FT_Byte** cursor,
570 FT_Byte* limit )
571 {
572 FT_Byte* cur = *cursor;
573 FT_Bool result = 0;
574
575
576 /* return 1 if we find a "true", 0 otherwise */
577 if ( cur + 3 < limit &&
578 cur[0] == 't' &&
579 cur[1] == 'r' &&
580 cur[2] == 'u' &&
581 cur[3] == 'e' )
582 {
583 result = 1;
584 cur += 5;
585 }
586 else if ( cur + 4 < limit &&
587 cur[0] == 'f' &&
588 cur[1] == 'a' &&
589 cur[2] == 'l' &&
590 cur[3] == 's' &&
591 cur[4] == 'e' )
592 {
593 result = 0;
594 cur += 6;
595 }
596 *cursor = cur;
597 return result;
598 }
599
600
601 static
602 FT_Int t1_tocoordarray( FT_Byte** cursor,
603 FT_Byte* limit,
604 FT_Int max_coords,
605 FT_Short* coords )
606 {
607 FT_Byte* cur = *cursor;
608 FT_Int count = 0;
609 FT_Byte c, ender;
610
611
612 if ( cur >= limit )
613 goto Exit;
614
615 /* check for the beginning of an array. */
616 /* If not, only one number will be read */
617 c = *cur;
618 ender = 0;
619
620 if ( c == '[' )
621 ender = ']';
622
623 if ( c == '{' )
624 ender = '}';
625
626 if ( ender )
627 cur++;
628
629 /* now, read the coordinates */
630 for ( ; cur < limit; )
631 {
632 /* skip whitespace in front of data */
633 for (;;)
634 {
635 c = *cur;
636 if ( c != ' ' && c != '\t' )
637 break;
638
639 cur++;
640 if ( cur >= limit )
641 goto Exit;
642 }
643
644 if ( count >= max_coords || c == ender )
645 break;
646
647 coords[count] = (FT_Short)( t1_tofixed( &cur, limit, 0 ) >> 16 );
648 count++;
649
650 if ( !ender )
651 break;
652 }
653
654 Exit:
655 *cursor = cur;
656 return count;
657 }
658
659
660 static
661 FT_Int t1_tofixedarray( FT_Byte** cursor,
662 FT_Byte* limit,
663 FT_Int max_values,
664 FT_Fixed* values,
665 FT_Int power_ten )
666 {
667 FT_Byte* cur = *cursor;
668 FT_Int count = 0;
669 FT_Byte c, ender;
670
671
672 if ( cur >= limit )
673 goto Exit;
674
675 /* check for the beginning of an array. */
676 /* If not, only one number will be read */
677 c = *cur;
678 ender = 0;
679
680 if ( c == '[' )
681 ender = ']';
682
683 if ( c == '{' )
684 ender = '}';
685
686 if ( ender )
687 cur++;
688
689 /* now, read the values */
690 for ( ; cur < limit; )
691 {
692 /* skip whitespace in front of data */
693 for (;;)
694 {
695 c = *cur;
696 if ( c != ' ' && c != '\t' )
697 break;
698
699 cur++;
700 if ( cur >= limit )
701 goto Exit;
702 }
703
704 if ( count >= max_values || c == ender )
705 break;
706
707 values[count] = t1_tofixed( &cur, limit, power_ten );
708 count++;
709
710 if ( !ender )
711 break;
712 }
713
714 Exit:
715 *cursor = cur;
716
717 return count;
718 }
719
720
721 /* Loads a simple field (i.e. non-table) into the current */
722 /* list of objects */
723 LOCAL_FUNC
724 FT_Error CID_Load_Field( CID_Parser* parser,
725 const CID_Field_Rec* field,
726 void* object )
727 {
728 CID_Token_Rec token;
729 FT_Byte* cur;
730 FT_Byte* limit;
731 FT_UInt count;
732 FT_UInt index;
733 FT_Error error;
734
735
736 CID_ToToken( parser, &token );
737 if ( !token.type )
738 goto Fail;
739
740 count = 1;
741 index = 0;
742 cur = token.start;
743 limit = token.limit;
744
745 {
746 FT_Byte* q = (FT_Byte*)object + field->offset;
747 FT_Long val;
748 FT_String* string;
749
750
751 switch ( field->type )
752 {
753 case t1_field_bool:
754 val = t1_tobool( &cur, limit );
755 goto Store_Integer;
756
757 case t1_field_fixed:
758 val = t1_tofixed( &cur, limit, 0 );
759 goto Store_Integer;
760
761 case t1_field_integer:
762 val = t1_toint( &cur, limit );
763
764 Store_Integer:
765 switch ( field->size )
766 {
767 case 1:
768 *(FT_Byte*)q = (FT_Byte)val;
769 break;
770
771 case 2:
772 *(FT_UShort*)q = (FT_UShort)val;
773 break;
774
775 case 4:
776 *(FT_Int32*)q = (FT_Int)val;
777 break;
778
779 default: /* for 64-bit systems */
780 *(FT_Long*)q = val;
781 }
782 break;
783
784 case t1_field_string:
785 {
786 FT_Memory memory = parser->memory;
787 FT_UInt len = limit-cur;
788
789
790 if ( ALLOC( string, len + 1 ) )
791 goto Exit;
792
793 MEM_Copy( string, cur, len );
794 string[len] = 0;
795
796 *(FT_String**)q = string;
797 }
798 break;
799
800 default:
801 /* an error occurred */
802 goto Fail;
803 }
804 }
805
806 error = 0;
807
808 Exit:
809 return error;
810
811 Fail:
812 error = T1_Err_Invalid_File_Format;
813 goto Exit;
814 }
815
816
817#define T1_MAX_TABLE_ELEMENTS 32
818
819
820 LOCAL_FUNC
821 FT_Error CID_Load_Field_Table( CID_Parser* parser,
822 const CID_Field_Rec* field,
823 void* object )
824 {
825 CID_Token_Rec elements[T1_MAX_TABLE_ELEMENTS];
826 CID_Token_Rec* token;
827 FT_Int num_elements;
828 FT_Error error = 0;
829 FT_Byte* old_cursor;
830 FT_Byte* old_limit;
831 CID_Field_Rec fieldrec = *(CID_Field_Rec*)field;
832
833
834 fieldrec.type = t1_field_integer;
835 if ( field->type == t1_field_fixed_array )
836 fieldrec.type = t1_field_fixed;
837
838 CID_ToTokenArray( parser, elements, 32, &num_elements );
839 if ( num_elements < 0 )
840 goto Fail;
841
842 if ( num_elements > T1_MAX_TABLE_ELEMENTS )
843 num_elements = T1_MAX_TABLE_ELEMENTS;
844
845 old_cursor = parser->cursor;
846 old_limit = parser->limit;
847
848 /* we store the elements count */
849 if ( field->count_offset )
850 *(FT_Byte*)( (FT_Byte*)object + field->count_offset ) = num_elements;
851
852 /* we now load each element, adjusting the field.offset on each one */
853 token = elements;
854 for ( ; num_elements > 0; num_elements--, token++ )
855 {
856 parser->cursor = token->start;
857 parser->limit = token->limit;
858 CID_Load_Field( parser, &fieldrec, object );
859 fieldrec.offset += fieldrec.size;
860 }
861
862 parser->cursor = old_cursor;
863 parser->limit = old_limit;
864
865 Exit:
866 return error;
867
868 Fail:
869 error = T1_Err_Invalid_File_Format;
870 goto Exit;
871 }
872
873
874 LOCAL_FUNC
875 FT_Long CID_ToInt( CID_Parser* parser )
876 {
877 return t1_toint( &parser->cursor, parser->limit );
878 }
879
880
881 LOCAL_FUNC
882 FT_Int CID_ToCoordArray( CID_Parser* parser,
883 FT_Int max_coords,
884 FT_Short* coords )
885 {
886 return t1_tocoordarray( &parser->cursor, parser->limit,
887 max_coords, coords );
888 }
889
890
891 LOCAL_FUNC
892 FT_Int CID_ToFixedArray( CID_Parser* parser,
893 FT_Int max_values,
894 FT_Fixed* values,
895 FT_Int power_ten )
896 {
897 return t1_tofixedarray( &parser->cursor, parser->limit,
898 max_values, values, power_ten );
899 }
900
901
902#if 0
903
904 /* return the value of an hexadecimal digit */
905 static
906 int hexa_value( char c )
907 {
908 unsigned int d;
909
910
911 d = (unsigned int)( c - '0' );
912 if ( d <= 9 )
913 return (int)d;
914
915 d = (unsigned int)( c - 'a' );
916 if ( d <= 5 )
917 return (int)( d + 10 );
918
919 d = (unsigned int)( c - 'A' );
920 if ( d <= 5 )
921 return (int)( d + 10 );
922
923 return -1;
924 }
925
926#endif /* 0 */
927
928
929 LOCAL_FUNC
930 FT_Error CID_New_Parser( CID_Parser* parser,
931 FT_Stream stream,
932 FT_Memory memory )
933 {
934 FT_Error error;
935 FT_ULong base_offset, offset, ps_len;
936 FT_Byte buffer[256 + 10];
937 FT_Int buff_len;
938
939
940 MEM_Set( parser, 0, sizeof ( *parser ) );
941 parser->stream = stream;
942 parser->memory = memory;
943
944 base_offset = FILE_Pos();
945
946 /* first of all, check the font format in the header */
947 if ( ACCESS_Frame( 31 ) )
948 goto Exit;
949
950 if ( strncmp( (char *)stream->cursor,
951 "%!PS-Adobe-3.0 Resource-CIDFont", 31 ) )
952 {
953 FT_TRACE2(( "[not a valid CID-keyed font]\n" ));
954 error = FT_Err_Unknown_File_Format;
955 }
956
957 FORGET_Frame();
958 if ( error )
959 goto Exit;
960
961 /* now, read the rest of the file, until we find a `StartData' */
962 buff_len = 256;
963 for (;;)
964 {
965 FT_Byte *p, *limit = buffer + 256;
966
967 /* fill input buffer */
968 buff_len -= 256;
969 if ( buff_len > 0 )
970 MEM_Move( buffer, limit, buff_len );
971
972 if ( FILE_Read( buffer, 256 + 10 - buff_len ) )
973 goto Exit;
974
975 buff_len = 256 + 10;
976
977 /* look for `StartData' */
978 for ( p = buffer; p < limit; p++ )
979 {
980 if ( p[0] == 'S' && strncmp( (char*)p, "StartData", 9 ) == 0 )
981 {
982 /* save offset of binary data after `StartData' */
983 offset = FILE_Pos() - ( limit - p ) + 10;
984 goto Found;
985 }
986 }
987 }
988
989 Found:
990 /* we have found the start of the binary data. We will now */
991 /* rewind and extract the frame of corresponding to the Postscript */
992 /* section */
993
994 ps_len = offset - base_offset;
995 if ( FILE_Seek( base_offset ) ||
996 EXTRACT_Frame( ps_len, parser->postscript ) )
997 goto Exit;
998
999 parser->data_offset = offset;
1000 parser->postscript_len = ps_len;
1001 parser->cursor = parser->postscript;
1002 parser->limit = parser->cursor + ps_len;
1003 parser->num_dict = -1;
1004
1005 Exit:
1006 return error;
1007 }
1008
1009
1010 LOCAL_FUNC
1011 void CID_Done_Parser( CID_Parser* parser )
1012 {
1013 /* always free the private dictionary */
1014 if ( parser->postscript )
1015 {
1016 FT_Stream stream = parser->stream;
1017
1018
1019 RELEASE_Frame( parser->postscript );
1020 }
1021 }
1022
1023
1024/* END */