1 /*******************************************************************
2  *
3  *  ftxgpos.c
4  *
5  *    TrueType Open GPOS 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 /* XXX There is *a lot* of duplicated code (cf. formats 7 and 8), but
19        I don't care currently.  I believe that it would be possible to
20        save about 50% of TTO code by carefully designing the structures,
21        sharing as much as possible with extensive use of macros.  This
22        is something for a volunteer :-)                                  */
23 
24 #include "tttypes.h"
25 #include "tttags.h"
26 #include "ttload.h"
27 #include "ttextend.h"
28 #include "ttmemory.h"
29 #include "ttfile.h"
30 
31 #include "ftxopen.h"
32 #include "ftxopenf.h"
33 
34 
35 #define GPOS_ID  Build_Extension_ID( 'G', 'P', 'O', 'S' )
36 
37 
38 
39   /**********************
40    * Extension Functions
41    **********************/
42 
43 
GPOS_Create(void * ext,PFace face)44   static TT_Error  GPOS_Create( void*  ext,
45                                 PFace  face )
46   {
47     DEFINE_LOAD_LOCALS( face->stream );
48 
49     TTO_GPOSHeader*  gpos = (TTO_GPOSHeader*)ext;
50     Long             table;
51 
52 
53     /* by convention */
54 
55     if ( !gpos )
56       return TT_Err_Ok;
57 
58     /* a null offset indicates that there is no GPOS table */
59 
60     gpos->offset = 0;
61 
62     /* we store the start offset and the size of the subtable */
63 
64     table = TT_LookUp_Table( face, TTAG_GPOS );
65     if ( table < 0 )
66       return TT_Err_Ok;             /* The table is optional */
67 
68     if ( FILE_Seek( face->dirTables[table].Offset ) ||
69          ACCESS_Frame( 4L ) )
70       return error;
71 
72     gpos->offset  = FILE_Pos() - 4L;    /* undo ACCESS_Frame() */
73     gpos->Version = GET_ULong();
74 
75     FORGET_Frame();
76 
77     gpos->loaded = FALSE;
78 
79     return TT_Err_Ok;
80   }
81 
82 
GPOS_Destroy(void * ext,PFace face)83   static TT_Error  GPOS_Destroy( void*  ext,
84                                  PFace  face )
85   {
86     TTO_GPOSHeader*  gpos = (TTO_GPOSHeader*)ext;
87 
88 
89     /* by convention */
90 
91     if ( !gpos )
92       return TT_Err_Ok;
93 
94     if ( gpos->loaded )
95     {
96       Free_LookupList( &gpos->LookupList, GPOS );
97       Free_FeatureList( &gpos->FeatureList );
98       Free_ScriptList( &gpos->ScriptList );
99     }
100 
101     return TT_Err_Ok;
102   }
103 
104 
105   EXPORT_FUNC
TT_Init_GPOS_Extension(TT_Engine engine)106   TT_Error  TT_Init_GPOS_Extension( TT_Engine  engine )
107   {
108     PEngine_Instance  _engine = HANDLE_Engine( engine );
109 
110 
111     if ( !_engine )
112       return TT_Err_Invalid_Engine;
113 
114     return  TT_Register_Extension( _engine,
115                                    GPOS_ID,
116                                    sizeof ( TTO_GPOSHeader ),
117                                    GPOS_Create,
118                                    GPOS_Destroy );
119   }
120 
121 
122   EXPORT_FUNC
TT_Load_GPOS_Table(TT_Face face,TTO_GPOSHeader * retptr,TTO_GDEFHeader * gdef)123   TT_Error  TT_Load_GPOS_Table( TT_Face          face,
124                                 TTO_GPOSHeader*  retptr,
125                                 TTO_GDEFHeader*  gdef )
126   {
127     ULong            cur_offset, new_offset, base_offset;
128 
129     TT_UShort        i, num_lookups;
130     TT_Error         error;
131     TT_Stream        stream;
132     TTO_GPOSHeader*  gpos;
133     TTO_Lookup*      lo;
134 
135     PFace  faze = HANDLE_Face( face );
136 
137 
138     if ( !retptr )
139       return TT_Err_Invalid_Argument;
140 
141     if ( !faze )
142       return TT_Err_Invalid_Face_Handle;
143 
144     error = TT_Extension_Get( faze, GPOS_ID, (void**)&gpos );
145     if ( error )
146       return error;
147 
148     if ( gpos->offset == 0 )
149       return TT_Err_Table_Missing;      /* no GPOS table; nothing to do */
150 
151     /* now access stream */
152 
153     if ( USE_Stream( faze->stream, stream ) )
154       return error;
155 
156     base_offset = gpos->offset;
157 
158     /* skip version */
159 
160     if ( FILE_Seek( base_offset + 4L ) ||
161          ACCESS_Frame( 2L ) )
162       return error;
163 
164     new_offset = GET_UShort() + base_offset;
165 
166     FORGET_Frame();
167 
168     cur_offset = FILE_Pos();
169     if ( FILE_Seek( new_offset ) ||
170          ( error = Load_ScriptList( &gpos->ScriptList,
171                                     faze ) ) != TT_Err_Ok )
172       return error;
173     (void)FILE_Seek( cur_offset );
174 
175     if ( ACCESS_Frame( 2L ) )
176       goto Fail3;
177 
178     new_offset = GET_UShort() + base_offset;
179 
180     FORGET_Frame();
181 
182     cur_offset = FILE_Pos();
183     if ( FILE_Seek( new_offset ) ||
184          ( error = Load_FeatureList( &gpos->FeatureList,
185                                      faze ) ) != TT_Err_Ok )
186       goto Fail3;
187     (void)FILE_Seek( cur_offset );
188 
189     if ( ACCESS_Frame( 2L ) )
190       goto Fail2;
191 
192     new_offset = GET_UShort() + base_offset;
193 
194     FORGET_Frame();
195 
196     cur_offset = FILE_Pos();
197     if ( FILE_Seek( new_offset ) ||
198          ( error = Load_LookupList( &gpos->LookupList,
199                                     faze, GPOS ) ) != TT_Err_Ok )
200       goto Fail2;
201 
202     gpos->gdef = gdef;      /* can be NULL */
203 
204     /* We now check the LookupFlags for values larger than 0xFF to find
205        out whether we need to load the `MarkAttachClassDef' field of the
206        GDEF table -- this hack is necessary for OpenType 1.2 tables since
207        the version field of the GDEF table hasn't been incremented.
208 
209        For constructed GDEF tables, we only load it if
210        `MarkAttachClassDef_offset' is not zero (nevertheless, a build of
211        a constructed mark attach table is not supported currently).       */
212 
213     if ( gdef &&
214          gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded )
215     {
216       lo          = gpos->LookupList.Lookup;
217       num_lookups = gpos->LookupList.LookupCount;
218 
219       for ( i = 0; i < num_lookups; i++ )
220       {
221         if ( lo[i].LookupFlag & IGNORE_SPECIAL_MARKS )
222         {
223           if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) ||
224                ACCESS_Frame( 2L ) )
225             goto Fail1;
226 
227           new_offset = GET_UShort();
228 
229           FORGET_Frame();
230 
231           if ( !new_offset )
232             return TTO_Err_Invalid_GDEF_SubTable;
233 
234           new_offset += base_offset;
235 
236           if ( FILE_Seek( new_offset ) ||
237                ( error = Load_ClassDefinition( &gdef->MarkAttachClassDef,
238                                                256, faze ) ) != TT_Err_Ok )
239             goto Fail1;
240 
241           break;
242         }
243       }
244     }
245 
246     gpos->loaded = TRUE;
247     *retptr = *gpos;
248     DONE_Stream( stream );
249 
250     return TT_Err_Ok;
251 
252   Fail1:
253     Free_LookupList( &gpos->LookupList, GPOS );
254 
255   Fail2:
256     Free_FeatureList( &gpos->FeatureList );
257 
258   Fail3:
259     Free_ScriptList( &gpos->ScriptList );
260 
261     /* release stream */
262 
263     DONE_Stream( stream );
264 
265     return error;
266   }
267 
268 
269 
270   /*****************************
271    * SubTable related functions
272    *****************************/
273 
274   /* shared tables */
275 
276   /* ValueRecord */
277 
Load_ValueRecord(TTO_ValueRecord * vr,TT_UShort format,PFace input)278   static TT_Error  Load_ValueRecord( TTO_ValueRecord*  vr,
279                                      TT_UShort         format,
280                                      PFace             input )
281   {
282     DEFINE_LOAD_LOCALS( input->stream );
283 
284     ULong    cur_offset, new_offset, base_offset;
285 
286 
287     base_offset = FILE_Pos();
288 
289     if ( format & HAVE_X_PLACEMENT )
290     {
291       if ( ACCESS_Frame( 2L ) )
292         return error;
293 
294       vr->XPlacement = GET_Short();
295 
296       FORGET_Frame();
297     }
298     else
299       vr->XPlacement = 0;
300 
301     if ( format & HAVE_Y_PLACEMENT )
302     {
303       if ( ACCESS_Frame( 2L ) )
304         return error;
305 
306       vr->YPlacement = GET_Short();
307 
308       FORGET_Frame();
309     }
310     else
311       vr->YPlacement = 0;
312 
313     if ( format & HAVE_X_ADVANCE )
314     {
315       if ( ACCESS_Frame( 2L ) )
316         return error;
317 
318       vr->XAdvance = GET_Short();
319 
320       FORGET_Frame();
321     }
322     else
323       vr->XAdvance = 0;
324 
325     if ( format & HAVE_Y_ADVANCE )
326     {
327       if ( ACCESS_Frame( 2L ) )
328         return error;
329 
330       vr->YAdvance = GET_Short();
331 
332       FORGET_Frame();
333     }
334     else
335       vr->YAdvance = 0;
336 
337     if ( format & HAVE_X_PLACEMENT_DEVICE )
338     {
339       if ( ACCESS_Frame( 2L ) )
340         return error;
341 
342       new_offset = GET_UShort() + base_offset;
343 
344       FORGET_Frame();
345 
346       cur_offset = FILE_Pos();
347       if ( FILE_Seek( new_offset ) ||
348            ( error = Load_Device( &vr->XPlacementDevice,
349                                   input ) ) != TT_Err_Ok )
350         return error;
351       (void)FILE_Seek( cur_offset );
352     }
353     else
354     {
355       vr->XPlacementDevice.StartSize  = 0;
356       vr->XPlacementDevice.EndSize    = 0;
357       vr->XPlacementDevice.DeltaValue = NULL;
358     }
359 
360     if ( format & HAVE_Y_PLACEMENT_DEVICE )
361     {
362       if ( ACCESS_Frame( 2L ) )
363         goto Fail3;
364 
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_Device( &vr->YPlacementDevice,
372                                   input ) ) != TT_Err_Ok )
373         goto Fail3;
374       (void)FILE_Seek( cur_offset );
375     }
376     else
377     {
378       vr->YPlacementDevice.StartSize  = 0;
379       vr->YPlacementDevice.EndSize    = 0;
380       vr->YPlacementDevice.DeltaValue = NULL;
381     }
382 
383     if ( format & HAVE_X_ADVANCE_DEVICE )
384     {
385       if ( ACCESS_Frame( 2L ) )
386         goto Fail2;
387 
388       new_offset = GET_UShort() + base_offset;
389 
390       FORGET_Frame();
391 
392       cur_offset = FILE_Pos();
393       if ( FILE_Seek( new_offset ) ||
394            ( error = Load_Device( &vr->XAdvanceDevice,
395                                   input ) ) != TT_Err_Ok )
396         goto Fail2;
397       (void)FILE_Seek( cur_offset );
398     }
399     else
400     {
401       vr->XAdvanceDevice.StartSize  = 0;
402       vr->XAdvanceDevice.EndSize    = 0;
403       vr->XAdvanceDevice.DeltaValue = NULL;
404     }
405 
406     if ( format & HAVE_Y_ADVANCE_DEVICE )
407     {
408       if ( ACCESS_Frame( 2L ) )
409         goto Fail1;
410 
411       new_offset = GET_UShort() + base_offset;
412 
413       FORGET_Frame();
414 
415       cur_offset = FILE_Pos();
416       if ( FILE_Seek( new_offset ) ||
417            ( error = Load_Device( &vr->YAdvanceDevice,
418                                   input ) ) != TT_Err_Ok )
419         goto Fail1;
420       (void)FILE_Seek( cur_offset );
421     }
422     else
423     {
424       vr->YAdvanceDevice.StartSize  = 0;
425       vr->YAdvanceDevice.EndSize    = 0;
426       vr->YAdvanceDevice.DeltaValue = NULL;
427     }
428 
429     if ( format & HAVE_X_ID_PLACEMENT )
430     {
431       if ( ACCESS_Frame( 2L ) )
432         goto Fail1;
433 
434       vr->XIdPlacement = GET_UShort();
435 
436       FORGET_Frame();
437     }
438     else
439       vr->XIdPlacement = 0;
440 
441     if ( format & HAVE_Y_ID_PLACEMENT )
442     {
443       if ( ACCESS_Frame( 2L ) )
444         goto Fail1;
445 
446       vr->YIdPlacement = GET_UShort();
447 
448       FORGET_Frame();
449     }
450     else
451       vr->YIdPlacement = 0;
452 
453     if ( format & HAVE_X_ID_ADVANCE )
454     {
455       if ( ACCESS_Frame( 2L ) )
456         goto Fail1;
457 
458       vr->XIdAdvance = GET_UShort();
459 
460       FORGET_Frame();
461     }
462     else
463       vr->XIdAdvance = 0;
464 
465     if ( format & HAVE_Y_ID_ADVANCE )
466     {
467       if ( ACCESS_Frame( 2L ) )
468         goto Fail1;
469 
470       vr->YIdAdvance = GET_UShort();
471 
472       FORGET_Frame();
473     }
474     else
475       vr->YIdAdvance = 0;
476 
477     return TT_Err_Ok;
478 
479   Fail1:
480     Free_Device( &vr->YAdvanceDevice );
481 
482   Fail2:
483     Free_Device( &vr->XAdvanceDevice );
484 
485   Fail3:
486     Free_Device( &vr->YPlacementDevice );
487     return error;
488   }
489 
490 
Free_ValueRecord(TTO_ValueRecord * vr,UShort format)491   static void  Free_ValueRecord( TTO_ValueRecord*  vr,
492                                  UShort            format )
493   {
494     if ( format & HAVE_Y_ADVANCE_DEVICE )
495       Free_Device( &vr->YAdvanceDevice );
496     if ( format & HAVE_X_ADVANCE_DEVICE )
497       Free_Device( &vr->XAdvanceDevice );
498     if ( format & HAVE_Y_PLACEMENT_DEVICE )
499       Free_Device( &vr->YPlacementDevice );
500     if ( format & HAVE_X_PLACEMENT_DEVICE )
501       Free_Device( &vr->XPlacementDevice );
502   }
503 
504 
505   /* AnchorFormat1 */
506   /* AnchorFormat2 */
507   /* AnchorFormat3 */
508   /* AnchorFormat4 */
509 
Load_Anchor(TTO_Anchor * an,PFace input)510   static TT_Error  Load_Anchor( TTO_Anchor*  an,
511                                 PFace        input )
512   {
513     DEFINE_LOAD_LOCALS( input->stream );
514 
515     ULong    cur_offset, new_offset, base_offset;
516 
517 
518     base_offset = FILE_Pos();
519 
520     if ( ACCESS_Frame( 2L ) )
521       return error;
522 
523     an->PosFormat = GET_UShort();
524 
525     FORGET_Frame();
526 
527     switch ( an->PosFormat )
528     {
529     case 1:
530       if ( ACCESS_Frame( 4L ) )
531         return error;
532 
533       an->af.af1.XCoordinate = GET_Short();
534       an->af.af1.YCoordinate = GET_Short();
535 
536       FORGET_Frame();
537       break;
538 
539     case 2:
540       if ( ACCESS_Frame( 6L ) )
541         return error;
542 
543       an->af.af2.XCoordinate = GET_Short();
544       an->af.af2.YCoordinate = GET_Short();
545       an->af.af2.AnchorPoint = GET_UShort();
546 
547       FORGET_Frame();
548       break;
549 
550     case 3:
551       if ( ACCESS_Frame( 6L ) )
552         return error;
553 
554       an->af.af3.XCoordinate = GET_Short();
555       an->af.af3.YCoordinate = GET_Short();
556 
557       new_offset = GET_UShort();
558 
559       FORGET_Frame();
560 
561       if ( new_offset )
562       {
563         new_offset += base_offset;
564 
565         cur_offset = FILE_Pos();
566         if ( FILE_Seek( new_offset ) ||
567              ( error = Load_Device( &an->af.af3.XDeviceTable,
568                                     input ) ) != TT_Err_Ok )
569           return error;
570         (void)FILE_Seek( cur_offset );
571       }
572       else
573       {
574         an->af.af3.XDeviceTable.StartSize  = 0;
575         an->af.af3.XDeviceTable.EndSize    = 0;
576         an->af.af3.XDeviceTable.DeltaValue = 0;
577       }
578 
579       if ( ACCESS_Frame( 2L ) )
580         goto Fail;
581 
582       new_offset = GET_UShort();
583 
584       FORGET_Frame();
585 
586       if ( new_offset )
587       {
588         new_offset += base_offset;
589 
590         cur_offset = FILE_Pos();
591         if ( FILE_Seek( new_offset ) ||
592              ( error = Load_Device( &an->af.af3.YDeviceTable,
593                                     input ) ) != TT_Err_Ok )
594           goto Fail;
595         (void)FILE_Seek( cur_offset );
596       }
597       else
598       {
599         an->af.af3.YDeviceTable.StartSize  = 0;
600         an->af.af3.YDeviceTable.EndSize    = 0;
601         an->af.af3.YDeviceTable.DeltaValue = 0;
602       }
603       break;
604 
605     case 4:
606       if ( ACCESS_Frame( 4L ) )
607         return error;
608 
609       an->af.af4.XIdAnchor = GET_UShort();
610       an->af.af4.YIdAnchor = GET_UShort();
611 
612       FORGET_Frame();
613       break;
614 
615     default:
616       return TTO_Err_Invalid_GPOS_SubTable_Format;
617     }
618 
619     return TT_Err_Ok;
620 
621   Fail:
622     Free_Device( &an->af.af3.XDeviceTable );
623     return error;
624   }
625 
626 
Free_Anchor(TTO_Anchor * an)627   static void  Free_Anchor( TTO_Anchor*  an )
628   {
629     if ( an->PosFormat == 3 )
630     {
631       Free_Device( &an->af.af3.YDeviceTable );
632       Free_Device( &an->af.af3.XDeviceTable );
633     }
634   }
635 
636 
637   /* MarkArray */
638 
Load_MarkArray(TTO_MarkArray * ma,PFace input)639   static TT_Error  Load_MarkArray ( TTO_MarkArray*  ma,
640                                     PFace           input )
641   {
642     DEFINE_LOAD_LOCALS( input->stream );
643 
644     UShort           n, count;
645     ULong            cur_offset, new_offset, base_offset;
646 
647     TTO_MarkRecord*  mr;
648 
649 
650     base_offset = FILE_Pos();
651 
652     if ( ACCESS_Frame( 2L ) )
653       return error;
654 
655     count = ma->MarkCount = GET_UShort();
656 
657     FORGET_Frame();
658 
659     ma->MarkRecord = NULL;
660 
661     if ( ALLOC_ARRAY( ma->MarkRecord, count, TTO_MarkRecord ) )
662       return error;
663 
664     mr = ma->MarkRecord;
665 
666     for ( n = 0; n < count; n++ )
667     {
668       if ( ACCESS_Frame( 4L ) )
669         goto Fail;
670 
671       mr[n].Class = GET_UShort();
672       new_offset  = GET_UShort() + base_offset;
673 
674       FORGET_Frame();
675 
676       cur_offset = FILE_Pos();
677       if ( FILE_Seek( new_offset ) ||
678            ( error = Load_Anchor( &mr[n].MarkAnchor, input ) ) != TT_Err_Ok )
679         goto Fail;
680       (void)FILE_Seek( cur_offset );
681     }
682 
683     return TT_Err_Ok;
684 
685   Fail:
686     for ( n = 0; n < count; n++ )
687       Free_Anchor( &mr[n].MarkAnchor );
688 
689     FREE( mr );
690     return error;
691   }
692 
693 
Free_MarkArray(TTO_MarkArray * ma)694   static void  Free_MarkArray( TTO_MarkArray*  ma )
695   {
696     UShort           n, count;
697 
698     TTO_MarkRecord*  mr;
699 
700 
701     if ( ma->MarkRecord )
702     {
703       count = ma->MarkCount;
704       mr    = ma->MarkRecord;
705 
706       for ( n = 0; n < count; n++ )
707         Free_Anchor( &mr[n].MarkAnchor );
708 
709       FREE( mr );
710     }
711   }
712 
713 
714   /* LookupType 1 */
715 
716   /* SinglePosFormat1 */
717   /* SinglePosFormat2 */
718 
Load_SinglePos(TTO_SinglePos * sp,PFace input)719   TT_Error  Load_SinglePos( TTO_SinglePos*  sp,
720                             PFace           input )
721   {
722     DEFINE_LOAD_LOCALS( input->stream );
723 
724     UShort            n, count, format;
725     ULong             cur_offset, new_offset, base_offset;
726 
727     TTO_ValueRecord*  v;
728 
729 
730     base_offset = FILE_Pos();
731 
732     if ( ACCESS_Frame( 6L ) )
733       return error;
734 
735     sp->PosFormat = GET_UShort();
736     new_offset    = GET_UShort() + base_offset;
737 
738     format = sp->ValueFormat = GET_UShort();
739 
740     FORGET_Frame();
741 
742     if ( !format )
743       return TTO_Err_Invalid_GPOS_SubTable;
744 
745     cur_offset = FILE_Pos();
746     if ( FILE_Seek( new_offset ) ||
747          ( error = Load_Coverage( &sp->Coverage, input ) ) != TT_Err_Ok )
748       return error;
749     (void)FILE_Seek( cur_offset );
750 
751     switch ( sp->PosFormat )
752     {
753     case 1:
754       error = Load_ValueRecord( &sp->spf.spf1.Value, format, input );
755       if ( error )
756         goto Fail2;
757       break;
758 
759     case 2:
760       if ( ACCESS_Frame( 2L ) )
761         goto Fail2;
762 
763       count = sp->spf.spf2.ValueCount = GET_UShort();
764 
765       FORGET_Frame();
766 
767       sp->spf.spf2.Value = NULL;
768 
769       if ( ALLOC_ARRAY( sp->spf.spf2.Value, count, TTO_ValueRecord ) )
770         goto Fail2;
771 
772       v = sp->spf.spf2.Value;
773 
774       for ( n = 0; n < count; n++ )
775       {
776         error = Load_ValueRecord( &v[n], format, input );
777         if ( error )
778           goto Fail1;
779       }
780       break;
781 
782     default:
783       return TTO_Err_Invalid_GPOS_SubTable_Format;
784     }
785 
786     return TT_Err_Ok;
787 
788   Fail1:
789     for ( n = 0; n < count; n++ )
790       Free_ValueRecord( &v[n], format );
791 
792     FREE( v );
793 
794   Fail2:
795     Free_Coverage( &sp->Coverage );
796     return error;
797   }
798 
799 
Free_SinglePos(TTO_SinglePos * sp)800   void  Free_SinglePos( TTO_SinglePos*  sp )
801   {
802     UShort            n, count, format;
803 
804     TTO_ValueRecord*  v;
805 
806 
807     format = sp->ValueFormat;
808 
809     switch ( sp->PosFormat )
810     {
811     case 1:
812       Free_ValueRecord( &sp->spf.spf1.Value, format );
813       break;
814 
815     case 2:
816       if ( sp->spf.spf2.Value )
817       {
818         count = sp->spf.spf2.ValueCount;
819         v     = sp->spf.spf2.Value;
820 
821         for ( n = 0; n < count; n++ )
822           Free_ValueRecord( &v[n], format );
823 
824         FREE( v );
825       }
826       break;
827     }
828 
829     Free_Coverage( &sp->Coverage );
830   }
831 
832 
833   /* LookupType 2 */
834 
835   /* PairSet */
836 
Load_PairSet(TTO_PairSet * ps,UShort format1,UShort format2,PFace input)837   static TT_Error  Load_PairSet ( TTO_PairSet*  ps,
838                                   UShort        format1,
839                                   UShort        format2,
840                                   PFace         input )
841   {
842     DEFINE_LOAD_LOCALS( input->stream );
843 
844     UShort                n, count;
845 
846     TTO_PairValueRecord*  pvr;
847 
848 
849     if ( ACCESS_Frame( 2L ) )
850       return error;
851 
852     count = ps->PairValueCount = GET_UShort();
853 
854     FORGET_Frame();
855 
856     ps->PairValueRecord = NULL;
857 
858     if ( ALLOC_ARRAY( ps->PairValueRecord, count, TTO_PairValueRecord ) )
859       return error;
860 
861     pvr = ps->PairValueRecord;
862 
863     for ( n = 0; n < count; n++ )
864     {
865       if ( ACCESS_Frame( 2L ) )
866         goto Fail;
867 
868       pvr[n].SecondGlyph = GET_UShort();
869 
870       FORGET_Frame();
871 
872       if ( format1 )
873       {
874         error = Load_ValueRecord( &pvr[n].Value1, format1, input );
875         if ( error )
876           goto Fail;
877       }
878       if ( format2 )
879       {
880         error = Load_ValueRecord( &pvr[n].Value2, format2, input );
881         if ( error )
882           goto Fail;
883       }
884     }
885 
886     return TT_Err_Ok;
887 
888   Fail:
889     for ( n = 0; n < count; n++ )
890     {
891       if ( format1 )
892         Free_ValueRecord( &pvr[n].Value1, format1 );
893       if ( format2 )
894         Free_ValueRecord( &pvr[n].Value2, format2 );
895     }
896 
897     FREE( pvr );
898     return error;
899   }
900 
901 
Free_PairSet(TTO_PairSet * ps,UShort format1,UShort format2)902   static void  Free_PairSet( TTO_PairSet*  ps,
903                              UShort        format1,
904                              UShort        format2 )
905   {
906     UShort                n, count;
907 
908     TTO_PairValueRecord*  pvr;
909 
910 
911     if ( ps->PairValueRecord )
912     {
913       count = ps->PairValueCount;
914       pvr   = ps->PairValueRecord;
915 
916       for ( n = 0; n < count; n++ )
917       {
918         if ( format1 )
919           Free_ValueRecord( &pvr[n].Value1, format1 );
920         if ( format2 )
921           Free_ValueRecord( &pvr[n].Value2, format2 );
922       }
923 
924       FREE( pvr );
925     }
926   }
927 
928 
929   /* PairPosFormat1 */
930 
Load_PairPosFormat1(TTO_PairPosFormat1 * ppf1,UShort format1,UShort format2,PFace input)931   static TT_Error  Load_PairPosFormat1( TTO_PairPosFormat1*  ppf1,
932                                         UShort               format1,
933                                         UShort               format2,
934                                         PFace                input )
935   {
936     DEFINE_LOAD_LOCALS( input->stream );
937 
938     UShort        n, count;
939     ULong         cur_offset, new_offset, base_offset;
940 
941     TTO_PairSet*  ps;
942 
943 
944     base_offset = FILE_Pos() - 8L;
945 
946     if ( ACCESS_Frame( 2L ) )
947       return error;
948 
949     count = ppf1->PairSetCount = GET_UShort();
950 
951     FORGET_Frame();
952 
953     ppf1->PairSet = NULL;
954 
955     if ( ALLOC_ARRAY( ppf1->PairSet, count, TTO_PairSet ) )
956       goto Fail;
957 
958     ps = ppf1->PairSet;
959 
960     for ( n = 0; n < count; n++ )
961     {
962       if ( ACCESS_Frame( 2L ) )
963         goto Fail;
964 
965       new_offset = GET_UShort() + base_offset;
966 
967       FORGET_Frame();
968 
969       cur_offset = FILE_Pos();
970       if ( FILE_Seek( new_offset ) ||
971            ( error = Load_PairSet( &ps[n], format1,
972                                    format2, input ) ) != TT_Err_Ok )
973         goto Fail;
974       (void)FILE_Seek( cur_offset );
975     }
976 
977     return TT_Err_Ok;
978 
979   Fail:
980     for ( n = 0; n < count; n++ )
981       Free_PairSet( &ps[n], format1, format2 );
982 
983     FREE( ps );
984     return error;
985   }
986 
987 
Free_PairPosFormat1(TTO_PairPosFormat1 * ppf1,UShort format1,UShort format2)988   static void  Free_PairPosFormat1( TTO_PairPosFormat1*  ppf1,
989                                     UShort               format1,
990                                     UShort               format2 )
991   {
992     UShort        n, count;
993 
994     TTO_PairSet*  ps;
995 
996 
997     if ( ppf1->PairSet )
998     {
999       count = ppf1->PairSetCount;
1000       ps    = ppf1->PairSet;
1001 
1002       for ( n = 0; n < count; n++ )
1003         Free_PairSet( &ps[n], format1, format2 );
1004 
1005       FREE( ps );
1006     }
1007   }
1008 
1009 
1010   /* PairPosFormat2 */
1011 
Load_PairPosFormat2(TTO_PairPosFormat2 * ppf2,UShort format1,UShort format2,PFace input)1012   static TT_Error  Load_PairPosFormat2( TTO_PairPosFormat2*  ppf2,
1013                                         UShort               format1,
1014                                         UShort               format2,
1015                                         PFace                input )
1016   {
1017     DEFINE_LOAD_LOCALS( input->stream );
1018 
1019     UShort             m, n, count1, count2;
1020     ULong              cur_offset, new_offset1, new_offset2, base_offset;
1021 
1022     TTO_Class1Record*  c1r;
1023     TTO_Class2Record*  c2r;
1024 
1025 
1026     base_offset = FILE_Pos() - 8L;
1027 
1028     if ( ACCESS_Frame( 8L ) )
1029       return error;
1030 
1031     new_offset1 = GET_UShort() + base_offset;
1032     new_offset2 = GET_UShort() + base_offset;
1033 
1034     /* `Class1Count' and `Class2Count' are the upper limits for class
1035        values, thus we read it now to make additional safety checks.  */
1036 
1037     count1 = ppf2->Class1Count = GET_UShort();
1038     count2 = ppf2->Class2Count = GET_UShort();
1039 
1040     FORGET_Frame();
1041 
1042     cur_offset = FILE_Pos();
1043     if ( FILE_Seek( new_offset1 ) ||
1044          ( error = Load_ClassDefinition( &ppf2->ClassDef1, count1,
1045                                          input ) ) != TT_Err_Ok )
1046       return error;
1047     (void)FILE_Seek( cur_offset );
1048 
1049     cur_offset = FILE_Pos();
1050     if ( FILE_Seek( new_offset2 ) ||
1051          ( error = Load_ClassDefinition( &ppf2->ClassDef2, count2,
1052                                          input ) ) != TT_Err_Ok )
1053       goto Fail2;
1054     (void)FILE_Seek( cur_offset );
1055 
1056     ppf2->Class1Record = NULL;
1057 
1058     if ( ALLOC_ARRAY( ppf2->Class1Record, count1, TTO_Class1Record ) )
1059       goto Fail1;
1060 
1061     c1r = ppf2->Class1Record;
1062 
1063     for ( m = 0; m < count1; m++ )
1064     {
1065       c1r[m].Class2Record = NULL;
1066 
1067       if ( ALLOC_ARRAY( c1r[m].Class2Record, count2, TTO_Class2Record ) )
1068         goto Fail1;
1069 
1070       c2r = c1r[m].Class2Record;
1071 
1072       for ( n = 0; n < count2; n++ )
1073       {
1074         if ( format1 )
1075         {
1076           Load_ValueRecord( &c2r[n].Value1, format1, input );
1077           if ( error )
1078             goto Fail1;
1079         }
1080         if ( format2 )
1081         {
1082           Load_ValueRecord( &c2r[n].Value2, format2, input );
1083           if ( error )
1084             goto Fail1;
1085         }
1086       }
1087     }
1088 
1089     return TT_Err_Ok;
1090 
1091   Fail1:
1092     for ( m = 0; m < count1; m++ )
1093     {
1094       c2r = c1r[m].Class2Record;
1095 
1096       for ( n = 0; n < count2; n++ )
1097       {
1098         if ( format1 )
1099           Free_ValueRecord( &c2r[n].Value1, format1 );
1100         if ( format2 )
1101           Free_ValueRecord( &c2r[n].Value2, format2 );
1102       }
1103 
1104       FREE( c2r );
1105     }
1106 
1107     FREE( c1r );
1108 
1109     Free_ClassDefinition( &ppf2->ClassDef2 );
1110 
1111   Fail2:
1112     Free_ClassDefinition( &ppf2->ClassDef1 );
1113     return error;
1114   }
1115 
1116 
Free_PairPosFormat2(TTO_PairPosFormat2 * ppf2,UShort format1,UShort format2)1117   static void  Free_PairPosFormat2( TTO_PairPosFormat2*  ppf2,
1118                                     UShort               format1,
1119                                     UShort               format2 )
1120   {
1121     UShort             m, n, count1, count2;
1122 
1123     TTO_Class1Record*  c1r;
1124     TTO_Class2Record*  c2r;
1125 
1126 
1127     if ( ppf2->Class1Record )
1128     {
1129       c1r    = ppf2->Class1Record;
1130       count1 = ppf2->Class1Count;
1131       count2 = ppf2->Class2Count;
1132 
1133       for ( m = 0; m < count1; m++ )
1134       {
1135         c2r = c1r[m].Class2Record;
1136 
1137         for ( n = 0; n < count2; n++ )
1138         {
1139           if ( format1 )
1140             Free_ValueRecord( &c2r[n].Value1, format1 );
1141           if ( format2 )
1142             Free_ValueRecord( &c2r[n].Value2, format2 );
1143         }
1144 
1145         FREE( c2r );
1146       }
1147 
1148       FREE( c1r );
1149 
1150       Free_ClassDefinition( &ppf2->ClassDef2 );
1151       Free_ClassDefinition( &ppf2->ClassDef1 );
1152     }
1153   }
1154 
1155 
Load_PairPos(TTO_PairPos * pp,PFace input)1156   TT_Error  Load_PairPos( TTO_PairPos*  pp,
1157                           PFace         input )
1158   {
1159     DEFINE_LOAD_LOCALS( input->stream );
1160 
1161     UShort            format1, format2;
1162     ULong             cur_offset, new_offset, base_offset;
1163 
1164 
1165     base_offset = FILE_Pos();
1166 
1167     if ( ACCESS_Frame( 8L ) )
1168       return error;
1169 
1170     pp->PosFormat = GET_UShort();
1171     new_offset    = GET_UShort() + base_offset;
1172 
1173     format1 = pp->ValueFormat1 = GET_UShort();
1174     format2 = pp->ValueFormat2 = GET_UShort();
1175 
1176     FORGET_Frame();
1177 
1178     cur_offset = FILE_Pos();
1179     if ( FILE_Seek( new_offset ) ||
1180          ( error = Load_Coverage( &pp->Coverage, input ) ) != TT_Err_Ok )
1181       return error;
1182     (void)FILE_Seek( cur_offset );
1183 
1184     switch ( pp->PosFormat )
1185     {
1186     case 1:
1187       error = Load_PairPosFormat1( &pp->ppf.ppf1, format1, format2, input );
1188       if ( error )
1189         goto Fail;
1190       break;
1191 
1192     case 2:
1193       error = Load_PairPosFormat2( &pp->ppf.ppf2, format1, format2, input );
1194       if ( error )
1195         goto Fail;
1196       break;
1197 
1198     default:
1199       return TTO_Err_Invalid_GPOS_SubTable_Format;
1200     }
1201 
1202     return TT_Err_Ok;
1203 
1204   Fail:
1205     Free_Coverage( &pp->Coverage );
1206     return error;
1207   }
1208 
1209 
Free_PairPos(TTO_PairPos * pp)1210   void  Free_PairPos( TTO_PairPos*  pp )
1211   {
1212     UShort  format1, format2;
1213 
1214 
1215     format1 = pp->ValueFormat1;
1216     format2 = pp->ValueFormat2;
1217 
1218     switch ( pp->PosFormat )
1219     {
1220     case 1:
1221       Free_PairPosFormat1( &pp->ppf.ppf1, format1, format2 );
1222       break;
1223 
1224     case 2:
1225       Free_PairPosFormat2( &pp->ppf.ppf2, format1, format2 );
1226       break;
1227     }
1228 
1229     Free_Coverage( &pp->Coverage );
1230   }
1231 
1232 
1233   /* LookupType 3 */
1234 
1235   /* CursivePosFormat1 */
1236 
Load_CursivePos(TTO_CursivePos * cp,PFace input)1237   TT_Error  Load_CursivePos( TTO_CursivePos*  cp,
1238                              PFace            input )
1239   {
1240     DEFINE_LOAD_LOCALS( input->stream );
1241 
1242     UShort                n, count;
1243     ULong                 cur_offset, new_offset, base_offset;
1244 
1245     TTO_EntryExitRecord*  eer;
1246 
1247 
1248     base_offset = FILE_Pos();
1249 
1250     if ( ACCESS_Frame( 4L ) )
1251       return error;
1252 
1253     cp->PosFormat = GET_UShort();
1254     new_offset    = GET_UShort() + base_offset;
1255 
1256     FORGET_Frame();
1257 
1258     cur_offset = FILE_Pos();
1259     if ( FILE_Seek( new_offset ) ||
1260          ( error = Load_Coverage( &cp->Coverage, input ) ) != TT_Err_Ok )
1261       return error;
1262     (void)FILE_Seek( cur_offset );
1263 
1264     if ( ACCESS_Frame( 2L ) )
1265       goto Fail2;
1266 
1267     count = cp->EntryExitCount = GET_UShort();
1268 
1269     FORGET_Frame();
1270 
1271     cp->EntryExitRecord = NULL;
1272 
1273     if ( ALLOC_ARRAY( cp->EntryExitRecord, count, TTO_EntryExitRecord ) )
1274       goto Fail2;
1275 
1276     eer = cp->EntryExitRecord;
1277 
1278     for ( n = 0; n < count; n++ )
1279     {
1280       if ( ACCESS_Frame( 2L ) )
1281         return error;
1282 
1283       new_offset = GET_UShort();
1284 
1285       FORGET_Frame();
1286 
1287       if ( new_offset )
1288       {
1289         new_offset += base_offset;
1290 
1291         cur_offset = FILE_Pos();
1292         if ( FILE_Seek( new_offset ) ||
1293              ( error = Load_Anchor( &eer[n].EntryAnchor,
1294                                     input ) ) != TT_Err_Ok )
1295           goto Fail1;
1296         (void)FILE_Seek( cur_offset );
1297       }
1298       else
1299         eer[n].EntryAnchor.PosFormat   = 0;
1300 
1301       if ( ACCESS_Frame( 2L ) )
1302         return error;
1303 
1304       new_offset = GET_UShort();
1305 
1306       FORGET_Frame();
1307 
1308       if ( new_offset )
1309       {
1310         new_offset += base_offset;
1311 
1312         cur_offset = FILE_Pos();
1313         if ( FILE_Seek( new_offset ) ||
1314              ( error = Load_Anchor( &eer[n].ExitAnchor,
1315                                     input ) ) != TT_Err_Ok )
1316           goto Fail1;
1317         (void)FILE_Seek( cur_offset );
1318       }
1319       else
1320         eer[n].ExitAnchor.PosFormat   = 0;
1321     }
1322 
1323     return TT_Err_Ok;
1324 
1325   Fail1:
1326     for ( n = 0; n < count; n++ )
1327     {
1328       Free_Anchor( &eer[n].EntryAnchor );
1329       Free_Anchor( &eer[n].ExitAnchor );
1330     }
1331 
1332     FREE( eer );
1333 
1334   Fail2:
1335     Free_Coverage( &cp->Coverage );
1336     return error;
1337   }
1338 
1339 
Free_CursivePos(TTO_CursivePos * cp)1340   void  Free_CursivePos( TTO_CursivePos*  cp )
1341   {
1342     UShort                n, count;
1343 
1344     TTO_EntryExitRecord*  eer;
1345 
1346 
1347     if ( cp->EntryExitRecord )
1348     {
1349       count = cp->EntryExitCount;
1350       eer   = cp->EntryExitRecord;
1351 
1352       for ( n = 0; n < count; n++ )
1353       {
1354         Free_Anchor( &eer[n].EntryAnchor );
1355         Free_Anchor( &eer[n].ExitAnchor );
1356       }
1357 
1358       FREE( eer );
1359     }
1360 
1361     Free_Coverage( &cp->Coverage );
1362   }
1363 
1364 
1365   /* LookupType 4 */
1366 
1367   /* BaseArray */
1368 
Load_BaseArray(TTO_BaseArray * ba,UShort num_classes,PFace input)1369   static TT_Error  Load_BaseArray( TTO_BaseArray*  ba,
1370                                    UShort          num_classes,
1371                                    PFace           input )
1372   {
1373     DEFINE_LOAD_LOCALS( input->stream );
1374 
1375     UShort           m, n, count;
1376     ULong            cur_offset, new_offset, base_offset;
1377 
1378     TTO_BaseRecord*  br;
1379     TTO_Anchor*      ban;
1380 
1381 
1382     base_offset = FILE_Pos();
1383 
1384     if ( ACCESS_Frame( 2L ) )
1385       return error;
1386 
1387     count = ba->BaseCount = GET_UShort();
1388 
1389     FORGET_Frame();
1390 
1391     ba->BaseRecord = NULL;
1392 
1393     if ( ALLOC_ARRAY( ba->BaseRecord, count, TTO_BaseRecord ) )
1394       return error;
1395 
1396     br = ba->BaseRecord;
1397 
1398     for ( m = 0; m < count; m++ )
1399     {
1400       br[m].BaseAnchor = NULL;
1401 
1402       if ( ALLOC_ARRAY( br[m].BaseAnchor, num_classes, TTO_Anchor ) )
1403         goto Fail;
1404 
1405       ban = br[m].BaseAnchor;
1406 
1407       for ( n = 0; n < num_classes; n++ )
1408       {
1409         if ( ACCESS_Frame( 2L ) )
1410           goto Fail;
1411 
1412         new_offset = GET_UShort() + base_offset;
1413 
1414         FORGET_Frame();
1415 
1416         cur_offset = FILE_Pos();
1417         if ( FILE_Seek( new_offset ) ||
1418              ( error = Load_Anchor( &ban[n], input ) ) != TT_Err_Ok )
1419           goto Fail;
1420         (void)FILE_Seek( cur_offset );
1421       }
1422     }
1423 
1424     return TT_Err_Ok;
1425 
1426   Fail:
1427     for ( m = 0; m < count; m++ )
1428     {
1429       ban = br[m].BaseAnchor;
1430 
1431       for ( n = 0; n < num_classes; n++ )
1432         Free_Anchor( &ban[n] );
1433 
1434       FREE( ban );
1435     }
1436 
1437     FREE( br );
1438     return error;
1439   }
1440 
1441 
Free_BaseArray(TTO_BaseArray * ba,UShort num_classes)1442   static void  Free_BaseArray( TTO_BaseArray*  ba,
1443                                UShort          num_classes )
1444   {
1445     UShort           m, n, count;
1446 
1447     TTO_BaseRecord*  br;
1448     TTO_Anchor*      ban;
1449 
1450 
1451     if ( ba->BaseRecord )
1452     {
1453       count = ba->BaseCount;
1454       br    = ba->BaseRecord;
1455 
1456       for ( m = 0; m < count; m++ )
1457       {
1458         ban = br[m].BaseAnchor;
1459 
1460         for ( n = 0; n < num_classes; n++ )
1461           Free_Anchor( &ban[n] );
1462 
1463         FREE( ban );
1464       }
1465 
1466       FREE( br );
1467     }
1468   }
1469 
1470 
1471   /* MarkBasePosFormat1 */
1472 
Load_MarkBasePos(TTO_MarkBasePos * mbp,PFace input)1473   TT_Error  Load_MarkBasePos( TTO_MarkBasePos*  mbp,
1474                               PFace             input )
1475   {
1476     DEFINE_LOAD_LOCALS( input->stream );
1477 
1478     ULong  cur_offset, new_offset, base_offset;
1479 
1480 
1481     base_offset = FILE_Pos();
1482 
1483     if ( ACCESS_Frame( 4L ) )
1484       return error;
1485 
1486     mbp->PosFormat = GET_UShort();
1487     new_offset     = GET_UShort() + base_offset;
1488 
1489     FORGET_Frame();
1490 
1491     cur_offset = FILE_Pos();
1492     if ( FILE_Seek( new_offset ) ||
1493          ( error = Load_Coverage( &mbp->MarkCoverage, input ) ) != TT_Err_Ok )
1494       return error;
1495     (void)FILE_Seek( cur_offset );
1496 
1497     if ( ACCESS_Frame( 2L ) )
1498       goto Fail3;
1499 
1500     new_offset = GET_UShort() + base_offset;
1501 
1502     FORGET_Frame();
1503 
1504     cur_offset = FILE_Pos();
1505     if ( FILE_Seek( new_offset ) ||
1506          ( error = Load_Coverage( &mbp->BaseCoverage, input ) ) != TT_Err_Ok )
1507       goto Fail3;
1508     (void)FILE_Seek( cur_offset );
1509 
1510     if ( ACCESS_Frame( 4L ) )
1511       goto Fail2;
1512 
1513     mbp->ClassCount = GET_UShort();
1514     new_offset      = GET_UShort() + base_offset;
1515 
1516     FORGET_Frame();
1517 
1518     cur_offset = FILE_Pos();
1519     if ( FILE_Seek( new_offset ) ||
1520          ( error = Load_MarkArray( &mbp->MarkArray, input ) ) != TT_Err_Ok )
1521       goto Fail2;
1522     (void)FILE_Seek( cur_offset );
1523 
1524     if ( ACCESS_Frame( 2L ) )
1525       goto Fail1;
1526 
1527     new_offset = GET_UShort() + base_offset;
1528 
1529     FORGET_Frame();
1530 
1531     cur_offset = FILE_Pos();
1532     if ( FILE_Seek( new_offset ) ||
1533          ( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount,
1534                                    input ) ) != TT_Err_Ok )
1535       goto Fail1;
1536 
1537     return TT_Err_Ok;
1538 
1539   Fail1:
1540     Free_MarkArray( &mbp->MarkArray );
1541 
1542   Fail2:
1543     Free_Coverage( &mbp->BaseCoverage );
1544 
1545   Fail3:
1546     Free_Coverage( &mbp->MarkCoverage );
1547     return error;
1548   }
1549 
1550 
Free_MarkBasePos(TTO_MarkBasePos * mbp)1551   void  Free_MarkBasePos( TTO_MarkBasePos*  mbp )
1552   {
1553     Free_BaseArray( &mbp->BaseArray, mbp->ClassCount );
1554     Free_MarkArray( &mbp->MarkArray );
1555     Free_Coverage( &mbp->BaseCoverage );
1556     Free_Coverage( &mbp->MarkCoverage );
1557   }
1558 
1559 
1560   /* LookupType 5 */
1561 
1562   /* LigatureAttach */
1563 
Load_LigatureAttach(TTO_LigatureAttach * lat,UShort num_classes,PFace input)1564   static TT_Error  Load_LigatureAttach( TTO_LigatureAttach*  lat,
1565                                         UShort               num_classes,
1566                                         PFace                input )
1567   {
1568     DEFINE_LOAD_LOCALS( input->stream );
1569 
1570     UShort                m, n, count;
1571     ULong                 cur_offset, new_offset, base_offset;
1572 
1573     TTO_ComponentRecord*  cr;
1574     TTO_Anchor*           lan;
1575 
1576 
1577     base_offset = FILE_Pos();
1578 
1579     if ( ACCESS_Frame( 2L ) )
1580       return error;
1581 
1582     count = lat->ComponentCount = GET_UShort();
1583 
1584     FORGET_Frame();
1585 
1586     lat->ComponentRecord = NULL;
1587 
1588     if ( ALLOC_ARRAY( lat->ComponentRecord, count, TTO_ComponentRecord ) )
1589       return error;
1590 
1591     cr = lat->ComponentRecord;
1592 
1593     for ( m = 0; m < count; m++ )
1594     {
1595       cr[m].LigatureAnchor = NULL;
1596 
1597       if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, TTO_Anchor ) )
1598         goto Fail;
1599 
1600       lan = cr[m].LigatureAnchor;
1601 
1602       for ( n = 0; n < num_classes; n++ )
1603       {
1604         if ( ACCESS_Frame( 2L ) )
1605           goto Fail;
1606 
1607         new_offset = GET_UShort();
1608 
1609         FORGET_Frame();
1610 
1611         if ( new_offset )
1612         {
1613           new_offset += base_offset;
1614 
1615           cur_offset = FILE_Pos();
1616           if ( FILE_Seek( new_offset ) ||
1617                ( error = Load_Anchor( &lan[n], input ) ) != TT_Err_Ok )
1618             goto Fail;
1619           (void)FILE_Seek( cur_offset );
1620         }
1621         else
1622           lan[n].PosFormat = 0;
1623       }
1624     }
1625 
1626     return TT_Err_Ok;
1627 
1628   Fail:
1629     for ( m = 0; m < count; m++ )
1630     {
1631       lan = cr[m].LigatureAnchor;
1632 
1633       for ( n = 0; n < num_classes; n++ )
1634         Free_Anchor( &lan[n] );
1635 
1636       FREE( lan );
1637     }
1638 
1639     FREE( cr );
1640     return error;
1641   }
1642 
1643 
Free_LigatureAttach(TTO_LigatureAttach * lat,UShort num_classes)1644   static void  Free_LigatureAttach( TTO_LigatureAttach*  lat,
1645                                     UShort               num_classes )
1646   {
1647     UShort           m, n, count;
1648 
1649     TTO_ComponentRecord*  cr;
1650     TTO_Anchor*           lan;
1651 
1652 
1653     if ( lat->ComponentRecord )
1654     {
1655       count = lat->ComponentCount;
1656       cr    = lat->ComponentRecord;
1657 
1658       for ( m = 0; m < count; m++ )
1659       {
1660         lan = cr[m].LigatureAnchor;
1661 
1662         for ( n = 0; n < num_classes; n++ )
1663           Free_Anchor( &lan[n] );
1664 
1665         FREE( lan );
1666       }
1667 
1668       FREE( cr );
1669     }
1670   }
1671 
1672 
1673   /* LigatureArray */
1674 
Load_LigatureArray(TTO_LigatureArray * la,UShort num_classes,PFace input)1675   static TT_Error  Load_LigatureArray( TTO_LigatureArray*  la,
1676                                        UShort              num_classes,
1677                                        PFace               input )
1678   {
1679     DEFINE_LOAD_LOCALS( input->stream );
1680 
1681     UShort               n, count;
1682     ULong                cur_offset, new_offset, base_offset;
1683 
1684     TTO_LigatureAttach*  lat;
1685 
1686 
1687     base_offset = FILE_Pos();
1688 
1689     if ( ACCESS_Frame( 2L ) )
1690       return error;
1691 
1692     count = la->LigatureCount = GET_UShort();
1693 
1694     FORGET_Frame();
1695 
1696     la->LigatureAttach = NULL;
1697 
1698     if ( ALLOC_ARRAY( la->LigatureAttach, count, TTO_LigatureAttach ) )
1699       return error;
1700 
1701     lat = la->LigatureAttach;
1702 
1703     for ( n = 0; n < count; n++ )
1704     {
1705       if ( ACCESS_Frame( 2L ) )
1706         goto Fail;
1707 
1708       new_offset = GET_UShort() + base_offset;
1709 
1710       FORGET_Frame();
1711 
1712       cur_offset = FILE_Pos();
1713       if ( FILE_Seek( new_offset ) ||
1714            ( error = Load_LigatureAttach( &lat[n], num_classes,
1715                                           input ) ) != TT_Err_Ok )
1716         goto Fail;
1717       (void)FILE_Seek( cur_offset );
1718     }
1719 
1720     return TT_Err_Ok;
1721 
1722   Fail:
1723     for ( n = 0; n < count; n++ )
1724       Free_LigatureAttach( &lat[n], num_classes );
1725 
1726     FREE( lat );
1727     return error;
1728   }
1729 
1730 
Free_LigatureArray(TTO_LigatureArray * la,UShort num_classes)1731   static void  Free_LigatureArray( TTO_LigatureArray*  la,
1732                                    UShort              num_classes )
1733   {
1734     UShort               n, count;
1735 
1736     TTO_LigatureAttach*  lat;
1737 
1738 
1739     if ( la->LigatureAttach )
1740     {
1741       count = la->LigatureCount;
1742       lat   = la->LigatureAttach;
1743 
1744       for ( n = 0; n < count; n++ )
1745         Free_LigatureAttach( &lat[n], num_classes );
1746 
1747       FREE( lat );
1748     }
1749   }
1750 
1751 
1752   /* MarkLigPosFormat1 */
1753 
Load_MarkLigPos(TTO_MarkLigPos * mlp,PFace input)1754   TT_Error  Load_MarkLigPos( TTO_MarkLigPos*  mlp,
1755                              PFace            input )
1756   {
1757     DEFINE_LOAD_LOCALS( input->stream );
1758 
1759     ULong  cur_offset, new_offset, base_offset;
1760 
1761 
1762     base_offset = FILE_Pos();
1763 
1764     if ( ACCESS_Frame( 4L ) )
1765       return error;
1766 
1767     mlp->PosFormat = GET_UShort();
1768     new_offset     = GET_UShort() + base_offset;
1769 
1770     FORGET_Frame();
1771 
1772     cur_offset = FILE_Pos();
1773     if ( FILE_Seek( new_offset ) ||
1774          ( error = Load_Coverage( &mlp->MarkCoverage, input ) ) != TT_Err_Ok )
1775       return error;
1776     (void)FILE_Seek( cur_offset );
1777 
1778     if ( ACCESS_Frame( 2L ) )
1779       goto Fail3;
1780 
1781     new_offset = GET_UShort() + base_offset;
1782 
1783     FORGET_Frame();
1784 
1785     cur_offset = FILE_Pos();
1786     if ( FILE_Seek( new_offset ) ||
1787          ( error = Load_Coverage( &mlp->LigatureCoverage,
1788                                   input ) ) != TT_Err_Ok )
1789       goto Fail3;
1790     (void)FILE_Seek( cur_offset );
1791 
1792     if ( ACCESS_Frame( 4L ) )
1793       goto Fail2;
1794 
1795     mlp->ClassCount = GET_UShort();
1796     new_offset      = GET_UShort() + base_offset;
1797 
1798     FORGET_Frame();
1799 
1800     cur_offset = FILE_Pos();
1801     if ( FILE_Seek( new_offset ) ||
1802          ( error = Load_MarkArray( &mlp->MarkArray, input ) ) != TT_Err_Ok )
1803       goto Fail2;
1804     (void)FILE_Seek( cur_offset );
1805 
1806     if ( ACCESS_Frame( 2L ) )
1807       goto Fail1;
1808 
1809     new_offset = GET_UShort() + base_offset;
1810 
1811     FORGET_Frame();
1812 
1813     cur_offset = FILE_Pos();
1814     if ( FILE_Seek( new_offset ) ||
1815          ( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount,
1816                                        input ) ) != TT_Err_Ok )
1817       goto Fail1;
1818 
1819     return TT_Err_Ok;
1820 
1821   Fail1:
1822     Free_MarkArray( &mlp->MarkArray );
1823 
1824   Fail2:
1825     Free_Coverage( &mlp->LigatureCoverage );
1826 
1827   Fail3:
1828     Free_Coverage( &mlp->MarkCoverage );
1829     return error;
1830   }
1831 
1832 
Free_MarkLigPos(TTO_MarkLigPos * mlp)1833   void  Free_MarkLigPos( TTO_MarkLigPos*  mlp )
1834   {
1835     Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount );
1836     Free_MarkArray( &mlp->MarkArray );
1837     Free_Coverage( &mlp->LigatureCoverage );
1838     Free_Coverage( &mlp->MarkCoverage );
1839   }
1840 
1841 
1842   /* LookupType 6 */
1843 
1844   /* Mark2Array */
1845 
Load_Mark2Array(TTO_Mark2Array * m2a,UShort num_classes,PFace input)1846   static TT_Error  Load_Mark2Array( TTO_Mark2Array*  m2a,
1847                                     UShort           num_classes,
1848                                     PFace            input )
1849   {
1850     DEFINE_LOAD_LOCALS( input->stream );
1851 
1852     UShort            m, n, count;
1853     ULong             cur_offset, new_offset, base_offset;
1854 
1855     TTO_Mark2Record*  m2r;
1856     TTO_Anchor*       m2an;
1857 
1858 
1859     base_offset = FILE_Pos();
1860 
1861     if ( ACCESS_Frame( 2L ) )
1862       return error;
1863 
1864     count = m2a->Mark2Count = GET_UShort();
1865 
1866     FORGET_Frame();
1867 
1868     m2a->Mark2Record = NULL;
1869 
1870     if ( ALLOC_ARRAY( m2a->Mark2Record, count, TTO_Mark2Record ) )
1871       return error;
1872 
1873     m2r = m2a->Mark2Record;
1874 
1875     for ( m = 0; m < count; m++ )
1876     {
1877       m2r[m].Mark2Anchor = NULL;
1878 
1879       if ( ALLOC_ARRAY( m2r[m].Mark2Anchor, num_classes, TTO_Anchor ) )
1880         goto Fail;
1881 
1882       m2an = m2r[m].Mark2Anchor;
1883 
1884       for ( n = 0; n < num_classes; n++ )
1885       {
1886         if ( ACCESS_Frame( 2L ) )
1887           goto Fail;
1888 
1889         new_offset = GET_UShort() + base_offset;
1890 
1891         FORGET_Frame();
1892 
1893         cur_offset = FILE_Pos();
1894         if ( FILE_Seek( new_offset ) ||
1895              ( error = Load_Anchor( &m2an[n], input ) ) != TT_Err_Ok )
1896           goto Fail;
1897         (void)FILE_Seek( cur_offset );
1898       }
1899     }
1900 
1901     return TT_Err_Ok;
1902 
1903   Fail:
1904     for ( m = 0; m < count; m++ )
1905     {
1906       m2an = m2r[m].Mark2Anchor;
1907 
1908       for ( n = 0; n < num_classes; n++ )
1909         Free_Anchor( &m2an[n] );
1910 
1911       FREE( m2an );
1912     }
1913 
1914     FREE( m2r );
1915     return error;
1916   }
1917 
1918 
Free_Mark2Array(TTO_Mark2Array * m2a,UShort num_classes)1919   static void  Free_Mark2Array( TTO_Mark2Array*  m2a,
1920                                 UShort           num_classes )
1921   {
1922     UShort            m, n, count;
1923 
1924     TTO_Mark2Record*  m2r;
1925     TTO_Anchor*       m2an;
1926 
1927 
1928     if ( m2a->Mark2Record )
1929     {
1930       count = m2a->Mark2Count;
1931       m2r   = m2a->Mark2Record;
1932 
1933       for ( m = 0; m < count; m++ )
1934       {
1935         m2an = m2r[m].Mark2Anchor;
1936 
1937         for ( n = 0; n < num_classes; n++ )
1938           Free_Anchor( &m2an[n] );
1939 
1940         FREE( m2an );
1941       }
1942 
1943       FREE( m2r );
1944     }
1945   }
1946 
1947 
1948   /* MarkMarkPosFormat1 */
1949 
Load_MarkMarkPos(TTO_MarkMarkPos * mmp,PFace input)1950   TT_Error  Load_MarkMarkPos( TTO_MarkMarkPos*  mmp,
1951                               PFace             input )
1952   {
1953     DEFINE_LOAD_LOCALS( input->stream );
1954 
1955     ULong  cur_offset, new_offset, base_offset;
1956 
1957 
1958     base_offset = FILE_Pos();
1959 
1960     if ( ACCESS_Frame( 4L ) )
1961       return error;
1962 
1963     mmp->PosFormat = GET_UShort();
1964     new_offset     = GET_UShort() + base_offset;
1965 
1966     FORGET_Frame();
1967 
1968     cur_offset = FILE_Pos();
1969     if ( FILE_Seek( new_offset ) ||
1970          ( error = Load_Coverage( &mmp->Mark1Coverage,
1971                                   input ) ) != TT_Err_Ok )
1972       return error;
1973     (void)FILE_Seek( cur_offset );
1974 
1975     if ( ACCESS_Frame( 2L ) )
1976       goto Fail3;
1977 
1978     new_offset = GET_UShort() + base_offset;
1979 
1980     FORGET_Frame();
1981 
1982     cur_offset = FILE_Pos();
1983     if ( FILE_Seek( new_offset ) ||
1984          ( error = Load_Coverage( &mmp->Mark2Coverage,
1985                                   input ) ) != TT_Err_Ok )
1986       goto Fail3;
1987     (void)FILE_Seek( cur_offset );
1988 
1989     if ( ACCESS_Frame( 4L ) )
1990       goto Fail2;
1991 
1992     mmp->ClassCount = GET_UShort();
1993     new_offset      = GET_UShort() + base_offset;
1994 
1995     FORGET_Frame();
1996 
1997     cur_offset = FILE_Pos();
1998     if ( FILE_Seek( new_offset ) ||
1999          ( error = Load_MarkArray( &mmp->Mark1Array, input ) ) != TT_Err_Ok )
2000       goto Fail2;
2001     (void)FILE_Seek( cur_offset );
2002 
2003     if ( ACCESS_Frame( 2L ) )
2004       goto Fail1;
2005 
2006     new_offset = GET_UShort() + base_offset;
2007 
2008     FORGET_Frame();
2009 
2010     cur_offset = FILE_Pos();
2011     if ( FILE_Seek( new_offset ) ||
2012          ( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount,
2013                                     input ) ) != TT_Err_Ok )
2014       goto Fail1;
2015 
2016     return TT_Err_Ok;
2017 
2018   Fail1:
2019     Free_MarkArray( &mmp->Mark1Array );
2020 
2021   Fail2:
2022     Free_Coverage( &mmp->Mark2Coverage );
2023 
2024   Fail3:
2025     Free_Coverage( &mmp->Mark1Coverage );
2026     return error;
2027   }
2028 
2029 
Free_MarkMarkPos(TTO_MarkMarkPos * mmp)2030   void  Free_MarkMarkPos( TTO_MarkMarkPos*  mmp )
2031   {
2032     Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount );
2033     Free_MarkArray( &mmp->Mark1Array );
2034     Free_Coverage( &mmp->Mark2Coverage );
2035     Free_Coverage( &mmp->Mark1Coverage );
2036   }
2037 
2038 
2039   /* LookupType 7 */
2040 
2041   /* PosRule */
2042 
Load_PosRule(TTO_PosRule * pr,PFace input)2043   static TT_Error  Load_PosRule( TTO_PosRule*  pr,
2044                                  PFace         input )
2045   {
2046     DEFINE_LOAD_LOCALS( input->stream );
2047 
2048     UShort                n, count;
2049     UShort*               i;
2050 
2051     TTO_PosLookupRecord*  plr;
2052 
2053 
2054     if ( ACCESS_Frame( 4L ) )
2055       return error;
2056 
2057     pr->GlyphCount = GET_UShort();
2058     pr->PosCount   = GET_UShort();
2059 
2060     FORGET_Frame();
2061 
2062     pr->Input = NULL;
2063 
2064     count = pr->GlyphCount - 1;         /* only GlyphCount - 1 elements */
2065 
2066     if ( ALLOC_ARRAY( pr->Input, count, UShort ) )
2067       return error;
2068 
2069     i = pr->Input;
2070 
2071     if ( ACCESS_Frame( count * 2L ) )
2072       goto Fail2;
2073 
2074     for ( n = 0; n < count; n++ )
2075       i[n] = GET_UShort();
2076 
2077     FORGET_Frame();
2078 
2079     pr->PosLookupRecord = NULL;
2080 
2081     count = pr->PosCount;
2082 
2083     if ( ALLOC_ARRAY( pr->PosLookupRecord, count, TTO_PosLookupRecord ) )
2084       goto Fail2;
2085 
2086     plr = pr->PosLookupRecord;
2087 
2088     if ( ACCESS_Frame( count * 4L ) )
2089       goto Fail1;
2090 
2091     for ( n = 0; n < count; n++ )
2092     {
2093       plr[n].SequenceIndex   = GET_UShort();
2094       plr[n].LookupListIndex = GET_UShort();
2095     }
2096 
2097     FORGET_Frame();
2098 
2099     return TT_Err_Ok;
2100 
2101   Fail1:
2102     FREE( plr );
2103 
2104   Fail2:
2105     FREE( i );
2106     return error;
2107   }
2108 
2109 
Free_PosRule(TTO_PosRule * pr)2110   static void  Free_PosRule( TTO_PosRule*  pr )
2111   {
2112     FREE( pr->PosLookupRecord );
2113     FREE( pr->Input );
2114   }
2115 
2116 
2117   /* PosRuleSet */
2118 
Load_PosRuleSet(TTO_PosRuleSet * prs,PFace input)2119   static TT_Error  Load_PosRuleSet( TTO_PosRuleSet*  prs,
2120                                     PFace            input )
2121   {
2122     DEFINE_LOAD_LOCALS( input->stream );
2123 
2124     UShort        n, count;
2125     ULong         cur_offset, new_offset, base_offset;
2126 
2127     TTO_PosRule*  pr;
2128 
2129 
2130     base_offset = FILE_Pos();
2131 
2132     if ( ACCESS_Frame( 2L ) )
2133       return error;
2134 
2135     count = prs->PosRuleCount = GET_UShort();
2136 
2137     FORGET_Frame();
2138 
2139     prs->PosRule = NULL;
2140 
2141     if ( ALLOC_ARRAY( prs->PosRule, count, TTO_PosRule ) )
2142       return error;
2143 
2144     pr = prs->PosRule;
2145 
2146     for ( n = 0; n < count; n++ )
2147     {
2148       if ( ACCESS_Frame( 2L ) )
2149         goto Fail;
2150 
2151       new_offset = GET_UShort() + base_offset;
2152 
2153       FORGET_Frame();
2154 
2155       cur_offset = FILE_Pos();
2156       if ( FILE_Seek( new_offset ) ||
2157            ( error = Load_PosRule( &pr[n], input ) ) != TT_Err_Ok )
2158         goto Fail;
2159       (void)FILE_Seek( cur_offset );
2160     }
2161 
2162     return TT_Err_Ok;
2163 
2164   Fail:
2165     for ( n = 0; n < count; n++ )
2166       Free_PosRule( &pr[n] );
2167 
2168     FREE( pr );
2169     return error;
2170   }
2171 
2172 
Free_PosRuleSet(TTO_PosRuleSet * prs)2173   static void  Free_PosRuleSet( TTO_PosRuleSet*  prs )
2174   {
2175     UShort        n, count;
2176 
2177     TTO_PosRule*  pr;
2178 
2179 
2180     if ( prs->PosRule )
2181     {
2182       count = prs->PosRuleCount;
2183       pr    = prs->PosRule;
2184 
2185       for ( n = 0; n < count; n++ )
2186         Free_PosRule( &pr[n] );
2187 
2188       FREE( pr );
2189     }
2190   }
2191 
2192 
2193   /* ContextPosFormat1 */
2194 
Load_ContextPos1(TTO_ContextPosFormat1 * cpf1,PFace input)2195   static TT_Error  Load_ContextPos1( TTO_ContextPosFormat1*  cpf1,
2196                                      PFace                   input )
2197   {
2198     DEFINE_LOAD_LOCALS( input->stream );
2199 
2200     UShort           n, count;
2201     ULong            cur_offset, new_offset, base_offset;
2202 
2203     TTO_PosRuleSet*  prs;
2204 
2205 
2206     base_offset = FILE_Pos() - 2L;
2207 
2208     if ( ACCESS_Frame( 2L ) )
2209       return error;
2210 
2211     new_offset = GET_UShort() + base_offset;
2212 
2213     FORGET_Frame();
2214 
2215     cur_offset = FILE_Pos();
2216     if ( FILE_Seek( new_offset ) ||
2217          ( error = Load_Coverage( &cpf1->Coverage, input ) ) != TT_Err_Ok )
2218       return error;
2219     (void)FILE_Seek( cur_offset );
2220 
2221     if ( ACCESS_Frame( 2L ) )
2222       goto Fail2;
2223 
2224     count = cpf1->PosRuleSetCount = GET_UShort();
2225 
2226     FORGET_Frame();
2227 
2228     cpf1->PosRuleSet = NULL;
2229 
2230     if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, TTO_PosRuleSet ) )
2231       goto Fail2;
2232 
2233     prs = cpf1->PosRuleSet;
2234 
2235     for ( n = 0; n < count; n++ )
2236     {
2237       if ( ACCESS_Frame( 2L ) )
2238         goto Fail1;
2239 
2240       new_offset = GET_UShort() + base_offset;
2241 
2242       FORGET_Frame();
2243 
2244       cur_offset = FILE_Pos();
2245       if ( FILE_Seek( new_offset ) ||
2246            ( error = Load_PosRuleSet( &prs[n], input ) ) != TT_Err_Ok )
2247         goto Fail1;
2248       (void)FILE_Seek( cur_offset );
2249     }
2250 
2251     return TT_Err_Ok;
2252 
2253   Fail1:
2254     for ( n = 0; n < count; n++ )
2255       Free_PosRuleSet( &prs[n] );
2256 
2257     FREE( prs );
2258 
2259   Fail2:
2260     Free_Coverage( &cpf1->Coverage );
2261     return error;
2262   }
2263 
2264 
Free_Context1(TTO_ContextPosFormat1 * cpf1)2265   static void  Free_Context1( TTO_ContextPosFormat1*  cpf1 )
2266   {
2267     UShort           n, count;
2268 
2269     TTO_PosRuleSet*  prs;
2270 
2271 
2272     if ( cpf1->PosRuleSet )
2273     {
2274       count = cpf1->PosRuleSetCount;
2275       prs   = cpf1->PosRuleSet;
2276 
2277       for ( n = 0; n < count; n++ )
2278         Free_PosRuleSet( &prs[n] );
2279 
2280       FREE( prs );
2281     }
2282 
2283     Free_Coverage( &cpf1->Coverage );
2284   }
2285 
2286 
2287   /* PosClassRule */
2288 
Load_PosClassRule(TTO_ContextPosFormat2 * cpf2,TTO_PosClassRule * pcr,PFace input)2289   static TT_Error  Load_PosClassRule( TTO_ContextPosFormat2*  cpf2,
2290                                       TTO_PosClassRule*       pcr,
2291                                       PFace                   input )
2292   {
2293     DEFINE_LOAD_LOCALS( input->stream );
2294 
2295     UShort                n, count;
2296 
2297     UShort*               c;
2298     TTO_PosLookupRecord*  plr;
2299     Bool*                 d;
2300 
2301 
2302     if ( ACCESS_Frame( 4L ) )
2303       return error;
2304 
2305     pcr->GlyphCount = GET_UShort();
2306     pcr->PosCount   = GET_UShort();
2307 
2308     FORGET_Frame();
2309 
2310     if ( pcr->GlyphCount > cpf2->MaxContextLength )
2311       cpf2->MaxContextLength = pcr->GlyphCount;
2312 
2313     pcr->Class = NULL;
2314 
2315     count = pcr->GlyphCount - 1;        /* only GlyphCount - 1 elements */
2316 
2317     if ( ALLOC_ARRAY( pcr->Class, count, UShort ) )
2318       return error;
2319 
2320     c = pcr->Class;
2321     d = cpf2->ClassDef.Defined;
2322 
2323     if ( ACCESS_Frame( count * 2L ) )
2324       goto Fail2;
2325 
2326     for ( n = 0; n < count; n++ )
2327     {
2328       c[n] = GET_UShort();
2329 
2330       /* We check whether the specific class is used at all.  If not,
2331          class 0 is used instead.                                     */
2332 
2333       if ( !d[c[n]] )
2334         c[n] = 0;
2335     }
2336 
2337     FORGET_Frame();
2338 
2339     pcr->PosLookupRecord = NULL;
2340 
2341     count = pcr->PosCount;
2342 
2343     if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, TTO_PosLookupRecord ) )
2344       goto Fail2;
2345 
2346     plr = pcr->PosLookupRecord;
2347 
2348     if ( ACCESS_Frame( count * 4L ) )
2349       goto Fail1;
2350 
2351     for ( n = 0; n < count; n++ )
2352     {
2353       plr[n].SequenceIndex   = GET_UShort();
2354       plr[n].LookupListIndex = GET_UShort();
2355     }
2356 
2357     FORGET_Frame();
2358 
2359     return TT_Err_Ok;
2360 
2361   Fail1:
2362     FREE( plr );
2363 
2364   Fail2:
2365     FREE( c );
2366     return error;
2367   }
2368 
2369 
Free_PosClassRule(TTO_PosClassRule * pcr)2370   static void  Free_PosClassRule( TTO_PosClassRule*  pcr )
2371   {
2372     FREE( pcr->PosLookupRecord );
2373     FREE( pcr->Class );
2374   }
2375 
2376 
2377   /* PosClassSet */
2378 
Load_PosClassSet(TTO_ContextPosFormat2 * cpf2,TTO_PosClassSet * pcs,PFace input)2379   static TT_Error  Load_PosClassSet( TTO_ContextPosFormat2*  cpf2,
2380                                      TTO_PosClassSet*        pcs,
2381                                      PFace                   input )
2382   {
2383     DEFINE_LOAD_LOCALS( input->stream );
2384 
2385     UShort             n, count;
2386     ULong              cur_offset, new_offset, base_offset;
2387 
2388     TTO_PosClassRule*  pcr;
2389 
2390 
2391     base_offset = FILE_Pos();
2392 
2393     if ( ACCESS_Frame( 2L ) )
2394       return error;
2395 
2396     count = pcs->PosClassRuleCount = GET_UShort();
2397 
2398     FORGET_Frame();
2399 
2400     pcs->PosClassRule = NULL;
2401 
2402     if ( ALLOC_ARRAY( pcs->PosClassRule, count, TTO_PosClassRule ) )
2403       return error;
2404 
2405     pcr = pcs->PosClassRule;
2406 
2407     for ( n = 0; n < count; n++ )
2408     {
2409       if ( ACCESS_Frame( 2L ) )
2410         goto Fail;
2411 
2412       new_offset = GET_UShort() + base_offset;
2413 
2414       FORGET_Frame();
2415 
2416       cur_offset = FILE_Pos();
2417       if ( FILE_Seek( new_offset ) ||
2418            ( error = Load_PosClassRule( cpf2, &pcr[n],
2419                                         input ) ) != TT_Err_Ok )
2420         goto Fail;
2421       (void)FILE_Seek( cur_offset );
2422     }
2423 
2424     return TT_Err_Ok;
2425 
2426   Fail:
2427     for ( n = 0; n < count; n++ )
2428       Free_PosClassRule( &pcr[n] );
2429 
2430     FREE( pcr );
2431     return error;
2432   }
2433 
2434 
Free_PosClassSet(TTO_PosClassSet * pcs)2435   static void  Free_PosClassSet( TTO_PosClassSet*  pcs )
2436   {
2437     UShort             n, count;
2438 
2439     TTO_PosClassRule*  pcr;
2440 
2441 
2442     if ( pcs->PosClassRule )
2443     {
2444       count = pcs->PosClassRuleCount;
2445       pcr   = pcs->PosClassRule;
2446 
2447       for ( n = 0; n < count; n++ )
2448         Free_PosClassRule( &pcr[n] );
2449 
2450       FREE( pcr );
2451     }
2452   }
2453 
2454 
2455   /* ContextPosFormat2 */
2456 
Load_ContextPos2(TTO_ContextPosFormat2 * cpf2,PFace input)2457   static TT_Error  Load_ContextPos2( TTO_ContextPosFormat2*  cpf2,
2458                                      PFace                   input )
2459   {
2460     DEFINE_LOAD_LOCALS( input->stream );
2461 
2462     UShort            n, count;
2463     ULong             cur_offset, new_offset, base_offset;
2464 
2465     TTO_PosClassSet*  pcs;
2466 
2467 
2468     base_offset = FILE_Pos() - 2;
2469 
2470     if ( ACCESS_Frame( 2L ) )
2471       return error;
2472 
2473     new_offset = GET_UShort() + base_offset;
2474 
2475     FORGET_Frame();
2476 
2477     cur_offset = FILE_Pos();
2478     if ( FILE_Seek( new_offset ) ||
2479          ( error = Load_Coverage( &cpf2->Coverage, input ) ) != TT_Err_Ok )
2480       return error;
2481     (void)FILE_Seek( cur_offset );
2482 
2483     if ( ACCESS_Frame( 4L ) )
2484       goto Fail3;
2485 
2486     new_offset = GET_UShort() + base_offset;
2487 
2488     /* `PosClassSetCount' is the upper limit for class values, thus we
2489        read it now to make an additional safety check.                 */
2490 
2491     count = cpf2->PosClassSetCount = GET_UShort();
2492 
2493     FORGET_Frame();
2494 
2495     cur_offset = FILE_Pos();
2496     if ( FILE_Seek( new_offset ) ||
2497          ( error = Load_ClassDefinition( &cpf2->ClassDef, count,
2498                                          input ) ) != TT_Err_Ok )
2499       goto Fail3;
2500     (void)FILE_Seek( cur_offset );
2501 
2502     cpf2->PosClassSet      = NULL;
2503     cpf2->MaxContextLength = 0;
2504 
2505     if ( ALLOC_ARRAY( cpf2->PosClassSet, count, TTO_PosClassSet ) )
2506       goto Fail2;
2507 
2508     pcs = cpf2->PosClassSet;
2509 
2510     for ( n = 0; n < count; n++ )
2511     {
2512       if ( ACCESS_Frame( 2L ) )
2513         goto Fail1;
2514 
2515       new_offset = GET_UShort() + base_offset;
2516 
2517       FORGET_Frame();
2518 
2519       if ( new_offset != base_offset )      /* not a NULL offset */
2520       {
2521         cur_offset = FILE_Pos();
2522         if ( FILE_Seek( new_offset ) ||
2523              ( error = Load_PosClassSet( cpf2, &pcs[n],
2524                                          input ) ) != TT_Err_Ok )
2525           goto Fail1;
2526         (void)FILE_Seek( cur_offset );
2527       }
2528       else
2529       {
2530         /* we create a PosClassSet table with no entries */
2531 
2532         cpf2->PosClassSet[n].PosClassRuleCount = 0;
2533         cpf2->PosClassSet[n].PosClassRule      = NULL;
2534       }
2535     }
2536 
2537     return TT_Err_Ok;
2538 
2539   Fail1:
2540     for ( n = 0; n < count; n++ )
2541       Free_PosClassSet( &pcs[n] );
2542 
2543     FREE( pcs );
2544 
2545   Fail2:
2546     Free_ClassDefinition( &cpf2->ClassDef );
2547 
2548   Fail3:
2549     Free_Coverage( &cpf2->Coverage );
2550     return error;
2551   }
2552 
2553 
Free_Context2(TTO_ContextPosFormat2 * cpf2)2554   static void  Free_Context2( TTO_ContextPosFormat2*  cpf2 )
2555   {
2556     UShort            n, count;
2557 
2558     TTO_PosClassSet*  pcs;
2559 
2560 
2561     if ( cpf2->PosClassSet )
2562     {
2563       count = cpf2->PosClassSetCount;
2564       pcs   = cpf2->PosClassSet;
2565 
2566       for ( n = 0; n < count; n++ )
2567         Free_PosClassSet( &pcs[n] );
2568 
2569       FREE( pcs );
2570     }
2571 
2572     Free_ClassDefinition( &cpf2->ClassDef );
2573     Free_Coverage( &cpf2->Coverage );
2574   }
2575 
2576 
2577   /* ContextPosFormat3 */
2578 
Load_ContextPos3(TTO_ContextPosFormat3 * cpf3,PFace input)2579   static TT_Error  Load_ContextPos3( TTO_ContextPosFormat3*  cpf3,
2580                                      PFace                   input )
2581   {
2582     DEFINE_LOAD_LOCALS( input->stream );
2583 
2584     UShort                n, count;
2585     ULong                 cur_offset, new_offset, base_offset;
2586 
2587     TTO_Coverage*         c;
2588     TTO_PosLookupRecord*  plr;
2589 
2590 
2591     base_offset = FILE_Pos() - 2L;
2592 
2593     if ( ACCESS_Frame( 4L ) )
2594       return error;
2595 
2596     cpf3->GlyphCount = GET_UShort();
2597     cpf3->PosCount   = GET_UShort();
2598 
2599     FORGET_Frame();
2600 
2601     cpf3->Coverage = NULL;
2602 
2603     count = cpf3->GlyphCount;
2604 
2605     if ( ALLOC_ARRAY( cpf3->Coverage, count, TTO_Coverage ) )
2606       return error;
2607 
2608     c = cpf3->Coverage;
2609 
2610     for ( n = 0; n < count; n++ )
2611     {
2612       if ( ACCESS_Frame( 2L ) )
2613         goto Fail2;
2614 
2615       new_offset = GET_UShort() + base_offset;
2616 
2617       FORGET_Frame();
2618 
2619       cur_offset = FILE_Pos();
2620       if ( FILE_Seek( new_offset ) ||
2621            ( error = Load_Coverage( &c[n], input ) ) != TT_Err_Ok )
2622         goto Fail2;
2623       (void)FILE_Seek( cur_offset );
2624     }
2625 
2626     cpf3->PosLookupRecord = NULL;
2627 
2628     count = cpf3->PosCount;
2629 
2630     if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, TTO_PosLookupRecord ) )
2631       goto Fail2;
2632 
2633     plr = cpf3->PosLookupRecord;
2634 
2635     if ( ACCESS_Frame( count * 4L ) )
2636       goto Fail1;
2637 
2638     for ( n = 0; n < count; n++ )
2639     {
2640       plr[n].SequenceIndex   = GET_UShort();
2641       plr[n].LookupListIndex = GET_UShort();
2642     }
2643 
2644     FORGET_Frame();
2645 
2646     return TT_Err_Ok;
2647 
2648   Fail1:
2649     FREE( plr );
2650 
2651   Fail2:
2652     for ( n = 0; n < count; n++ )
2653       Free_Coverage( &c[n] );
2654 
2655     FREE( c );
2656     return error;
2657   }
2658 
2659 
Free_Context3(TTO_ContextPosFormat3 * cpf3)2660   static void  Free_Context3( TTO_ContextPosFormat3*  cpf3 )
2661   {
2662     UShort         n, count;
2663 
2664     TTO_Coverage*  c;
2665 
2666 
2667     FREE( cpf3->PosLookupRecord );
2668 
2669     if ( cpf3->Coverage )
2670     {
2671       count = cpf3->GlyphCount;
2672       c     = cpf3->Coverage;
2673 
2674       for ( n = 0; n < count; n++ )
2675         Free_Coverage( &c[n] );
2676 
2677       FREE( c );
2678     }
2679   }
2680 
2681 
2682   /* ContextPos */
2683 
Load_ContextPos(TTO_ContextPos * cp,PFace input)2684   TT_Error  Load_ContextPos( TTO_ContextPos*  cp,
2685                              PFace            input )
2686   {
2687     DEFINE_LOAD_LOCALS( input->stream );
2688 
2689 
2690     if ( ACCESS_Frame( 2L ) )
2691       return error;
2692 
2693     cp->PosFormat = GET_UShort();
2694 
2695     FORGET_Frame();
2696 
2697     switch ( cp->PosFormat )
2698     {
2699     case 1:
2700       return Load_ContextPos1( &cp->cpf.cpf1, input );
2701 
2702     case 2:
2703       return Load_ContextPos2( &cp->cpf.cpf2, input );
2704 
2705     case 3:
2706       return Load_ContextPos3( &cp->cpf.cpf3, input );
2707 
2708     default:
2709       return TTO_Err_Invalid_GPOS_SubTable_Format;
2710     }
2711 
2712     return TT_Err_Ok;               /* never reached */
2713   }
2714 
2715 
Free_ContextPos(TTO_ContextPos * cp)2716   void  Free_ContextPos( TTO_ContextPos*  cp )
2717   {
2718     switch ( cp->PosFormat )
2719     {
2720     case 1:
2721       Free_Context1( &cp->cpf.cpf1 );
2722       break;
2723 
2724     case 2:
2725       Free_Context2( &cp->cpf.cpf2 );
2726       break;
2727 
2728     case 3:
2729       Free_Context3( &cp->cpf.cpf3 );
2730       break;
2731     }
2732   }
2733 
2734 
2735   /* LookupType 8 */
2736 
2737   /* ChainPosRule */
2738 
Load_ChainPosRule(TTO_ChainPosRule * cpr,PFace input)2739   static TT_Error  Load_ChainPosRule( TTO_ChainPosRule*  cpr,
2740                                       PFace              input )
2741   {
2742     DEFINE_LOAD_LOCALS( input->stream );
2743 
2744     UShort                n, count;
2745     UShort*               b;
2746     UShort*               i;
2747     UShort*               l;
2748 
2749     TTO_PosLookupRecord*  plr;
2750 
2751 
2752     if ( ACCESS_Frame( 2L ) )
2753       return error;
2754 
2755     cpr->BacktrackGlyphCount = GET_UShort();
2756 
2757     FORGET_Frame();
2758 
2759     cpr->Backtrack = NULL;
2760 
2761     count = cpr->BacktrackGlyphCount;
2762 
2763     if ( ALLOC_ARRAY( cpr->Backtrack, count, UShort ) )
2764       return error;
2765 
2766     b = cpr->Backtrack;
2767 
2768     if ( ACCESS_Frame( count * 2L ) )
2769       goto Fail4;
2770 
2771     for ( n = 0; n < count; n++ )
2772       b[n] = GET_UShort();
2773 
2774     FORGET_Frame();
2775 
2776     if ( ACCESS_Frame( 2L ) )
2777       goto Fail4;
2778 
2779     cpr->InputGlyphCount = GET_UShort();
2780 
2781     FORGET_Frame();
2782 
2783     cpr->Input = NULL;
2784 
2785     count = cpr->InputGlyphCount - 1;  /* only InputGlyphCount - 1 elements */
2786 
2787     if ( ALLOC_ARRAY( cpr->Input, count, UShort ) )
2788       goto Fail4;
2789 
2790     i = cpr->Input;
2791 
2792     if ( ACCESS_Frame( count * 2L ) )
2793       goto Fail3;
2794 
2795     for ( n = 0; n < count; n++ )
2796       i[n] = GET_UShort();
2797 
2798     FORGET_Frame();
2799 
2800     if ( ACCESS_Frame( 2L ) )
2801       goto Fail3;
2802 
2803     cpr->LookaheadGlyphCount = GET_UShort();
2804 
2805     FORGET_Frame();
2806 
2807     cpr->Lookahead = NULL;
2808 
2809     count = cpr->LookaheadGlyphCount;
2810 
2811     if ( ALLOC_ARRAY( cpr->Lookahead, count, UShort ) )
2812       goto Fail3;
2813 
2814     l = cpr->Lookahead;
2815 
2816     if ( ACCESS_Frame( count * 2L ) )
2817       goto Fail2;
2818 
2819     for ( n = 0; n < count; n++ )
2820       l[n] = GET_UShort();
2821 
2822     FORGET_Frame();
2823 
2824     if ( ACCESS_Frame( 2L ) )
2825       goto Fail2;
2826 
2827     cpr->PosCount = GET_UShort();
2828 
2829     FORGET_Frame();
2830 
2831     cpr->PosLookupRecord = NULL;
2832 
2833     count = cpr->PosCount;
2834 
2835     if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, TTO_PosLookupRecord ) )
2836       goto Fail2;
2837 
2838     plr = cpr->PosLookupRecord;
2839 
2840     if ( ACCESS_Frame( count * 4L ) )
2841       goto Fail1;
2842 
2843     for ( n = 0; n < count; n++ )
2844     {
2845       plr[n].SequenceIndex   = GET_UShort();
2846       plr[n].LookupListIndex = GET_UShort();
2847     }
2848 
2849     FORGET_Frame();
2850 
2851     return TT_Err_Ok;
2852 
2853   Fail1:
2854     FREE( plr );
2855 
2856   Fail2:
2857     FREE( l );
2858 
2859   Fail3:
2860     FREE( i );
2861 
2862   Fail4:
2863     FREE( b );
2864     return error;
2865   }
2866 
2867 
Free_ChainPosRule(TTO_ChainPosRule * cpr)2868   static void  Free_ChainPosRule( TTO_ChainPosRule*  cpr )
2869   {
2870     FREE( cpr->PosLookupRecord );
2871     FREE( cpr->Lookahead );
2872     FREE( cpr->Input );
2873     FREE( cpr->Backtrack );
2874   }
2875 
2876 
2877   /* ChainPosRuleSet */
2878 
Load_ChainPosRuleSet(TTO_ChainPosRuleSet * cprs,PFace input)2879   static TT_Error  Load_ChainPosRuleSet( TTO_ChainPosRuleSet*  cprs,
2880                                          PFace                 input )
2881   {
2882     DEFINE_LOAD_LOCALS( input->stream );
2883 
2884     UShort             n, count;
2885     ULong              cur_offset, new_offset, base_offset;
2886 
2887     TTO_ChainPosRule*  cpr;
2888 
2889 
2890     base_offset = FILE_Pos();
2891 
2892     if ( ACCESS_Frame( 2L ) )
2893       return error;
2894 
2895     count = cprs->ChainPosRuleCount = GET_UShort();
2896 
2897     FORGET_Frame();
2898 
2899     cprs->ChainPosRule = NULL;
2900 
2901     if ( ALLOC_ARRAY( cprs->ChainPosRule, count, TTO_ChainPosRule ) )
2902       return error;
2903 
2904     cpr = cprs->ChainPosRule;
2905 
2906     for ( n = 0; n < count; n++ )
2907     {
2908       if ( ACCESS_Frame( 2L ) )
2909         goto Fail;
2910 
2911       new_offset = GET_UShort() + base_offset;
2912 
2913       FORGET_Frame();
2914 
2915       cur_offset = FILE_Pos();
2916       if ( FILE_Seek( new_offset ) ||
2917            ( error = Load_ChainPosRule( &cpr[n], input ) ) != TT_Err_Ok )
2918         goto Fail;
2919       (void)FILE_Seek( cur_offset );
2920     }
2921 
2922     return TT_Err_Ok;
2923 
2924   Fail:
2925     for ( n = 0; n < count; n++ )
2926       Free_ChainPosRule( &cpr[n] );
2927 
2928     FREE( cpr );
2929     return error;
2930   }
2931 
2932 
Free_ChainPosRuleSet(TTO_ChainPosRuleSet * cprs)2933   static void  Free_ChainPosRuleSet( TTO_ChainPosRuleSet*  cprs )
2934   {
2935     UShort             n, count;
2936 
2937     TTO_ChainPosRule*  cpr;
2938 
2939 
2940     if ( cprs->ChainPosRule )
2941     {
2942       count = cprs->ChainPosRuleCount;
2943       cpr   = cprs->ChainPosRule;
2944 
2945       for ( n = 0; n < count; n++ )
2946         Free_ChainPosRule( &cpr[n] );
2947 
2948       FREE( cpr );
2949     }
2950   }
2951 
2952 
2953   /* ChainContextPosFormat1 */
2954 
Load_ChainContextPos1(TTO_ChainContextPosFormat1 * ccpf1,PFace input)2955   static TT_Error  Load_ChainContextPos1( TTO_ChainContextPosFormat1*  ccpf1,
2956                                           PFace                        input )
2957   {
2958     DEFINE_LOAD_LOCALS( input->stream );
2959 
2960     UShort                n, count;
2961     ULong                 cur_offset, new_offset, base_offset;
2962 
2963     TTO_ChainPosRuleSet*  cprs;
2964 
2965 
2966     base_offset = FILE_Pos() - 2L;
2967 
2968     if ( ACCESS_Frame( 2L ) )
2969       return error;
2970 
2971     new_offset = GET_UShort() + base_offset;
2972 
2973     FORGET_Frame();
2974 
2975     cur_offset = FILE_Pos();
2976     if ( FILE_Seek( new_offset ) ||
2977          ( error = Load_Coverage( &ccpf1->Coverage, input ) ) != TT_Err_Ok )
2978       return error;
2979     (void)FILE_Seek( cur_offset );
2980 
2981     if ( ACCESS_Frame( 2L ) )
2982       goto Fail2;
2983 
2984     count = ccpf1->ChainPosRuleSetCount = GET_UShort();
2985 
2986     FORGET_Frame();
2987 
2988     ccpf1->ChainPosRuleSet = NULL;
2989 
2990     if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, TTO_ChainPosRuleSet ) )
2991       goto Fail2;
2992 
2993     cprs = ccpf1->ChainPosRuleSet;
2994 
2995     for ( n = 0; n < count; n++ )
2996     {
2997       if ( ACCESS_Frame( 2L ) )
2998         goto Fail1;
2999 
3000       new_offset = GET_UShort() + base_offset;
3001 
3002       FORGET_Frame();
3003 
3004       cur_offset = FILE_Pos();
3005       if ( FILE_Seek( new_offset ) ||
3006            ( error = Load_ChainPosRuleSet( &cprs[n], input ) ) != TT_Err_Ok )
3007         goto Fail1;
3008       (void)FILE_Seek( cur_offset );
3009     }
3010 
3011     return TT_Err_Ok;
3012 
3013   Fail1:
3014     for ( n = 0; n < count; n++ )
3015       Free_ChainPosRuleSet( &cprs[n] );
3016 
3017     FREE( cprs );
3018 
3019   Fail2:
3020     Free_Coverage( &ccpf1->Coverage );
3021     return error;
3022   }
3023 
3024 
Free_ChainContext1(TTO_ChainContextPosFormat1 * ccpf1)3025   static void  Free_ChainContext1( TTO_ChainContextPosFormat1*  ccpf1 )
3026   {
3027     UShort                n, count;
3028 
3029     TTO_ChainPosRuleSet*  cprs;
3030 
3031 
3032     if ( ccpf1->ChainPosRuleSet )
3033     {
3034       count = ccpf1->ChainPosRuleSetCount;
3035       cprs  = ccpf1->ChainPosRuleSet;
3036 
3037       for ( n = 0; n < count; n++ )
3038         Free_ChainPosRuleSet( &cprs[n] );
3039 
3040       FREE( cprs );
3041     }
3042 
3043     Free_Coverage( &ccpf1->Coverage );
3044   }
3045 
3046 
3047   /* ChainPosClassRule */
3048 
Load_ChainPosClassRule(TTO_ChainContextPosFormat2 * ccpf2,TTO_ChainPosClassRule * cpcr,PFace input)3049   static TT_Error  Load_ChainPosClassRule(
3050                      TTO_ChainContextPosFormat2*  ccpf2,
3051                      TTO_ChainPosClassRule*       cpcr,
3052                      PFace                        input )
3053   {
3054     DEFINE_LOAD_LOCALS( input->stream );
3055 
3056     UShort                n, count;
3057 
3058     UShort*               b;
3059     UShort*               i;
3060     UShort*               l;
3061     TTO_PosLookupRecord*  plr;
3062     Bool*                 d;
3063 
3064 
3065     if ( ACCESS_Frame( 2L ) )
3066       return error;
3067 
3068     cpcr->BacktrackGlyphCount = GET_UShort();
3069 
3070     FORGET_Frame();
3071 
3072     if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength )
3073       ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount;
3074 
3075     cpcr->Backtrack = NULL;
3076 
3077     count = cpcr->BacktrackGlyphCount;
3078 
3079     if ( ALLOC_ARRAY( cpcr->Backtrack, count, UShort ) )
3080       return error;
3081 
3082     b = cpcr->Backtrack;
3083     d = ccpf2->BacktrackClassDef.Defined;
3084 
3085     if ( ACCESS_Frame( count * 2L ) )
3086       goto Fail4;
3087 
3088     for ( n = 0; n < count; n++ )
3089     {
3090       b[n] = GET_UShort();
3091 
3092       /* We check whether the specific class is used at all.  If not,
3093          class 0 is used instead.                                     */
3094 
3095       if ( !d[b[n]] )
3096         b[n] = 0;
3097     }
3098 
3099     FORGET_Frame();
3100 
3101     if ( ACCESS_Frame( 2L ) )
3102       goto Fail4;
3103 
3104     cpcr->InputGlyphCount = GET_UShort();
3105 
3106     if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength )
3107       ccpf2->MaxInputLength = cpcr->InputGlyphCount;
3108 
3109     FORGET_Frame();
3110 
3111     cpcr->Input = NULL;
3112 
3113     count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
3114 
3115     if ( ALLOC_ARRAY( cpcr->Input, count, UShort ) )
3116       goto Fail4;
3117 
3118     i = cpcr->Input;
3119     d = ccpf2->InputClassDef.Defined;
3120 
3121     if ( ACCESS_Frame( count * 2L ) )
3122       goto Fail3;
3123 
3124     for ( n = 0; n < count; n++ )
3125     {
3126       i[n] = GET_UShort();
3127 
3128       if ( !d[i[n]] )
3129         i[n] = 0;
3130     }
3131 
3132     FORGET_Frame();
3133 
3134     if ( ACCESS_Frame( 2L ) )
3135       goto Fail3;
3136 
3137     cpcr->LookaheadGlyphCount = GET_UShort();
3138 
3139     FORGET_Frame();
3140 
3141     if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength )
3142       ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount;
3143 
3144     cpcr->Lookahead = NULL;
3145 
3146     count = cpcr->LookaheadGlyphCount;
3147 
3148     if ( ALLOC_ARRAY( cpcr->Lookahead, count, UShort ) )
3149       goto Fail3;
3150 
3151     l = cpcr->Lookahead;
3152     d = ccpf2->LookaheadClassDef.Defined;
3153 
3154     if ( ACCESS_Frame( count * 2L ) )
3155       goto Fail2;
3156 
3157     for ( n = 0; n < count; n++ )
3158     {
3159       l[n] = GET_UShort();
3160 
3161       if ( !d[l[n]] )
3162         l[n] = 0;
3163     }
3164 
3165     FORGET_Frame();
3166 
3167     if ( ACCESS_Frame( 2L ) )
3168       goto Fail2;
3169 
3170     cpcr->PosCount = GET_UShort();
3171 
3172     FORGET_Frame();
3173 
3174     cpcr->PosLookupRecord = NULL;
3175 
3176     count = cpcr->PosCount;
3177 
3178     if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, TTO_PosLookupRecord ) )
3179       goto Fail2;
3180 
3181     plr = cpcr->PosLookupRecord;
3182 
3183     if ( ACCESS_Frame( count * 4L ) )
3184       goto Fail1;
3185 
3186     for ( n = 0; n < count; n++ )
3187     {
3188       plr[n].SequenceIndex   = GET_UShort();
3189       plr[n].LookupListIndex = GET_UShort();
3190     }
3191 
3192     FORGET_Frame();
3193 
3194     return TT_Err_Ok;
3195 
3196   Fail1:
3197     FREE( plr );
3198 
3199   Fail2:
3200     FREE( l );
3201 
3202   Fail3:
3203     FREE( i );
3204 
3205   Fail4:
3206     FREE( b );
3207     return error;
3208   }
3209 
3210 
Free_ChainPosClassRule(TTO_ChainPosClassRule * cpcr)3211   static void  Free_ChainPosClassRule( TTO_ChainPosClassRule*  cpcr )
3212   {
3213     FREE( cpcr->PosLookupRecord );
3214     FREE( cpcr->Lookahead );
3215     FREE( cpcr->Input );
3216     FREE( cpcr->Backtrack );
3217   }
3218 
3219 
3220   /* PosClassSet */
3221 
Load_ChainPosClassSet(TTO_ChainContextPosFormat2 * ccpf2,TTO_ChainPosClassSet * cpcs,PFace input)3222   static TT_Error  Load_ChainPosClassSet(
3223                      TTO_ChainContextPosFormat2*  ccpf2,
3224                      TTO_ChainPosClassSet*        cpcs,
3225                      PFace                        input )
3226   {
3227     DEFINE_LOAD_LOCALS( input->stream );
3228 
3229     UShort                  n, count;
3230     ULong                   cur_offset, new_offset, base_offset;
3231 
3232     TTO_ChainPosClassRule*  cpcr;
3233 
3234 
3235     base_offset = FILE_Pos();
3236 
3237     if ( ACCESS_Frame( 2L ) )
3238       return error;
3239 
3240     count = cpcs->ChainPosClassRuleCount = GET_UShort();
3241 
3242     FORGET_Frame();
3243 
3244     cpcs->ChainPosClassRule = NULL;
3245 
3246     if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count,
3247                       TTO_ChainPosClassRule ) )
3248       return error;
3249 
3250     cpcr = cpcs->ChainPosClassRule;
3251 
3252     for ( n = 0; n < count; n++ )
3253     {
3254       if ( ACCESS_Frame( 2L ) )
3255         goto Fail;
3256 
3257       new_offset = GET_UShort() + base_offset;
3258 
3259       FORGET_Frame();
3260 
3261       cur_offset = FILE_Pos();
3262       if ( FILE_Seek( new_offset ) ||
3263            ( error = Load_ChainPosClassRule( ccpf2, &cpcr[n],
3264                                              input ) ) != TT_Err_Ok )
3265         goto Fail;
3266       (void)FILE_Seek( cur_offset );
3267     }
3268 
3269     return TT_Err_Ok;
3270 
3271   Fail:
3272     for ( n = 0; n < count; n++ )
3273       Free_ChainPosClassRule( &cpcr[n] );
3274 
3275     FREE( cpcr );
3276     return error;
3277   }
3278 
3279 
Free_ChainPosClassSet(TTO_ChainPosClassSet * cpcs)3280   static void  Free_ChainPosClassSet( TTO_ChainPosClassSet*  cpcs )
3281   {
3282     UShort                  n, count;
3283 
3284     TTO_ChainPosClassRule*  cpcr;
3285 
3286 
3287     if ( cpcs->ChainPosClassRule )
3288     {
3289       count = cpcs->ChainPosClassRuleCount;
3290       cpcr  = cpcs->ChainPosClassRule;
3291 
3292       for ( n = 0; n < count; n++ )
3293         Free_ChainPosClassRule( &cpcr[n] );
3294 
3295       FREE( cpcr );
3296     }
3297   }
3298 
3299 
3300   /* ChainContextPosFormat2 */
3301 
Load_ChainContextPos2(TTO_ChainContextPosFormat2 * ccpf2,PFace input)3302   static TT_Error  Load_ChainContextPos2( TTO_ChainContextPosFormat2*  ccpf2,
3303                                           PFace                        input )
3304   {
3305     DEFINE_LOAD_LOCALS( input->stream );
3306 
3307     UShort                 n, count;
3308     ULong                  cur_offset, new_offset, base_offset;
3309     ULong                  backtrack_offset, input_offset, lookahead_offset;
3310 
3311     TTO_ChainPosClassSet*  cpcs;
3312 
3313 
3314     base_offset = FILE_Pos() - 2;
3315 
3316     if ( ACCESS_Frame( 2L ) )
3317       return error;
3318 
3319     new_offset = GET_UShort() + base_offset;
3320 
3321     FORGET_Frame();
3322 
3323     cur_offset = FILE_Pos();
3324     if ( FILE_Seek( new_offset ) ||
3325          ( error = Load_Coverage( &ccpf2->Coverage, input ) ) != TT_Err_Ok )
3326       return error;
3327     (void)FILE_Seek( cur_offset );
3328 
3329     if ( ACCESS_Frame( 8L ) )
3330       goto Fail5;
3331 
3332     backtrack_offset = GET_UShort() + base_offset;
3333     input_offset     = GET_UShort() + base_offset;
3334     lookahead_offset = GET_UShort() + base_offset;
3335 
3336     /* `ChainPosClassSetCount' is the upper limit for input class values,
3337        thus we read it now to make an additional safety check.            */
3338 
3339     count = ccpf2->ChainPosClassSetCount = GET_UShort();
3340 
3341     FORGET_Frame();
3342 
3343     cur_offset = FILE_Pos();
3344     if ( FILE_Seek( backtrack_offset ) ||
3345          ( error = Load_ClassDefinition( &ccpf2->BacktrackClassDef, count,
3346                                          input ) ) != TT_Err_Ok )
3347       goto Fail5;
3348     if ( FILE_Seek( input_offset ) ||
3349          ( error = Load_ClassDefinition( &ccpf2->InputClassDef, count,
3350                                          input ) ) != TT_Err_Ok )
3351       goto Fail4;
3352     if ( FILE_Seek( lookahead_offset ) ||
3353          ( error = Load_ClassDefinition( &ccpf2->LookaheadClassDef, count,
3354                                          input ) ) != TT_Err_Ok )
3355       goto Fail3;
3356     (void)FILE_Seek( cur_offset );
3357 
3358     ccpf2->ChainPosClassSet   = NULL;
3359     ccpf2->MaxBacktrackLength = 0;
3360     ccpf2->MaxInputLength     = 0;
3361     ccpf2->MaxLookaheadLength = 0;
3362 
3363     if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, TTO_ChainPosClassSet ) )
3364       goto Fail2;
3365 
3366     cpcs = ccpf2->ChainPosClassSet;
3367 
3368     for ( n = 0; n < count; n++ )
3369     {
3370       if ( ACCESS_Frame( 2L ) )
3371         goto Fail1;
3372 
3373       new_offset = GET_UShort() + base_offset;
3374 
3375       FORGET_Frame();
3376 
3377       if ( new_offset != base_offset )      /* not a NULL offset */
3378       {
3379         cur_offset = FILE_Pos();
3380         if ( FILE_Seek( new_offset ) ||
3381              ( error = Load_ChainPosClassSet( ccpf2, &cpcs[n],
3382                                               input ) ) != TT_Err_Ok )
3383           goto Fail1;
3384         (void)FILE_Seek( cur_offset );
3385       }
3386       else
3387       {
3388         /* we create a ChainPosClassSet table with no entries */
3389 
3390         ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0;
3391         ccpf2->ChainPosClassSet[n].ChainPosClassRule      = NULL;
3392       }
3393     }
3394 
3395     return TT_Err_Ok;
3396 
3397   Fail1:
3398     for ( n = 0; n < count; n++ )
3399       Free_ChainPosClassSet( &cpcs[n] );
3400 
3401     FREE( cpcs );
3402 
3403   Fail2:
3404     Free_ClassDefinition( &ccpf2->LookaheadClassDef );
3405 
3406   Fail3:
3407     Free_ClassDefinition( &ccpf2->InputClassDef );
3408 
3409   Fail4:
3410     Free_ClassDefinition( &ccpf2->BacktrackClassDef );
3411 
3412   Fail5:
3413     Free_Coverage( &ccpf2->Coverage );
3414     return error;
3415   }
3416 
3417 
Free_ChainContext2(TTO_ChainContextPosFormat2 * ccpf2)3418   static void  Free_ChainContext2( TTO_ChainContextPosFormat2*  ccpf2 )
3419   {
3420     UShort                 n, count;
3421 
3422     TTO_ChainPosClassSet*  cpcs;
3423 
3424 
3425     if ( ccpf2->ChainPosClassSet )
3426     {
3427       count = ccpf2->ChainPosClassSetCount;
3428       cpcs  = ccpf2->ChainPosClassSet;
3429 
3430       for ( n = 0; n < count; n++ )
3431         Free_ChainPosClassSet( &cpcs[n] );
3432 
3433       FREE( cpcs );
3434     }
3435 
3436     Free_ClassDefinition( &ccpf2->LookaheadClassDef );
3437     Free_ClassDefinition( &ccpf2->InputClassDef );
3438     Free_ClassDefinition( &ccpf2->BacktrackClassDef );
3439 
3440     Free_Coverage( &ccpf2->Coverage );
3441   }
3442 
3443 
3444   /* ChainContextPosFormat3 */
3445 
Load_ChainContextPos3(TTO_ChainContextPosFormat3 * ccpf3,PFace input)3446   static TT_Error  Load_ChainContextPos3( TTO_ChainContextPosFormat3*  ccpf3,
3447                                           PFace                        input )
3448   {
3449     DEFINE_LOAD_LOCALS( input->stream );
3450 
3451     UShort                n, count;
3452     UShort                backtrack_count, input_count, lookahead_count;
3453     ULong                 cur_offset, new_offset, base_offset;
3454 
3455     TTO_Coverage*         b;
3456     TTO_Coverage*         i;
3457     TTO_Coverage*         l;
3458     TTO_PosLookupRecord*  plr;
3459 
3460 
3461     base_offset = FILE_Pos() - 2L;
3462 
3463     if ( ACCESS_Frame( 2L ) )
3464       return error;
3465 
3466     ccpf3->BacktrackGlyphCount = GET_UShort();
3467 
3468     FORGET_Frame();
3469 
3470     ccpf3->BacktrackCoverage = NULL;
3471 
3472     backtrack_count = ccpf3->BacktrackGlyphCount;
3473 
3474     if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count,
3475                       TTO_Coverage ) )
3476       return error;
3477 
3478     b = ccpf3->BacktrackCoverage;
3479 
3480     for ( n = 0; n < backtrack_count; n++ )
3481     {
3482       if ( ACCESS_Frame( 2L ) )
3483         goto Fail4;
3484 
3485       new_offset = GET_UShort() + base_offset;
3486 
3487       FORGET_Frame();
3488 
3489       cur_offset = FILE_Pos();
3490       if ( FILE_Seek( new_offset ) ||
3491            ( error = Load_Coverage( &b[n], input ) ) != TT_Err_Ok )
3492         goto Fail4;
3493       (void)FILE_Seek( cur_offset );
3494     }
3495 
3496     if ( ACCESS_Frame( 2L ) )
3497       goto Fail4;
3498 
3499     ccpf3->InputGlyphCount = GET_UShort();
3500 
3501     FORGET_Frame();
3502 
3503     ccpf3->InputCoverage = NULL;
3504 
3505     input_count = ccpf3->InputGlyphCount;
3506 
3507     if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, TTO_Coverage ) )
3508       goto Fail4;
3509 
3510     i = ccpf3->InputCoverage;
3511 
3512     for ( n = 0; n < input_count; n++ )
3513     {
3514       if ( ACCESS_Frame( 2L ) )
3515         goto Fail3;
3516 
3517       new_offset = GET_UShort() + base_offset;
3518 
3519       FORGET_Frame();
3520 
3521       cur_offset = FILE_Pos();
3522       if ( FILE_Seek( new_offset ) ||
3523            ( error = Load_Coverage( &i[n], input ) ) != TT_Err_Ok )
3524         goto Fail3;
3525       (void)FILE_Seek( cur_offset );
3526     }
3527 
3528     if ( ACCESS_Frame( 2L ) )
3529       goto Fail3;
3530 
3531     ccpf3->LookaheadGlyphCount = GET_UShort();
3532 
3533     FORGET_Frame();
3534 
3535     ccpf3->LookaheadCoverage = NULL;
3536 
3537     lookahead_count = ccpf3->LookaheadGlyphCount;
3538 
3539     if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count,
3540                       TTO_Coverage ) )
3541       goto Fail3;
3542 
3543     l = ccpf3->LookaheadCoverage;
3544 
3545     for ( n = 0; n < lookahead_count; n++ )
3546     {
3547       if ( ACCESS_Frame( 2L ) )
3548         goto Fail2;
3549 
3550       new_offset = GET_UShort() + base_offset;
3551 
3552       FORGET_Frame();
3553 
3554       cur_offset = FILE_Pos();
3555       if ( FILE_Seek( new_offset ) ||
3556            ( error = Load_Coverage( &l[n], input ) ) != TT_Err_Ok )
3557         goto Fail2;
3558       (void)FILE_Seek( cur_offset );
3559     }
3560 
3561     if ( ACCESS_Frame( 2L ) )
3562       goto Fail2;
3563 
3564     ccpf3->PosCount = GET_UShort();
3565 
3566     FORGET_Frame();
3567 
3568     ccpf3->PosLookupRecord = NULL;
3569 
3570     count = ccpf3->PosCount;
3571 
3572     if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, TTO_PosLookupRecord ) )
3573       goto Fail2;
3574 
3575     plr = ccpf3->PosLookupRecord;
3576 
3577     if ( ACCESS_Frame( count * 4L ) )
3578       goto Fail1;
3579 
3580     for ( n = 0; n < count; n++ )
3581     {
3582       plr[n].SequenceIndex   = GET_UShort();
3583       plr[n].LookupListIndex = GET_UShort();
3584     }
3585 
3586     FORGET_Frame();
3587 
3588     return TT_Err_Ok;
3589 
3590   Fail1:
3591     FREE( plr );
3592 
3593   Fail2:
3594     for ( n = 0; n < lookahead_count; n++ )
3595       Free_Coverage( &l[n] );
3596 
3597     FREE( l );
3598 
3599   Fail3:
3600     for ( n = 0; n < input_count; n++ )
3601       Free_Coverage( &i[n] );
3602 
3603     FREE( i );
3604 
3605   Fail4:
3606     for ( n = 0; n < backtrack_count; n++ )
3607       Free_Coverage( &b[n] );
3608 
3609     FREE( b );
3610     return error;
3611   }
3612 
3613 
Free_ChainContext3(TTO_ChainContextPosFormat3 * ccpf3)3614   static void  Free_ChainContext3( TTO_ChainContextPosFormat3*  ccpf3 )
3615   {
3616     UShort         n, count;
3617 
3618     TTO_Coverage*  c;
3619 
3620 
3621     FREE( ccpf3->PosLookupRecord );
3622 
3623     if ( ccpf3->LookaheadCoverage )
3624     {
3625       count = ccpf3->LookaheadGlyphCount;
3626       c     = ccpf3->LookaheadCoverage;
3627 
3628       for ( n = 0; n < count; n++ )
3629         Free_Coverage( &c[n] );
3630 
3631       FREE( c );
3632     }
3633 
3634     if ( ccpf3->InputCoverage )
3635     {
3636       count = ccpf3->InputGlyphCount;
3637       c     = ccpf3->InputCoverage;
3638 
3639       for ( n = 0; n < count; n++ )
3640         Free_Coverage( &c[n] );
3641 
3642       FREE( c );
3643     }
3644 
3645     if ( ccpf3->BacktrackCoverage )
3646     {
3647       count = ccpf3->BacktrackGlyphCount;
3648       c     = ccpf3->BacktrackCoverage;
3649 
3650       for ( n = 0; n < count; n++ )
3651         Free_Coverage( &c[n] );
3652 
3653       FREE( c );
3654     }
3655   }
3656 
3657 
3658   /* ChainContextPos */
3659 
Load_ChainContextPos(TTO_ChainContextPos * ccp,PFace input)3660   TT_Error  Load_ChainContextPos( TTO_ChainContextPos*  ccp,
3661                                   PFace                 input )
3662   {
3663     DEFINE_LOAD_LOCALS( input->stream );
3664 
3665 
3666     if ( ACCESS_Frame( 2L ) )
3667       return error;
3668 
3669     ccp->PosFormat = GET_UShort();
3670 
3671     FORGET_Frame();
3672 
3673     switch ( ccp->PosFormat )
3674     {
3675     case 1:
3676       return Load_ChainContextPos1( &ccp->ccpf.ccpf1, input );
3677 
3678     case 2:
3679       return Load_ChainContextPos2( &ccp->ccpf.ccpf2, input );
3680 
3681     case 3:
3682       return Load_ChainContextPos3( &ccp->ccpf.ccpf3, input );
3683 
3684     default:
3685       return TTO_Err_Invalid_GPOS_SubTable_Format;
3686     }
3687 
3688     return TT_Err_Ok;               /* never reached */
3689   }
3690 
3691 
Free_ChainContextPos(TTO_ChainContextPos * ccp)3692   void  Free_ChainContextPos( TTO_ChainContextPos*  ccp )
3693   {
3694     switch ( ccp->PosFormat )
3695     {
3696     case 1:
3697       Free_ChainContext1( &ccp->ccpf.ccpf1 );
3698       break;
3699 
3700     case 2:
3701       Free_ChainContext2( &ccp->ccpf.ccpf2 );
3702       break;
3703 
3704     case 3:
3705       Free_ChainContext3( &ccp->ccpf.ccpf3 );
3706       break;
3707     }
3708   }
3709 
3710 
3711 
3712   /***********
3713    * GPOS API
3714    ***********/
3715 
3716 
3717   EXPORT_FUNC
TT_GPOS_Select_Script(TTO_GPOSHeader * gpos,TT_ULong script_tag,TT_UShort * script_index)3718   TT_Error  TT_GPOS_Select_Script( TTO_GPOSHeader*  gpos,
3719                                    TT_ULong         script_tag,
3720                                    TT_UShort*       script_index )
3721   {
3722     UShort             n;
3723 
3724     TTO_ScriptList*    sl;
3725     TTO_ScriptRecord*  sr;
3726 
3727 
3728     if ( !gpos || !script_index )
3729       return TT_Err_Invalid_Argument;
3730 
3731     sl = &gpos->ScriptList;
3732     sr = sl->ScriptRecord;
3733 
3734     for ( n = 0; n < sl->ScriptCount; n++ )
3735       if ( script_tag == sr[n].ScriptTag )
3736       {
3737         *script_index = n;
3738 
3739         return TT_Err_Ok;
3740       }
3741 
3742     return TTO_Err_Not_Covered;
3743   }
3744 
3745 
3746   EXPORT_FUNC
TT_GPOS_Select_Language(TTO_GPOSHeader * gpos,TT_ULong language_tag,TT_UShort script_index,TT_UShort * language_index,TT_UShort * req_feature_index)3747   TT_Error  TT_GPOS_Select_Language( TTO_GPOSHeader*  gpos,
3748                                      TT_ULong         language_tag,
3749                                      TT_UShort        script_index,
3750                                      TT_UShort*       language_index,
3751                                      TT_UShort*       req_feature_index )
3752   {
3753     UShort              n;
3754 
3755     TTO_ScriptList*     sl;
3756     TTO_ScriptRecord*   sr;
3757     TTO_Script*         s;
3758     TTO_LangSysRecord*  lsr;
3759 
3760 
3761     if ( !gpos || !language_index || !req_feature_index )
3762       return TT_Err_Invalid_Argument;
3763 
3764     sl = &gpos->ScriptList;
3765     sr = sl->ScriptRecord;
3766 
3767     if ( script_index >= sl->ScriptCount )
3768       return TT_Err_Invalid_Argument;
3769 
3770     s   = &sr[script_index].Script;
3771     lsr = s->LangSysRecord;
3772 
3773     for ( n = 0; n < s->LangSysCount; n++ )
3774       if ( language_tag == lsr[n].LangSysTag )
3775       {
3776         *language_index = n;
3777         *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
3778 
3779         return TT_Err_Ok;
3780       }
3781 
3782     return TTO_Err_Not_Covered;
3783   }
3784 
3785 
3786   /* selecting 0xFFFF for language_index asks for the values of the
3787      default language (DefaultLangSys)                              */
3788 
3789   EXPORT_FUNC
TT_GPOS_Select_Feature(TTO_GPOSHeader * gpos,TT_ULong feature_tag,TT_UShort script_index,TT_UShort language_index,TT_UShort * feature_index)3790   TT_Error  TT_GPOS_Select_Feature( TTO_GPOSHeader*  gpos,
3791                                     TT_ULong         feature_tag,
3792                                     TT_UShort        script_index,
3793                                     TT_UShort        language_index,
3794                                     TT_UShort*       feature_index )
3795   {
3796     UShort              n;
3797 
3798     TTO_ScriptList*     sl;
3799     TTO_ScriptRecord*   sr;
3800     TTO_Script*         s;
3801     TTO_LangSysRecord*  lsr;
3802     TTO_LangSys*        ls;
3803     UShort*             fi;
3804 
3805     TTO_FeatureList*    fl;
3806     TTO_FeatureRecord*  fr;
3807 
3808 
3809     if ( !gpos || !feature_index )
3810       return TT_Err_Invalid_Argument;
3811 
3812     sl = &gpos->ScriptList;
3813     sr = sl->ScriptRecord;
3814 
3815     fl = &gpos->FeatureList;
3816     fr = fl->FeatureRecord;
3817 
3818     if ( script_index >= sl->ScriptCount )
3819       return TT_Err_Invalid_Argument;
3820 
3821     s   = &sr[script_index].Script;
3822     lsr = s->LangSysRecord;
3823 
3824     if ( language_index == 0xFFFF )
3825       ls = &s->DefaultLangSys;
3826     else
3827     {
3828       if ( language_index >= s->LangSysCount )
3829         return TT_Err_Invalid_Argument;
3830 
3831       ls = &lsr[language_index].LangSys;
3832     }
3833 
3834     fi = ls->FeatureIndex;
3835 
3836     for ( n = 0; n < ls->FeatureCount; n++ )
3837     {
3838       if ( fi[n] >= fl->FeatureCount )
3839         return TTO_Err_Invalid_GPOS_SubTable_Format;
3840 
3841       if ( feature_tag == fr[fi[n]].FeatureTag )
3842       {
3843         *feature_index = fi[n];
3844 
3845         return TT_Err_Ok;
3846       }
3847     }
3848 
3849     return TTO_Err_Not_Covered;
3850   }
3851 
3852 
3853   /* The next three functions return a null-terminated list */
3854 
3855   EXPORT_FUNC
TT_GPOS_Query_Scripts(TTO_GPOSHeader * gpos,TT_ULong ** script_tag_list)3856   TT_Error  TT_GPOS_Query_Scripts( TTO_GPOSHeader*  gpos,
3857                                    TT_ULong**       script_tag_list )
3858   {
3859     UShort             n;
3860     TT_Error           error;
3861     ULong*             stl;
3862 
3863     TTO_ScriptList*    sl;
3864     TTO_ScriptRecord*  sr;
3865 
3866 
3867     if ( !gpos || !script_tag_list )
3868       return TT_Err_Invalid_Argument;
3869 
3870     sl = &gpos->ScriptList;
3871     sr = sl->ScriptRecord;
3872 
3873     if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, ULong ) )
3874       return error;
3875 
3876     for ( n = 0; n < sl->ScriptCount; n++ )
3877       stl[n] = sr[n].ScriptTag;
3878     stl[n] = 0;
3879 
3880     *script_tag_list = stl;
3881 
3882     return TT_Err_Ok;
3883   }
3884 
3885 
3886   EXPORT_FUNC
TT_GPOS_Query_Languages(TTO_GPOSHeader * gpos,TT_UShort script_index,TT_ULong ** language_tag_list)3887   TT_Error  TT_GPOS_Query_Languages( TTO_GPOSHeader*  gpos,
3888                                      TT_UShort        script_index,
3889                                      TT_ULong**       language_tag_list )
3890   {
3891     UShort              n;
3892     TT_Error            error;
3893     ULong*              ltl;
3894 
3895     TTO_ScriptList*     sl;
3896     TTO_ScriptRecord*   sr;
3897     TTO_Script*         s;
3898     TTO_LangSysRecord*  lsr;
3899 
3900 
3901     if ( !gpos || !language_tag_list )
3902       return TT_Err_Invalid_Argument;
3903 
3904     sl = &gpos->ScriptList;
3905     sr = sl->ScriptRecord;
3906 
3907     if ( script_index >= sl->ScriptCount )
3908       return TT_Err_Invalid_Argument;
3909 
3910     s   = &sr[script_index].Script;
3911     lsr = s->LangSysRecord;
3912 
3913     if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, ULong ) )
3914       return error;
3915 
3916     for ( n = 0; n < s->LangSysCount; n++ )
3917       ltl[n] = lsr[n].LangSysTag;
3918     ltl[n] = 0;
3919 
3920     *language_tag_list = ltl;
3921 
3922     return TT_Err_Ok;
3923   }
3924 
3925 
3926   /* selecting 0xFFFF for language_index asks for the values of the
3927      default language (DefaultLangSys)                              */
3928 
3929   EXPORT_FUNC
TT_GPOS_Query_Features(TTO_GPOSHeader * gpos,TT_UShort script_index,TT_UShort language_index,TT_ULong ** feature_tag_list)3930   TT_Error  TT_GPOS_Query_Features( TTO_GPOSHeader*  gpos,
3931                                     TT_UShort        script_index,
3932                                     TT_UShort        language_index,
3933                                     TT_ULong**       feature_tag_list )
3934   {
3935     UShort              n;
3936     TT_Error            error;
3937     ULong*              ftl;
3938 
3939     TTO_ScriptList*     sl;
3940     TTO_ScriptRecord*   sr;
3941     TTO_Script*         s;
3942     TTO_LangSysRecord*  lsr;
3943     TTO_LangSys*        ls;
3944     UShort*             fi;
3945 
3946     TTO_FeatureList*    fl;
3947     TTO_FeatureRecord*  fr;
3948 
3949 
3950     if ( !gpos || !feature_tag_list )
3951       return TT_Err_Invalid_Argument;
3952 
3953     sl = &gpos->ScriptList;
3954     sr = sl->ScriptRecord;
3955 
3956     fl = &gpos->FeatureList;
3957     fr = fl->FeatureRecord;
3958 
3959     if ( script_index >= sl->ScriptCount )
3960       return TT_Err_Invalid_Argument;
3961 
3962     s   = &sr[script_index].Script;
3963     lsr = s->LangSysRecord;
3964 
3965     if ( language_index == 0xFFFF )
3966       ls = &s->DefaultLangSys;
3967     else
3968     {
3969       if ( language_index >= s->LangSysCount )
3970         return TT_Err_Invalid_Argument;
3971 
3972       ls = &lsr[language_index].LangSys;
3973     }
3974 
3975     fi = ls->FeatureIndex;
3976 
3977     if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, ULong ) )
3978       return error;
3979 
3980     for ( n = 0; n < ls->FeatureCount; n++ )
3981     {
3982       if ( fi[n] >= fl->FeatureCount )
3983       {
3984         FREE( ftl );
3985         return TTO_Err_Invalid_GPOS_SubTable_Format;
3986       }
3987       ftl[n] = fr[fi[n]].FeatureTag;
3988     }
3989     ftl[n] = 0;
3990 
3991     *feature_tag_list = ftl;
3992 
3993     return TT_Err_Ok;
3994   }
3995 
3996 
3997   EXPORT_FUNC
TT_GPOS_Add_Feature(TTO_GPOSHeader * gpos,TT_UShort feature_index,TT_UShort property)3998   TT_Error  TT_GPOS_Add_Feature( TTO_GPOSHeader*  gpos,
3999                                  TT_UShort        feature_index,
4000                                  TT_UShort        property )
4001   {
4002     UShort       i;
4003 
4004     TTO_Feature  feature;
4005     UShort*      properties;
4006     UShort*      index;
4007 
4008 
4009     if ( !gpos ||
4010          feature_index >= gpos->FeatureList.FeatureCount )
4011       return TT_Err_Invalid_Argument;
4012 
4013     properties = gpos->LookupList.Properties;
4014 
4015     feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
4016     index   = feature.LookupListIndex;
4017 
4018     for ( i = 0; i < feature.LookupListCount; i++ )
4019       properties[index[i]] |= property;
4020 
4021     return TT_Err_Ok;
4022   }
4023 
4024 
4025   EXPORT_FUNC
TT_GPOS_Clear_Features(TTO_GPOSHeader * gpos)4026   TT_Error  TT_GPOS_Clear_Features( TTO_GPOSHeader*  gpos )
4027   {
4028     UShort   i;
4029 
4030     UShort*  properties;
4031 
4032 
4033     if ( !gpos )
4034       return TT_Err_Invalid_Argument;
4035 
4036     properties = gpos->LookupList.Properties;
4037 
4038     for ( i = 0; i < gpos->LookupList.LookupCount; i++ )
4039       properties[i] = 0;
4040 
4041     return TT_Err_Ok;
4042   }
4043 
4044 
4045 /* END */
4046