Imported Upstream version 0.9.12
[platform/upstream/harfbuzz.git] / src / hb-old / harfbuzz-gsub.c
1 /*
2  * Copyright (C) 1998-2004  David Turner and Werner Lemberg
3  * Copyright (C) 2006  Behdad Esfahbod
4  * Copyright (C) 2007  Red Hat, Inc.
5  *
6  * This is part of HarfBuzz, an OpenType Layout engine library.
7  *
8  * Permission is hereby granted, without written agreement and without
9  * license or royalty fees, to use, copy, modify, and distribute this
10  * software and its documentation for any purpose, provided that the
11  * above copyright notice and the following two paragraphs appear in
12  * all copies of this software.
13  *
14  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
15  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
17  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18  * DAMAGE.
19  *
20  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
21  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
23  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
24  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25  *
26  * Red Hat Author(s): Behdad Esfahbod
27  */
28
29 #include "harfbuzz-impl.h"
30 #include "harfbuzz-gsub-private.h"
31 #include "harfbuzz-open-private.h"
32 #include "harfbuzz-gdef-private.h"
33
34 static HB_Error  GSUB_Do_Glyph_Lookup( HB_GSUBHeader*   gsub,
35                                        HB_UShort         lookup_index,
36                                        HB_Buffer        buffer,
37                                        HB_UShort         context_length,
38                                        int               nesting_level );
39
40
41
42 /**********************
43  * Auxiliary functions
44  **********************/
45
46
47
48 HB_Error  HB_Load_GSUB_Table( HB_Stream stream,
49                               HB_GSUBHeader** retptr,
50                               HB_GDEFHeader*  gdef,
51                               HB_Stream       gdefStream )
52 {
53   HB_Error         error;
54   HB_UInt         cur_offset, new_offset, base_offset;
55
56   HB_GSUBHeader*  gsub;
57
58   if ( !retptr )
59     return ERR(HB_Err_Invalid_Argument);
60
61   if ( GOTO_Table( TTAG_GSUB ) )
62     return error;
63
64   base_offset = FILE_Pos();
65
66   if ( ALLOC ( gsub, sizeof( *gsub ) ) ) 
67       return error;
68   
69
70   /* skip version */
71
72   if ( FILE_Seek( base_offset + 4L ) ||
73        ACCESS_Frame( 2L ) )
74     goto Fail4;
75
76   new_offset = GET_UShort() + base_offset;
77
78   FORGET_Frame();
79
80   cur_offset = FILE_Pos();
81   if ( FILE_Seek( new_offset ) ||
82        ( error = _HB_OPEN_Load_ScriptList( &gsub->ScriptList,
83                                   stream ) ) != HB_Err_Ok )
84     goto Fail4;
85   (void)FILE_Seek( cur_offset );
86
87   if ( ACCESS_Frame( 2L ) )
88     goto Fail3;
89
90   new_offset = GET_UShort() + base_offset;
91
92   FORGET_Frame();
93
94   cur_offset = FILE_Pos();
95   if ( FILE_Seek( new_offset ) ||
96        ( error = _HB_OPEN_Load_FeatureList( &gsub->FeatureList,
97                                    stream ) ) != HB_Err_Ok )
98     goto Fail3;
99   (void)FILE_Seek( cur_offset );
100
101   if ( ACCESS_Frame( 2L ) )
102     goto Fail2;
103
104   new_offset = GET_UShort() + base_offset;
105
106   FORGET_Frame();
107
108   cur_offset = FILE_Pos();
109   if ( FILE_Seek( new_offset ) ||
110        ( error = _HB_OPEN_Load_LookupList( &gsub->LookupList,
111                                   stream, HB_Type_GSUB ) ) != HB_Err_Ok )
112     goto Fail2;
113
114   gsub->gdef = gdef;      /* can be NULL */
115
116   if ( ( error =  _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, gdefStream,
117                                                                      gsub->LookupList.Lookup,
118                                                                      gsub->LookupList.LookupCount ) ) )
119     goto Fail1;
120
121   *retptr = gsub;
122
123   return HB_Err_Ok;
124
125 Fail1:
126   _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB );
127
128 Fail2:
129   _HB_OPEN_Free_FeatureList( &gsub->FeatureList );
130
131 Fail3:
132   _HB_OPEN_Free_ScriptList( &gsub->ScriptList );
133
134 Fail4:
135   FREE ( gsub );
136
137
138   return error;
139 }
140
141
142 HB_Error   HB_Done_GSUB_Table( HB_GSUBHeader* gsub )
143 {
144   _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB );
145   _HB_OPEN_Free_FeatureList( &gsub->FeatureList );
146   _HB_OPEN_Free_ScriptList( &gsub->ScriptList );
147
148   FREE( gsub );
149
150   return HB_Err_Ok;
151 }
152
153 /*****************************
154  * SubTable related functions
155  *****************************/
156
157
158 /* LookupType 1 */
159
160 /* SingleSubstFormat1 */
161 /* SingleSubstFormat2 */
162
163 static HB_Error  Load_SingleSubst( HB_GSUB_SubTable* st,
164                                    HB_Stream         stream )
165 {
166   HB_Error error;
167   HB_SingleSubst*  ss = &st->single;
168
169   HB_UShort n, count;
170   HB_UInt cur_offset, new_offset, base_offset;
171
172   HB_UShort*  s;
173
174
175   base_offset = FILE_Pos();
176
177   if ( ACCESS_Frame( 4L ) )
178     return error;
179
180   ss->SubstFormat = GET_UShort();
181   new_offset      = GET_UShort() + base_offset;
182
183   FORGET_Frame();
184
185   cur_offset = FILE_Pos();
186   if ( FILE_Seek( new_offset ) ||
187        ( error = _HB_OPEN_Load_Coverage( &ss->Coverage, stream ) ) != HB_Err_Ok )
188     return error;
189   (void)FILE_Seek( cur_offset );
190
191   switch ( ss->SubstFormat )
192   {
193   case 1:
194     if ( ACCESS_Frame( 2L ) )
195       goto Fail2;
196
197     ss->ssf.ssf1.DeltaGlyphID = GET_UShort();
198
199     FORGET_Frame();
200
201     break;
202
203   case 2:
204     if ( ACCESS_Frame( 2L ) )
205       goto Fail2;
206
207     count = ss->ssf.ssf2.GlyphCount = GET_UShort();
208
209     FORGET_Frame();
210
211     ss->ssf.ssf2.Substitute = NULL;
212
213     if ( ALLOC_ARRAY( ss->ssf.ssf2.Substitute, count, HB_UShort ) )
214       goto Fail2;
215
216     s = ss->ssf.ssf2.Substitute;
217
218     if ( ACCESS_Frame( count * 2L ) )
219       goto Fail1;
220
221     for ( n = 0; n < count; n++ )
222       s[n] = GET_UShort();
223
224     FORGET_Frame();
225
226     break;
227
228   default:
229     return ERR(HB_Err_Invalid_SubTable_Format);
230   }
231
232   return HB_Err_Ok;
233
234 Fail1:
235   FREE( s );
236
237 Fail2:
238   _HB_OPEN_Free_Coverage( &ss->Coverage );
239   return error;
240 }
241
242
243 static void  Free_SingleSubst( HB_GSUB_SubTable* st )
244 {
245   HB_SingleSubst*  ss = &st->single;
246
247   switch ( ss->SubstFormat )
248   {
249   case 1:
250     break;
251
252   case 2:
253     FREE( ss->ssf.ssf2.Substitute );
254     break;
255
256   default:
257     break;
258   }
259
260   _HB_OPEN_Free_Coverage( &ss->Coverage );
261 }
262
263
264 static HB_Error  Lookup_SingleSubst( HB_GSUBHeader*   gsub,
265                                      HB_GSUB_SubTable* st,
266                                      HB_Buffer        buffer,
267                                      HB_UShort         flags,
268                                      HB_UShort         context_length,
269                                      int               nesting_level )
270 {
271   HB_UShort index, value, property;
272   HB_Error  error;
273   HB_SingleSubst*  ss = &st->single;
274   HB_GDEFHeader*   gdef = gsub->gdef;
275
276   HB_UNUSED(nesting_level);
277
278   if ( context_length != 0xFFFF && context_length < 1 )
279     return HB_Err_Not_Covered;
280
281   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
282     return error;
283
284   error = _HB_OPEN_Coverage_Index( &ss->Coverage, IN_CURGLYPH(), &index );
285   if ( error )
286     return error;
287
288   switch ( ss->SubstFormat )
289   {
290   case 1:
291     value = ( IN_CURGLYPH() + ss->ssf.ssf1.DeltaGlyphID ) & 0xFFFF;
292     if ( REPLACE_Glyph( buffer, value, nesting_level ) )
293       return error;
294     break;
295
296   case 2:
297     if ( index >= ss->ssf.ssf2.GlyphCount )
298       return ERR(HB_Err_Invalid_SubTable);
299     value = ss->ssf.ssf2.Substitute[index];
300     if ( REPLACE_Glyph( buffer, value, nesting_level ) )
301       return error;
302     break;
303
304   default:
305     return ERR(HB_Err_Invalid_SubTable);
306   }
307
308   if ( gdef && gdef->NewGlyphClasses )
309   {
310     /* we inherit the old glyph class to the substituted glyph */
311
312     error = _HB_GDEF_Add_Glyph_Property( gdef, value, property );
313     if ( error && error != HB_Err_Not_Covered )
314       return error;
315   }
316
317   return HB_Err_Ok;
318 }
319
320
321 /* LookupType 2 */
322
323 /* Sequence */
324
325 static HB_Error  Load_Sequence( HB_Sequence*  s,
326                                 HB_Stream      stream )
327 {
328   HB_Error error;
329
330   HB_UShort n, count;
331   HB_UShort*  sub;
332
333
334   if ( ACCESS_Frame( 2L ) )
335     return error;
336
337   count = s->GlyphCount = GET_UShort();
338
339   FORGET_Frame();
340
341   s->Substitute = NULL;
342
343   if ( count )
344   {
345     if ( ALLOC_ARRAY( s->Substitute, count, HB_UShort ) )
346       return error;
347
348     sub = s->Substitute;
349
350     if ( ACCESS_Frame( count * 2L ) )
351     {
352       FREE( sub );
353       return error;
354     }
355
356     for ( n = 0; n < count; n++ )
357       sub[n] = GET_UShort();
358
359     FORGET_Frame();
360   }
361
362   return HB_Err_Ok;
363 }
364
365
366 static void  Free_Sequence( HB_Sequence*  s )
367 {
368   FREE( s->Substitute );
369 }
370
371
372 /* MultipleSubstFormat1 */
373
374 static HB_Error  Load_MultipleSubst( HB_GSUB_SubTable* st,
375                                      HB_Stream         stream )
376 {
377   HB_Error error;
378   HB_MultipleSubst*  ms = &st->multiple;
379
380   HB_UShort      n = 0, m, count;
381   HB_UInt       cur_offset, new_offset, base_offset;
382
383   HB_Sequence*  s;
384
385
386   base_offset = FILE_Pos();
387
388   if ( ACCESS_Frame( 4L ) )
389     return error;
390
391   ms->SubstFormat = GET_UShort();             /* should be 1 */
392   new_offset      = GET_UShort() + base_offset;
393
394   FORGET_Frame();
395
396   cur_offset = FILE_Pos();
397   if ( FILE_Seek( new_offset ) ||
398        ( error = _HB_OPEN_Load_Coverage( &ms->Coverage, stream ) ) != HB_Err_Ok )
399     return error;
400   (void)FILE_Seek( cur_offset );
401
402   if ( ACCESS_Frame( 2L ) )
403     goto Fail2;
404
405   count = ms->SequenceCount = GET_UShort();
406
407   FORGET_Frame();
408
409   ms->Sequence = NULL;
410
411   if ( ALLOC_ARRAY( ms->Sequence, count, HB_Sequence ) )
412     goto Fail2;
413
414   s = ms->Sequence;
415
416   for ( n = 0; n < count; n++ )
417   {
418     if ( ACCESS_Frame( 2L ) )
419       goto Fail1;
420
421     new_offset = GET_UShort() + base_offset;
422
423     FORGET_Frame();
424
425     cur_offset = FILE_Pos();
426     if ( FILE_Seek( new_offset ) ||
427          ( error = Load_Sequence( &s[n], stream ) ) != HB_Err_Ok )
428       goto Fail1;
429     (void)FILE_Seek( cur_offset );
430   }
431
432   return HB_Err_Ok;
433
434 Fail1:
435   for ( m = 0; m < n; m++ )
436     Free_Sequence( &s[m] );
437
438   FREE( s );
439
440 Fail2:
441   _HB_OPEN_Free_Coverage( &ms->Coverage );
442   return error;
443 }
444
445
446 static void  Free_MultipleSubst( HB_GSUB_SubTable* st )
447 {
448   HB_UShort      n, count;
449   HB_MultipleSubst*  ms = &st->multiple;
450
451   HB_Sequence*  s;
452
453
454   if ( ms->Sequence )
455   {
456     count = ms->SequenceCount;
457     s     = ms->Sequence;
458
459     for ( n = 0; n < count; n++ )
460       Free_Sequence( &s[n] );
461
462     FREE( s );
463   }
464
465   _HB_OPEN_Free_Coverage( &ms->Coverage );
466 }
467
468
469 static HB_Error  Lookup_MultipleSubst( HB_GSUBHeader*    gsub,
470                                        HB_GSUB_SubTable* st,
471                                        HB_Buffer         buffer,
472                                        HB_UShort          flags,
473                                        HB_UShort          context_length,
474                                        int                nesting_level )
475 {
476   HB_Error  error;
477   HB_UShort index, property, n, count;
478   HB_UShort*s;
479   HB_MultipleSubst*  ms = &st->multiple;
480   HB_GDEFHeader*     gdef = gsub->gdef;
481
482   HB_UNUSED(nesting_level);
483
484   if ( context_length != 0xFFFF && context_length < 1 )
485     return HB_Err_Not_Covered;
486
487   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
488     return error;
489
490   error = _HB_OPEN_Coverage_Index( &ms->Coverage, IN_CURGLYPH(), &index );
491   if ( error )
492     return error;
493
494   if ( index >= ms->SequenceCount )
495     return ERR(HB_Err_Invalid_SubTable);
496
497   count = ms->Sequence[index].GlyphCount;
498   s     = ms->Sequence[index].Substitute;
499
500   if ( ADD_String( buffer, 1, count, s, 0xFFFF, 0xFFFF ) )
501     return error;
502
503   if ( gdef && gdef->NewGlyphClasses )
504   {
505     /* this is a guess only ... */
506
507     if ( property == HB_GDEF_LIGATURE )
508       property = HB_GDEF_BASE_GLYPH;
509
510     for ( n = 0; n < count; n++ )
511     {
512       error = _HB_GDEF_Add_Glyph_Property( gdef, s[n], property );
513       if ( error && error != HB_Err_Not_Covered )
514         return error;
515     }
516   }
517
518   return HB_Err_Ok;
519 }
520
521
522 /* LookupType 3 */
523
524 /* AlternateSet */
525
526 static HB_Error  Load_AlternateSet( HB_AlternateSet*  as,
527                                     HB_Stream          stream )
528 {
529   HB_Error error;
530
531   HB_UShort n, count;
532   HB_UShort*  a;
533
534
535   if ( ACCESS_Frame( 2L ) )
536     return error;
537
538   count = as->GlyphCount = GET_UShort();
539
540   FORGET_Frame();
541
542   as->Alternate = NULL;
543
544   if ( ALLOC_ARRAY( as->Alternate, count, HB_UShort ) )
545     return error;
546
547   a = as->Alternate;
548
549   if ( ACCESS_Frame( count * 2L ) )
550   {
551     FREE( a );
552     return error;
553   }
554
555   for ( n = 0; n < count; n++ )
556     a[n] = GET_UShort();
557
558   FORGET_Frame();
559
560   return HB_Err_Ok;
561 }
562
563
564 static void  Free_AlternateSet( HB_AlternateSet*  as )
565 {
566   FREE( as->Alternate );
567 }
568
569
570 /* AlternateSubstFormat1 */
571
572 static HB_Error  Load_AlternateSubst( HB_GSUB_SubTable* st,
573                                       HB_Stream         stream )
574 {
575   HB_Error error;
576   HB_AlternateSubst* as = &st->alternate;
577
578   HB_UShort          n = 0, m, count;
579   HB_UInt           cur_offset, new_offset, base_offset;
580
581   HB_AlternateSet*  aset;
582
583
584   base_offset = FILE_Pos();
585
586   if ( ACCESS_Frame( 4L ) )
587     return error;
588
589   as->SubstFormat = GET_UShort();             /* should be 1 */
590   new_offset      = GET_UShort() + base_offset;
591
592   FORGET_Frame();
593
594   cur_offset = FILE_Pos();
595   if ( FILE_Seek( new_offset ) ||
596        ( error = _HB_OPEN_Load_Coverage( &as->Coverage, stream ) ) != HB_Err_Ok )
597     return error;
598   (void)FILE_Seek( cur_offset );
599
600   if ( ACCESS_Frame( 2L ) )
601     goto Fail2;
602
603   count = as->AlternateSetCount = GET_UShort();
604
605   FORGET_Frame();
606
607   as->AlternateSet = NULL;
608
609   if ( ALLOC_ARRAY( as->AlternateSet, count, HB_AlternateSet ) )
610     goto Fail2;
611
612   aset = as->AlternateSet;
613
614   for ( n = 0; n < count; n++ )
615   {
616     if ( ACCESS_Frame( 2L ) )
617       goto Fail1;
618
619     new_offset = GET_UShort() + base_offset;
620
621     FORGET_Frame();
622
623     cur_offset = FILE_Pos();
624     if ( FILE_Seek( new_offset ) ||
625          ( error = Load_AlternateSet( &aset[n], stream ) ) != HB_Err_Ok )
626       goto Fail1;
627     (void)FILE_Seek( cur_offset );
628   }
629
630   return HB_Err_Ok;
631
632 Fail1:
633   for ( m = 0; m < n; m++ )
634     Free_AlternateSet( &aset[m] );
635
636   FREE( aset );
637
638 Fail2:
639   _HB_OPEN_Free_Coverage( &as->Coverage );
640   return error;
641 }
642
643
644 static void  Free_AlternateSubst( HB_GSUB_SubTable* st )
645 {
646   HB_UShort          n, count;
647   HB_AlternateSubst* as = &st->alternate;
648
649   HB_AlternateSet*  aset;
650
651
652   if ( as->AlternateSet )
653   {
654     count = as->AlternateSetCount;
655     aset  = as->AlternateSet;
656
657     for ( n = 0; n < count; n++ )
658       Free_AlternateSet( &aset[n] );
659
660     FREE( aset );
661   }
662
663   _HB_OPEN_Free_Coverage( &as->Coverage );
664 }
665
666
667 static HB_Error  Lookup_AlternateSubst( HB_GSUBHeader*    gsub,
668                                         HB_GSUB_SubTable* st,
669                                         HB_Buffer         buffer,
670                                         HB_UShort          flags,
671                                         HB_UShort          context_length,
672                                         int                nesting_level )
673 {
674   HB_Error          error;
675   HB_UShort         index, value, alt_index, property;
676   HB_AlternateSubst* as = &st->alternate;
677   HB_GDEFHeader*     gdef = gsub->gdef;
678   HB_AlternateSet  aset;
679
680   HB_UNUSED(nesting_level);
681
682   if ( context_length != 0xFFFF && context_length < 1 )
683     return HB_Err_Not_Covered;
684
685   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
686     return error;
687
688   error = _HB_OPEN_Coverage_Index( &as->Coverage, IN_CURGLYPH(), &index );
689   if ( error )
690     return error;
691
692   aset = as->AlternateSet[index];
693
694   /* we use a user-defined callback function to get the alternate index */
695
696   if ( gsub->altfunc )
697     alt_index = (gsub->altfunc)( buffer->out_pos, IN_CURGLYPH(),
698                                  aset.GlyphCount, aset.Alternate,
699                                  gsub->data );
700   else
701     alt_index = 0;
702
703   value = aset.Alternate[alt_index];
704   if ( REPLACE_Glyph( buffer, value, nesting_level ) )
705     return error;
706
707   if ( gdef && gdef->NewGlyphClasses )
708   {
709     /* we inherit the old glyph class to the substituted glyph */
710
711     error = _HB_GDEF_Add_Glyph_Property( gdef, value, property );
712     if ( error && error != HB_Err_Not_Covered )
713       return error;
714   }
715
716   return HB_Err_Ok;
717 }
718
719
720 /* LookupType 4 */
721
722 /* Ligature */
723
724 static HB_Error  Load_Ligature( HB_Ligature*  l,
725                                 HB_Stream      stream )
726 {
727   HB_Error error;
728
729   HB_UShort n, count;
730   HB_UShort*  c;
731
732
733   if ( ACCESS_Frame( 4L ) )
734     return error;
735
736   l->LigGlyph       = GET_UShort();
737   l->ComponentCount = GET_UShort();
738
739   FORGET_Frame();
740
741   l->Component = NULL;
742
743   count = l->ComponentCount - 1;      /* only ComponentCount - 1 elements */
744
745   if ( ALLOC_ARRAY( l->Component, count, HB_UShort ) )
746     return error;
747
748   c = l->Component;
749
750   if ( ACCESS_Frame( count * 2L ) )
751   {
752     FREE( c );
753     return error;
754   }
755
756   for ( n = 0; n < count; n++ )
757     c[n] = GET_UShort();
758
759   FORGET_Frame();
760
761   return HB_Err_Ok;
762 }
763
764
765 static void  Free_Ligature( HB_Ligature*  l )
766 {
767   FREE( l->Component );
768 }
769
770
771 /* LigatureSet */
772
773 static HB_Error  Load_LigatureSet( HB_LigatureSet*  ls,
774                                    HB_Stream         stream )
775 {
776   HB_Error error;
777
778   HB_UShort      n = 0, m, count;
779   HB_UInt       cur_offset, new_offset, base_offset;
780
781   HB_Ligature*  l;
782
783
784   base_offset = FILE_Pos();
785
786   if ( ACCESS_Frame( 2L ) )
787     return error;
788
789   count = ls->LigatureCount = GET_UShort();
790
791   FORGET_Frame();
792
793   ls->Ligature = NULL;
794
795   if ( ALLOC_ARRAY( ls->Ligature, count, HB_Ligature ) )
796     return error;
797
798   l = ls->Ligature;
799
800   for ( n = 0; n < count; n++ )
801   {
802     if ( ACCESS_Frame( 2L ) )
803       goto Fail;
804
805     new_offset = GET_UShort() + base_offset;
806
807     FORGET_Frame();
808
809     cur_offset = FILE_Pos();
810     if ( FILE_Seek( new_offset ) ||
811          ( error = Load_Ligature( &l[n], stream ) ) != HB_Err_Ok )
812       goto Fail;
813     (void)FILE_Seek( cur_offset );
814   }
815
816   return HB_Err_Ok;
817
818 Fail:
819   for ( m = 0; m < n; m++ )
820     Free_Ligature( &l[m] );
821
822   FREE( l );
823   return error;
824 }
825
826
827 static void  Free_LigatureSet( HB_LigatureSet*  ls )
828 {
829   HB_UShort      n, count;
830
831   HB_Ligature*  l;
832
833
834   if ( ls->Ligature )
835   {
836     count = ls->LigatureCount;
837     l     = ls->Ligature;
838
839     for ( n = 0; n < count; n++ )
840       Free_Ligature( &l[n] );
841
842     FREE( l );
843   }
844 }
845
846
847 /* LigatureSubstFormat1 */
848
849 static HB_Error  Load_LigatureSubst( HB_GSUB_SubTable* st,
850                                      HB_Stream         stream )
851 {
852   HB_Error error;
853   HB_LigatureSubst*  ls = &st->ligature;
854
855   HB_UShort         n = 0, m, count;
856   HB_UInt          cur_offset, new_offset, base_offset;
857
858   HB_LigatureSet*  lset;
859
860
861   base_offset = FILE_Pos();
862
863   if ( ACCESS_Frame( 4L ) )
864     return error;
865
866   ls->SubstFormat = GET_UShort();             /* should be 1 */
867   new_offset      = GET_UShort() + base_offset;
868
869   FORGET_Frame();
870
871   cur_offset = FILE_Pos();
872   if ( FILE_Seek( new_offset ) ||
873        ( error = _HB_OPEN_Load_Coverage( &ls->Coverage, stream ) ) != HB_Err_Ok )
874     return error;
875   (void)FILE_Seek( cur_offset );
876
877   if ( ACCESS_Frame( 2L ) )
878     goto Fail2;
879
880   count = ls->LigatureSetCount = GET_UShort();
881
882   FORGET_Frame();
883
884   ls->LigatureSet = NULL;
885
886   if ( ALLOC_ARRAY( ls->LigatureSet, count, HB_LigatureSet ) )
887     goto Fail2;
888
889   lset = ls->LigatureSet;
890
891   for ( n = 0; n < count; n++ )
892   {
893     if ( ACCESS_Frame( 2L ) )
894       goto Fail1;
895
896     new_offset = GET_UShort() + base_offset;
897
898     FORGET_Frame();
899
900     cur_offset = FILE_Pos();
901     if ( FILE_Seek( new_offset ) ||
902          ( error = Load_LigatureSet( &lset[n], stream ) ) != HB_Err_Ok )
903       goto Fail1;
904     (void)FILE_Seek( cur_offset );
905   }
906
907   return HB_Err_Ok;
908
909 Fail1:
910   for ( m = 0; m < n; m++ )
911     Free_LigatureSet( &lset[m] );
912
913   FREE( lset );
914
915 Fail2:
916   _HB_OPEN_Free_Coverage( &ls->Coverage );
917   return error;
918 }
919
920
921 static void  Free_LigatureSubst( HB_GSUB_SubTable* st )
922 {
923   HB_UShort         n, count;
924   HB_LigatureSubst*  ls = &st->ligature;
925
926   HB_LigatureSet*  lset;
927
928
929   if ( ls->LigatureSet )
930   {
931     count = ls->LigatureSetCount;
932     lset  = ls->LigatureSet;
933
934     for ( n = 0; n < count; n++ )
935       Free_LigatureSet( &lset[n] );
936
937     FREE( lset );
938   }
939
940   _HB_OPEN_Free_Coverage( &ls->Coverage );
941 }
942
943
944 static HB_Error  Lookup_LigatureSubst( HB_GSUBHeader*    gsub,
945                                        HB_GSUB_SubTable* st,
946                                        HB_Buffer         buffer,
947                                        HB_UShort          flags,
948                                        HB_UShort          context_length,
949                                        int                nesting_level )
950 {
951   HB_UShort      index, property;
952   HB_Error       error;
953   HB_UShort      numlig, i, j, is_mark, first_is_mark = FALSE;
954   HB_UShort*     c;
955   HB_LigatureSubst*  ls = &st->ligature;
956   HB_GDEFHeader*     gdef = gsub->gdef;
957
958   HB_Ligature*  lig;
959
960   HB_UNUSED(nesting_level);
961
962   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
963     return error;
964
965   if ( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
966     first_is_mark = TRUE;
967
968   error = _HB_OPEN_Coverage_Index( &ls->Coverage, IN_CURGLYPH(), &index );
969   if ( error )
970     return error;
971
972   if ( index >= ls->LigatureSetCount )
973      return ERR(HB_Err_Invalid_SubTable);
974
975   lig = ls->LigatureSet[index].Ligature;
976
977   for ( numlig = ls->LigatureSet[index].LigatureCount;
978         numlig;
979         numlig--, lig++ )
980   {
981     if ( buffer->in_pos + lig->ComponentCount > buffer->in_length )
982       goto next_ligature;               /* Not enough glyphs in input */
983
984     c    = lig->Component;
985
986     is_mark = first_is_mark;
987
988     if ( context_length != 0xFFFF && context_length < lig->ComponentCount )
989       break;
990
991     for ( i = 1, j = buffer->in_pos + 1; i < lig->ComponentCount; i++, j++ )
992     {
993       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
994       {
995         if ( error && error != HB_Err_Not_Covered )
996           return error;
997
998         if ( j + lig->ComponentCount - i == (HB_Int)buffer->in_length )
999           goto next_ligature;
1000         j++;
1001       }
1002
1003       if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
1004         is_mark = FALSE;
1005
1006       if ( IN_GLYPH( j ) != c[i - 1] )
1007         goto next_ligature;
1008     }
1009
1010     if ( gdef && gdef->NewGlyphClasses )
1011     {
1012       /* this is just a guess ... */
1013
1014       error = _HB_GDEF_Add_Glyph_Property( gdef, lig->LigGlyph,
1015                                   is_mark ? HB_GDEF_MARK : HB_GDEF_LIGATURE );
1016       if ( error && error != HB_Err_Not_Covered )
1017         return error;
1018     }
1019
1020     if ( j == buffer->in_pos + i ) /* No input glyphs skipped */
1021     {
1022       /* We don't use a new ligature ID if there are no skipped
1023          glyphs and the ligature already has an ID.             */
1024
1025       if ( IN_LIGID( buffer->in_pos ) )
1026       {
1027         if ( ADD_String( buffer, i, 1, &lig->LigGlyph,
1028                         0xFFFF, 0xFFFF ) )
1029           return error;
1030       }
1031       else
1032       {
1033         HB_UShort ligID = _hb_buffer_allocate_ligid( buffer );
1034         if ( ADD_String( buffer, i, 1, &lig->LigGlyph,
1035                         0xFFFF, ligID ) )
1036           return error;
1037       }
1038     }
1039     else
1040     {
1041       HB_UShort ligID = _hb_buffer_allocate_ligid( buffer );
1042       if ( ADD_Glyph( buffer, lig->LigGlyph, 0xFFFF, ligID ) )
1043         return error;
1044
1045       /* Now we must do a second loop to copy the skipped glyphs to
1046          `out' and assign component values to it.  We start with the
1047          glyph after the first component.  Glyphs between component
1048          i and i+1 belong to component i.  Together with the ligID
1049          value it is later possible to check whether a specific
1050          component value really belongs to a given ligature.         */
1051
1052       for ( i = 0; i < lig->ComponentCount - 1; i++ )
1053       {
1054         while ( CHECK_Property( gdef, IN_CURITEM(),
1055                                 flags, &property ) )
1056           if ( ADD_Glyph( buffer, IN_CURGLYPH(), i, ligID ) )
1057             return error;
1058
1059         (buffer->in_pos)++;
1060       }
1061     }
1062
1063     return HB_Err_Ok;
1064
1065   next_ligature:
1066     ;
1067   }
1068
1069   return HB_Err_Not_Covered;
1070 }
1071
1072
1073 /* Do the actual substitution for a context substitution (either format
1074    5 or 6).  This is only called after we've determined that the input
1075    matches the subrule.                                                 */
1076
1077 static HB_Error  Do_ContextSubst( HB_GSUBHeader*        gsub,
1078                                   HB_UShort              GlyphCount,
1079                                   HB_UShort              SubstCount,
1080                                   HB_SubstLookupRecord* subst,
1081                                   HB_Buffer             buffer,
1082                                   int                    nesting_level )
1083 {
1084   HB_Error  error;
1085   HB_UInt   i, old_pos;
1086
1087
1088   i = 0;
1089
1090   while ( i < GlyphCount )
1091   {
1092     if ( SubstCount && i == subst->SequenceIndex )
1093     {
1094       old_pos = buffer->in_pos;
1095
1096       /* Do a substitution */
1097
1098       error = GSUB_Do_Glyph_Lookup( gsub, subst->LookupListIndex, buffer,
1099                                     GlyphCount, nesting_level );
1100
1101       subst++;
1102       SubstCount--;
1103       i += buffer->in_pos - old_pos;
1104
1105       if ( error == HB_Err_Not_Covered )
1106       {
1107         if ( COPY_Glyph( buffer ) )
1108           return error;
1109         i++;
1110       }
1111       else if ( error )
1112         return error;
1113     }
1114     else
1115     {
1116       /* No substitution for this index */
1117
1118       if ( COPY_Glyph( buffer ) )
1119         return error;
1120       i++;
1121     }
1122   }
1123
1124   return HB_Err_Ok;
1125 }
1126
1127
1128 /* LookupType 5 */
1129
1130 /* SubRule */
1131
1132 static HB_Error  Load_SubRule( HB_SubRule*  sr,
1133                                HB_Stream     stream )
1134 {
1135   HB_Error error;
1136
1137   HB_UShort               n, count;
1138   HB_UShort*              i;
1139
1140   HB_SubstLookupRecord*  slr;
1141
1142
1143   if ( ACCESS_Frame( 4L ) )
1144     return error;
1145
1146   sr->GlyphCount = GET_UShort();
1147   sr->SubstCount = GET_UShort();
1148
1149   FORGET_Frame();
1150
1151   sr->Input = NULL;
1152
1153   count = sr->GlyphCount - 1;         /* only GlyphCount - 1 elements */
1154
1155   if ( ALLOC_ARRAY( sr->Input, count, HB_UShort ) )
1156     return error;
1157
1158   i = sr->Input;
1159
1160   if ( ACCESS_Frame( count * 2L ) )
1161     goto Fail2;
1162
1163   for ( n = 0; n < count; n++ )
1164     i[n] = GET_UShort();
1165
1166   FORGET_Frame();
1167
1168   sr->SubstLookupRecord = NULL;
1169
1170   count = sr->SubstCount;
1171
1172   if ( ALLOC_ARRAY( sr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
1173     goto Fail2;
1174
1175   slr = sr->SubstLookupRecord;
1176
1177   if ( ACCESS_Frame( count * 4L ) )
1178     goto Fail1;
1179
1180   for ( n = 0; n < count; n++ )
1181   {
1182     slr[n].SequenceIndex   = GET_UShort();
1183     slr[n].LookupListIndex = GET_UShort();
1184   }
1185
1186   FORGET_Frame();
1187
1188   return HB_Err_Ok;
1189
1190 Fail1:
1191   FREE( slr );
1192
1193 Fail2:
1194   FREE( i );
1195   return error;
1196 }
1197
1198
1199 static void  Free_SubRule( HB_SubRule*  sr )
1200 {
1201   FREE( sr->SubstLookupRecord );
1202   FREE( sr->Input );
1203 }
1204
1205
1206 /* SubRuleSet */
1207
1208 static HB_Error  Load_SubRuleSet( HB_SubRuleSet*  srs,
1209                                   HB_Stream        stream )
1210 {
1211   HB_Error error;
1212
1213   HB_UShort     n = 0, m, count;
1214   HB_UInt      cur_offset, new_offset, base_offset;
1215
1216   HB_SubRule*  sr;
1217
1218
1219   base_offset = FILE_Pos();
1220
1221   if ( ACCESS_Frame( 2L ) )
1222     return error;
1223
1224   count = srs->SubRuleCount = GET_UShort();
1225
1226   FORGET_Frame();
1227
1228   srs->SubRule = NULL;
1229
1230   if ( ALLOC_ARRAY( srs->SubRule, count, HB_SubRule ) )
1231     return error;
1232
1233   sr = srs->SubRule;
1234
1235   for ( n = 0; n < count; n++ )
1236   {
1237     if ( ACCESS_Frame( 2L ) )
1238       goto Fail;
1239
1240     new_offset = GET_UShort() + base_offset;
1241
1242     FORGET_Frame();
1243
1244     cur_offset = FILE_Pos();
1245     if ( FILE_Seek( new_offset ) ||
1246          ( error = Load_SubRule( &sr[n], stream ) ) != HB_Err_Ok )
1247       goto Fail;
1248     (void)FILE_Seek( cur_offset );
1249   }
1250
1251   return HB_Err_Ok;
1252
1253 Fail:
1254   for ( m = 0; m < n; m++ )
1255     Free_SubRule( &sr[m] );
1256
1257   FREE( sr );
1258   return error;
1259 }
1260
1261
1262 static void  Free_SubRuleSet( HB_SubRuleSet*  srs )
1263 {
1264   HB_UShort     n, count;
1265
1266   HB_SubRule*  sr;
1267
1268
1269   if ( srs->SubRule )
1270   {
1271     count = srs->SubRuleCount;
1272     sr    = srs->SubRule;
1273
1274     for ( n = 0; n < count; n++ )
1275       Free_SubRule( &sr[n] );
1276
1277     FREE( sr );
1278   }
1279 }
1280
1281
1282 /* ContextSubstFormat1 */
1283
1284 static HB_Error  Load_ContextSubst1( HB_ContextSubstFormat1*  csf1,
1285                                      HB_Stream                 stream )
1286 {
1287   HB_Error error;
1288
1289   HB_UShort        n = 0, m, count;
1290   HB_UInt         cur_offset, new_offset, base_offset;
1291
1292   HB_SubRuleSet*  srs;
1293
1294
1295   base_offset = FILE_Pos() - 2L;
1296
1297   if ( ACCESS_Frame( 2L ) )
1298     return error;
1299
1300   new_offset = GET_UShort() + base_offset;
1301
1302   FORGET_Frame();
1303
1304   cur_offset = FILE_Pos();
1305   if ( FILE_Seek( new_offset ) ||
1306        ( error = _HB_OPEN_Load_Coverage( &csf1->Coverage, stream ) ) != HB_Err_Ok )
1307     return error;
1308   (void)FILE_Seek( cur_offset );
1309
1310   if ( ACCESS_Frame( 2L ) )
1311     goto Fail2;
1312
1313   count = csf1->SubRuleSetCount = GET_UShort();
1314
1315   FORGET_Frame();
1316
1317   csf1->SubRuleSet = NULL;
1318
1319   if ( ALLOC_ARRAY( csf1->SubRuleSet, count, HB_SubRuleSet ) )
1320     goto Fail2;
1321
1322   srs = csf1->SubRuleSet;
1323
1324   for ( n = 0; n < count; n++ )
1325   {
1326     if ( ACCESS_Frame( 2L ) )
1327       goto Fail1;
1328
1329     new_offset = GET_UShort() + base_offset;
1330
1331     FORGET_Frame();
1332
1333     cur_offset = FILE_Pos();
1334     if ( FILE_Seek( new_offset ) ||
1335          ( error = Load_SubRuleSet( &srs[n], stream ) ) != HB_Err_Ok )
1336       goto Fail1;
1337     (void)FILE_Seek( cur_offset );
1338   }
1339
1340   return HB_Err_Ok;
1341
1342 Fail1:
1343   for ( m = 0; m < n; m++ )
1344     Free_SubRuleSet( &srs[m] );
1345
1346   FREE( srs );
1347
1348 Fail2:
1349   _HB_OPEN_Free_Coverage( &csf1->Coverage );
1350   return error;
1351 }
1352
1353
1354 static void  Free_ContextSubst1( HB_ContextSubstFormat1* csf1 )
1355 {
1356   HB_UShort        n, count;
1357
1358   HB_SubRuleSet*  srs;
1359
1360
1361   if ( csf1->SubRuleSet )
1362   {
1363     count = csf1->SubRuleSetCount;
1364     srs   = csf1->SubRuleSet;
1365
1366     for ( n = 0; n < count; n++ )
1367       Free_SubRuleSet( &srs[n] );
1368
1369     FREE( srs );
1370   }
1371
1372   _HB_OPEN_Free_Coverage( &csf1->Coverage );
1373 }
1374
1375
1376 /* SubClassRule */
1377
1378 static HB_Error  Load_SubClassRule( HB_ContextSubstFormat2*  csf2,
1379                                     HB_SubClassRule*         scr,
1380                                     HB_Stream                 stream )
1381 {
1382   HB_Error error;
1383
1384   HB_UShort               n, count;
1385
1386   HB_UShort*              c;
1387   HB_SubstLookupRecord*  slr;
1388
1389
1390   if ( ACCESS_Frame( 4L ) )
1391     return error;
1392
1393   scr->GlyphCount = GET_UShort();
1394   scr->SubstCount = GET_UShort();
1395
1396   if ( scr->GlyphCount > csf2->MaxContextLength )
1397     csf2->MaxContextLength = scr->GlyphCount;
1398
1399   FORGET_Frame();
1400
1401   scr->Class = NULL;
1402
1403   count = scr->GlyphCount - 1;        /* only GlyphCount - 1 elements */
1404
1405   if ( ALLOC_ARRAY( scr->Class, count, HB_UShort ) )
1406     return error;
1407
1408   c = scr->Class;
1409
1410   if ( ACCESS_Frame( count * 2L ) )
1411     goto Fail2;
1412
1413   for ( n = 0; n < count; n++ )
1414     c[n] = GET_UShort();
1415
1416   FORGET_Frame();
1417
1418   scr->SubstLookupRecord = NULL;
1419
1420   count = scr->SubstCount;
1421
1422   if ( ALLOC_ARRAY( scr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
1423     goto Fail2;
1424
1425   slr = scr->SubstLookupRecord;
1426
1427   if ( ACCESS_Frame( count * 4L ) )
1428     goto Fail1;
1429
1430   for ( n = 0; n < count; n++ )
1431   {
1432     slr[n].SequenceIndex   = GET_UShort();
1433     slr[n].LookupListIndex = GET_UShort();
1434   }
1435
1436   FORGET_Frame();
1437
1438   return HB_Err_Ok;
1439
1440 Fail1:
1441   FREE( slr );
1442
1443 Fail2:
1444   FREE( c );
1445   return error;
1446 }
1447
1448
1449 static void  Free_SubClassRule( HB_SubClassRule*  scr )
1450 {
1451   FREE( scr->SubstLookupRecord );
1452   FREE( scr->Class );
1453 }
1454
1455
1456 /* SubClassSet */
1457
1458 static HB_Error  Load_SubClassSet( HB_ContextSubstFormat2*  csf2,
1459                                    HB_SubClassSet*          scs,
1460                                    HB_Stream                 stream )
1461 {
1462   HB_Error error;
1463
1464   HB_UShort          n = 0, m, count;
1465   HB_UInt           cur_offset, new_offset, base_offset;
1466
1467   HB_SubClassRule*  scr;
1468
1469
1470   base_offset = FILE_Pos();
1471
1472   if ( ACCESS_Frame( 2L ) )
1473     return error;
1474
1475   count = scs->SubClassRuleCount = GET_UShort();
1476
1477   FORGET_Frame();
1478
1479   scs->SubClassRule = NULL;
1480
1481   if ( ALLOC_ARRAY( scs->SubClassRule, count, HB_SubClassRule ) )
1482     return error;
1483
1484   scr = scs->SubClassRule;
1485
1486   for ( n = 0; n < count; n++ )
1487   {
1488     if ( ACCESS_Frame( 2L ) )
1489       goto Fail;
1490
1491     new_offset = GET_UShort() + base_offset;
1492
1493     FORGET_Frame();
1494
1495     cur_offset = FILE_Pos();
1496     if ( FILE_Seek( new_offset ) ||
1497          ( error = Load_SubClassRule( csf2, &scr[n],
1498                                       stream ) ) != HB_Err_Ok )
1499       goto Fail;
1500     (void)FILE_Seek( cur_offset );
1501   }
1502
1503   return HB_Err_Ok;
1504
1505 Fail:
1506   for ( m = 0; m < n; m++ )
1507     Free_SubClassRule( &scr[m] );
1508
1509   FREE( scr );
1510   return error;
1511 }
1512
1513
1514 static void  Free_SubClassSet( HB_SubClassSet*  scs )
1515 {
1516   HB_UShort          n, count;
1517
1518   HB_SubClassRule*  scr;
1519
1520
1521   if ( scs->SubClassRule )
1522   {
1523     count = scs->SubClassRuleCount;
1524     scr   = scs->SubClassRule;
1525
1526     for ( n = 0; n < count; n++ )
1527       Free_SubClassRule( &scr[n] );
1528
1529     FREE( scr );
1530   }
1531 }
1532
1533
1534 /* ContextSubstFormat2 */
1535
1536 static HB_Error  Load_ContextSubst2( HB_ContextSubstFormat2*  csf2,
1537                                      HB_Stream                 stream )
1538 {
1539   HB_Error error;
1540
1541   HB_UShort         n = 0, m, count;
1542   HB_UInt          cur_offset, new_offset, base_offset;
1543
1544   HB_SubClassSet*  scs;
1545
1546
1547   base_offset = FILE_Pos() - 2;
1548
1549   if ( ACCESS_Frame( 2L ) )
1550     return error;
1551
1552   new_offset = GET_UShort() + base_offset;
1553
1554   FORGET_Frame();
1555
1556   cur_offset = FILE_Pos();
1557   if ( FILE_Seek( new_offset ) ||
1558        ( error = _HB_OPEN_Load_Coverage( &csf2->Coverage, stream ) ) != HB_Err_Ok )
1559     return error;
1560   (void)FILE_Seek( cur_offset );
1561
1562   if ( ACCESS_Frame( 4L ) )
1563     goto Fail3;
1564
1565   new_offset = GET_UShort() + base_offset;
1566
1567   /* `SubClassSetCount' is the upper limit for class values, thus we
1568      read it now to make an additional safety check.                 */
1569
1570   count = csf2->SubClassSetCount = GET_UShort();
1571
1572   FORGET_Frame();
1573
1574   cur_offset = FILE_Pos();
1575   if ( FILE_Seek( new_offset ) ||
1576        ( error = _HB_OPEN_Load_ClassDefinition( &csf2->ClassDef, count,
1577                                        stream ) ) != HB_Err_Ok )
1578     goto Fail3;
1579   (void)FILE_Seek( cur_offset );
1580
1581   csf2->SubClassSet      = NULL;
1582   csf2->MaxContextLength = 0;
1583
1584   if ( ALLOC_ARRAY( csf2->SubClassSet, count, HB_SubClassSet ) )
1585     goto Fail2;
1586
1587   scs = csf2->SubClassSet;
1588
1589   for ( n = 0; n < count; n++ )
1590   {
1591     if ( ACCESS_Frame( 2L ) )
1592       goto Fail1;
1593
1594     new_offset = GET_UShort() + base_offset;
1595
1596     FORGET_Frame();
1597
1598     if ( new_offset != base_offset )      /* not a NULL offset */
1599     {
1600       cur_offset = FILE_Pos();
1601       if ( FILE_Seek( new_offset ) ||
1602            ( error = Load_SubClassSet( csf2, &scs[n],
1603                                        stream ) ) != HB_Err_Ok )
1604         goto Fail1;
1605       (void)FILE_Seek( cur_offset );
1606     }
1607     else
1608     {
1609       /* we create a SubClassSet table with no entries */
1610
1611       csf2->SubClassSet[n].SubClassRuleCount = 0;
1612       csf2->SubClassSet[n].SubClassRule      = NULL;
1613     }
1614   }
1615
1616   return HB_Err_Ok;
1617
1618 Fail1:
1619   for ( m = 0; m < n; m++ )
1620     Free_SubClassSet( &scs[m] );
1621
1622   FREE( scs );
1623
1624 Fail2:
1625   _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef );
1626
1627 Fail3:
1628   _HB_OPEN_Free_Coverage( &csf2->Coverage );
1629   return error;
1630 }
1631
1632
1633 static void  Free_ContextSubst2( HB_ContextSubstFormat2*  csf2 )
1634 {
1635   HB_UShort         n, count;
1636
1637   HB_SubClassSet*  scs;
1638
1639
1640   if ( csf2->SubClassSet )
1641   {
1642     count = csf2->SubClassSetCount;
1643     scs   = csf2->SubClassSet;
1644
1645     for ( n = 0; n < count; n++ )
1646       Free_SubClassSet( &scs[n] );
1647
1648     FREE( scs );
1649   }
1650
1651   _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef );
1652   _HB_OPEN_Free_Coverage( &csf2->Coverage );
1653 }
1654
1655
1656 /* ContextSubstFormat3 */
1657
1658 static HB_Error  Load_ContextSubst3( HB_ContextSubstFormat3*  csf3,
1659                                      HB_Stream                 stream )
1660 {
1661   HB_Error error;
1662
1663   HB_UShort               n = 0, m, count;
1664   HB_UInt                cur_offset, new_offset, base_offset;
1665
1666   HB_Coverage*           c;
1667   HB_SubstLookupRecord*  slr;
1668
1669
1670   base_offset = FILE_Pos() - 2L;
1671
1672   if ( ACCESS_Frame( 4L ) )
1673     return error;
1674
1675   csf3->GlyphCount = GET_UShort();
1676   csf3->SubstCount = GET_UShort();
1677
1678   FORGET_Frame();
1679
1680   csf3->Coverage = NULL;
1681
1682   count = csf3->GlyphCount;
1683
1684   if ( ALLOC_ARRAY( csf3->Coverage, count, HB_Coverage ) )
1685     return error;
1686
1687   c = csf3->Coverage;
1688
1689   for ( n = 0; n < count; n++ )
1690   {
1691     if ( ACCESS_Frame( 2L ) )
1692       goto Fail2;
1693
1694     new_offset = GET_UShort() + base_offset;
1695
1696     FORGET_Frame();
1697
1698     cur_offset = FILE_Pos();
1699     if ( FILE_Seek( new_offset ) ||
1700          ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok )
1701       goto Fail2;
1702     (void)FILE_Seek( cur_offset );
1703   }
1704
1705   csf3->SubstLookupRecord = NULL;
1706
1707   count = csf3->SubstCount;
1708
1709   if ( ALLOC_ARRAY( csf3->SubstLookupRecord, count,
1710                     HB_SubstLookupRecord ) )
1711     goto Fail2;
1712
1713   slr = csf3->SubstLookupRecord;
1714
1715   if ( ACCESS_Frame( count * 4L ) )
1716     goto Fail1;
1717
1718   for ( n = 0; n < count; n++ )
1719   {
1720     slr[n].SequenceIndex   = GET_UShort();
1721     slr[n].LookupListIndex = GET_UShort();
1722   }
1723
1724   FORGET_Frame();
1725
1726   return HB_Err_Ok;
1727
1728 Fail1:
1729   FREE( slr );
1730
1731 Fail2:
1732   for ( m = 0; m < n; m++ )
1733     _HB_OPEN_Free_Coverage( &c[m] );
1734
1735   FREE( c );
1736   return error;
1737 }
1738
1739
1740 static void  Free_ContextSubst3( HB_ContextSubstFormat3*  csf3 )
1741 {
1742   HB_UShort      n, count;
1743
1744   HB_Coverage*  c;
1745
1746
1747   FREE( csf3->SubstLookupRecord );
1748
1749   if ( csf3->Coverage )
1750   {
1751     count = csf3->GlyphCount;
1752     c     = csf3->Coverage;
1753
1754     for ( n = 0; n < count; n++ )
1755       _HB_OPEN_Free_Coverage( &c[n] );
1756
1757     FREE( c );
1758   }
1759 }
1760
1761
1762 /* ContextSubst */
1763
1764 static HB_Error  Load_ContextSubst( HB_GSUB_SubTable* st,
1765                                     HB_Stream         stream )
1766 {
1767   HB_Error error;
1768   HB_ContextSubst*  cs = &st->context;
1769
1770
1771   if ( ACCESS_Frame( 2L ) )
1772     return error;
1773
1774   cs->SubstFormat = GET_UShort();
1775
1776   FORGET_Frame();
1777
1778   switch ( cs->SubstFormat )
1779   {
1780   case 1:  return Load_ContextSubst1( &cs->csf.csf1, stream );
1781   case 2:  return Load_ContextSubst2( &cs->csf.csf2, stream );
1782   case 3:  return Load_ContextSubst3( &cs->csf.csf3, stream );
1783   default: return ERR(HB_Err_Invalid_SubTable_Format);
1784   }
1785
1786   return HB_Err_Ok;               /* never reached */
1787 }
1788
1789
1790 static void  Free_ContextSubst( HB_GSUB_SubTable* st )
1791 {
1792   HB_ContextSubst*  cs = &st->context;
1793
1794   switch ( cs->SubstFormat )
1795   {
1796   case 1:  Free_ContextSubst1( &cs->csf.csf1 ); break;
1797   case 2:  Free_ContextSubst2( &cs->csf.csf2 ); break;
1798   case 3:  Free_ContextSubst3( &cs->csf.csf3 ); break;
1799   default:                                              break;
1800   }
1801 }
1802
1803
1804 static HB_Error  Lookup_ContextSubst1( HB_GSUBHeader*          gsub,
1805                                        HB_ContextSubstFormat1* csf1,
1806                                        HB_Buffer               buffer,
1807                                        HB_UShort                flags,
1808                                        HB_UShort                context_length,
1809                                        int                      nesting_level )
1810 {
1811   HB_UShort        index, property;
1812   HB_UShort        i, j, k, numsr;
1813   HB_Error         error;
1814
1815   HB_SubRule*     sr;
1816   HB_GDEFHeader*  gdef;
1817
1818
1819   gdef = gsub->gdef;
1820
1821   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
1822     return error;
1823
1824   error = _HB_OPEN_Coverage_Index( &csf1->Coverage, IN_CURGLYPH(), &index );
1825   if ( error )
1826     return error;
1827
1828   sr    = csf1->SubRuleSet[index].SubRule;
1829   numsr = csf1->SubRuleSet[index].SubRuleCount;
1830
1831   for ( k = 0; k < numsr; k++ )
1832   {
1833     if ( context_length != 0xFFFF && context_length < sr[k].GlyphCount )
1834       goto next_subrule;
1835
1836     if ( buffer->in_pos + sr[k].GlyphCount > buffer->in_length )
1837       goto next_subrule;                        /* context is too long */
1838
1839     for ( i = 1, j = buffer->in_pos + 1; i < sr[k].GlyphCount; i++, j++ )
1840     {
1841       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
1842       {
1843         if ( error && error != HB_Err_Not_Covered )
1844           return error;
1845
1846         if ( j + sr[k].GlyphCount - i == (HB_Int)buffer->in_length )
1847           goto next_subrule;
1848         j++;
1849       }
1850
1851       if ( IN_GLYPH( j ) != sr[k].Input[i - 1] )
1852         goto next_subrule;
1853     }
1854
1855     return Do_ContextSubst( gsub, sr[k].GlyphCount,
1856                             sr[k].SubstCount, sr[k].SubstLookupRecord,
1857                             buffer,
1858                             nesting_level );
1859   next_subrule:
1860     ;
1861   }
1862
1863   return HB_Err_Not_Covered;
1864 }
1865
1866
1867 static HB_Error  Lookup_ContextSubst2( HB_GSUBHeader*          gsub,
1868                                        HB_ContextSubstFormat2* csf2,
1869                                        HB_Buffer               buffer,
1870                                        HB_UShort                flags,
1871                                        HB_UShort                context_length,
1872                                        int                      nesting_level )
1873 {
1874   HB_UShort          index, property;
1875   HB_Error           error;
1876   HB_UShort          i, j, k, known_classes;
1877
1878   HB_UShort*         classes;
1879   HB_UShort*         cl;
1880
1881   HB_SubClassSet*   scs;
1882   HB_SubClassRule*  sr;
1883   HB_GDEFHeader*    gdef;
1884
1885
1886   gdef = gsub->gdef;
1887
1888   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
1889     return error;
1890
1891   /* Note: The coverage table in format 2 doesn't give an index into
1892            anything.  It just lets us know whether or not we need to
1893            do any lookup at all.                                     */
1894
1895   error = _HB_OPEN_Coverage_Index( &csf2->Coverage, IN_CURGLYPH(), &index );
1896   if ( error )
1897     return error;
1898
1899   if (csf2->MaxContextLength < 1)
1900     return HB_Err_Not_Covered;
1901
1902   if ( ALLOC_ARRAY( classes, csf2->MaxContextLength, HB_UShort ) )
1903     return error;
1904
1905   error = _HB_OPEN_Get_Class( &csf2->ClassDef, IN_CURGLYPH(),
1906                      &classes[0], NULL );
1907   if ( error && error != HB_Err_Not_Covered )
1908     goto End;
1909   known_classes = 0;
1910
1911   scs = &csf2->SubClassSet[classes[0]];
1912   if ( !scs )
1913   {
1914     error = ERR(HB_Err_Invalid_SubTable);
1915     goto End;
1916   }
1917
1918   for ( k = 0; k < scs->SubClassRuleCount; k++ )
1919   {
1920     sr  = &scs->SubClassRule[k];
1921
1922     if ( context_length != 0xFFFF && context_length < sr->GlyphCount )
1923       goto next_subclassrule;
1924
1925     if ( buffer->in_pos + sr->GlyphCount > buffer->in_length )
1926       goto next_subclassrule;                      /* context is too long */
1927
1928     cl   = sr->Class;
1929
1930     /* Start at 1 because [0] is implied */
1931
1932     for ( i = 1, j = buffer->in_pos + 1; i < sr->GlyphCount; i++, j++ )
1933     {
1934       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
1935       {
1936         if ( error && error != HB_Err_Not_Covered )
1937           goto End;
1938
1939         if ( j + sr->GlyphCount - i < (HB_Int)buffer->in_length )
1940           goto next_subclassrule;
1941         j++;
1942       }
1943
1944       if ( i > known_classes )
1945       {
1946         /* Keeps us from having to do this for each rule */
1947
1948         error = _HB_OPEN_Get_Class( &csf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
1949         if ( error && error != HB_Err_Not_Covered )
1950           goto End;
1951         known_classes = i;
1952       }
1953
1954       if ( cl[i - 1] != classes[i] )
1955         goto next_subclassrule;
1956     }
1957
1958     error = Do_ContextSubst( gsub, sr->GlyphCount,
1959                              sr->SubstCount, sr->SubstLookupRecord,
1960                              buffer,
1961                              nesting_level );
1962     goto End;
1963
1964   next_subclassrule:
1965     ;
1966   }
1967
1968   error = HB_Err_Not_Covered;
1969
1970 End:
1971   FREE( classes );
1972   return error;
1973 }
1974
1975
1976 static HB_Error  Lookup_ContextSubst3( HB_GSUBHeader*          gsub,
1977                                        HB_ContextSubstFormat3* csf3,
1978                                        HB_Buffer               buffer,
1979                                        HB_UShort                flags,
1980                                        HB_UShort                context_length,
1981                                        int                      nesting_level )
1982 {
1983   HB_Error         error;
1984   HB_UShort        index, i, j, property;
1985
1986   HB_Coverage*    c;
1987   HB_GDEFHeader*  gdef;
1988
1989
1990   gdef = gsub->gdef;
1991
1992   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
1993     return error;
1994
1995   if ( context_length != 0xFFFF && context_length < csf3->GlyphCount )
1996     return HB_Err_Not_Covered;
1997
1998   if ( buffer->in_pos + csf3->GlyphCount > buffer->in_length )
1999     return HB_Err_Not_Covered;         /* context is too long */
2000
2001   c    = csf3->Coverage;
2002
2003   for ( i = 1, j = buffer->in_pos + 1; i < csf3->GlyphCount; i++, j++ )
2004   {
2005     while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
2006     {
2007       if ( error && error != HB_Err_Not_Covered )
2008         return error;
2009
2010       if ( j + csf3->GlyphCount - i == (HB_Int)buffer->in_length )
2011         return HB_Err_Not_Covered;
2012       j++;
2013     }
2014
2015     error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index );
2016     if ( error )
2017       return error;
2018   }
2019
2020   return Do_ContextSubst( gsub, csf3->GlyphCount,
2021                           csf3->SubstCount, csf3->SubstLookupRecord,
2022                           buffer,
2023                           nesting_level );
2024 }
2025
2026
2027 static HB_Error  Lookup_ContextSubst( HB_GSUBHeader*    gsub,
2028                                       HB_GSUB_SubTable* st,
2029                                       HB_Buffer         buffer,
2030                                       HB_UShort          flags,
2031                                       HB_UShort          context_length,
2032                                       int                nesting_level )
2033 {
2034   HB_ContextSubst*  cs = &st->context;
2035
2036   switch ( cs->SubstFormat )
2037   {
2038   case 1:  return Lookup_ContextSubst1( gsub, &cs->csf.csf1, buffer, flags, context_length, nesting_level );
2039   case 2:  return Lookup_ContextSubst2( gsub, &cs->csf.csf2, buffer, flags, context_length, nesting_level );
2040   case 3:  return Lookup_ContextSubst3( gsub, &cs->csf.csf3, buffer, flags, context_length, nesting_level );
2041   default: return ERR(HB_Err_Invalid_SubTable_Format);
2042   }
2043
2044   return HB_Err_Ok;               /* never reached */
2045 }
2046
2047
2048 /* LookupType 6 */
2049
2050 /* ChainSubRule */
2051
2052 static HB_Error  Load_ChainSubRule( HB_ChainSubRule*  csr,
2053                                     HB_Stream          stream )
2054 {
2055   HB_Error error;
2056
2057   HB_UShort               n, count;
2058   HB_UShort*              b;
2059   HB_UShort*              i;
2060   HB_UShort*              l;
2061
2062   HB_SubstLookupRecord*  slr;
2063
2064
2065   if ( ACCESS_Frame( 2L ) )
2066     return error;
2067
2068   csr->BacktrackGlyphCount = GET_UShort();
2069
2070   FORGET_Frame();
2071
2072   csr->Backtrack = NULL;
2073
2074   count = csr->BacktrackGlyphCount;
2075
2076   if ( ALLOC_ARRAY( csr->Backtrack, count, HB_UShort ) )
2077     return error;
2078
2079   b = csr->Backtrack;
2080
2081   if ( ACCESS_Frame( count * 2L ) )
2082     goto Fail4;
2083
2084   for ( n = 0; n < count; n++ )
2085     b[n] = GET_UShort();
2086
2087   FORGET_Frame();
2088
2089   if ( ACCESS_Frame( 2L ) )
2090     goto Fail4;
2091
2092   csr->InputGlyphCount = GET_UShort();
2093
2094   FORGET_Frame();
2095
2096   csr->Input = NULL;
2097
2098   count = csr->InputGlyphCount - 1;  /* only InputGlyphCount - 1 elements */
2099
2100   if ( ALLOC_ARRAY( csr->Input, count, HB_UShort ) )
2101     goto Fail4;
2102
2103   i = csr->Input;
2104
2105   if ( ACCESS_Frame( count * 2L ) )
2106     goto Fail3;
2107
2108   for ( n = 0; n < count; n++ )
2109     i[n] = GET_UShort();
2110
2111   FORGET_Frame();
2112
2113   if ( ACCESS_Frame( 2L ) )
2114     goto Fail3;
2115
2116   csr->LookaheadGlyphCount = GET_UShort();
2117
2118   FORGET_Frame();
2119
2120   csr->Lookahead = NULL;
2121
2122   count = csr->LookaheadGlyphCount;
2123
2124   if ( ALLOC_ARRAY( csr->Lookahead, count, HB_UShort ) )
2125     goto Fail3;
2126
2127   l = csr->Lookahead;
2128
2129   if ( ACCESS_Frame( count * 2L ) )
2130     goto Fail2;
2131
2132   for ( n = 0; n < count; n++ )
2133     l[n] = GET_UShort();
2134
2135   FORGET_Frame();
2136
2137   if ( ACCESS_Frame( 2L ) )
2138     goto Fail2;
2139
2140   csr->SubstCount = GET_UShort();
2141
2142   FORGET_Frame();
2143
2144   csr->SubstLookupRecord = NULL;
2145
2146   count = csr->SubstCount;
2147
2148   if ( ALLOC_ARRAY( csr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
2149     goto Fail2;
2150
2151   slr = csr->SubstLookupRecord;
2152
2153   if ( ACCESS_Frame( count * 4L ) )
2154     goto Fail1;
2155
2156   for ( n = 0; n < count; n++ )
2157   {
2158     slr[n].SequenceIndex   = GET_UShort();
2159     slr[n].LookupListIndex = GET_UShort();
2160   }
2161
2162   FORGET_Frame();
2163
2164   return HB_Err_Ok;
2165
2166 Fail1:
2167   FREE( slr );
2168
2169 Fail2:
2170   FREE( l );
2171
2172 Fail3:
2173   FREE( i );
2174
2175 Fail4:
2176   FREE( b );
2177   return error;
2178 }
2179
2180
2181 static void  Free_ChainSubRule( HB_ChainSubRule*  csr )
2182 {
2183   FREE( csr->SubstLookupRecord );
2184   FREE( csr->Lookahead );
2185   FREE( csr->Input );
2186   FREE( csr->Backtrack );
2187 }
2188
2189
2190 /* ChainSubRuleSet */
2191
2192 static HB_Error  Load_ChainSubRuleSet( HB_ChainSubRuleSet*  csrs,
2193                                        HB_Stream             stream )
2194 {
2195   HB_Error error;
2196
2197   HB_UShort          n = 0, m, count;
2198   HB_UInt           cur_offset, new_offset, base_offset;
2199
2200   HB_ChainSubRule*  csr;
2201
2202
2203   base_offset = FILE_Pos();
2204
2205   if ( ACCESS_Frame( 2L ) )
2206     return error;
2207
2208   count = csrs->ChainSubRuleCount = GET_UShort();
2209
2210   FORGET_Frame();
2211
2212   csrs->ChainSubRule = NULL;
2213
2214   if ( ALLOC_ARRAY( csrs->ChainSubRule, count, HB_ChainSubRule ) )
2215     return error;
2216
2217   csr = csrs->ChainSubRule;
2218
2219   for ( n = 0; n < count; n++ )
2220   {
2221     if ( ACCESS_Frame( 2L ) )
2222       goto Fail;
2223
2224     new_offset = GET_UShort() + base_offset;
2225
2226     FORGET_Frame();
2227
2228     cur_offset = FILE_Pos();
2229     if ( FILE_Seek( new_offset ) ||
2230          ( error = Load_ChainSubRule( &csr[n], stream ) ) != HB_Err_Ok )
2231       goto Fail;
2232     (void)FILE_Seek( cur_offset );
2233   }
2234
2235   return HB_Err_Ok;
2236
2237 Fail:
2238   for ( m = 0; m < n; m++ )
2239     Free_ChainSubRule( &csr[m] );
2240
2241   FREE( csr );
2242   return error;
2243 }
2244
2245
2246 static void  Free_ChainSubRuleSet( HB_ChainSubRuleSet*  csrs )
2247 {
2248   HB_UShort          n, count;
2249
2250   HB_ChainSubRule*  csr;
2251
2252
2253   if ( csrs->ChainSubRule )
2254   {
2255     count = csrs->ChainSubRuleCount;
2256     csr   = csrs->ChainSubRule;
2257
2258     for ( n = 0; n < count; n++ )
2259       Free_ChainSubRule( &csr[n] );
2260
2261     FREE( csr );
2262   }
2263 }
2264
2265
2266 /* ChainContextSubstFormat1 */
2267
2268 static HB_Error  Load_ChainContextSubst1(
2269                    HB_ChainContextSubstFormat1*  ccsf1,
2270                    HB_Stream                      stream )
2271 {
2272   HB_Error error;
2273
2274   HB_UShort             n = 0, m, count;
2275   HB_UInt              cur_offset, new_offset, base_offset;
2276
2277   HB_ChainSubRuleSet*  csrs;
2278
2279
2280   base_offset = FILE_Pos() - 2L;
2281
2282   if ( ACCESS_Frame( 2L ) )
2283     return error;
2284
2285   new_offset = GET_UShort() + base_offset;
2286
2287   FORGET_Frame();
2288
2289   cur_offset = FILE_Pos();
2290   if ( FILE_Seek( new_offset ) ||
2291        ( error = _HB_OPEN_Load_Coverage( &ccsf1->Coverage, stream ) ) != HB_Err_Ok )
2292     return error;
2293   (void)FILE_Seek( cur_offset );
2294
2295   if ( ACCESS_Frame( 2L ) )
2296     goto Fail2;
2297
2298   count = ccsf1->ChainSubRuleSetCount = GET_UShort();
2299
2300   FORGET_Frame();
2301
2302   ccsf1->ChainSubRuleSet = NULL;
2303
2304   if ( ALLOC_ARRAY( ccsf1->ChainSubRuleSet, count, HB_ChainSubRuleSet ) )
2305     goto Fail2;
2306
2307   csrs = ccsf1->ChainSubRuleSet;
2308
2309   for ( n = 0; n < count; n++ )
2310   {
2311     if ( ACCESS_Frame( 2L ) )
2312       goto Fail1;
2313
2314     new_offset = GET_UShort() + base_offset;
2315
2316     FORGET_Frame();
2317
2318     cur_offset = FILE_Pos();
2319     if ( FILE_Seek( new_offset ) ||
2320          ( error = Load_ChainSubRuleSet( &csrs[n], stream ) ) != HB_Err_Ok )
2321       goto Fail1;
2322     (void)FILE_Seek( cur_offset );
2323   }
2324
2325   return HB_Err_Ok;
2326
2327 Fail1:
2328   for ( m = 0; m < n; m++ )
2329     Free_ChainSubRuleSet( &csrs[m] );
2330
2331   FREE( csrs );
2332
2333 Fail2:
2334   _HB_OPEN_Free_Coverage( &ccsf1->Coverage );
2335   return error;
2336 }
2337
2338
2339 static void  Free_ChainContextSubst1( HB_ChainContextSubstFormat1*  ccsf1 )
2340 {
2341   HB_UShort             n, count;
2342
2343   HB_ChainSubRuleSet*  csrs;
2344
2345
2346   if ( ccsf1->ChainSubRuleSet )
2347   {
2348     count = ccsf1->ChainSubRuleSetCount;
2349     csrs  = ccsf1->ChainSubRuleSet;
2350
2351     for ( n = 0; n < count; n++ )
2352       Free_ChainSubRuleSet( &csrs[n] );
2353
2354     FREE( csrs );
2355   }
2356
2357   _HB_OPEN_Free_Coverage( &ccsf1->Coverage );
2358 }
2359
2360
2361 /* ChainSubClassRule */
2362
2363 static HB_Error  Load_ChainSubClassRule(
2364                    HB_ChainContextSubstFormat2*  ccsf2,
2365                    HB_ChainSubClassRule*         cscr,
2366                    HB_Stream                      stream )
2367 {
2368   HB_Error error;
2369
2370   HB_UShort               n, count;
2371
2372   HB_UShort*              b;
2373   HB_UShort*              i;
2374   HB_UShort*              l;
2375   HB_SubstLookupRecord*  slr;
2376
2377
2378   if ( ACCESS_Frame( 2L ) )
2379     return error;
2380
2381   cscr->BacktrackGlyphCount = GET_UShort();
2382
2383   FORGET_Frame();
2384
2385   if ( cscr->BacktrackGlyphCount > ccsf2->MaxBacktrackLength )
2386     ccsf2->MaxBacktrackLength = cscr->BacktrackGlyphCount;
2387
2388   cscr->Backtrack = NULL;
2389
2390   count = cscr->BacktrackGlyphCount;
2391
2392   if ( ALLOC_ARRAY( cscr->Backtrack, count, HB_UShort ) )
2393     return error;
2394
2395   b = cscr->Backtrack;
2396
2397   if ( ACCESS_Frame( count * 2L ) )
2398     goto Fail4;
2399
2400   for ( n = 0; n < count; n++ )
2401     b[n] = GET_UShort();
2402
2403   FORGET_Frame();
2404
2405   if ( ACCESS_Frame( 2L ) )
2406     goto Fail4;
2407
2408   cscr->InputGlyphCount = GET_UShort();
2409
2410   FORGET_Frame();
2411
2412   if ( cscr->InputGlyphCount > ccsf2->MaxInputLength )
2413     ccsf2->MaxInputLength = cscr->InputGlyphCount;
2414
2415   cscr->Input = NULL;
2416
2417   count = cscr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
2418
2419   if ( ALLOC_ARRAY( cscr->Input, count, HB_UShort ) )
2420     goto Fail4;
2421
2422   i = cscr->Input;
2423
2424   if ( ACCESS_Frame( count * 2L ) )
2425     goto Fail3;
2426
2427   for ( n = 0; n < count; n++ )
2428     i[n] = GET_UShort();
2429
2430   FORGET_Frame();
2431
2432   if ( ACCESS_Frame( 2L ) )
2433     goto Fail3;
2434
2435   cscr->LookaheadGlyphCount = GET_UShort();
2436
2437   FORGET_Frame();
2438
2439   if ( cscr->LookaheadGlyphCount > ccsf2->MaxLookaheadLength )
2440     ccsf2->MaxLookaheadLength = cscr->LookaheadGlyphCount;
2441
2442   cscr->Lookahead = NULL;
2443
2444   count = cscr->LookaheadGlyphCount;
2445
2446   if ( ALLOC_ARRAY( cscr->Lookahead, count, HB_UShort ) )
2447     goto Fail3;
2448
2449   l = cscr->Lookahead;
2450
2451   if ( ACCESS_Frame( count * 2L ) )
2452     goto Fail2;
2453
2454   for ( n = 0; n < count; n++ )
2455     l[n] = GET_UShort();
2456
2457   FORGET_Frame();
2458
2459   if ( ACCESS_Frame( 2L ) )
2460     goto Fail2;
2461
2462   cscr->SubstCount = GET_UShort();
2463
2464   FORGET_Frame();
2465
2466   cscr->SubstLookupRecord = NULL;
2467
2468   count = cscr->SubstCount;
2469
2470   if ( ALLOC_ARRAY( cscr->SubstLookupRecord, count,
2471                     HB_SubstLookupRecord ) )
2472     goto Fail2;
2473
2474   slr = cscr->SubstLookupRecord;
2475
2476   if ( ACCESS_Frame( count * 4L ) )
2477     goto Fail1;
2478
2479   for ( n = 0; n < count; n++ )
2480   {
2481     slr[n].SequenceIndex   = GET_UShort();
2482     slr[n].LookupListIndex = GET_UShort();
2483   }
2484
2485   FORGET_Frame();
2486
2487   return HB_Err_Ok;
2488
2489 Fail1:
2490   FREE( slr );
2491
2492 Fail2:
2493   FREE( l );
2494
2495 Fail3:
2496   FREE( i );
2497
2498 Fail4:
2499   FREE( b );
2500   return error;
2501 }
2502
2503
2504 static void  Free_ChainSubClassRule( HB_ChainSubClassRule*  cscr )
2505 {
2506   FREE( cscr->SubstLookupRecord );
2507   FREE( cscr->Lookahead );
2508   FREE( cscr->Input );
2509   FREE( cscr->Backtrack );
2510 }
2511
2512
2513 /* SubClassSet */
2514
2515 static HB_Error  Load_ChainSubClassSet(
2516                    HB_ChainContextSubstFormat2*  ccsf2,
2517                    HB_ChainSubClassSet*          cscs,
2518                    HB_Stream                      stream )
2519 {
2520   HB_Error error;
2521
2522   HB_UShort               n = 0, m, count;
2523   HB_UInt                cur_offset, new_offset, base_offset;
2524
2525   HB_ChainSubClassRule*  cscr;
2526
2527
2528   base_offset = FILE_Pos();
2529
2530   if ( ACCESS_Frame( 2L ) )
2531     return error;
2532
2533   count = cscs->ChainSubClassRuleCount = GET_UShort();
2534
2535   FORGET_Frame();
2536
2537   cscs->ChainSubClassRule = NULL;
2538
2539   if ( ALLOC_ARRAY( cscs->ChainSubClassRule, count,
2540                     HB_ChainSubClassRule ) )
2541     return error;
2542
2543   cscr = cscs->ChainSubClassRule;
2544
2545   for ( n = 0; n < count; n++ )
2546   {
2547     if ( ACCESS_Frame( 2L ) )
2548       goto Fail;
2549
2550     new_offset = GET_UShort() + base_offset;
2551
2552     FORGET_Frame();
2553
2554     cur_offset = FILE_Pos();
2555     if ( FILE_Seek( new_offset ) ||
2556          ( error = Load_ChainSubClassRule( ccsf2, &cscr[n],
2557                                            stream ) ) != HB_Err_Ok )
2558       goto Fail;
2559     (void)FILE_Seek( cur_offset );
2560   }
2561
2562   return HB_Err_Ok;
2563
2564 Fail:
2565   for ( m = 0; m < n; m++ )
2566     Free_ChainSubClassRule( &cscr[m] );
2567
2568   FREE( cscr );
2569   return error;
2570 }
2571
2572
2573 static void  Free_ChainSubClassSet( HB_ChainSubClassSet*  cscs )
2574 {
2575   HB_UShort               n, count;
2576
2577   HB_ChainSubClassRule*  cscr;
2578
2579
2580   if ( cscs->ChainSubClassRule )
2581   {
2582     count = cscs->ChainSubClassRuleCount;
2583     cscr  = cscs->ChainSubClassRule;
2584
2585     for ( n = 0; n < count; n++ )
2586       Free_ChainSubClassRule( &cscr[n] );
2587
2588     FREE( cscr );
2589   }
2590 }
2591
2592
2593 /* ChainContextSubstFormat2 */
2594
2595 static HB_Error  Load_ChainContextSubst2(
2596                    HB_ChainContextSubstFormat2*  ccsf2,
2597                    HB_Stream                      stream )
2598 {
2599   HB_Error error;
2600
2601   HB_UShort              n = 0, m, count;
2602   HB_UInt               cur_offset, new_offset, base_offset;
2603   HB_UInt               backtrack_offset, input_offset, lookahead_offset;
2604
2605   HB_ChainSubClassSet*  cscs;
2606
2607
2608   base_offset = FILE_Pos() - 2;
2609
2610   if ( ACCESS_Frame( 2L ) )
2611     return error;
2612
2613   new_offset = GET_UShort() + base_offset;
2614
2615   FORGET_Frame();
2616
2617   cur_offset = FILE_Pos();
2618   if ( FILE_Seek( new_offset ) ||
2619        ( error = _HB_OPEN_Load_Coverage( &ccsf2->Coverage, stream ) ) != HB_Err_Ok )
2620     return error;
2621   (void)FILE_Seek( cur_offset );
2622
2623   if ( ACCESS_Frame( 8L ) )
2624     goto Fail5;
2625
2626   backtrack_offset = GET_UShort();
2627   input_offset     = GET_UShort();
2628   lookahead_offset = GET_UShort();
2629
2630   /* `ChainSubClassSetCount' is the upper limit for input class values,
2631      thus we read it now to make an additional safety check. No limit
2632      is known or needed for the other two class definitions          */
2633
2634   count = ccsf2->ChainSubClassSetCount = GET_UShort();
2635
2636   FORGET_Frame();
2637
2638   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->BacktrackClassDef, 65535,
2639                                                        backtrack_offset, base_offset,
2640                                                        stream ) ) != HB_Err_Ok )
2641       goto Fail5;
2642
2643   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->InputClassDef, count,
2644                                                        input_offset, base_offset,
2645                                                        stream ) ) != HB_Err_Ok )
2646       goto Fail4;
2647   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->LookaheadClassDef, 65535,
2648                                                        lookahead_offset, base_offset,
2649                                                        stream ) ) != HB_Err_Ok )
2650     goto Fail3;
2651
2652   ccsf2->ChainSubClassSet   = NULL;
2653   ccsf2->MaxBacktrackLength = 0;
2654   ccsf2->MaxInputLength     = 0;
2655   ccsf2->MaxLookaheadLength = 0;
2656
2657   if ( ALLOC_ARRAY( ccsf2->ChainSubClassSet, count, HB_ChainSubClassSet ) )
2658     goto Fail2;
2659
2660   cscs = ccsf2->ChainSubClassSet;
2661
2662   for ( n = 0; n < count; n++ )
2663   {
2664     if ( ACCESS_Frame( 2L ) )
2665       goto Fail1;
2666
2667     new_offset = GET_UShort() + base_offset;
2668
2669     FORGET_Frame();
2670
2671     if ( new_offset != base_offset )      /* not a NULL offset */
2672     {
2673       cur_offset = FILE_Pos();
2674       if ( FILE_Seek( new_offset ) ||
2675            ( error = Load_ChainSubClassSet( ccsf2, &cscs[n],
2676                                             stream ) ) != HB_Err_Ok )
2677         goto Fail1;
2678       (void)FILE_Seek( cur_offset );
2679     }
2680     else
2681     {
2682       /* we create a ChainSubClassSet table with no entries */
2683
2684       ccsf2->ChainSubClassSet[n].ChainSubClassRuleCount = 0;
2685       ccsf2->ChainSubClassSet[n].ChainSubClassRule      = NULL;
2686     }
2687   }
2688
2689   return HB_Err_Ok;
2690
2691 Fail1:
2692   for ( m = 0; m < n; m++ )
2693     Free_ChainSubClassSet( &cscs[m] );
2694
2695   FREE( cscs );
2696
2697 Fail2:
2698   _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef );
2699
2700 Fail3:
2701   _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef );
2702
2703 Fail4:
2704   _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef );
2705
2706 Fail5:
2707   _HB_OPEN_Free_Coverage( &ccsf2->Coverage );
2708   return error;
2709 }
2710
2711
2712 static void  Free_ChainContextSubst2( HB_ChainContextSubstFormat2*  ccsf2 )
2713 {
2714   HB_UShort              n, count;
2715
2716   HB_ChainSubClassSet*  cscs;
2717
2718
2719   if ( ccsf2->ChainSubClassSet )
2720   {
2721     count = ccsf2->ChainSubClassSetCount;
2722     cscs  = ccsf2->ChainSubClassSet;
2723
2724     for ( n = 0; n < count; n++ )
2725       Free_ChainSubClassSet( &cscs[n] );
2726
2727     FREE( cscs );
2728   }
2729
2730   _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef );
2731   _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef );
2732   _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef );
2733
2734   _HB_OPEN_Free_Coverage( &ccsf2->Coverage );
2735 }
2736
2737
2738 /* ChainContextSubstFormat3 */
2739
2740 static HB_Error  Load_ChainContextSubst3(
2741                    HB_ChainContextSubstFormat3*  ccsf3,
2742                    HB_Stream                      stream )
2743 {
2744   HB_Error error;
2745
2746   HB_UShort               n, nb = 0, ni =0, nl = 0, m, count;
2747   HB_UShort               backtrack_count, input_count, lookahead_count;
2748   HB_UInt                cur_offset, new_offset, base_offset;
2749
2750   HB_Coverage*           b;
2751   HB_Coverage*           i;
2752   HB_Coverage*           l;
2753   HB_SubstLookupRecord*  slr;
2754
2755
2756   base_offset = FILE_Pos() - 2L;
2757
2758   if ( ACCESS_Frame( 2L ) )
2759     return error;
2760
2761   ccsf3->BacktrackGlyphCount = GET_UShort();
2762
2763   FORGET_Frame();
2764
2765   ccsf3->BacktrackCoverage = NULL;
2766
2767   backtrack_count = ccsf3->BacktrackGlyphCount;
2768
2769   if ( ALLOC_ARRAY( ccsf3->BacktrackCoverage, backtrack_count,
2770                     HB_Coverage ) )
2771     return error;
2772
2773   b = ccsf3->BacktrackCoverage;
2774
2775   for ( nb = 0; nb < backtrack_count; nb++ )
2776   {
2777     if ( ACCESS_Frame( 2L ) )
2778       goto Fail4;
2779
2780     new_offset = GET_UShort() + base_offset;
2781
2782     FORGET_Frame();
2783
2784     cur_offset = FILE_Pos();
2785     if ( FILE_Seek( new_offset ) ||
2786          ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
2787       goto Fail4;
2788     (void)FILE_Seek( cur_offset );
2789   }
2790
2791   if ( ACCESS_Frame( 2L ) )
2792     goto Fail4;
2793
2794   ccsf3->InputGlyphCount = GET_UShort();
2795
2796   FORGET_Frame();
2797
2798   ccsf3->InputCoverage = NULL;
2799
2800   input_count = ccsf3->InputGlyphCount;
2801
2802   if ( ALLOC_ARRAY( ccsf3->InputCoverage, input_count, HB_Coverage ) )
2803     goto Fail4;
2804
2805   i = ccsf3->InputCoverage;
2806
2807   for ( ni = 0; ni < input_count; ni++ )
2808   {
2809     if ( ACCESS_Frame( 2L ) )
2810       goto Fail3;
2811
2812     new_offset = GET_UShort() + base_offset;
2813
2814     FORGET_Frame();
2815
2816     cur_offset = FILE_Pos();
2817     if ( FILE_Seek( new_offset ) ||
2818          ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok )
2819       goto Fail3;
2820     (void)FILE_Seek( cur_offset );
2821   }
2822
2823   if ( ACCESS_Frame( 2L ) )
2824     goto Fail3;
2825
2826   ccsf3->LookaheadGlyphCount = GET_UShort();
2827
2828   FORGET_Frame();
2829
2830   ccsf3->LookaheadCoverage = NULL;
2831
2832   lookahead_count = ccsf3->LookaheadGlyphCount;
2833
2834   if ( ALLOC_ARRAY( ccsf3->LookaheadCoverage, lookahead_count,
2835                     HB_Coverage ) )
2836     goto Fail3;
2837
2838   l = ccsf3->LookaheadCoverage;
2839
2840   for ( nl = 0; nl < lookahead_count; nl++ )
2841   {
2842     if ( ACCESS_Frame( 2L ) )
2843       goto Fail2;
2844
2845     new_offset = GET_UShort() + base_offset;
2846
2847     FORGET_Frame();
2848
2849     cur_offset = FILE_Pos();
2850     if ( FILE_Seek( new_offset ) ||
2851          ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
2852       goto Fail2;
2853     (void)FILE_Seek( cur_offset );
2854   }
2855
2856   if ( ACCESS_Frame( 2L ) )
2857     goto Fail2;
2858
2859   ccsf3->SubstCount = GET_UShort();
2860
2861   FORGET_Frame();
2862
2863   ccsf3->SubstLookupRecord = NULL;
2864
2865   count = ccsf3->SubstCount;
2866
2867   if ( ALLOC_ARRAY( ccsf3->SubstLookupRecord, count,
2868                     HB_SubstLookupRecord ) )
2869     goto Fail2;
2870
2871   slr = ccsf3->SubstLookupRecord;
2872
2873   if ( ACCESS_Frame( count * 4L ) )
2874     goto Fail1;
2875
2876   for ( n = 0; n < count; n++ )
2877   {
2878     slr[n].SequenceIndex   = GET_UShort();
2879     slr[n].LookupListIndex = GET_UShort();
2880   }
2881
2882   FORGET_Frame();
2883
2884   return HB_Err_Ok;
2885
2886 Fail1:
2887   FREE( slr );
2888
2889 Fail2:
2890   for ( m = 0; m < nl; m++ )
2891     _HB_OPEN_Free_Coverage( &l[m] );
2892
2893   FREE( l );
2894
2895 Fail3:
2896   for ( m = 0; m < ni; m++ )
2897     _HB_OPEN_Free_Coverage( &i[m] );
2898
2899   FREE( i );
2900
2901 Fail4:
2902   for ( m = 0; m < nb; m++ )
2903     _HB_OPEN_Free_Coverage( &b[m] );
2904
2905   FREE( b );
2906   return error;
2907 }
2908
2909
2910 static void  Free_ChainContextSubst3( HB_ChainContextSubstFormat3*  ccsf3 )
2911 {
2912   HB_UShort      n, count;
2913
2914   HB_Coverage*  c;
2915
2916
2917   FREE( ccsf3->SubstLookupRecord );
2918
2919   if ( ccsf3->LookaheadCoverage )
2920   {
2921     count = ccsf3->LookaheadGlyphCount;
2922     c     = ccsf3->LookaheadCoverage;
2923
2924     for ( n = 0; n < count; n++ )
2925       _HB_OPEN_Free_Coverage( &c[n] );
2926
2927     FREE( c );
2928   }
2929
2930   if ( ccsf3->InputCoverage )
2931   {
2932     count = ccsf3->InputGlyphCount;
2933     c     = ccsf3->InputCoverage;
2934
2935     for ( n = 0; n < count; n++ )
2936       _HB_OPEN_Free_Coverage( &c[n] );
2937
2938     FREE( c );
2939   }
2940
2941   if ( ccsf3->BacktrackCoverage )
2942   {
2943     count = ccsf3->BacktrackGlyphCount;
2944     c     = ccsf3->BacktrackCoverage;
2945
2946     for ( n = 0; n < count; n++ )
2947       _HB_OPEN_Free_Coverage( &c[n] );
2948
2949     FREE( c );
2950   }
2951 }
2952
2953
2954 /* ChainContextSubst */
2955
2956 static HB_Error  Load_ChainContextSubst( HB_GSUB_SubTable* st,
2957                                          HB_Stream         stream )
2958 {
2959   HB_Error error;
2960   HB_ChainContextSubst*  ccs = &st->chain;
2961
2962   if ( ACCESS_Frame( 2L ) )
2963     return error;
2964
2965   ccs->SubstFormat = GET_UShort();
2966
2967   FORGET_Frame();
2968
2969   switch ( ccs->SubstFormat ) {
2970     case 1:  return Load_ChainContextSubst1( &ccs->ccsf.ccsf1, stream );
2971     case 2:  return Load_ChainContextSubst2( &ccs->ccsf.ccsf2, stream );
2972     case 3:  return Load_ChainContextSubst3( &ccs->ccsf.ccsf3, stream );
2973     default: return ERR(HB_Err_Invalid_SubTable_Format);
2974   }
2975
2976   return HB_Err_Ok;               /* never reached */
2977 }
2978
2979
2980 static void  Free_ChainContextSubst( HB_GSUB_SubTable* st )
2981 {
2982   HB_ChainContextSubst*  ccs = &st->chain;
2983
2984   switch ( ccs->SubstFormat ) {
2985     case 1:  Free_ChainContextSubst1( &ccs->ccsf.ccsf1 ); break;
2986     case 2:  Free_ChainContextSubst2( &ccs->ccsf.ccsf2 ); break;
2987     case 3:  Free_ChainContextSubst3( &ccs->ccsf.ccsf3 ); break;
2988     default:                                                      break;
2989   }
2990 }
2991
2992
2993 static HB_Error  Lookup_ChainContextSubst1( HB_GSUBHeader*               gsub,
2994                                             HB_ChainContextSubstFormat1* ccsf1,
2995                                             HB_Buffer                    buffer,
2996                                             HB_UShort                     flags,
2997                                             HB_UShort                     context_length,
2998                                             int                           nesting_level )
2999 {
3000   HB_UShort          index, property;
3001   HB_UShort          i, j, k, num_csr;
3002   HB_UShort          bgc, igc, lgc;
3003   HB_Error           error;
3004
3005   HB_ChainSubRule*  csr;
3006   HB_ChainSubRule   curr_csr;
3007   HB_GDEFHeader*    gdef;
3008
3009
3010   gdef = gsub->gdef;
3011
3012   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3013     return error;
3014
3015   error = _HB_OPEN_Coverage_Index( &ccsf1->Coverage, IN_CURGLYPH(), &index );
3016   if ( error )
3017     return error;
3018
3019   csr     = ccsf1->ChainSubRuleSet[index].ChainSubRule;
3020   num_csr = ccsf1->ChainSubRuleSet[index].ChainSubRuleCount;
3021
3022   for ( k = 0; k < num_csr; k++ )
3023   {
3024     curr_csr = csr[k];
3025     bgc      = curr_csr.BacktrackGlyphCount;
3026     igc      = curr_csr.InputGlyphCount;
3027     lgc      = curr_csr.LookaheadGlyphCount;
3028
3029     if ( context_length != 0xFFFF && context_length < igc )
3030       goto next_chainsubrule;
3031
3032     /* check whether context is too long; it is a first guess only */
3033
3034     if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
3035       goto next_chainsubrule;
3036
3037     if ( bgc )
3038     {
3039       /* since we don't know in advance the number of glyphs to inspect,
3040          we search backwards for matches in the backtrack glyph array    */
3041
3042       for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
3043       {
3044         while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
3045         {
3046           if ( error && error != HB_Err_Not_Covered )
3047             return error;
3048
3049           if ( j + 1 == bgc - i )
3050             goto next_chainsubrule;
3051           j--;
3052         }
3053
3054         /* In OpenType 1.3, it is undefined whether the offsets of
3055            backtrack glyphs is in logical order or not.  Version 1.4
3056            will clarify this:
3057
3058              Logical order -      a  b  c  d  e  f  g  h  i  j
3059                                               i
3060              Input offsets -                  0  1
3061              Backtrack offsets -  3  2  1  0
3062              Lookahead offsets -                    0  1  2  3           */
3063
3064         if ( OUT_GLYPH( j ) != curr_csr.Backtrack[i] )
3065           goto next_chainsubrule;
3066       }
3067     }
3068
3069     /* Start at 1 because [0] is implied */
3070
3071     for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
3072     {
3073       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3074       {
3075         if ( error && error != HB_Err_Not_Covered )
3076           return error;
3077
3078         if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
3079           goto next_chainsubrule;
3080         j++;
3081       }
3082
3083       if ( IN_GLYPH( j ) != curr_csr.Input[i - 1] )
3084           goto next_chainsubrule;
3085     }
3086
3087     /* we are starting to check for lookahead glyphs right after the
3088        last context glyph                                            */
3089
3090     for ( i = 0; i < lgc; i++, j++ )
3091     {
3092       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3093       {
3094         if ( error && error != HB_Err_Not_Covered )
3095           return error;
3096
3097         if ( j + lgc - i == (HB_Int)buffer->in_length )
3098           goto next_chainsubrule;
3099         j++;
3100       }
3101
3102       if ( IN_GLYPH( j ) != curr_csr.Lookahead[i] )
3103         goto next_chainsubrule;
3104     }
3105
3106     return Do_ContextSubst( gsub, igc,
3107                             curr_csr.SubstCount,
3108                             curr_csr.SubstLookupRecord,
3109                             buffer,
3110                             nesting_level );
3111
3112   next_chainsubrule:
3113     ;
3114   }
3115
3116   return HB_Err_Not_Covered;
3117 }
3118
3119
3120 static HB_Error  Lookup_ChainContextSubst2( HB_GSUBHeader*               gsub,
3121                                             HB_ChainContextSubstFormat2* ccsf2,
3122                                             HB_Buffer                    buffer,
3123                                             HB_UShort                     flags,
3124                                             HB_UShort                     context_length,
3125                                             int                           nesting_level )
3126 {
3127   HB_UShort              index, property;
3128   HB_Error               error;
3129   HB_UShort              i, j, k;
3130   HB_UShort              bgc, igc, lgc;
3131   HB_UShort              known_backtrack_classes,
3132                          known_input_classes,
3133                          known_lookahead_classes;
3134
3135   HB_UShort*             backtrack_classes;
3136   HB_UShort*             input_classes;
3137   HB_UShort*             lookahead_classes;
3138
3139   HB_UShort*             bc;
3140   HB_UShort*             ic;
3141   HB_UShort*             lc;
3142
3143   HB_ChainSubClassSet*  cscs;
3144   HB_ChainSubClassRule  ccsr;
3145   HB_GDEFHeader*        gdef;
3146
3147
3148   gdef = gsub->gdef;
3149
3150   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3151     return error;
3152
3153   /* Note: The coverage table in format 2 doesn't give an index into
3154            anything.  It just lets us know whether or not we need to
3155            do any lookup at all.                                     */
3156
3157   error = _HB_OPEN_Coverage_Index( &ccsf2->Coverage, IN_CURGLYPH(), &index );
3158   if ( error )
3159     return error;
3160
3161   if (ccsf2->MaxInputLength < 1)
3162     return HB_Err_Not_Covered;
3163
3164   if ( ALLOC_ARRAY( backtrack_classes, ccsf2->MaxBacktrackLength, HB_UShort ) )
3165     return error;
3166   known_backtrack_classes = 0;
3167
3168   if ( ALLOC_ARRAY( input_classes, ccsf2->MaxInputLength, HB_UShort ) )
3169     goto End3;
3170   known_input_classes = 1;
3171
3172   if ( ALLOC_ARRAY( lookahead_classes, ccsf2->MaxLookaheadLength, HB_UShort ) )
3173     goto End2;
3174   known_lookahead_classes = 0;
3175
3176   error = _HB_OPEN_Get_Class( &ccsf2->InputClassDef, IN_CURGLYPH(),
3177                      &input_classes[0], NULL );
3178   if ( error && error != HB_Err_Not_Covered )
3179     goto End1;
3180
3181   cscs = &ccsf2->ChainSubClassSet[input_classes[0]];
3182   if ( !cscs )
3183   {
3184     error = ERR(HB_Err_Invalid_SubTable);
3185     goto End1;
3186   }
3187
3188   for ( k = 0; k < cscs->ChainSubClassRuleCount; k++ )
3189   {
3190     ccsr = cscs->ChainSubClassRule[k];
3191     bgc  = ccsr.BacktrackGlyphCount;
3192     igc  = ccsr.InputGlyphCount;
3193     lgc  = ccsr.LookaheadGlyphCount;
3194
3195     if ( context_length != 0xFFFF && context_length < igc )
3196       goto next_chainsubclassrule;
3197
3198     /* check whether context is too long; it is a first guess only */
3199
3200     if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
3201       goto next_chainsubclassrule;
3202
3203     if ( bgc )
3204     {
3205       /* Since we don't know in advance the number of glyphs to inspect,
3206          we search backwards for matches in the backtrack glyph array.
3207          Note that `known_backtrack_classes' starts at index 0.         */
3208
3209       bc       = ccsr.Backtrack;
3210
3211       for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
3212       {
3213         while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
3214         {
3215           if ( error && error != HB_Err_Not_Covered )
3216             goto End1;
3217
3218           if ( j + 1 == bgc - i )
3219             goto next_chainsubclassrule;
3220           j--;
3221         }
3222
3223         if ( i >= known_backtrack_classes )
3224         {
3225           /* Keeps us from having to do this for each rule */
3226
3227           error = _HB_OPEN_Get_Class( &ccsf2->BacktrackClassDef, OUT_GLYPH( j ),
3228                              &backtrack_classes[i], NULL );
3229           if ( error && error != HB_Err_Not_Covered )
3230             goto End1;
3231           known_backtrack_classes = i;
3232         }
3233
3234         if ( bc[i] != backtrack_classes[i] )
3235           goto next_chainsubclassrule;
3236       }
3237     }
3238
3239     ic       = ccsr.Input;
3240
3241     /* Start at 1 because [0] is implied */
3242
3243     for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
3244     {
3245       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3246       {
3247         if ( error && error != HB_Err_Not_Covered )
3248           goto End1;
3249
3250         if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
3251           goto next_chainsubclassrule;
3252         j++;
3253       }
3254
3255       if ( i >= known_input_classes )
3256       {
3257         error = _HB_OPEN_Get_Class( &ccsf2->InputClassDef, IN_GLYPH( j ),
3258                            &input_classes[i], NULL );
3259         if ( error && error != HB_Err_Not_Covered )
3260           goto End1;
3261         known_input_classes = i;
3262       }
3263
3264       if ( ic[i - 1] != input_classes[i] )
3265         goto next_chainsubclassrule;
3266     }
3267
3268     /* we are starting to check for lookahead glyphs right after the
3269        last context glyph                                            */
3270
3271     lc       = ccsr.Lookahead;
3272
3273     for ( i = 0; i < lgc; i++, j++ )
3274     {
3275       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3276       {
3277         if ( error && error != HB_Err_Not_Covered )
3278           goto End1;
3279
3280         if ( j + lgc - i == (HB_Int)buffer->in_length )
3281           goto next_chainsubclassrule;
3282         j++;
3283       }
3284
3285       if ( i >= known_lookahead_classes )
3286       {
3287         error = _HB_OPEN_Get_Class( &ccsf2->LookaheadClassDef, IN_GLYPH( j ),
3288                            &lookahead_classes[i], NULL );
3289         if ( error && error != HB_Err_Not_Covered )
3290           goto End1;
3291         known_lookahead_classes = i;
3292       }
3293
3294       if ( lc[i] != lookahead_classes[i] )
3295         goto next_chainsubclassrule;
3296     }
3297
3298     error = Do_ContextSubst( gsub, igc,
3299                              ccsr.SubstCount,
3300                              ccsr.SubstLookupRecord,
3301                              buffer,
3302                              nesting_level );
3303     goto End1;
3304
3305   next_chainsubclassrule:
3306     ;
3307   }
3308
3309   error = HB_Err_Not_Covered;
3310
3311 End1:
3312   FREE( lookahead_classes );
3313
3314 End2:
3315   FREE( input_classes );
3316
3317 End3:
3318   FREE( backtrack_classes );
3319   return error;
3320 }
3321
3322
3323 static HB_Error  Lookup_ChainContextSubst3( HB_GSUBHeader*               gsub,
3324                                             HB_ChainContextSubstFormat3* ccsf3,
3325                                             HB_Buffer                    buffer,
3326                                             HB_UShort                     flags,
3327                                             HB_UShort                     context_length,
3328                                             int                           nesting_level )
3329 {
3330   HB_UShort        index, i, j, property;
3331   HB_UShort        bgc, igc, lgc;
3332   HB_Error         error;
3333
3334   HB_Coverage*    bc;
3335   HB_Coverage*    ic;
3336   HB_Coverage*    lc;
3337   HB_GDEFHeader*  gdef;
3338
3339
3340   gdef = gsub->gdef;
3341
3342   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3343     return error;
3344
3345   bgc = ccsf3->BacktrackGlyphCount;
3346   igc = ccsf3->InputGlyphCount;
3347   lgc = ccsf3->LookaheadGlyphCount;
3348
3349   if ( context_length != 0xFFFF && context_length < igc )
3350     return HB_Err_Not_Covered;
3351
3352   /* check whether context is too long; it is a first guess only */
3353
3354   if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
3355     return HB_Err_Not_Covered;
3356
3357   if ( bgc )
3358   {
3359     /* Since we don't know in advance the number of glyphs to inspect,
3360        we search backwards for matches in the backtrack glyph array    */
3361
3362     bc       = ccsf3->BacktrackCoverage;
3363
3364     for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
3365     {
3366       while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
3367       {
3368         if ( error && error != HB_Err_Not_Covered )
3369           return error;
3370
3371         if ( j + 1 == bgc - i )
3372           return HB_Err_Not_Covered;
3373         j--;
3374       }
3375
3376       error = _HB_OPEN_Coverage_Index( &bc[i], OUT_GLYPH( j ), &index );
3377       if ( error )
3378         return error;
3379     }
3380   }
3381
3382   ic       = ccsf3->InputCoverage;
3383
3384   for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
3385   {
3386     /* We already called CHECK_Property for IN_GLYPH( buffer->in_pos ) */
3387     while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3388     {
3389       if ( error && error != HB_Err_Not_Covered )
3390         return error;
3391
3392       if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
3393         return HB_Err_Not_Covered;
3394       j++;
3395     }
3396
3397     error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index );
3398     if ( error )
3399       return error;
3400   }
3401
3402   /* we are starting for lookahead glyphs right after the last context
3403      glyph                                                             */
3404
3405   lc       = ccsf3->LookaheadCoverage;
3406
3407   for ( i = 0; i < lgc; i++, j++ )
3408   {
3409     while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3410     {
3411       if ( error && error != HB_Err_Not_Covered )
3412         return error;
3413
3414       if ( j + lgc - i == (HB_Int)buffer->in_length )
3415         return HB_Err_Not_Covered;
3416       j++;
3417     }
3418
3419     error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
3420     if ( error )
3421       return error;
3422   }
3423
3424   return Do_ContextSubst( gsub, igc,
3425                           ccsf3->SubstCount,
3426                           ccsf3->SubstLookupRecord,
3427                           buffer,
3428                           nesting_level );
3429 }
3430
3431
3432 static HB_Error  Lookup_ChainContextSubst( HB_GSUBHeader*    gsub,
3433                                            HB_GSUB_SubTable* st,
3434                                            HB_Buffer         buffer,
3435                                            HB_UShort          flags,
3436                                            HB_UShort          context_length,
3437                                            int                nesting_level )
3438 {
3439   HB_ChainContextSubst*  ccs = &st->chain;
3440
3441   switch ( ccs->SubstFormat ) {
3442     case 1:  return Lookup_ChainContextSubst1( gsub, &ccs->ccsf.ccsf1, buffer, flags, context_length, nesting_level );
3443     case 2:  return Lookup_ChainContextSubst2( gsub, &ccs->ccsf.ccsf2, buffer, flags, context_length, nesting_level );
3444     case 3:  return Lookup_ChainContextSubst3( gsub, &ccs->ccsf.ccsf3, buffer, flags, context_length, nesting_level );
3445     default: return ERR(HB_Err_Invalid_SubTable_Format);
3446   }
3447 }
3448
3449
3450 static HB_Error  Load_ReverseChainContextSubst( HB_GSUB_SubTable* st,
3451                                                 HB_Stream         stream )
3452 {
3453   HB_Error error;
3454   HB_ReverseChainContextSubst*  rccs = &st->reverse;
3455
3456   HB_UShort               m, count;
3457
3458   HB_UShort               nb = 0, nl = 0, n;
3459   HB_UShort               backtrack_count, lookahead_count;
3460   HB_UInt                cur_offset, new_offset, base_offset;
3461
3462   HB_Coverage*           b;
3463   HB_Coverage*           l;
3464   HB_UShort*              sub;
3465
3466   base_offset = FILE_Pos();
3467
3468   if ( ACCESS_Frame( 2L ) )
3469     return error;
3470
3471   rccs->SubstFormat = GET_UShort();
3472
3473   if ( rccs->SubstFormat != 1 )
3474     return ERR(HB_Err_Invalid_SubTable_Format);
3475
3476   FORGET_Frame();
3477
3478   if ( ACCESS_Frame( 2L ) )
3479     return error;
3480
3481   new_offset = GET_UShort() + base_offset;
3482
3483   FORGET_Frame();
3484
3485   cur_offset = FILE_Pos();
3486   if ( FILE_Seek( new_offset ) ||
3487        ( error = _HB_OPEN_Load_Coverage( &rccs->Coverage, stream ) ) != HB_Err_Ok )
3488     return error;
3489   (void)FILE_Seek( cur_offset );
3490
3491
3492   if ( ACCESS_Frame( 2L ) )
3493     goto Fail4;
3494
3495   rccs->BacktrackGlyphCount = GET_UShort();
3496
3497   FORGET_Frame();
3498
3499   rccs->BacktrackCoverage = NULL;
3500
3501   backtrack_count = rccs->BacktrackGlyphCount;
3502
3503   if ( ALLOC_ARRAY( rccs->BacktrackCoverage, backtrack_count,
3504                     HB_Coverage ) )
3505     goto Fail4;
3506
3507   b = rccs->BacktrackCoverage;
3508
3509   for ( nb = 0; nb < backtrack_count; nb++ )
3510   {
3511     if ( ACCESS_Frame( 2L ) )
3512       goto Fail3;
3513
3514     new_offset = GET_UShort() + base_offset;
3515
3516     FORGET_Frame();
3517
3518     cur_offset = FILE_Pos();
3519     if ( FILE_Seek( new_offset ) ||
3520          ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
3521       goto Fail3;
3522     (void)FILE_Seek( cur_offset );
3523   }
3524
3525
3526   if ( ACCESS_Frame( 2L ) )
3527     goto Fail3;
3528
3529   rccs->LookaheadGlyphCount = GET_UShort();
3530
3531   FORGET_Frame();
3532
3533   rccs->LookaheadCoverage = NULL;
3534
3535   lookahead_count = rccs->LookaheadGlyphCount;
3536
3537   if ( ALLOC_ARRAY( rccs->LookaheadCoverage, lookahead_count,
3538                     HB_Coverage ) )
3539     goto Fail3;
3540
3541   l = rccs->LookaheadCoverage;
3542
3543   for ( nl = 0; nl < lookahead_count; nl++ )
3544   {
3545     if ( ACCESS_Frame( 2L ) )
3546       goto Fail2;
3547
3548     new_offset = GET_UShort() + base_offset;
3549
3550     FORGET_Frame();
3551
3552     cur_offset = FILE_Pos();
3553     if ( FILE_Seek( new_offset ) ||
3554          ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
3555       goto Fail2;
3556     (void)FILE_Seek( cur_offset );
3557   }
3558
3559   if ( ACCESS_Frame( 2L ) )
3560     goto Fail2;
3561
3562   rccs->GlyphCount = GET_UShort();
3563
3564   FORGET_Frame();
3565
3566   rccs->Substitute = NULL;
3567
3568   count = rccs->GlyphCount;
3569
3570   if ( ALLOC_ARRAY( rccs->Substitute, count,
3571                     HB_UShort ) )
3572     goto Fail2;
3573
3574   sub = rccs->Substitute;
3575
3576   if ( ACCESS_Frame( count * 2L ) )
3577     goto Fail1;
3578
3579   for ( n = 0; n < count; n++ )
3580     sub[n] = GET_UShort();
3581
3582   FORGET_Frame();
3583
3584   return HB_Err_Ok;
3585
3586 Fail1:
3587   FREE( sub );
3588
3589 Fail2:
3590   for ( m = 0; m < nl; m++ )
3591     _HB_OPEN_Free_Coverage( &l[m] );
3592
3593   FREE( l );
3594
3595 Fail3:
3596   for ( m = 0; m < nb; m++ )
3597     _HB_OPEN_Free_Coverage( &b[m] );
3598
3599   FREE( b );
3600
3601 Fail4:
3602   _HB_OPEN_Free_Coverage( &rccs->Coverage );
3603   return error;
3604 }
3605
3606
3607 static void  Free_ReverseChainContextSubst( HB_GSUB_SubTable* st )
3608 {
3609   HB_UShort      n, count;
3610   HB_ReverseChainContextSubst*  rccs = &st->reverse;
3611
3612   HB_Coverage*  c;
3613
3614   _HB_OPEN_Free_Coverage( &rccs->Coverage );
3615
3616   if ( rccs->LookaheadCoverage )
3617   {
3618     count = rccs->LookaheadGlyphCount;
3619     c     = rccs->LookaheadCoverage;
3620
3621     for ( n = 0; n < count; n++ )
3622       _HB_OPEN_Free_Coverage( &c[n] );
3623
3624     FREE( c );
3625   }
3626
3627   if ( rccs->BacktrackCoverage )
3628   {
3629     count = rccs->BacktrackGlyphCount;
3630     c     = rccs->BacktrackCoverage;
3631
3632     for ( n = 0; n < count; n++ )
3633       _HB_OPEN_Free_Coverage( &c[n] );
3634
3635     FREE( c );
3636   }
3637
3638   FREE ( rccs->Substitute );
3639 }
3640
3641
3642 static HB_Error  Lookup_ReverseChainContextSubst( HB_GSUBHeader*    gsub,
3643                                                   HB_GSUB_SubTable* st,
3644                                                   HB_Buffer         buffer,
3645                                                   HB_UShort          flags,
3646                                                   HB_UShort         context_length,
3647                                                   int               nesting_level )
3648 {
3649   HB_UShort        index, input_index, i, j, property;
3650   HB_UShort        bgc, lgc;
3651   HB_Error         error;
3652
3653   HB_ReverseChainContextSubst*  rccs = &st->reverse;
3654   HB_Coverage*    bc;
3655   HB_Coverage*    lc;
3656   HB_GDEFHeader*  gdef;
3657
3658   if ( nesting_level != 1 || context_length != 0xFFFF )
3659     return HB_Err_Not_Covered;
3660
3661   gdef = gsub->gdef;
3662
3663   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3664     return error;
3665
3666   bgc = rccs->BacktrackGlyphCount;
3667   lgc = rccs->LookaheadGlyphCount;
3668
3669   /* check whether context is too long; it is a first guess only */
3670
3671   if ( bgc > buffer->in_pos || buffer->in_pos + 1 + lgc > buffer->in_length )
3672     return HB_Err_Not_Covered;
3673
3674   if ( bgc )
3675   {
3676     /* Since we don't know in advance the number of glyphs to inspect,
3677        we search backwards for matches in the backtrack glyph array    */
3678
3679     bc       = rccs->BacktrackCoverage;
3680
3681     for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
3682     {
3683       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3684       {
3685         if ( error && error != HB_Err_Not_Covered )
3686           return error;
3687
3688         if ( j + 1 == bgc - i )
3689           return HB_Err_Not_Covered;
3690         j--;
3691       }
3692
3693       error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
3694       if ( error )
3695         return error;
3696     }
3697   }
3698
3699   j = buffer->in_pos;
3700
3701   error = _HB_OPEN_Coverage_Index( &rccs->Coverage, IN_GLYPH( j ), &input_index );
3702   if ( error )
3703       return error;
3704
3705   lc       = rccs->LookaheadCoverage;
3706
3707   for ( i = 0, j = buffer->in_pos + 1; i < lgc; i++, j++ )
3708   {
3709     while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3710     {
3711       if ( error && error != HB_Err_Not_Covered )
3712         return error;
3713
3714       if ( j + lgc - i == (HB_Int)buffer->in_length )
3715         return HB_Err_Not_Covered;
3716       j++;
3717     }
3718
3719     error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
3720     if ( error )
3721       return error;
3722   }
3723
3724   IN_CURGLYPH() = rccs->Substitute[input_index];
3725   buffer->in_pos--; /* Reverse! */
3726
3727   return error;
3728 }
3729
3730
3731
3732 /***********
3733  * GSUB API
3734  ***********/
3735
3736
3737
3738 HB_Error  HB_GSUB_Select_Script( HB_GSUBHeader*  gsub,
3739                                  HB_UInt         script_tag,
3740                                  HB_UShort*       script_index )
3741 {
3742   HB_UShort          n;
3743
3744   HB_ScriptList*    sl;
3745   HB_ScriptRecord*  sr;
3746
3747
3748   if ( !gsub || !script_index )
3749     return ERR(HB_Err_Invalid_Argument);
3750
3751   sl = &gsub->ScriptList;
3752   sr = sl->ScriptRecord;
3753
3754   for ( n = 0; n < sl->ScriptCount; n++ )
3755     if ( script_tag == sr[n].ScriptTag )
3756     {
3757       *script_index = n;
3758
3759       return HB_Err_Ok;
3760     }
3761
3762   return HB_Err_Not_Covered;
3763 }
3764
3765
3766
3767 HB_Error  HB_GSUB_Select_Language( HB_GSUBHeader*  gsub,
3768                                    HB_UInt         language_tag,
3769                                    HB_UShort        script_index,
3770                                    HB_UShort*       language_index,
3771                                    HB_UShort*       req_feature_index )
3772 {
3773   HB_UShort           n;
3774
3775   HB_ScriptList*     sl;
3776   HB_ScriptRecord*   sr;
3777   HB_ScriptTable*    s;
3778   HB_LangSysRecord*  lsr;
3779
3780
3781   if ( !gsub || !language_index || !req_feature_index )
3782     return ERR(HB_Err_Invalid_Argument);
3783
3784   sl = &gsub->ScriptList;
3785   sr = sl->ScriptRecord;
3786
3787   if ( script_index >= sl->ScriptCount )
3788     return ERR(HB_Err_Invalid_Argument);
3789
3790   s   = &sr[script_index].Script;
3791   lsr = s->LangSysRecord;
3792
3793   for ( n = 0; n < s->LangSysCount; n++ )
3794     if ( language_tag == lsr[n].LangSysTag )
3795     {
3796       *language_index = n;
3797       *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
3798
3799       return HB_Err_Ok;
3800     }
3801
3802   return HB_Err_Not_Covered;
3803 }
3804
3805
3806 /* selecting 0xFFFF for language_index asks for the values of the
3807    default language (DefaultLangSys)                              */
3808
3809
3810 HB_Error  HB_GSUB_Select_Feature( HB_GSUBHeader*  gsub,
3811                                   HB_UInt         feature_tag,
3812                                   HB_UShort        script_index,
3813                                   HB_UShort        language_index,
3814                                   HB_UShort*       feature_index )
3815 {
3816   HB_UShort           n;
3817
3818   HB_ScriptList*     sl;
3819   HB_ScriptRecord*   sr;
3820   HB_ScriptTable*    s;
3821   HB_LangSysRecord*  lsr;
3822   HB_LangSys*        ls;
3823   HB_UShort*          fi;
3824
3825   HB_FeatureList*    fl;
3826   HB_FeatureRecord*  fr;
3827
3828
3829   if ( !gsub || !feature_index )
3830     return ERR(HB_Err_Invalid_Argument);
3831
3832   sl = &gsub->ScriptList;
3833   sr = sl->ScriptRecord;
3834
3835   fl = &gsub->FeatureList;
3836   fr = fl->FeatureRecord;
3837
3838   if ( script_index >= sl->ScriptCount )
3839     return ERR(HB_Err_Invalid_Argument);
3840
3841   s   = &sr[script_index].Script;
3842   lsr = s->LangSysRecord;
3843
3844   if ( language_index == 0xFFFF )
3845     ls = &s->DefaultLangSys;
3846   else
3847   {
3848     if ( language_index >= s->LangSysCount )
3849       return ERR(HB_Err_Invalid_Argument);
3850
3851     ls = &lsr[language_index].LangSys;
3852   }
3853
3854   fi = ls->FeatureIndex;
3855
3856   for ( n = 0; n < ls->FeatureCount; n++ )
3857   {
3858     if ( fi[n] >= fl->FeatureCount )
3859       return ERR(HB_Err_Invalid_SubTable_Format);
3860
3861     if ( feature_tag == fr[fi[n]].FeatureTag )
3862     {
3863       *feature_index = fi[n];
3864
3865       return HB_Err_Ok;
3866     }
3867   }
3868
3869   return HB_Err_Not_Covered;
3870 }
3871
3872
3873 /* The next three functions return a null-terminated list */
3874
3875
3876 HB_Error  HB_GSUB_Query_Scripts( HB_GSUBHeader*  gsub,
3877                                  HB_UInt**       script_tag_list )
3878 {
3879   HB_UShort          n;
3880   HB_Error           error;
3881   HB_UInt*          stl;
3882
3883   HB_ScriptList*    sl;
3884   HB_ScriptRecord*  sr;
3885
3886
3887   if ( !gsub || !script_tag_list )
3888     return ERR(HB_Err_Invalid_Argument);
3889
3890   sl = &gsub->ScriptList;
3891   sr = sl->ScriptRecord;
3892
3893   if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) )
3894     return error;
3895
3896   for ( n = 0; n < sl->ScriptCount; n++ )
3897     stl[n] = sr[n].ScriptTag;
3898   stl[n] = 0;
3899
3900   *script_tag_list = stl;
3901
3902   return HB_Err_Ok;
3903 }
3904
3905
3906
3907 HB_Error  HB_GSUB_Query_Languages( HB_GSUBHeader*  gsub,
3908                                    HB_UShort        script_index,
3909                                    HB_UInt**       language_tag_list )
3910 {
3911   HB_UShort           n;
3912   HB_Error            error;
3913   HB_UInt*           ltl;
3914
3915   HB_ScriptList*     sl;
3916   HB_ScriptRecord*   sr;
3917   HB_ScriptTable*    s;
3918   HB_LangSysRecord*  lsr;
3919
3920
3921   if ( !gsub || !language_tag_list )
3922     return ERR(HB_Err_Invalid_Argument);
3923
3924   sl = &gsub->ScriptList;
3925   sr = sl->ScriptRecord;
3926
3927   if ( script_index >= sl->ScriptCount )
3928     return ERR(HB_Err_Invalid_Argument);
3929
3930   s   = &sr[script_index].Script;
3931   lsr = s->LangSysRecord;
3932
3933   if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) )
3934     return error;
3935
3936   for ( n = 0; n < s->LangSysCount; n++ )
3937     ltl[n] = lsr[n].LangSysTag;
3938   ltl[n] = 0;
3939
3940   *language_tag_list = ltl;
3941
3942   return HB_Err_Ok;
3943 }
3944
3945
3946 /* selecting 0xFFFF for language_index asks for the values of the
3947    default language (DefaultLangSys)                              */
3948
3949
3950 HB_Error  HB_GSUB_Query_Features( HB_GSUBHeader*  gsub,
3951                                   HB_UShort        script_index,
3952                                   HB_UShort        language_index,
3953                                   HB_UInt**       feature_tag_list )
3954 {
3955   HB_UShort           n;
3956   HB_Error            error;
3957   HB_UInt*           ftl;
3958
3959   HB_ScriptList*     sl;
3960   HB_ScriptRecord*   sr;
3961   HB_ScriptTable*    s;
3962   HB_LangSysRecord*  lsr;
3963   HB_LangSys*        ls;
3964   HB_UShort*          fi;
3965
3966   HB_FeatureList*    fl;
3967   HB_FeatureRecord*  fr;
3968
3969
3970   if ( !gsub || !feature_tag_list )
3971     return ERR(HB_Err_Invalid_Argument);
3972
3973   sl = &gsub->ScriptList;
3974   sr = sl->ScriptRecord;
3975
3976   fl = &gsub->FeatureList;
3977   fr = fl->FeatureRecord;
3978
3979   if ( script_index >= sl->ScriptCount )
3980     return ERR(HB_Err_Invalid_Argument);
3981
3982   s   = &sr[script_index].Script;
3983   lsr = s->LangSysRecord;
3984
3985   if ( language_index == 0xFFFF )
3986     ls = &s->DefaultLangSys;
3987   else
3988   {
3989     if ( language_index >= s->LangSysCount )
3990       return ERR(HB_Err_Invalid_Argument);
3991
3992     ls = &lsr[language_index].LangSys;
3993   }
3994
3995   fi = ls->FeatureIndex;
3996
3997   if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) )
3998     return error;
3999
4000   for ( n = 0; n < ls->FeatureCount; n++ )
4001   {
4002     if ( fi[n] >= fl->FeatureCount )
4003     {
4004       FREE( ftl );
4005       return ERR(HB_Err_Invalid_SubTable_Format);
4006     }
4007     ftl[n] = fr[fi[n]].FeatureTag;
4008   }
4009   ftl[n] = 0;
4010
4011   *feature_tag_list = ftl;
4012
4013   return HB_Err_Ok;
4014 }
4015
4016
4017 /* Do an individual subtable lookup.  Returns HB_Err_Ok if substitution
4018    has been done, or HB_Err_Not_Covered if not.                        */
4019 static HB_Error  GSUB_Do_Glyph_Lookup( HB_GSUBHeader* gsub,
4020                                        HB_UShort       lookup_index,
4021                                        HB_Buffer      buffer,
4022                                        HB_UShort       context_length,
4023                                        int             nesting_level )
4024 {
4025   HB_Error               error = HB_Err_Not_Covered;
4026   HB_UShort              i, flags, lookup_count;
4027   HB_Lookup*             lo;
4028   int                    lookup_type;
4029
4030   nesting_level++;
4031
4032   if ( nesting_level > HB_MAX_NESTING_LEVEL )
4033     return ERR(HB_Err_Not_Covered); /* ERR() call intended */
4034
4035   lookup_count = gsub->LookupList.LookupCount;
4036   if (lookup_index >= lookup_count)
4037     return error;
4038
4039   lo    = &gsub->LookupList.Lookup[lookup_index];
4040   flags = lo->LookupFlag;
4041   lookup_type = lo->LookupType;
4042
4043   for ( i = 0; i < lo->SubTableCount; i++ )
4044   {
4045     HB_GSUB_SubTable *st = &lo->SubTable[i].st.gsub;
4046
4047     switch (lookup_type) {
4048       case HB_GSUB_LOOKUP_SINGLE:
4049         error = Lookup_SingleSubst              ( gsub, st, buffer, flags, context_length, nesting_level ); break;
4050       case HB_GSUB_LOOKUP_MULTIPLE:
4051         error = Lookup_MultipleSubst            ( gsub, st, buffer, flags, context_length, nesting_level ); break;
4052       case HB_GSUB_LOOKUP_ALTERNATE:
4053         error = Lookup_AlternateSubst           ( gsub, st, buffer, flags, context_length, nesting_level ); break;
4054       case HB_GSUB_LOOKUP_LIGATURE:
4055         error = Lookup_LigatureSubst            ( gsub, st, buffer, flags, context_length, nesting_level ); break;
4056       case HB_GSUB_LOOKUP_CONTEXT:
4057         error = Lookup_ContextSubst             ( gsub, st, buffer, flags, context_length, nesting_level ); break;
4058       case HB_GSUB_LOOKUP_CHAIN:
4059         error = Lookup_ChainContextSubst        ( gsub, st, buffer, flags, context_length, nesting_level ); break;
4060     /*case HB_GSUB_LOOKUP_EXTENSION:
4061         error = Lookup_ExtensionSubst           ( gsub, st, buffer, flags, context_length, nesting_level ); break;*/
4062       case HB_GSUB_LOOKUP_REVERSE_CHAIN:
4063         error = Lookup_ReverseChainContextSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
4064       default:
4065         error = HB_Err_Not_Covered;
4066     };
4067
4068     /* Check whether we have a successful substitution or an error other
4069        than HB_Err_Not_Covered                                          */
4070     if ( error != HB_Err_Not_Covered )
4071       return error;
4072   }
4073
4074   return HB_Err_Not_Covered;
4075 }
4076
4077
4078 HB_INTERNAL HB_Error
4079 _HB_GSUB_Load_SubTable( HB_GSUB_SubTable* st,
4080                         HB_Stream         stream,
4081                         HB_UShort         lookup_type )
4082 {
4083   switch (lookup_type) {
4084     case HB_GSUB_LOOKUP_SINGLE:         return Load_SingleSubst                 ( st, stream );
4085     case HB_GSUB_LOOKUP_MULTIPLE:       return Load_MultipleSubst               ( st, stream );
4086     case HB_GSUB_LOOKUP_ALTERNATE:      return Load_AlternateSubst              ( st, stream );
4087     case HB_GSUB_LOOKUP_LIGATURE:       return Load_LigatureSubst               ( st, stream );
4088     case HB_GSUB_LOOKUP_CONTEXT:        return Load_ContextSubst                ( st, stream );
4089     case HB_GSUB_LOOKUP_CHAIN:          return Load_ChainContextSubst           ( st, stream );
4090   /*case HB_GSUB_LOOKUP_EXTENSION:      return Load_ExtensionSubst              ( st, stream );*/
4091     case HB_GSUB_LOOKUP_REVERSE_CHAIN:  return Load_ReverseChainContextSubst    ( st, stream );
4092     default:                            return ERR(HB_Err_Invalid_SubTable_Format);
4093   };
4094 }
4095
4096
4097 HB_INTERNAL void
4098 _HB_GSUB_Free_SubTable( HB_GSUB_SubTable* st,
4099                         HB_UShort         lookup_type )
4100 {
4101   switch ( lookup_type ) {
4102     case HB_GSUB_LOOKUP_SINGLE:         Free_SingleSubst                ( st ); return;
4103     case HB_GSUB_LOOKUP_MULTIPLE:       Free_MultipleSubst              ( st ); return;
4104     case HB_GSUB_LOOKUP_ALTERNATE:      Free_AlternateSubst             ( st ); return;
4105     case HB_GSUB_LOOKUP_LIGATURE:       Free_LigatureSubst              ( st ); return;
4106     case HB_GSUB_LOOKUP_CONTEXT:        Free_ContextSubst               ( st ); return;
4107     case HB_GSUB_LOOKUP_CHAIN:          Free_ChainContextSubst          ( st ); return;
4108   /*case HB_GSUB_LOOKUP_EXTENSION:      Free_ExtensionSubst             ( st ); return;*/
4109     case HB_GSUB_LOOKUP_REVERSE_CHAIN:  Free_ReverseChainContextSubst   ( st ); return;
4110     default:                                                                    return;
4111   };
4112 }
4113
4114
4115
4116 /* apply one lookup to the input string object */
4117
4118 static HB_Error  GSUB_Do_String_Lookup( HB_GSUBHeader*   gsub,
4119                                    HB_UShort         lookup_index,
4120                                    HB_Buffer        buffer )
4121 {
4122   HB_Error  error, retError = HB_Err_Not_Covered;
4123
4124   HB_UInt*  properties = gsub->LookupList.Properties;
4125   int       lookup_type = gsub->LookupList.Lookup[lookup_index].LookupType;
4126
4127   const int       nesting_level = 0;
4128   /* 0xFFFF indicates that we don't have a context length yet */
4129   const HB_UShort context_length = 0xFFFF;
4130
4131   switch (lookup_type) {
4132
4133     case HB_GSUB_LOOKUP_SINGLE:
4134     case HB_GSUB_LOOKUP_MULTIPLE:
4135     case HB_GSUB_LOOKUP_ALTERNATE:
4136     case HB_GSUB_LOOKUP_LIGATURE:
4137     case HB_GSUB_LOOKUP_CONTEXT:
4138     case HB_GSUB_LOOKUP_CHAIN:
4139       /* in/out forward substitution (implemented lazy) */
4140
4141       _hb_buffer_clear_output ( buffer );
4142       buffer->in_pos = 0;
4143   while ( buffer->in_pos < buffer->in_length )
4144   {
4145     if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
4146     {
4147           error = GSUB_Do_Glyph_Lookup( gsub, lookup_index, buffer, context_length, nesting_level );
4148       if ( error )
4149       {
4150         if ( error != HB_Err_Not_Covered )
4151           return error;
4152       }
4153       else
4154         retError = error;
4155     }
4156     else
4157       error = HB_Err_Not_Covered;
4158
4159     if ( error == HB_Err_Not_Covered )
4160           if ( COPY_Glyph ( buffer ) )
4161         return error;
4162   }
4163       /* we shouldn't swap if error occurred.
4164        *
4165        * also don't swap if nothing changed (ie HB_Err_Not_Covered).
4166        * shouldn't matter in that case though.
4167        */
4168       if ( retError == HB_Err_Ok )
4169         _hb_buffer_swap( buffer );
4170
4171   return retError;
4172
4173     case HB_GSUB_LOOKUP_REVERSE_CHAIN:
4174       /* in-place backward substitution */
4175
4176       buffer->in_pos = buffer->in_length - 1;
4177     do
4178     {
4179       if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
4180         {
4181           error = GSUB_Do_Glyph_Lookup( gsub, lookup_index, buffer, context_length, nesting_level );
4182           if ( error )
4183             {
4184               if ( error != HB_Err_Not_Covered )
4185                 return error;
4186             }
4187           else
4188             retError = error;
4189         }
4190         else
4191           error = HB_Err_Not_Covered;
4192
4193         if ( error == HB_Err_Not_Covered )
4194           buffer->in_pos--;
4195       }
4196       while ((HB_Int) buffer->in_pos >= 0);
4197
4198       return retError;
4199
4200   /*case HB_GSUB_LOOKUP_EXTENSION:*/
4201     default:
4202   return retError;
4203   };
4204 }
4205
4206
4207 HB_Error  HB_GSUB_Add_Feature( HB_GSUBHeader*  gsub,
4208                                HB_UShort        feature_index,
4209                                HB_UInt          property )
4210 {
4211   HB_UShort    i;
4212
4213   HB_Feature  feature;
4214   HB_UInt*     properties;
4215   HB_UShort*   index;
4216   HB_UShort    lookup_count;
4217
4218   /* Each feature can only be added once */
4219
4220   if ( !gsub ||
4221        feature_index >= gsub->FeatureList.FeatureCount ||
4222        gsub->FeatureList.ApplyCount == gsub->FeatureList.FeatureCount )
4223     return ERR(HB_Err_Invalid_Argument);
4224
4225   gsub->FeatureList.ApplyOrder[gsub->FeatureList.ApplyCount++] = feature_index;
4226
4227   properties = gsub->LookupList.Properties;
4228
4229   feature = gsub->FeatureList.FeatureRecord[feature_index].Feature;
4230   index   = feature.LookupListIndex;
4231   lookup_count = gsub->LookupList.LookupCount;
4232
4233   for ( i = 0; i < feature.LookupListCount; i++ )
4234   {
4235     HB_UShort lookup_index = index[i];
4236     if (lookup_index < lookup_count)
4237       properties[lookup_index] |= property;
4238   }
4239
4240   return HB_Err_Ok;
4241 }
4242
4243
4244
4245 HB_Error  HB_GSUB_Clear_Features( HB_GSUBHeader*  gsub )
4246 {
4247   HB_UShort i;
4248
4249   HB_UInt*  properties;
4250
4251
4252   if ( !gsub )
4253     return ERR(HB_Err_Invalid_Argument);
4254
4255   gsub->FeatureList.ApplyCount = 0;
4256
4257   properties = gsub->LookupList.Properties;
4258
4259   for ( i = 0; i < gsub->LookupList.LookupCount; i++ )
4260     properties[i] = 0;
4261
4262   return HB_Err_Ok;
4263 }
4264
4265
4266
4267 HB_Error  HB_GSUB_Register_Alternate_Function( HB_GSUBHeader*  gsub,
4268                                                HB_AltFunction  altfunc,
4269                                                void*            data )
4270 {
4271   if ( !gsub )
4272     return ERR(HB_Err_Invalid_Argument);
4273
4274   gsub->altfunc = altfunc;
4275   gsub->data    = data;
4276
4277   return HB_Err_Ok;
4278 }
4279
4280 /* returns error if one happened, otherwise returns HB_Err_Not_Covered if no
4281  * feature were applied, or HB_Err_Ok otherwise.
4282  */
4283 HB_Error  HB_GSUB_Apply_String( HB_GSUBHeader*   gsub,
4284                                 HB_Buffer        buffer )
4285 {
4286   HB_Error          error, retError = HB_Err_Not_Covered;
4287   int               i, j, lookup_count, num_features;
4288
4289   if ( !gsub ||
4290        !buffer)
4291     return ERR(HB_Err_Invalid_Argument);
4292
4293   if ( buffer->in_length == 0 )
4294     return retError;
4295
4296   lookup_count = gsub->LookupList.LookupCount;
4297   num_features = gsub->FeatureList.ApplyCount;
4298
4299   for ( i = 0; i < num_features; i++)
4300   {
4301     HB_UShort  feature_index = gsub->FeatureList.ApplyOrder[i];
4302     HB_Feature feature = gsub->FeatureList.FeatureRecord[feature_index].Feature;
4303
4304     for ( j = 0; j < feature.LookupListCount; j++ )
4305     {
4306       HB_UShort         lookup_index = feature.LookupListIndex[j];
4307
4308       /* Skip nonexistant lookups */
4309       if (lookup_index >= lookup_count)
4310        continue;
4311
4312         error = GSUB_Do_String_Lookup( gsub, lookup_index, buffer );
4313       if ( error )
4314       {
4315         if ( error != HB_Err_Not_Covered )
4316           return error;
4317       }
4318       else
4319         retError = error;
4320     }
4321   }
4322
4323   error = retError;
4324
4325   return error;
4326 }
4327
4328
4329 /* END */