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 
HB_Load_GSUB_Table(HB_Stream stream,HB_GSUBHeader ** retptr,HB_GDEFHeader * gdef,HB_Stream gdefStream)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 = HB_Err_Ok;
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 
HB_Done_GSUB_Table(HB_GSUBHeader * gsub)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 
Load_SingleSubst(HB_GSUB_SubTable * st,HB_Stream stream)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 
Free_SingleSubst(HB_GSUB_SubTable * st)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 
Lookup_SingleSubst(HB_GSUBHeader * gsub,HB_GSUB_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)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 
Load_Sequence(HB_Sequence * s,HB_Stream stream)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 
Free_Sequence(HB_Sequence * s)366 static void  Free_Sequence( HB_Sequence*  s )
367 {
368   FREE( s->Substitute );
369 }
370 
371 
372 /* MultipleSubstFormat1 */
373 
Load_MultipleSubst(HB_GSUB_SubTable * st,HB_Stream stream)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 
Free_MultipleSubst(HB_GSUB_SubTable * st)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 
Lookup_MultipleSubst(HB_GSUBHeader * gsub,HB_GSUB_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)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 
Load_AlternateSet(HB_AlternateSet * as,HB_Stream stream)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 
Free_AlternateSet(HB_AlternateSet * as)564 static void  Free_AlternateSet( HB_AlternateSet*  as )
565 {
566   FREE( as->Alternate );
567 }
568 
569 
570 /* AlternateSubstFormat1 */
571 
Load_AlternateSubst(HB_GSUB_SubTable * st,HB_Stream stream)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 
Free_AlternateSubst(HB_GSUB_SubTable * st)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 
Lookup_AlternateSubst(HB_GSUBHeader * gsub,HB_GSUB_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)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 
Load_Ligature(HB_Ligature * l,HB_Stream stream)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 
Free_Ligature(HB_Ligature * l)765 static void  Free_Ligature( HB_Ligature*  l )
766 {
767   FREE( l->Component );
768 }
769 
770 
771 /* LigatureSet */
772 
Load_LigatureSet(HB_LigatureSet * ls,HB_Stream stream)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 
Free_LigatureSet(HB_LigatureSet * ls)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 
Load_LigatureSubst(HB_GSUB_SubTable * st,HB_Stream stream)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 
Free_LigatureSubst(HB_GSUB_SubTable * st)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 
Lookup_LigatureSubst(HB_GSUBHeader * gsub,HB_GSUB_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)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 
Do_ContextSubst(HB_GSUBHeader * gsub,HB_UShort GlyphCount,HB_UShort SubstCount,HB_SubstLookupRecord * subst,HB_Buffer buffer,int nesting_level)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 
Load_SubRule(HB_SubRule * sr,HB_Stream stream)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 
Free_SubRule(HB_SubRule * sr)1199 static void  Free_SubRule( HB_SubRule*  sr )
1200 {
1201   FREE( sr->SubstLookupRecord );
1202   FREE( sr->Input );
1203 }
1204 
1205 
1206 /* SubRuleSet */
1207 
Load_SubRuleSet(HB_SubRuleSet * srs,HB_Stream stream)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 
Free_SubRuleSet(HB_SubRuleSet * srs)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 
Load_ContextSubst1(HB_ContextSubstFormat1 * csf1,HB_Stream stream)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 
Free_ContextSubst1(HB_ContextSubstFormat1 * csf1)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 
Load_SubClassRule(HB_ContextSubstFormat2 * csf2,HB_SubClassRule * scr,HB_Stream stream)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 
Free_SubClassRule(HB_SubClassRule * scr)1449 static void  Free_SubClassRule( HB_SubClassRule*  scr )
1450 {
1451   FREE( scr->SubstLookupRecord );
1452   FREE( scr->Class );
1453 }
1454 
1455 
1456 /* SubClassSet */
1457 
Load_SubClassSet(HB_ContextSubstFormat2 * csf2,HB_SubClassSet * scs,HB_Stream stream)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 
Free_SubClassSet(HB_SubClassSet * scs)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 
Load_ContextSubst2(HB_ContextSubstFormat2 * csf2,HB_Stream stream)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 
Free_ContextSubst2(HB_ContextSubstFormat2 * csf2)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 
Load_ContextSubst3(HB_ContextSubstFormat3 * csf3,HB_Stream stream)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 
Free_ContextSubst3(HB_ContextSubstFormat3 * csf3)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 
Load_ContextSubst(HB_GSUB_SubTable * st,HB_Stream stream)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 
Free_ContextSubst(HB_GSUB_SubTable * st)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 
Lookup_ContextSubst1(HB_GSUBHeader * gsub,HB_ContextSubstFormat1 * csf1,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)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 
Lookup_ContextSubst2(HB_GSUBHeader * gsub,HB_ContextSubstFormat2 * csf2,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)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 
Lookup_ContextSubst3(HB_GSUBHeader * gsub,HB_ContextSubstFormat3 * csf3,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)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 
Lookup_ContextSubst(HB_GSUBHeader * gsub,HB_GSUB_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)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 
Load_ChainSubRule(HB_ChainSubRule * csr,HB_Stream stream)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 
Free_ChainSubRule(HB_ChainSubRule * csr)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 
Load_ChainSubRuleSet(HB_ChainSubRuleSet * csrs,HB_Stream stream)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 
Free_ChainSubRuleSet(HB_ChainSubRuleSet * csrs)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 
Load_ChainContextSubst1(HB_ChainContextSubstFormat1 * ccsf1,HB_Stream stream)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 
Free_ChainContextSubst1(HB_ChainContextSubstFormat1 * ccsf1)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 
Load_ChainSubClassRule(HB_ChainContextSubstFormat2 * ccsf2,HB_ChainSubClassRule * cscr,HB_Stream stream)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 
Free_ChainSubClassRule(HB_ChainSubClassRule * cscr)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 
Load_ChainSubClassSet(HB_ChainContextSubstFormat2 * ccsf2,HB_ChainSubClassSet * cscs,HB_Stream stream)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 
Free_ChainSubClassSet(HB_ChainSubClassSet * cscs)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 
Load_ChainContextSubst2(HB_ChainContextSubstFormat2 * ccsf2,HB_Stream stream)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 
Free_ChainContextSubst2(HB_ChainContextSubstFormat2 * ccsf2)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 
Load_ChainContextSubst3(HB_ChainContextSubstFormat3 * ccsf3,HB_Stream stream)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 
Free_ChainContextSubst3(HB_ChainContextSubstFormat3 * ccsf3)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 
Load_ChainContextSubst(HB_GSUB_SubTable * st,HB_Stream stream)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 
Free_ChainContextSubst(HB_GSUB_SubTable * st)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 
Lookup_ChainContextSubst1(HB_GSUBHeader * gsub,HB_ChainContextSubstFormat1 * ccsf1,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)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 
Lookup_ChainContextSubst2(HB_GSUBHeader * gsub,HB_ChainContextSubstFormat2 * ccsf2,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)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 
Lookup_ChainContextSubst3(HB_GSUBHeader * gsub,HB_ChainContextSubstFormat3 * ccsf3,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)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 
Lookup_ChainContextSubst(HB_GSUBHeader * gsub,HB_GSUB_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)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 
Load_ReverseChainContextSubst(HB_GSUB_SubTable * st,HB_Stream stream)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 
Free_ReverseChainContextSubst(HB_GSUB_SubTable * st)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 
Lookup_ReverseChainContextSubst(HB_GSUBHeader * gsub,HB_GSUB_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)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 
HB_GSUB_Select_Script(HB_GSUBHeader * gsub,HB_UInt script_tag,HB_UShort * script_index)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 
HB_GSUB_Select_Language(HB_GSUBHeader * gsub,HB_UInt language_tag,HB_UShort script_index,HB_UShort * language_index,HB_UShort * req_feature_index)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 
HB_GSUB_Select_Feature(HB_GSUBHeader * gsub,HB_UInt feature_tag,HB_UShort script_index,HB_UShort language_index,HB_UShort * feature_index)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 
HB_GSUB_Query_Scripts(HB_GSUBHeader * gsub,HB_UInt ** script_tag_list)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 
HB_GSUB_Query_Languages(HB_GSUBHeader * gsub,HB_UShort script_index,HB_UInt ** language_tag_list)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 
HB_GSUB_Query_Features(HB_GSUBHeader * gsub,HB_UShort script_index,HB_UShort language_index,HB_UInt ** feature_tag_list)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.                        */
GSUB_Do_Glyph_Lookup(HB_GSUBHeader * gsub,HB_UShort lookup_index,HB_Buffer buffer,HB_UShort context_length,int nesting_level)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
_HB_GSUB_Load_SubTable(HB_GSUB_SubTable * st,HB_Stream stream,HB_UShort lookup_type)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
_HB_GSUB_Free_SubTable(HB_GSUB_SubTable * st,HB_UShort lookup_type)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 
GSUB_Do_String_Lookup(HB_GSUBHeader * gsub,HB_UShort lookup_index,HB_Buffer buffer)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 
HB_GSUB_Add_Feature(HB_GSUBHeader * gsub,HB_UShort feature_index,HB_UInt property)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 
HB_GSUB_Clear_Features(HB_GSUBHeader * gsub)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 
HB_GSUB_Register_Alternate_Function(HB_GSUBHeader * gsub,HB_AltFunction altfunc,void * data)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  */
HB_GSUB_Apply_String(HB_GSUBHeader * gsub,HB_Buffer buffer)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 */
4330