1 /*******************************************************************
2  *
3  *  ftxopen.c
4  *
5  *    TrueType Open common table support.
6  *
7  *  Copyright 1996-1999 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 #include "tttypes.h"
19 #include "ttload.h"
20 #include "ttextend.h"
21 #include "ttmemory.h"
22 #include "ttfile.h"
23 
24 #include "ftxopen.h"
25 #include "ftxopenf.h"
26 
27 
28   /***************************
29    * Script related functions
30    ***************************/
31 
32 
33   /* LangSys */
34 
Load_LangSys(TTO_LangSys * ls,PFace input)35   static TT_Error  Load_LangSys( TTO_LangSys*  ls,
36                                  PFace         input )
37   {
38     DEFINE_LOAD_LOCALS( input->stream );
39 
40     UShort   n, count;
41 
42     UShort*  fi;
43 
44 
45     if ( ACCESS_Frame( 6L ) )
46       return error;
47 
48     ls->LookupOrderOffset    = GET_UShort();    /* should be 0 */
49     ls->ReqFeatureIndex      = GET_UShort();
50     count = ls->FeatureCount = GET_UShort();
51 
52     FORGET_Frame();
53 
54     ls->FeatureIndex = NULL;
55 
56     if ( ALLOC_ARRAY( ls->FeatureIndex, count, UShort ) )
57       return error;
58 
59     if ( ACCESS_Frame( count * 2L ) )
60     {
61       FREE( ls->FeatureIndex );
62       return error;
63     }
64 
65     fi = ls->FeatureIndex;
66 
67     for ( n = 0; n < count; n++ )
68       fi[n] = GET_UShort();
69 
70     FORGET_Frame();
71 
72     return TT_Err_Ok;
73   }
74 
75 
Free_LangSys(TTO_LangSys * ls)76   static void  Free_LangSys( TTO_LangSys*  ls )
77   {
78     FREE( ls->FeatureIndex );
79   }
80 
81 
82   /* Script */
83 
Load_Script(TTO_Script * s,PFace input)84   static TT_Error  Load_Script( TTO_Script*  s,
85                                 PFace        input )
86   {
87     DEFINE_LOAD_LOCALS( input->stream );
88 
89     UShort              n, count;
90     ULong               cur_offset, new_offset, base_offset;
91 
92     TTO_LangSysRecord*  lsr;
93 
94 
95     base_offset = FILE_Pos();
96 
97     if ( ACCESS_Frame( 2L ) )
98       return error;
99 
100     new_offset = GET_UShort() + base_offset;
101 
102     FORGET_Frame();
103 
104     if ( new_offset != base_offset )        /* not a NULL offset */
105     {
106       cur_offset = FILE_Pos();
107       if ( FILE_Seek( new_offset ) ||
108            ( error = Load_LangSys( &s->DefaultLangSys,
109                                    input ) ) != TT_Err_Ok )
110         return error;
111       (void)FILE_Seek( cur_offset );
112     }
113     else
114     {
115       /* we create a DefaultLangSys table with no entries */
116 
117       s->DefaultLangSys.LookupOrderOffset = 0;
118       s->DefaultLangSys.ReqFeatureIndex   = 0xFFFF;
119       s->DefaultLangSys.FeatureCount      = 0;
120       s->DefaultLangSys.FeatureIndex      = NULL;
121     }
122 
123     if ( ACCESS_Frame( 2L ) )
124       goto Fail2;
125 
126     count = s->LangSysCount = GET_UShort();
127 
128     /* safety check; otherwise the official handling of TrueType Open
129        fonts won't work */
130 
131     if ( s->LangSysCount == 0 && s->DefaultLangSys.FeatureCount == 0 )
132     {
133       error = TTO_Err_Invalid_SubTable;
134       goto Fail2;
135     }
136 
137     FORGET_Frame();
138 
139     s->LangSysRecord = NULL;
140 
141     if ( ALLOC_ARRAY( s->LangSysRecord, count, TTO_LangSysRecord ) )
142       goto Fail2;
143 
144     lsr = s->LangSysRecord;
145 
146     for ( n = 0; n < count; n++ )
147     {
148       if ( ACCESS_Frame( 6L ) )
149         goto Fail1;
150 
151       lsr[n].LangSysTag = GET_ULong();
152       new_offset = GET_UShort() + base_offset;
153 
154       FORGET_Frame();
155 
156       cur_offset = FILE_Pos();
157       if ( FILE_Seek( new_offset ) ||
158            ( error = Load_LangSys( &lsr[n].LangSys, input ) ) != TT_Err_Ok )
159         goto Fail1;
160       (void)FILE_Seek( cur_offset );
161     }
162 
163     return TT_Err_Ok;
164 
165   Fail1:
166     for ( n = 0; n < count; n++ )
167       Free_LangSys( &lsr[n].LangSys );
168 
169     FREE( s->LangSysRecord );
170 
171   Fail2:
172     Free_LangSys( &s->DefaultLangSys );
173     return error;
174   }
175 
176 
Free_Script(TTO_Script * s)177   static void  Free_Script( TTO_Script*  s )
178   {
179     UShort              n, count;
180 
181     TTO_LangSysRecord*  lsr;
182 
183 
184     Free_LangSys( &s->DefaultLangSys );
185 
186     if ( s->LangSysRecord )
187     {
188       count = s->LangSysCount;
189       lsr   = s->LangSysRecord;
190 
191       for ( n = 0; n < count; n++ )
192         Free_LangSys( &lsr[n].LangSys );
193 
194       FREE( lsr );
195     }
196   }
197 
198 
199   /* ScriptList */
200 
Load_ScriptList(TTO_ScriptList * sl,PFace input)201   TT_Error  Load_ScriptList( TTO_ScriptList*  sl,
202                              PFace            input )
203   {
204     DEFINE_LOAD_LOCALS( input->stream );
205 
206     UShort             n, count;
207     ULong              cur_offset, new_offset, base_offset;
208 
209     TTO_ScriptRecord*  sr;
210 
211 
212     base_offset = FILE_Pos();
213 
214     if ( ACCESS_Frame( 2L ) )
215       return error;
216 
217     count = sl->ScriptCount = GET_UShort();
218 
219     FORGET_Frame();
220 
221     sl->ScriptRecord = NULL;
222 
223     if ( ALLOC_ARRAY( sl->ScriptRecord, count, TTO_ScriptRecord ) )
224       return error;
225 
226     sr = sl->ScriptRecord;
227 
228     for ( n = 0; n < count; n++ )
229     {
230       if ( ACCESS_Frame( 6L ) )
231         goto Fail;
232 
233       sr[n].ScriptTag = GET_ULong();
234       new_offset = GET_UShort() + base_offset;
235 
236       FORGET_Frame();
237 
238       cur_offset = FILE_Pos();
239       if ( FILE_Seek( new_offset ) ||
240            ( error = Load_Script( &sr[n].Script, input ) ) != TT_Err_Ok )
241         goto Fail;
242       (void)FILE_Seek( cur_offset );
243     }
244 
245     return TT_Err_Ok;
246 
247   Fail:
248     for ( n = 0; n < count; n++ )
249       Free_Script( &sr[n].Script );
250 
251     FREE( sl->ScriptRecord );
252     return error;
253   }
254 
255 
Free_ScriptList(TTO_ScriptList * sl)256   void  Free_ScriptList( TTO_ScriptList*  sl )
257   {
258     UShort             n, count;
259 
260     TTO_ScriptRecord*  sr;
261 
262 
263     if ( sl->ScriptRecord )
264     {
265       count = sl->ScriptCount;
266       sr    = sl->ScriptRecord;
267 
268       for ( n = 0; n < count; n++ )
269         Free_Script( &sr[n].Script );
270 
271       FREE( sr );
272     }
273   }
274 
275 
276 
277   /*********************************
278    * Feature List related functions
279    *********************************/
280 
281 
282   /* Feature */
283 
Load_Feature(TTO_Feature * f,PFace input)284   static TT_Error  Load_Feature( TTO_Feature*  f,
285                                  PFace         input )
286   {
287     DEFINE_LOAD_LOCALS( input->stream );
288 
289     UShort   n, count;
290 
291     UShort*  lli;
292 
293 
294     if ( ACCESS_Frame( 4L ) )
295       return error;
296 
297     f->FeatureParams           = GET_UShort();    /* should be 0 */
298     count = f->LookupListCount = GET_UShort();
299 
300     FORGET_Frame();
301 
302     f->LookupListIndex = NULL;
303 
304     if ( ALLOC_ARRAY( f->LookupListIndex, count, UShort ) )
305       return error;
306 
307     lli = f->LookupListIndex;
308 
309     if ( ACCESS_Frame( count * 2L ) )
310     {
311       FREE( f->LookupListIndex );
312       return error;
313     }
314 
315     for ( n = 0; n < count; n++ )
316       lli[n] = GET_UShort();
317 
318     FORGET_Frame();
319 
320     return TT_Err_Ok;
321   }
322 
323 
Free_Feature(TTO_Feature * f)324   static void  Free_Feature( TTO_Feature*  f )
325   {
326     FREE( f->LookupListIndex );
327   }
328 
329 
330   /* FeatureList */
331 
Load_FeatureList(TTO_FeatureList * fl,PFace input)332   TT_Error  Load_FeatureList( TTO_FeatureList*  fl,
333                               PFace             input )
334   {
335     DEFINE_LOAD_LOCALS( input->stream );
336 
337     UShort              n, count;
338     ULong               cur_offset, new_offset, base_offset;
339 
340     TTO_FeatureRecord*  fr;
341 
342 
343     base_offset = FILE_Pos();
344 
345     if ( ACCESS_Frame( 2L ) )
346       return error;
347 
348     count = fl->FeatureCount = GET_UShort();
349 
350     FORGET_Frame();
351 
352     fl->FeatureRecord = NULL;
353 
354     if ( ALLOC_ARRAY( fl->FeatureRecord, count, TTO_FeatureRecord ) )
355       return error;
356 
357     fr = fl->FeatureRecord;
358 
359     for ( n = 0; n < count; n++ )
360     {
361       if ( ACCESS_Frame( 6L ) )
362         goto Fail;
363 
364       fr[n].FeatureTag = GET_ULong();
365       new_offset = GET_UShort() + base_offset;
366 
367       FORGET_Frame();
368 
369       cur_offset = FILE_Pos();
370       if ( FILE_Seek( new_offset ) ||
371            ( error = Load_Feature( &fr[n].Feature, input ) ) != TT_Err_Ok )
372         goto Fail;
373       (void)FILE_Seek( cur_offset );
374     }
375 
376     return TT_Err_Ok;
377 
378   Fail:
379     for ( n = 0; n < count; n++ )
380       Free_Feature( &fr[n].Feature );
381 
382     FREE( fl->FeatureRecord );
383     return error;
384   }
385 
386 
Free_FeatureList(TTO_FeatureList * fl)387   void  Free_FeatureList( TTO_FeatureList*  fl )
388   {
389     UShort              n, count;
390 
391     TTO_FeatureRecord*  fr;
392 
393 
394     if ( fl->FeatureRecord )
395     {
396       count = fl->FeatureCount;
397       fr    = fl->FeatureRecord;
398 
399       for ( n = 0; n < count; n++ )
400         Free_Feature( &fr[n].Feature );
401 
402       FREE( fr );
403     }
404   }
405 
406 
407 
408   /********************************
409    * Lookup List related functions
410    ********************************/
411 
412   /* the subroutines of the following two functions are defined in
413      ftxgsub.c and ftxgpos.c respectively                          */
414 
415 
416   /* SubTable */
417 
Load_SubTable(TTO_SubTable * st,PFace input,TTO_Type table_type,UShort lookup_type)418   static TT_Error  Load_SubTable( TTO_SubTable*  st,
419                                   PFace          input,
420                                   TTO_Type       table_type,
421                                   UShort         lookup_type )
422   {
423     if ( table_type == GSUB )
424       switch ( lookup_type )
425       {
426       case GSUB_LOOKUP_SINGLE:
427         return Load_SingleSubst( &st->st.gsub.single, input );
428 
429       case GSUB_LOOKUP_MULTIPLE:
430         return Load_MultipleSubst( &st->st.gsub.multiple, input );
431 
432       case GSUB_LOOKUP_ALTERNATE:
433         return Load_AlternateSubst( &st->st.gsub.alternate, input );
434 
435       case GSUB_LOOKUP_LIGATURE:
436         return Load_LigatureSubst( &st->st.gsub.ligature, input );
437 
438       case GSUB_LOOKUP_CONTEXT:
439         return Load_ContextSubst( &st->st.gsub.context, input );
440 
441       case GSUB_LOOKUP_CHAIN:
442         return Load_ChainContextSubst( &st->st.gsub.chain, input );
443 
444       default:
445         return TTO_Err_Invalid_GSUB_SubTable_Format;
446       }
447     else
448       switch ( lookup_type )
449       {
450         case GPOS_LOOKUP_SINGLE:
451           return Load_SinglePos( &st->st.gpos.single, input );
452 
453         case GPOS_LOOKUP_PAIR:
454           return Load_PairPos( &st->st.gpos.pair, input );
455 
456         case GPOS_LOOKUP_CURSIVE:
457           return Load_CursivePos( &st->st.gpos.cursive, input );
458 
459         case GPOS_LOOKUP_MARKBASE:
460           return Load_MarkBasePos( &st->st.gpos.markbase, input );
461 
462         case GPOS_LOOKUP_MARKLIG:
463           return Load_MarkLigPos( &st->st.gpos.marklig, input );
464 
465         case GPOS_LOOKUP_MARKMARK:
466           return Load_MarkMarkPos( &st->st.gpos.markmark, input );
467 
468         case GPOS_LOOKUP_CONTEXT:
469           return Load_ContextPos( &st->st.gpos.context, input );
470 
471         case GPOS_LOOKUP_CHAIN:
472           return Load_ChainContextPos ( &st->st.gpos.chain, input );
473 
474         default:
475           return TTO_Err_Invalid_GPOS_SubTable_Format;
476       }
477 
478     return TT_Err_Ok;           /* never reached */
479   }
480 
481 
Free_SubTable(TTO_SubTable * st,TTO_Type table_type,UShort lookup_type)482   static void  Free_SubTable( TTO_SubTable*  st,
483                               TTO_Type       table_type,
484                               UShort         lookup_type )
485   {
486     if ( table_type == GSUB )
487       switch ( lookup_type )
488       {
489       case GSUB_LOOKUP_SINGLE:
490         Free_SingleSubst( &st->st.gsub.single );
491         break;
492 
493       case GSUB_LOOKUP_MULTIPLE:
494         Free_MultipleSubst( &st->st.gsub.multiple );
495         break;
496 
497       case GSUB_LOOKUP_ALTERNATE:
498         Free_AlternateSubst( &st->st.gsub.alternate );
499         break;
500 
501       case GSUB_LOOKUP_LIGATURE:
502         Free_LigatureSubst( &st->st.gsub.ligature );
503         break;
504 
505       case GSUB_LOOKUP_CONTEXT:
506         Free_ContextSubst( &st->st.gsub.context );
507         break;
508 
509       case GSUB_LOOKUP_CHAIN:
510         Free_ChainContextSubst( &st->st.gsub.chain );
511         break;
512       }
513     else
514       switch ( lookup_type )
515       {
516       case GPOS_LOOKUP_SINGLE:
517         Free_SinglePos( &st->st.gpos.single );
518         break;
519 
520       case GPOS_LOOKUP_PAIR:
521         Free_PairPos( &st->st.gpos.pair );
522         break;
523 
524       case GPOS_LOOKUP_CURSIVE:
525         Free_CursivePos( &st->st.gpos.cursive );
526         break;
527 
528       case GPOS_LOOKUP_MARKBASE:
529         Free_MarkBasePos( &st->st.gpos.markbase );
530         break;
531 
532       case GPOS_LOOKUP_MARKLIG:
533         Free_MarkLigPos( &st->st.gpos.marklig );
534         break;
535 
536       case GPOS_LOOKUP_MARKMARK:
537         Free_MarkMarkPos( &st->st.gpos.markmark );
538         break;
539 
540       case GPOS_LOOKUP_CONTEXT:
541         Free_ContextPos( &st->st.gpos.context );
542         break;
543 
544       case GPOS_LOOKUP_CHAIN:
545         Free_ChainContextPos ( &st->st.gpos.chain );
546         break;
547       }
548   }
549 
550 
551   /* Lookup */
552 
Load_Lookup(TTO_Lookup * l,PFace input,TTO_Type type)553   static TT_Error  Load_Lookup( TTO_Lookup*   l,
554                                 PFace         input,
555                                 TTO_Type      type )
556   {
557     DEFINE_LOAD_LOCALS( input->stream );
558 
559     UShort         n, count;
560     ULong          cur_offset, new_offset, base_offset;
561 
562     TTO_SubTable*  st;
563 
564 
565     base_offset = FILE_Pos();
566 
567     if ( ACCESS_Frame( 6L ) )
568       return error;
569 
570     l->LookupType            = GET_UShort();
571     l->LookupFlag            = GET_UShort();
572     count = l->SubTableCount = GET_UShort();
573 
574     FORGET_Frame();
575 
576     l->SubTable = NULL;
577 
578     if ( ALLOC_ARRAY( l->SubTable, count, TTO_SubTable ) )
579       return error;
580 
581     st = l->SubTable;
582 
583     for ( n = 0; n < count; n++ )
584     {
585       if ( ACCESS_Frame( 2L ) )
586         goto Fail;
587 
588       new_offset = GET_UShort() + base_offset;
589 
590       FORGET_Frame();
591 
592       cur_offset = FILE_Pos();
593       if ( FILE_Seek( new_offset ) ||
594            ( error = Load_SubTable( &st[n], input,
595                                     type, l->LookupType ) ) != TT_Err_Ok )
596         goto Fail;
597       (void)FILE_Seek( cur_offset );
598     }
599 
600     return TT_Err_Ok;
601 
602   Fail:
603     for ( n = 0; n < count; n++ )
604       Free_SubTable( &st[n], type, l->LookupType );
605 
606     FREE( l->SubTable );
607     return error;
608   }
609 
610 
Free_Lookup(TTO_Lookup * l,TTO_Type type)611   static void  Free_Lookup( TTO_Lookup*   l,
612                             TTO_Type      type )
613   {
614     UShort         n, count;
615 
616     TTO_SubTable*  st;
617 
618 
619     if ( l->SubTable )
620     {
621       count = l->SubTableCount;
622       st    = l->SubTable;
623 
624       for ( n = 0; n < count; n++ )
625         Free_SubTable( &st[n], type, l->LookupType );
626 
627       FREE( st );
628     }
629   }
630 
631 
632   /* LookupList */
633 
Load_LookupList(TTO_LookupList * ll,PFace input,TTO_Type type)634   TT_Error  Load_LookupList( TTO_LookupList*  ll,
635                              PFace            input,
636                              TTO_Type         type )
637   {
638     DEFINE_LOAD_LOCALS( input->stream );
639 
640     UShort       n, count;
641     ULong        cur_offset, new_offset, base_offset;
642 
643     TTO_Lookup*  l;
644 
645 
646     base_offset = FILE_Pos();
647 
648     if ( ACCESS_Frame( 2L ) )
649       return error;
650 
651     count = ll->LookupCount = GET_UShort();
652 
653     FORGET_Frame();
654 
655     ll->Lookup = NULL;
656 
657     if ( ALLOC_ARRAY( ll->Lookup, count, TTO_Lookup ) )
658       return error;
659     if ( ALLOC_ARRAY( ll->Properties, count, UShort ) )
660       goto Fail2;
661 
662     l = ll->Lookup;
663 
664     for ( n = 0; n < count; n++ )
665     {
666       if ( ACCESS_Frame( 2L ) )
667         goto Fail1;
668 
669       new_offset = GET_UShort() + base_offset;
670 
671       FORGET_Frame();
672 
673       cur_offset = FILE_Pos();
674       if ( FILE_Seek( new_offset ) ||
675            ( error = Load_Lookup( &l[n], input, type ) ) != TT_Err_Ok )
676         goto Fail1;
677       (void)FILE_Seek( cur_offset );
678     }
679 
680     return TT_Err_Ok;
681 
682   Fail1:
683     FREE( ll->Properties );
684 
685     for ( n = 0; n < count; n++ )
686       Free_Lookup( &l[n], type );
687 
688   Fail2:
689     FREE( ll->Lookup );
690     return error;
691   }
692 
693 
Free_LookupList(TTO_LookupList * ll,TTO_Type type)694   void  Free_LookupList( TTO_LookupList*  ll,
695                          TTO_Type         type )
696   {
697     UShort       n, count;
698 
699     TTO_Lookup*  l;
700 
701 
702     FREE( ll->Properties );
703 
704     if ( ll->Lookup )
705     {
706       count = ll->LookupCount;
707       l     = ll->Lookup;
708 
709       for ( n = 0; n < count; n++ )
710         Free_Lookup( &l[n], type );
711 
712       FREE( l );
713     }
714   }
715 
716 
717 
718   /*****************************
719    * Coverage related functions
720    *****************************/
721 
722 
723   /* CoverageFormat1 */
724 
Load_Coverage1(TTO_CoverageFormat1 * cf1,PFace input)725   static TT_Error  Load_Coverage1( TTO_CoverageFormat1*  cf1,
726                                    PFace                 input )
727   {
728     DEFINE_LOAD_LOCALS( input->stream );
729 
730     UShort   n, count;
731 
732     UShort*  ga;
733 
734 
735     if ( ACCESS_Frame( 2L ) )
736       return error;
737 
738     count = cf1->GlyphCount = GET_UShort();
739 
740     FORGET_Frame();
741 
742     cf1->GlyphArray = NULL;
743 
744     if ( ALLOC_ARRAY( cf1->GlyphArray, count, UShort ) )
745       return error;
746 
747     ga = cf1->GlyphArray;
748 
749     if ( ACCESS_Frame( count * 2L ) )
750     {
751       FREE( cf1->GlyphArray );
752       return error;
753     }
754 
755     for ( n = 0; n < count; n++ )
756       ga[n] = GET_UShort();
757 
758     FORGET_Frame();
759 
760     return TT_Err_Ok;
761   }
762 
763 
Free_Coverage1(TTO_CoverageFormat1 * cf1)764   static void  Free_Coverage1( TTO_CoverageFormat1*  cf1 )
765   {
766     FREE( cf1->GlyphArray );
767   }
768 
769 
770   /* CoverageFormat2 */
771 
Load_Coverage2(TTO_CoverageFormat2 * cf2,PFace input)772   static TT_Error  Load_Coverage2( TTO_CoverageFormat2*  cf2,
773                                    PFace                 input )
774   {
775     DEFINE_LOAD_LOCALS( input->stream );
776 
777     UShort            n, count;
778 
779     TTO_RangeRecord*  rr;
780 
781 
782     if ( ACCESS_Frame( 2L ) )
783       return error;
784 
785     count = cf2->RangeCount = GET_UShort();
786 
787     FORGET_Frame();
788 
789     cf2->RangeRecord = NULL;
790 
791     if ( ALLOC_ARRAY( cf2->RangeRecord, count, TTO_RangeRecord ) )
792       return error;
793 
794     rr = cf2->RangeRecord;
795 
796     if ( ACCESS_Frame( count * 6L ) )
797       goto Fail;
798 
799     for ( n = 0; n < count; n++ )
800     {
801       rr[n].Start              = GET_UShort();
802       rr[n].End                = GET_UShort();
803       rr[n].StartCoverageIndex = GET_UShort();
804 
805       /* sanity check; we are limited to 16bit integers */
806       if ( rr[n].Start > rr[n].End ||
807            ( rr[n].End - rr[n].Start + (long)rr[n].StartCoverageIndex ) >=
808              0x10000L )
809       {
810         error = TTO_Err_Invalid_SubTable;
811         goto Fail;
812       }
813     }
814 
815     FORGET_Frame();
816 
817     return TT_Err_Ok;
818 
819   Fail:
820     FREE( cf2->RangeRecord );
821     return error;
822   }
823 
824 
Free_Coverage2(TTO_CoverageFormat2 * cf2)825   static void  Free_Coverage2( TTO_CoverageFormat2*  cf2 )
826   {
827     FREE( cf2->RangeRecord );
828   }
829 
830 
Load_Coverage(TTO_Coverage * c,PFace input)831   TT_Error  Load_Coverage( TTO_Coverage*  c,
832                            PFace          input )
833   {
834     DEFINE_LOAD_LOCALS( input->stream );
835 
836 
837     if ( ACCESS_Frame( 2L ) )
838       return error;
839 
840     c->CoverageFormat = GET_UShort();
841 
842     FORGET_Frame();
843 
844     switch ( c->CoverageFormat )
845     {
846     case 1:
847       return Load_Coverage1( &c->cf.cf1, input );
848 
849     case 2:
850       return Load_Coverage2( &c->cf.cf2, input );
851 
852     default:
853       return TTO_Err_Invalid_SubTable_Format;
854     }
855 
856     return TT_Err_Ok;               /* never reached */
857   }
858 
859 
Free_Coverage(TTO_Coverage * c)860   void  Free_Coverage( TTO_Coverage*  c )
861   {
862     switch ( c->CoverageFormat )
863     {
864     case 1:
865       Free_Coverage1( &c->cf.cf1 );
866       break;
867 
868     case 2:
869       Free_Coverage2( &c->cf.cf2 );
870       break;
871     }
872   }
873 
874 
Coverage_Index1(TTO_CoverageFormat1 * cf1,UShort glyphID,UShort * index)875   static TT_Error  Coverage_Index1( TTO_CoverageFormat1*  cf1,
876                                     UShort                glyphID,
877                                     UShort*               index )
878   {
879     UShort   min, max, new_min, new_max, middle;
880 
881     UShort*  array = cf1->GlyphArray;
882 
883 
884     /* binary search */
885 
886     new_min = 0;
887     new_max = cf1->GlyphCount - 1;
888 
889     do
890     {
891       min = new_min;
892       max = new_max;
893 
894       /* we use (min + max) / 2 = max - (max - min) / 2  to avoid
895          overflow and rounding errors                             */
896 
897       middle = max - ( ( max - min ) >> 1 );
898 
899       if ( glyphID == array[middle] )
900       {
901         *index = middle;
902         return TT_Err_Ok;
903       }
904       else if ( glyphID < array[middle] )
905       {
906         if ( middle == min )
907           break;
908         new_max = middle - 1;
909       }
910       else
911       {
912         if ( middle == max )
913           break;
914         new_min = middle + 1;
915       }
916     } while ( min < max );
917 
918     return TTO_Err_Not_Covered;
919   }
920 
921 
Coverage_Index2(TTO_CoverageFormat2 * cf2,UShort glyphID,UShort * index)922   static TT_Error  Coverage_Index2( TTO_CoverageFormat2*  cf2,
923                                     UShort                glyphID,
924                                     UShort*               index )
925   {
926     UShort            min, max, new_min, new_max, middle;
927 
928     TTO_RangeRecord*  rr = cf2->RangeRecord;
929 
930 
931     /* binary search */
932 
933     new_min = 0;
934     new_max = cf2->RangeCount - 1;
935 
936     do
937     {
938       min = new_min;
939       max = new_max;
940 
941       /* we use (min + max) / 2 = max - (max - min) / 2  to avoid
942          overflow and rounding errors                             */
943 
944       middle = max - ( ( max - min ) >> 1 );
945 
946       if ( glyphID >= rr[middle].Start && glyphID <= rr[middle].End )
947       {
948         *index = rr[middle].StartCoverageIndex + glyphID - rr[middle].Start;
949         return TT_Err_Ok;
950       }
951       else if ( glyphID < rr[middle].Start )
952       {
953         if ( middle == min )
954           break;
955         new_max = middle - 1;
956       }
957       else
958       {
959         if ( middle == max )
960           break;
961         new_min = middle + 1;
962       }
963     } while ( min < max );
964 
965     return TTO_Err_Not_Covered;
966   }
967 
968 
Coverage_Index(TTO_Coverage * c,UShort glyphID,UShort * index)969   TT_Error  Coverage_Index( TTO_Coverage*  c,
970                             UShort         glyphID,
971                             UShort*        index )
972   {
973     switch ( c->CoverageFormat )
974     {
975     case 1:
976       return Coverage_Index1( &c->cf.cf1, glyphID, index );
977 
978     case 2:
979       return Coverage_Index2( &c->cf.cf2, glyphID, index );
980 
981     default:
982       return TTO_Err_Invalid_SubTable_Format;
983     }
984 
985     return TT_Err_Ok;               /* never reached */
986   }
987 
988 
989 
990   /*************************************
991    * Class Definition related functions
992    *************************************/
993 
994 
995   /* ClassDefFormat1 */
996 
Load_ClassDef1(TTO_ClassDefinition * cd,UShort limit,PFace input)997   static TT_Error  Load_ClassDef1( TTO_ClassDefinition*  cd,
998                                    UShort                limit,
999                                    PFace                 input )
1000   {
1001     DEFINE_LOAD_LOCALS( input->stream );
1002 
1003     UShort                n, count;
1004 
1005     UShort*               cva;
1006     Bool*                 d;
1007 
1008     TTO_ClassDefFormat1*  cdf1;
1009 
1010 
1011     cdf1 = &cd->cd.cd1;
1012 
1013     if ( ACCESS_Frame( 4L ) )
1014       return error;
1015 
1016     cdf1->StartGlyph         = GET_UShort();
1017     count = cdf1->GlyphCount = GET_UShort();
1018 
1019     FORGET_Frame();
1020 
1021     /* sanity check; we are limited to 16bit integers */
1022 
1023     if ( cdf1->StartGlyph + (long)count >= 0x10000L )
1024       return TTO_Err_Invalid_SubTable;
1025 
1026     cdf1->ClassValueArray = NULL;
1027 
1028     if ( ALLOC_ARRAY( cdf1->ClassValueArray, count, UShort ) )
1029       return error;
1030 
1031     d   = cd->Defined;
1032     cva = cdf1->ClassValueArray;
1033 
1034     if ( ACCESS_Frame( count * 2L ) )
1035       goto Fail;
1036 
1037     for ( n = 0; n < count; n++ )
1038     {
1039       cva[n] = GET_UShort();
1040       if ( cva[n] >= limit )
1041       {
1042         error = TTO_Err_Invalid_SubTable;
1043         goto Fail;
1044       }
1045       d[cva[n]] = TRUE;
1046     }
1047 
1048     FORGET_Frame();
1049 
1050     return TT_Err_Ok;
1051 
1052   Fail:
1053     FREE( cva );
1054 
1055     return error;
1056   }
1057 
1058 
Free_ClassDef1(TTO_ClassDefFormat1 * cdf1)1059   static void  Free_ClassDef1( TTO_ClassDefFormat1*  cdf1 )
1060   {
1061     FREE( cdf1->ClassValueArray );
1062   }
1063 
1064 
1065   /* ClassDefFormat2 */
1066 
Load_ClassDef2(TTO_ClassDefinition * cd,UShort limit,PFace input)1067   static TT_Error  Load_ClassDef2 ( TTO_ClassDefinition*  cd,
1068                                     UShort                limit,
1069                                     PFace                 input )
1070   {
1071     DEFINE_LOAD_LOCALS( input->stream );
1072 
1073     UShort                 n, count;
1074 
1075     TTO_ClassRangeRecord*  crr;
1076     Bool*                  d;
1077 
1078     TTO_ClassDefFormat2*   cdf2;
1079 
1080 
1081     cdf2 = &cd->cd.cd2;
1082 
1083     if ( ACCESS_Frame( 2L ) )
1084       return error;
1085 
1086     count = cdf2->ClassRangeCount = GET_UShort();
1087 
1088     FORGET_Frame();
1089 
1090     cdf2->ClassRangeRecord = NULL;
1091 
1092     if ( ALLOC_ARRAY( cdf2->ClassRangeRecord, count, TTO_ClassRangeRecord ) )
1093       return error;
1094 
1095     d   = cd->Defined;
1096     crr = cdf2->ClassRangeRecord;
1097 
1098     if ( ACCESS_Frame( count * 6L ) )
1099       goto Fail;
1100 
1101     for ( n = 0; n < count; n++ )
1102     {
1103       crr[n].Start = GET_UShort();
1104       crr[n].End   = GET_UShort();
1105       crr[n].Class = GET_UShort();
1106 
1107       /* sanity check */
1108 
1109       if ( crr[n].Start > crr[n].End ||
1110            crr[n].Class >= limit )
1111       {
1112         error = TTO_Err_Invalid_SubTable;
1113         goto Fail;
1114       }
1115       d[crr[n].Class] = TRUE;
1116     }
1117 
1118     FORGET_Frame();
1119 
1120     return TT_Err_Ok;
1121 
1122   Fail:
1123     FREE( crr );
1124 
1125     return error;
1126   }
1127 
1128 
Free_ClassDef2(TTO_ClassDefFormat2 * cdf2)1129   static void  Free_ClassDef2( TTO_ClassDefFormat2*  cdf2 )
1130   {
1131     FREE( cdf2->ClassRangeRecord );
1132   }
1133 
1134 
1135   /* ClassDefinition */
1136 
Load_ClassDefinition(TTO_ClassDefinition * cd,UShort limit,PFace input)1137   TT_Error  Load_ClassDefinition( TTO_ClassDefinition*  cd,
1138                                   UShort                limit,
1139                                   PFace                 input )
1140   {
1141     DEFINE_LOAD_LOCALS( input->stream );
1142 
1143 
1144     if ( ALLOC_ARRAY( cd->Defined, limit, Bool ) )
1145       return error;
1146 
1147     if ( ACCESS_Frame( 2L ) )
1148       goto Fail;
1149 
1150     cd->ClassFormat = GET_UShort();
1151 
1152     FORGET_Frame();
1153 
1154     switch ( cd->ClassFormat )
1155     {
1156     case 1:
1157       error = Load_ClassDef1( cd, limit, input );
1158       break;
1159 
1160     case 2:
1161       error = Load_ClassDef2( cd, limit, input );
1162       break;
1163 
1164     default:
1165       error = TTO_Err_Invalid_SubTable_Format;
1166       break;
1167     }
1168 
1169     if ( error )
1170       goto Fail;
1171 
1172     cd->loaded = TRUE;
1173 
1174     return TT_Err_Ok;
1175 
1176   Fail:
1177     FREE( cd->Defined );
1178     return error;
1179   }
1180 
1181 
Free_ClassDefinition(TTO_ClassDefinition * cd)1182   void  Free_ClassDefinition( TTO_ClassDefinition*  cd )
1183   {
1184     if ( !cd->loaded )
1185       return;
1186 
1187     FREE( cd->Defined );
1188 
1189     switch ( cd->ClassFormat )
1190     {
1191     case 1:
1192       Free_ClassDef1( &cd->cd.cd1 );
1193       break;
1194 
1195     case 2:
1196       Free_ClassDef2( &cd->cd.cd2 );
1197       break;
1198     }
1199   }
1200 
1201 
Get_Class1(TTO_ClassDefFormat1 * cdf1,UShort glyphID,UShort * class,UShort * index)1202   static TT_Error  Get_Class1( TTO_ClassDefFormat1*  cdf1,
1203                                UShort                glyphID,
1204                                UShort*               class,
1205                                UShort*               index )
1206   {
1207     UShort*  cva = cdf1->ClassValueArray;
1208 
1209 
1210     *index = 0;
1211 
1212     if ( glyphID >= cdf1->StartGlyph &&
1213          glyphID <= cdf1->StartGlyph + cdf1->GlyphCount )
1214     {
1215       *class = cva[glyphID - cdf1->StartGlyph];
1216       return TT_Err_Ok;
1217     }
1218     else
1219     {
1220       *class = 0;
1221       return TTO_Err_Not_Covered;
1222     }
1223   }
1224 
1225 
1226   /* we need the index value of the last searched class range record
1227      in case of failure for constructed GDEF tables                  */
1228 
Get_Class2(TTO_ClassDefFormat2 * cdf2,UShort glyphID,UShort * class,UShort * index)1229   static TT_Error  Get_Class2( TTO_ClassDefFormat2*  cdf2,
1230                                UShort                glyphID,
1231                                UShort*               class,
1232                                UShort*               index )
1233   {
1234     TT_Error               error = TT_Err_Ok;
1235     UShort                 min, max, new_min, new_max, middle;
1236 
1237     TTO_ClassRangeRecord*  crr = cdf2->ClassRangeRecord;
1238 
1239 
1240     /* binary search */
1241 
1242     new_min = 0;
1243     new_max = cdf2->ClassRangeCount - 1;
1244 
1245     do
1246     {
1247       min = new_min;
1248       max = new_max;
1249 
1250       /* we use (min + max) / 2 = max - (max - min) / 2  to avoid
1251          overflow and rounding errors                             */
1252 
1253       middle = max - ( ( max - min ) >> 1 );
1254 
1255       if ( glyphID >= crr[middle].Start && glyphID <= crr[middle].End )
1256       {
1257         *class = crr[middle].Class;
1258         error  = TT_Err_Ok;
1259         break;
1260       }
1261       else if ( glyphID < crr[middle].Start )
1262       {
1263         if ( middle == min )
1264         {
1265           *class = 0;
1266           error  = TTO_Err_Not_Covered;
1267           break;
1268         }
1269         new_max = middle - 1;
1270       }
1271       else
1272       {
1273         if ( middle == max )
1274         {
1275           *class = 0;
1276           error  = TTO_Err_Not_Covered;
1277           break;
1278         }
1279         new_min = middle + 1;
1280       }
1281     } while ( min < max );
1282 
1283     if ( index )
1284       *index = middle;
1285 
1286     return error;
1287   }
1288 
1289 
Get_Class(TTO_ClassDefinition * cd,UShort glyphID,UShort * class,UShort * index)1290   TT_Error  Get_Class( TTO_ClassDefinition*  cd,
1291                        UShort                glyphID,
1292                        UShort*               class,
1293                        UShort*               index )
1294   {
1295     switch ( cd->ClassFormat )
1296     {
1297     case 1:
1298       return Get_Class1( &cd->cd.cd1, glyphID, class, index );
1299 
1300     case 2:
1301       return Get_Class2( &cd->cd.cd2, glyphID, class, index );
1302 
1303     default:
1304       return TTO_Err_Invalid_SubTable_Format;
1305     }
1306 
1307     return TT_Err_Ok;               /* never reached */
1308   }
1309 
1310 
1311 
1312   /***************************
1313    * Device related functions
1314    ***************************/
1315 
1316 
Load_Device(TTO_Device * d,PFace input)1317   TT_Error  Load_Device( TTO_Device*  d,
1318                          PFace        input )
1319   {
1320     DEFINE_LOAD_LOCALS( input->stream );
1321 
1322     UShort   n, count;
1323 
1324     UShort*  dv;
1325 
1326 
1327     if ( ACCESS_Frame( 6L ) )
1328       return error;
1329 
1330     d->StartSize   = GET_UShort();
1331     d->EndSize     = GET_UShort();
1332     d->DeltaFormat = GET_UShort();
1333 
1334     FORGET_Frame();
1335 
1336     if ( d->StartSize > d->EndSize ||
1337          d->DeltaFormat == 0 || d->DeltaFormat > 3 )
1338       return TTO_Err_Invalid_SubTable;
1339 
1340     d->DeltaValue = NULL;
1341 
1342     count = ( ( d->EndSize - d->StartSize + 1 ) >>
1343                 ( 4 - d->DeltaFormat ) ) + 1;
1344 
1345     if ( ALLOC_ARRAY( d->DeltaValue, count, UShort ) )
1346       return error;
1347 
1348     if ( ACCESS_Frame( count * 2L ) )
1349     {
1350       FREE( d->DeltaValue );
1351       return error;
1352     }
1353 
1354     dv = d->DeltaValue;
1355 
1356     for ( n = 0; n < count; n++ )
1357       dv[n] = GET_UShort();
1358 
1359     FORGET_Frame();
1360 
1361     return TT_Err_Ok;
1362   }
1363 
1364 
Free_Device(TTO_Device * d)1365   void  Free_Device( TTO_Device*  d )
1366   {
1367     FREE( d->DeltaValue );
1368   }
1369 
1370 
1371   /* Since we have the delta values stored in compressed form, we must
1372      uncompress it now.  To simplify the interface, the function always
1373      returns a meaningful value in `value'; the error is just for
1374      information.
1375                                  |
1376      format = 1: 0011223344556677|8899101112131415|...
1377                                  |
1378                       byte 1           byte 2
1379 
1380        00: (byte >> 14) & mask
1381        11: (byte >> 12) & mask
1382        ...
1383 
1384        mask = 0x0003
1385                                  |
1386      format = 2: 0000111122223333|4444555566667777|...
1387                                  |
1388                       byte 1           byte 2
1389 
1390        0000: (byte >> 12) & mask
1391        1111: (byte >>  8) & mask
1392        ...
1393 
1394        mask = 0x000F
1395                                  |
1396      format = 3: 0000000011111111|2222222233333333|...
1397                                  |
1398                       byte 1           byte 2
1399 
1400        00000000: (byte >> 8) & mask
1401        11111111: (byte >> 0) & mask
1402        ....
1403 
1404        mask = 0x00FF                                    */
1405 
Get_Device(TTO_Device * d,UShort size,Short * value)1406   TT_Error  Get_Device( TTO_Device*  d,
1407                         UShort       size,
1408                         Short*       value )
1409   {
1410     UShort  byte, bits, mask, f, s;
1411 
1412 
1413     f = d->DeltaFormat;
1414 
1415     if ( size >= d->StartSize && size <= d->EndSize )
1416     {
1417       s    = size - d->StartSize;
1418       byte = d->DeltaValue[s >> ( 4 - f )];
1419       bits = byte >> ( 16 - ( s % ( 1 << ( 4 - f ) ) + 1 ) * ( 1 << f ) );
1420       mask = 0xFFFF >> ( 16 - ( 1 << f ) );
1421 
1422       *value = (Short)( bits & mask );
1423 
1424       /* conversion to a signed value */
1425 
1426       if ( *value >= ( ( mask + 1 ) >> 1 ) )
1427         *value -= mask + 1;
1428 
1429       return TT_Err_Ok;
1430     }
1431     else
1432     {
1433       *value = 0;
1434       return TTO_Err_Not_Covered;
1435     }
1436   }
1437 
1438 
1439 /* END */
1440