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;
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   HB_Bool*                d;
1389 
1390 
1391   if ( ACCESS_Frame( 4L ) )
1392     return error;
1393 
1394   scr->GlyphCount = GET_UShort();
1395   scr->SubstCount = GET_UShort();
1396 
1397   if ( scr->GlyphCount > csf2->MaxContextLength )
1398     csf2->MaxContextLength = scr->GlyphCount;
1399 
1400   FORGET_Frame();
1401 
1402   scr->Class = NULL;
1403 
1404   count = scr->GlyphCount - 1;        /* only GlyphCount - 1 elements */
1405 
1406   if ( ALLOC_ARRAY( scr->Class, count, HB_UShort ) )
1407     return error;
1408 
1409   c = scr->Class;
1410   d = csf2->ClassDef.Defined;
1411 
1412   if ( ACCESS_Frame( count * 2L ) )
1413     goto Fail2;
1414 
1415   for ( n = 0; n < count; n++ )
1416   {
1417     c[n] = GET_UShort();
1418 
1419     /* We check whether the specific class is used at all.  If not,
1420        class 0 is used instead.                                     */
1421     if ( !d[c[n]] )
1422       c[n] = 0;
1423   }
1424 
1425   FORGET_Frame();
1426 
1427   scr->SubstLookupRecord = NULL;
1428 
1429   count = scr->SubstCount;
1430 
1431   if ( ALLOC_ARRAY( scr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
1432     goto Fail2;
1433 
1434   slr = scr->SubstLookupRecord;
1435 
1436   if ( ACCESS_Frame( count * 4L ) )
1437     goto Fail1;
1438 
1439   for ( n = 0; n < count; n++ )
1440   {
1441     slr[n].SequenceIndex   = GET_UShort();
1442     slr[n].LookupListIndex = GET_UShort();
1443   }
1444 
1445   FORGET_Frame();
1446 
1447   return HB_Err_Ok;
1448 
1449 Fail1:
1450   FREE( slr );
1451 
1452 Fail2:
1453   FREE( c );
1454   return error;
1455 }
1456 
1457 
Free_SubClassRule(HB_SubClassRule * scr)1458 static void  Free_SubClassRule( HB_SubClassRule*  scr )
1459 {
1460   FREE( scr->SubstLookupRecord );
1461   FREE( scr->Class );
1462 }
1463 
1464 
1465 /* SubClassSet */
1466 
Load_SubClassSet(HB_ContextSubstFormat2 * csf2,HB_SubClassSet * scs,HB_Stream stream)1467 static HB_Error  Load_SubClassSet( HB_ContextSubstFormat2*  csf2,
1468 				   HB_SubClassSet*          scs,
1469 				   HB_Stream                 stream )
1470 {
1471   HB_Error error;
1472 
1473   HB_UShort          n = 0, m, count;
1474   HB_UInt           cur_offset, new_offset, base_offset;
1475 
1476   HB_SubClassRule*  scr;
1477 
1478 
1479   base_offset = FILE_Pos();
1480 
1481   if ( ACCESS_Frame( 2L ) )
1482     return error;
1483 
1484   count = scs->SubClassRuleCount = GET_UShort();
1485 
1486   FORGET_Frame();
1487 
1488   scs->SubClassRule = NULL;
1489 
1490   if ( ALLOC_ARRAY( scs->SubClassRule, count, HB_SubClassRule ) )
1491     return error;
1492 
1493   scr = scs->SubClassRule;
1494 
1495   for ( n = 0; n < count; n++ )
1496   {
1497     if ( ACCESS_Frame( 2L ) )
1498       goto Fail;
1499 
1500     new_offset = GET_UShort() + base_offset;
1501 
1502     FORGET_Frame();
1503 
1504     cur_offset = FILE_Pos();
1505     if ( FILE_Seek( new_offset ) ||
1506 	 ( error = Load_SubClassRule( csf2, &scr[n],
1507 				      stream ) ) != HB_Err_Ok )
1508       goto Fail;
1509     (void)FILE_Seek( cur_offset );
1510   }
1511 
1512   return HB_Err_Ok;
1513 
1514 Fail:
1515   for ( m = 0; m < n; m++ )
1516     Free_SubClassRule( &scr[m] );
1517 
1518   FREE( scr );
1519   return error;
1520 }
1521 
1522 
Free_SubClassSet(HB_SubClassSet * scs)1523 static void  Free_SubClassSet( HB_SubClassSet*  scs )
1524 {
1525   HB_UShort          n, count;
1526 
1527   HB_SubClassRule*  scr;
1528 
1529 
1530   if ( scs->SubClassRule )
1531   {
1532     count = scs->SubClassRuleCount;
1533     scr   = scs->SubClassRule;
1534 
1535     for ( n = 0; n < count; n++ )
1536       Free_SubClassRule( &scr[n] );
1537 
1538     FREE( scr );
1539   }
1540 }
1541 
1542 
1543 /* ContextSubstFormat2 */
1544 
Load_ContextSubst2(HB_ContextSubstFormat2 * csf2,HB_Stream stream)1545 static HB_Error  Load_ContextSubst2( HB_ContextSubstFormat2*  csf2,
1546 				     HB_Stream                 stream )
1547 {
1548   HB_Error error;
1549 
1550   HB_UShort         n = 0, m, count;
1551   HB_UInt          cur_offset, new_offset, base_offset;
1552 
1553   HB_SubClassSet*  scs;
1554 
1555 
1556   base_offset = FILE_Pos() - 2;
1557 
1558   if ( ACCESS_Frame( 2L ) )
1559     return error;
1560 
1561   new_offset = GET_UShort() + base_offset;
1562 
1563   FORGET_Frame();
1564 
1565   cur_offset = FILE_Pos();
1566   if ( FILE_Seek( new_offset ) ||
1567        ( error = _HB_OPEN_Load_Coverage( &csf2->Coverage, stream ) ) != HB_Err_Ok )
1568     return error;
1569   (void)FILE_Seek( cur_offset );
1570 
1571   if ( ACCESS_Frame( 4L ) )
1572     goto Fail3;
1573 
1574   new_offset = GET_UShort() + base_offset;
1575 
1576   /* `SubClassSetCount' is the upper limit for class values, thus we
1577      read it now to make an additional safety check.                 */
1578 
1579   count = csf2->SubClassSetCount = GET_UShort();
1580 
1581   FORGET_Frame();
1582 
1583   cur_offset = FILE_Pos();
1584   if ( FILE_Seek( new_offset ) ||
1585        ( error = _HB_OPEN_Load_ClassDefinition( &csf2->ClassDef, count,
1586 				       stream ) ) != HB_Err_Ok )
1587     goto Fail3;
1588   (void)FILE_Seek( cur_offset );
1589 
1590   csf2->SubClassSet      = NULL;
1591   csf2->MaxContextLength = 0;
1592 
1593   if ( ALLOC_ARRAY( csf2->SubClassSet, count, HB_SubClassSet ) )
1594     goto Fail2;
1595 
1596   scs = csf2->SubClassSet;
1597 
1598   for ( n = 0; n < count; n++ )
1599   {
1600     if ( ACCESS_Frame( 2L ) )
1601       goto Fail1;
1602 
1603     new_offset = GET_UShort() + base_offset;
1604 
1605     FORGET_Frame();
1606 
1607     if ( new_offset != base_offset )      /* not a NULL offset */
1608     {
1609       cur_offset = FILE_Pos();
1610       if ( FILE_Seek( new_offset ) ||
1611 	   ( error = Load_SubClassSet( csf2, &scs[n],
1612 				       stream ) ) != HB_Err_Ok )
1613 	goto Fail1;
1614       (void)FILE_Seek( cur_offset );
1615     }
1616     else
1617     {
1618       /* we create a SubClassSet table with no entries */
1619 
1620       csf2->SubClassSet[n].SubClassRuleCount = 0;
1621       csf2->SubClassSet[n].SubClassRule      = NULL;
1622     }
1623   }
1624 
1625   return HB_Err_Ok;
1626 
1627 Fail1:
1628   for ( m = 0; m < n; m++ )
1629     Free_SubClassSet( &scs[m] );
1630 
1631   FREE( scs );
1632 
1633 Fail2:
1634   _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef );
1635 
1636 Fail3:
1637   _HB_OPEN_Free_Coverage( &csf2->Coverage );
1638   return error;
1639 }
1640 
1641 
Free_ContextSubst2(HB_ContextSubstFormat2 * csf2)1642 static void  Free_ContextSubst2( HB_ContextSubstFormat2*  csf2 )
1643 {
1644   HB_UShort         n, count;
1645 
1646   HB_SubClassSet*  scs;
1647 
1648 
1649   if ( csf2->SubClassSet )
1650   {
1651     count = csf2->SubClassSetCount;
1652     scs   = csf2->SubClassSet;
1653 
1654     for ( n = 0; n < count; n++ )
1655       Free_SubClassSet( &scs[n] );
1656 
1657     FREE( scs );
1658   }
1659 
1660   _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef );
1661   _HB_OPEN_Free_Coverage( &csf2->Coverage );
1662 }
1663 
1664 
1665 /* ContextSubstFormat3 */
1666 
Load_ContextSubst3(HB_ContextSubstFormat3 * csf3,HB_Stream stream)1667 static HB_Error  Load_ContextSubst3( HB_ContextSubstFormat3*  csf3,
1668 				     HB_Stream                 stream )
1669 {
1670   HB_Error error;
1671 
1672   HB_UShort               n = 0, m, count;
1673   HB_UInt                cur_offset, new_offset, base_offset;
1674 
1675   HB_Coverage*           c;
1676   HB_SubstLookupRecord*  slr;
1677 
1678 
1679   base_offset = FILE_Pos() - 2L;
1680 
1681   if ( ACCESS_Frame( 4L ) )
1682     return error;
1683 
1684   csf3->GlyphCount = GET_UShort();
1685   csf3->SubstCount = GET_UShort();
1686 
1687   FORGET_Frame();
1688 
1689   csf3->Coverage = NULL;
1690 
1691   count = csf3->GlyphCount;
1692 
1693   if ( ALLOC_ARRAY( csf3->Coverage, count, HB_Coverage ) )
1694     return error;
1695 
1696   c = csf3->Coverage;
1697 
1698   for ( n = 0; n < count; n++ )
1699   {
1700     if ( ACCESS_Frame( 2L ) )
1701       goto Fail2;
1702 
1703     new_offset = GET_UShort() + base_offset;
1704 
1705     FORGET_Frame();
1706 
1707     cur_offset = FILE_Pos();
1708     if ( FILE_Seek( new_offset ) ||
1709 	 ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok )
1710       goto Fail2;
1711     (void)FILE_Seek( cur_offset );
1712   }
1713 
1714   csf3->SubstLookupRecord = NULL;
1715 
1716   count = csf3->SubstCount;
1717 
1718   if ( ALLOC_ARRAY( csf3->SubstLookupRecord, count,
1719 		    HB_SubstLookupRecord ) )
1720     goto Fail2;
1721 
1722   slr = csf3->SubstLookupRecord;
1723 
1724   if ( ACCESS_Frame( count * 4L ) )
1725     goto Fail1;
1726 
1727   for ( n = 0; n < count; n++ )
1728   {
1729     slr[n].SequenceIndex   = GET_UShort();
1730     slr[n].LookupListIndex = GET_UShort();
1731   }
1732 
1733   FORGET_Frame();
1734 
1735   return HB_Err_Ok;
1736 
1737 Fail1:
1738   FREE( slr );
1739 
1740 Fail2:
1741   for ( m = 0; m < n; m++ )
1742     _HB_OPEN_Free_Coverage( &c[m] );
1743 
1744   FREE( c );
1745   return error;
1746 }
1747 
1748 
Free_ContextSubst3(HB_ContextSubstFormat3 * csf3)1749 static void  Free_ContextSubst3( HB_ContextSubstFormat3*  csf3 )
1750 {
1751   HB_UShort      n, count;
1752 
1753   HB_Coverage*  c;
1754 
1755 
1756   FREE( csf3->SubstLookupRecord );
1757 
1758   if ( csf3->Coverage )
1759   {
1760     count = csf3->GlyphCount;
1761     c     = csf3->Coverage;
1762 
1763     for ( n = 0; n < count; n++ )
1764       _HB_OPEN_Free_Coverage( &c[n] );
1765 
1766     FREE( c );
1767   }
1768 }
1769 
1770 
1771 /* ContextSubst */
1772 
Load_ContextSubst(HB_GSUB_SubTable * st,HB_Stream stream)1773 static HB_Error  Load_ContextSubst( HB_GSUB_SubTable* st,
1774 				    HB_Stream         stream )
1775 {
1776   HB_Error error;
1777   HB_ContextSubst*  cs = &st->context;
1778 
1779 
1780   if ( ACCESS_Frame( 2L ) )
1781     return error;
1782 
1783   cs->SubstFormat = GET_UShort();
1784 
1785   FORGET_Frame();
1786 
1787   switch ( cs->SubstFormat )
1788   {
1789   case 1:  return Load_ContextSubst1( &cs->csf.csf1, stream );
1790   case 2:  return Load_ContextSubst2( &cs->csf.csf2, stream );
1791   case 3:  return Load_ContextSubst3( &cs->csf.csf3, stream );
1792   default: return ERR(HB_Err_Invalid_SubTable_Format);
1793   }
1794 
1795   return HB_Err_Ok;               /* never reached */
1796 }
1797 
1798 
Free_ContextSubst(HB_GSUB_SubTable * st)1799 static void  Free_ContextSubst( HB_GSUB_SubTable* st )
1800 {
1801   HB_ContextSubst*  cs = &st->context;
1802 
1803   switch ( cs->SubstFormat )
1804   {
1805   case 1:  Free_ContextSubst1( &cs->csf.csf1 ); break;
1806   case 2:  Free_ContextSubst2( &cs->csf.csf2 ); break;
1807   case 3:  Free_ContextSubst3( &cs->csf.csf3 ); break;
1808   default:						break;
1809   }
1810 }
1811 
1812 
Lookup_ContextSubst1(HB_GSUBHeader * gsub,HB_ContextSubstFormat1 * csf1,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)1813 static HB_Error  Lookup_ContextSubst1( HB_GSUBHeader*          gsub,
1814 				       HB_ContextSubstFormat1* csf1,
1815 				       HB_Buffer               buffer,
1816 				       HB_UShort                flags,
1817 				       HB_UShort                context_length,
1818 				       int                      nesting_level )
1819 {
1820   HB_UShort        index, property;
1821   HB_UShort        i, j, k, numsr;
1822   HB_Error         error;
1823 
1824   HB_SubRule*     sr;
1825   HB_GDEFHeader*  gdef;
1826 
1827 
1828   gdef = gsub->gdef;
1829 
1830   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
1831     return error;
1832 
1833   error = _HB_OPEN_Coverage_Index( &csf1->Coverage, IN_CURGLYPH(), &index );
1834   if ( error )
1835     return error;
1836 
1837   sr    = csf1->SubRuleSet[index].SubRule;
1838   numsr = csf1->SubRuleSet[index].SubRuleCount;
1839 
1840   for ( k = 0; k < numsr; k++ )
1841   {
1842     if ( context_length != 0xFFFF && context_length < sr[k].GlyphCount )
1843       goto next_subrule;
1844 
1845     if ( buffer->in_pos + sr[k].GlyphCount > buffer->in_length )
1846       goto next_subrule;                        /* context is too long */
1847 
1848     for ( i = 1, j = buffer->in_pos + 1; i < sr[k].GlyphCount; i++, j++ )
1849     {
1850       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
1851       {
1852 	if ( error && error != HB_Err_Not_Covered )
1853 	  return error;
1854 
1855 	if ( j + sr[k].GlyphCount - i == (HB_Int)buffer->in_length )
1856 	  goto next_subrule;
1857 	j++;
1858       }
1859 
1860       if ( IN_GLYPH( j ) != sr[k].Input[i - 1] )
1861 	goto next_subrule;
1862     }
1863 
1864     return Do_ContextSubst( gsub, sr[k].GlyphCount,
1865 			    sr[k].SubstCount, sr[k].SubstLookupRecord,
1866 			    buffer,
1867 			    nesting_level );
1868   next_subrule:
1869     ;
1870   }
1871 
1872   return HB_Err_Not_Covered;
1873 }
1874 
1875 
Lookup_ContextSubst2(HB_GSUBHeader * gsub,HB_ContextSubstFormat2 * csf2,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)1876 static HB_Error  Lookup_ContextSubst2( HB_GSUBHeader*          gsub,
1877 				       HB_ContextSubstFormat2* csf2,
1878 				       HB_Buffer               buffer,
1879 				       HB_UShort                flags,
1880 				       HB_UShort                context_length,
1881 				       int                      nesting_level )
1882 {
1883   HB_UShort          index, property;
1884   HB_Error           error;
1885   HB_UShort          i, j, k, known_classes;
1886 
1887   HB_UShort*         classes;
1888   HB_UShort*         cl;
1889 
1890   HB_SubClassSet*   scs;
1891   HB_SubClassRule*  sr;
1892   HB_GDEFHeader*    gdef;
1893 
1894 
1895   gdef = gsub->gdef;
1896 
1897   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
1898     return error;
1899 
1900   /* Note: The coverage table in format 2 doesn't give an index into
1901 	   anything.  It just lets us know whether or not we need to
1902 	   do any lookup at all.                                     */
1903 
1904   error = _HB_OPEN_Coverage_Index( &csf2->Coverage, IN_CURGLYPH(), &index );
1905   if ( error )
1906     return error;
1907 
1908   if ( ALLOC_ARRAY( classes, csf2->MaxContextLength, HB_UShort ) )
1909     return error;
1910 
1911   error = _HB_OPEN_Get_Class( &csf2->ClassDef, IN_CURGLYPH(),
1912 		     &classes[0], NULL );
1913   if ( error && error != HB_Err_Not_Covered )
1914     goto End;
1915   known_classes = 0;
1916 
1917   scs = &csf2->SubClassSet[classes[0]];
1918   if ( !scs )
1919   {
1920     error = ERR(HB_Err_Invalid_SubTable);
1921     goto End;
1922   }
1923 
1924   for ( k = 0; k < scs->SubClassRuleCount; k++ )
1925   {
1926     sr  = &scs->SubClassRule[k];
1927 
1928     if ( context_length != 0xFFFF && context_length < sr->GlyphCount )
1929       goto next_subclassrule;
1930 
1931     if ( buffer->in_pos + sr->GlyphCount > buffer->in_length )
1932       goto next_subclassrule;                      /* context is too long */
1933 
1934     cl   = sr->Class;
1935 
1936     /* Start at 1 because [0] is implied */
1937 
1938     for ( i = 1, j = buffer->in_pos + 1; i < sr->GlyphCount; i++, j++ )
1939     {
1940       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
1941       {
1942 	if ( error && error != HB_Err_Not_Covered )
1943 	  goto End;
1944 
1945 	if ( j + sr->GlyphCount - i < (HB_Int)buffer->in_length )
1946 	  goto next_subclassrule;
1947 	j++;
1948       }
1949 
1950       if ( i > known_classes )
1951       {
1952 	/* Keeps us from having to do this for each rule */
1953 
1954 	error = _HB_OPEN_Get_Class( &csf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
1955 	if ( error && error != HB_Err_Not_Covered )
1956 	  goto End;
1957 	known_classes = i;
1958       }
1959 
1960       if ( cl[i - 1] != classes[i] )
1961 	goto next_subclassrule;
1962     }
1963 
1964     error = Do_ContextSubst( gsub, sr->GlyphCount,
1965 			     sr->SubstCount, sr->SubstLookupRecord,
1966 			     buffer,
1967 			     nesting_level );
1968     goto End;
1969 
1970   next_subclassrule:
1971     ;
1972   }
1973 
1974   error = HB_Err_Not_Covered;
1975 
1976 End:
1977   FREE( classes );
1978   return error;
1979 }
1980 
1981 
Lookup_ContextSubst3(HB_GSUBHeader * gsub,HB_ContextSubstFormat3 * csf3,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)1982 static HB_Error  Lookup_ContextSubst3( HB_GSUBHeader*          gsub,
1983 				       HB_ContextSubstFormat3* csf3,
1984 				       HB_Buffer               buffer,
1985 				       HB_UShort                flags,
1986 				       HB_UShort                context_length,
1987 				       int                      nesting_level )
1988 {
1989   HB_Error         error;
1990   HB_UShort        index, i, j, property;
1991 
1992   HB_Coverage*    c;
1993   HB_GDEFHeader*  gdef;
1994 
1995 
1996   gdef = gsub->gdef;
1997 
1998   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
1999     return error;
2000 
2001   if ( context_length != 0xFFFF && context_length < csf3->GlyphCount )
2002     return HB_Err_Not_Covered;
2003 
2004   if ( buffer->in_pos + csf3->GlyphCount > buffer->in_length )
2005     return HB_Err_Not_Covered;         /* context is too long */
2006 
2007   c    = csf3->Coverage;
2008 
2009   for ( i = 1, j = buffer->in_pos + 1; i < csf3->GlyphCount; i++, j++ )
2010   {
2011     while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
2012     {
2013       if ( error && error != HB_Err_Not_Covered )
2014 	return error;
2015 
2016       if ( j + csf3->GlyphCount - i == (HB_Int)buffer->in_length )
2017 	return HB_Err_Not_Covered;
2018       j++;
2019     }
2020 
2021     error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index );
2022     if ( error )
2023       return error;
2024   }
2025 
2026   return Do_ContextSubst( gsub, csf3->GlyphCount,
2027 			  csf3->SubstCount, csf3->SubstLookupRecord,
2028 			  buffer,
2029 			  nesting_level );
2030 }
2031 
2032 
Lookup_ContextSubst(HB_GSUBHeader * gsub,HB_GSUB_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)2033 static HB_Error  Lookup_ContextSubst( HB_GSUBHeader*    gsub,
2034 				      HB_GSUB_SubTable* st,
2035 				      HB_Buffer         buffer,
2036 				      HB_UShort          flags,
2037 				      HB_UShort          context_length,
2038 				      int                nesting_level )
2039 {
2040   HB_ContextSubst*  cs = &st->context;
2041 
2042   switch ( cs->SubstFormat )
2043   {
2044   case 1:  return Lookup_ContextSubst1( gsub, &cs->csf.csf1, buffer, flags, context_length, nesting_level );
2045   case 2:  return Lookup_ContextSubst2( gsub, &cs->csf.csf2, buffer, flags, context_length, nesting_level );
2046   case 3:  return Lookup_ContextSubst3( gsub, &cs->csf.csf3, buffer, flags, context_length, nesting_level );
2047   default: return ERR(HB_Err_Invalid_SubTable_Format);
2048   }
2049 
2050   return HB_Err_Ok;               /* never reached */
2051 }
2052 
2053 
2054 /* LookupType 6 */
2055 
2056 /* ChainSubRule */
2057 
Load_ChainSubRule(HB_ChainSubRule * csr,HB_Stream stream)2058 static HB_Error  Load_ChainSubRule( HB_ChainSubRule*  csr,
2059 				    HB_Stream          stream )
2060 {
2061   HB_Error error;
2062 
2063   HB_UShort               n, count;
2064   HB_UShort*              b;
2065   HB_UShort*              i;
2066   HB_UShort*              l;
2067 
2068   HB_SubstLookupRecord*  slr;
2069 
2070 
2071   if ( ACCESS_Frame( 2L ) )
2072     return error;
2073 
2074   csr->BacktrackGlyphCount = GET_UShort();
2075 
2076   FORGET_Frame();
2077 
2078   csr->Backtrack = NULL;
2079 
2080   count = csr->BacktrackGlyphCount;
2081 
2082   if ( ALLOC_ARRAY( csr->Backtrack, count, HB_UShort ) )
2083     return error;
2084 
2085   b = csr->Backtrack;
2086 
2087   if ( ACCESS_Frame( count * 2L ) )
2088     goto Fail4;
2089 
2090   for ( n = 0; n < count; n++ )
2091     b[n] = GET_UShort();
2092 
2093   FORGET_Frame();
2094 
2095   if ( ACCESS_Frame( 2L ) )
2096     goto Fail4;
2097 
2098   csr->InputGlyphCount = GET_UShort();
2099 
2100   FORGET_Frame();
2101 
2102   csr->Input = NULL;
2103 
2104   count = csr->InputGlyphCount - 1;  /* only InputGlyphCount - 1 elements */
2105 
2106   if ( ALLOC_ARRAY( csr->Input, count, HB_UShort ) )
2107     goto Fail4;
2108 
2109   i = csr->Input;
2110 
2111   if ( ACCESS_Frame( count * 2L ) )
2112     goto Fail3;
2113 
2114   for ( n = 0; n < count; n++ )
2115     i[n] = GET_UShort();
2116 
2117   FORGET_Frame();
2118 
2119   if ( ACCESS_Frame( 2L ) )
2120     goto Fail3;
2121 
2122   csr->LookaheadGlyphCount = GET_UShort();
2123 
2124   FORGET_Frame();
2125 
2126   csr->Lookahead = NULL;
2127 
2128   count = csr->LookaheadGlyphCount;
2129 
2130   if ( ALLOC_ARRAY( csr->Lookahead, count, HB_UShort ) )
2131     goto Fail3;
2132 
2133   l = csr->Lookahead;
2134 
2135   if ( ACCESS_Frame( count * 2L ) )
2136     goto Fail2;
2137 
2138   for ( n = 0; n < count; n++ )
2139     l[n] = GET_UShort();
2140 
2141   FORGET_Frame();
2142 
2143   if ( ACCESS_Frame( 2L ) )
2144     goto Fail2;
2145 
2146   csr->SubstCount = GET_UShort();
2147 
2148   FORGET_Frame();
2149 
2150   csr->SubstLookupRecord = NULL;
2151 
2152   count = csr->SubstCount;
2153 
2154   if ( ALLOC_ARRAY( csr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
2155     goto Fail2;
2156 
2157   slr = csr->SubstLookupRecord;
2158 
2159   if ( ACCESS_Frame( count * 4L ) )
2160     goto Fail1;
2161 
2162   for ( n = 0; n < count; n++ )
2163   {
2164     slr[n].SequenceIndex   = GET_UShort();
2165     slr[n].LookupListIndex = GET_UShort();
2166   }
2167 
2168   FORGET_Frame();
2169 
2170   return HB_Err_Ok;
2171 
2172 Fail1:
2173   FREE( slr );
2174 
2175 Fail2:
2176   FREE( l );
2177 
2178 Fail3:
2179   FREE( i );
2180 
2181 Fail4:
2182   FREE( b );
2183   return error;
2184 }
2185 
2186 
Free_ChainSubRule(HB_ChainSubRule * csr)2187 static void  Free_ChainSubRule( HB_ChainSubRule*  csr )
2188 {
2189   FREE( csr->SubstLookupRecord );
2190   FREE( csr->Lookahead );
2191   FREE( csr->Input );
2192   FREE( csr->Backtrack );
2193 }
2194 
2195 
2196 /* ChainSubRuleSet */
2197 
Load_ChainSubRuleSet(HB_ChainSubRuleSet * csrs,HB_Stream stream)2198 static HB_Error  Load_ChainSubRuleSet( HB_ChainSubRuleSet*  csrs,
2199 				       HB_Stream             stream )
2200 {
2201   HB_Error error;
2202 
2203   HB_UShort          n = 0, m, count;
2204   HB_UInt           cur_offset, new_offset, base_offset;
2205 
2206   HB_ChainSubRule*  csr;
2207 
2208 
2209   base_offset = FILE_Pos();
2210 
2211   if ( ACCESS_Frame( 2L ) )
2212     return error;
2213 
2214   count = csrs->ChainSubRuleCount = GET_UShort();
2215 
2216   FORGET_Frame();
2217 
2218   csrs->ChainSubRule = NULL;
2219 
2220   if ( ALLOC_ARRAY( csrs->ChainSubRule, count, HB_ChainSubRule ) )
2221     return error;
2222 
2223   csr = csrs->ChainSubRule;
2224 
2225   for ( n = 0; n < count; n++ )
2226   {
2227     if ( ACCESS_Frame( 2L ) )
2228       goto Fail;
2229 
2230     new_offset = GET_UShort() + base_offset;
2231 
2232     FORGET_Frame();
2233 
2234     cur_offset = FILE_Pos();
2235     if ( FILE_Seek( new_offset ) ||
2236 	 ( error = Load_ChainSubRule( &csr[n], stream ) ) != HB_Err_Ok )
2237       goto Fail;
2238     (void)FILE_Seek( cur_offset );
2239   }
2240 
2241   return HB_Err_Ok;
2242 
2243 Fail:
2244   for ( m = 0; m < n; m++ )
2245     Free_ChainSubRule( &csr[m] );
2246 
2247   FREE( csr );
2248   return error;
2249 }
2250 
2251 
Free_ChainSubRuleSet(HB_ChainSubRuleSet * csrs)2252 static void  Free_ChainSubRuleSet( HB_ChainSubRuleSet*  csrs )
2253 {
2254   HB_UShort          n, count;
2255 
2256   HB_ChainSubRule*  csr;
2257 
2258 
2259   if ( csrs->ChainSubRule )
2260   {
2261     count = csrs->ChainSubRuleCount;
2262     csr   = csrs->ChainSubRule;
2263 
2264     for ( n = 0; n < count; n++ )
2265       Free_ChainSubRule( &csr[n] );
2266 
2267     FREE( csr );
2268   }
2269 }
2270 
2271 
2272 /* ChainContextSubstFormat1 */
2273 
Load_ChainContextSubst1(HB_ChainContextSubstFormat1 * ccsf1,HB_Stream stream)2274 static HB_Error  Load_ChainContextSubst1(
2275 		   HB_ChainContextSubstFormat1*  ccsf1,
2276 		   HB_Stream                      stream )
2277 {
2278   HB_Error error;
2279 
2280   HB_UShort             n = 0, m, count;
2281   HB_UInt              cur_offset, new_offset, base_offset;
2282 
2283   HB_ChainSubRuleSet*  csrs;
2284 
2285 
2286   base_offset = FILE_Pos() - 2L;
2287 
2288   if ( ACCESS_Frame( 2L ) )
2289     return error;
2290 
2291   new_offset = GET_UShort() + base_offset;
2292 
2293   FORGET_Frame();
2294 
2295   cur_offset = FILE_Pos();
2296   if ( FILE_Seek( new_offset ) ||
2297        ( error = _HB_OPEN_Load_Coverage( &ccsf1->Coverage, stream ) ) != HB_Err_Ok )
2298     return error;
2299   (void)FILE_Seek( cur_offset );
2300 
2301   if ( ACCESS_Frame( 2L ) )
2302     goto Fail2;
2303 
2304   count = ccsf1->ChainSubRuleSetCount = GET_UShort();
2305 
2306   FORGET_Frame();
2307 
2308   ccsf1->ChainSubRuleSet = NULL;
2309 
2310   if ( ALLOC_ARRAY( ccsf1->ChainSubRuleSet, count, HB_ChainSubRuleSet ) )
2311     goto Fail2;
2312 
2313   csrs = ccsf1->ChainSubRuleSet;
2314 
2315   for ( n = 0; n < count; n++ )
2316   {
2317     if ( ACCESS_Frame( 2L ) )
2318       goto Fail1;
2319 
2320     new_offset = GET_UShort() + base_offset;
2321 
2322     FORGET_Frame();
2323 
2324     cur_offset = FILE_Pos();
2325     if ( FILE_Seek( new_offset ) ||
2326 	 ( error = Load_ChainSubRuleSet( &csrs[n], stream ) ) != HB_Err_Ok )
2327       goto Fail1;
2328     (void)FILE_Seek( cur_offset );
2329   }
2330 
2331   return HB_Err_Ok;
2332 
2333 Fail1:
2334   for ( m = 0; m < n; m++ )
2335     Free_ChainSubRuleSet( &csrs[m] );
2336 
2337   FREE( csrs );
2338 
2339 Fail2:
2340   _HB_OPEN_Free_Coverage( &ccsf1->Coverage );
2341   return error;
2342 }
2343 
2344 
Free_ChainContextSubst1(HB_ChainContextSubstFormat1 * ccsf1)2345 static void  Free_ChainContextSubst1( HB_ChainContextSubstFormat1*  ccsf1 )
2346 {
2347   HB_UShort             n, count;
2348 
2349   HB_ChainSubRuleSet*  csrs;
2350 
2351 
2352   if ( ccsf1->ChainSubRuleSet )
2353   {
2354     count = ccsf1->ChainSubRuleSetCount;
2355     csrs  = ccsf1->ChainSubRuleSet;
2356 
2357     for ( n = 0; n < count; n++ )
2358       Free_ChainSubRuleSet( &csrs[n] );
2359 
2360     FREE( csrs );
2361   }
2362 
2363   _HB_OPEN_Free_Coverage( &ccsf1->Coverage );
2364 }
2365 
2366 
2367 /* ChainSubClassRule */
2368 
Load_ChainSubClassRule(HB_ChainContextSubstFormat2 * ccsf2,HB_ChainSubClassRule * cscr,HB_Stream stream)2369 static HB_Error  Load_ChainSubClassRule(
2370 		   HB_ChainContextSubstFormat2*  ccsf2,
2371 		   HB_ChainSubClassRule*         cscr,
2372 		   HB_Stream                      stream )
2373 {
2374   HB_Error error;
2375 
2376   HB_UShort               n, count;
2377 
2378   HB_UShort*              b;
2379   HB_UShort*              i;
2380   HB_UShort*              l;
2381   HB_SubstLookupRecord*  slr;
2382   HB_Bool*                d;
2383 
2384 
2385   if ( ACCESS_Frame( 2L ) )
2386     return error;
2387 
2388   cscr->BacktrackGlyphCount = GET_UShort();
2389 
2390   FORGET_Frame();
2391 
2392   if ( cscr->BacktrackGlyphCount > ccsf2->MaxBacktrackLength )
2393     ccsf2->MaxBacktrackLength = cscr->BacktrackGlyphCount;
2394 
2395   cscr->Backtrack = NULL;
2396 
2397   count = cscr->BacktrackGlyphCount;
2398 
2399   if ( ALLOC_ARRAY( cscr->Backtrack, count, HB_UShort ) )
2400     return error;
2401 
2402   b = cscr->Backtrack;
2403   d = ccsf2->BacktrackClassDef.Defined;
2404 
2405   if ( ACCESS_Frame( count * 2L ) )
2406     goto Fail4;
2407 
2408   for ( n = 0; n < count; n++ )
2409   {
2410     b[n] = GET_UShort();
2411 
2412     /* We check whether the specific class is used at all.  If not,
2413        class 0 is used instead.                                     */
2414 
2415     if ( !d[b[n]] )
2416       b[n] = 0;
2417   }
2418 
2419   FORGET_Frame();
2420 
2421   if ( ACCESS_Frame( 2L ) )
2422     goto Fail4;
2423 
2424   cscr->InputGlyphCount = GET_UShort();
2425 
2426   FORGET_Frame();
2427 
2428   if ( cscr->InputGlyphCount > ccsf2->MaxInputLength )
2429     ccsf2->MaxInputLength = cscr->InputGlyphCount;
2430 
2431   cscr->Input = NULL;
2432 
2433   count = cscr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
2434 
2435   if ( ALLOC_ARRAY( cscr->Input, count, HB_UShort ) )
2436     goto Fail4;
2437 
2438   i = cscr->Input;
2439   d = ccsf2->InputClassDef.Defined;
2440 
2441   if ( ACCESS_Frame( count * 2L ) )
2442     goto Fail3;
2443 
2444   for ( n = 0; n < count; n++ )
2445   {
2446     i[n] = GET_UShort();
2447 
2448     if ( !d[i[n]] )
2449       i[n] = 0;
2450   }
2451 
2452   FORGET_Frame();
2453 
2454   if ( ACCESS_Frame( 2L ) )
2455     goto Fail3;
2456 
2457   cscr->LookaheadGlyphCount = GET_UShort();
2458 
2459   FORGET_Frame();
2460 
2461   if ( cscr->LookaheadGlyphCount > ccsf2->MaxLookaheadLength )
2462     ccsf2->MaxLookaheadLength = cscr->LookaheadGlyphCount;
2463 
2464   cscr->Lookahead = NULL;
2465 
2466   count = cscr->LookaheadGlyphCount;
2467 
2468   if ( ALLOC_ARRAY( cscr->Lookahead, count, HB_UShort ) )
2469     goto Fail3;
2470 
2471   l = cscr->Lookahead;
2472   d = ccsf2->LookaheadClassDef.Defined;
2473 
2474   if ( ACCESS_Frame( count * 2L ) )
2475     goto Fail2;
2476 
2477   for ( n = 0; n < count; n++ )
2478   {
2479     l[n] = GET_UShort();
2480 
2481     if ( !d[l[n]] )
2482       l[n] = 0;
2483   }
2484 
2485   FORGET_Frame();
2486 
2487   if ( ACCESS_Frame( 2L ) )
2488     goto Fail2;
2489 
2490   cscr->SubstCount = GET_UShort();
2491 
2492   FORGET_Frame();
2493 
2494   cscr->SubstLookupRecord = NULL;
2495 
2496   count = cscr->SubstCount;
2497 
2498   if ( ALLOC_ARRAY( cscr->SubstLookupRecord, count,
2499 		    HB_SubstLookupRecord ) )
2500     goto Fail2;
2501 
2502   slr = cscr->SubstLookupRecord;
2503 
2504   if ( ACCESS_Frame( count * 4L ) )
2505     goto Fail1;
2506 
2507   for ( n = 0; n < count; n++ )
2508   {
2509     slr[n].SequenceIndex   = GET_UShort();
2510     slr[n].LookupListIndex = GET_UShort();
2511   }
2512 
2513   FORGET_Frame();
2514 
2515   return HB_Err_Ok;
2516 
2517 Fail1:
2518   FREE( slr );
2519 
2520 Fail2:
2521   FREE( l );
2522 
2523 Fail3:
2524   FREE( i );
2525 
2526 Fail4:
2527   FREE( b );
2528   return error;
2529 }
2530 
2531 
Free_ChainSubClassRule(HB_ChainSubClassRule * cscr)2532 static void  Free_ChainSubClassRule( HB_ChainSubClassRule*  cscr )
2533 {
2534   FREE( cscr->SubstLookupRecord );
2535   FREE( cscr->Lookahead );
2536   FREE( cscr->Input );
2537   FREE( cscr->Backtrack );
2538 }
2539 
2540 
2541 /* SubClassSet */
2542 
Load_ChainSubClassSet(HB_ChainContextSubstFormat2 * ccsf2,HB_ChainSubClassSet * cscs,HB_Stream stream)2543 static HB_Error  Load_ChainSubClassSet(
2544 		   HB_ChainContextSubstFormat2*  ccsf2,
2545 		   HB_ChainSubClassSet*          cscs,
2546 		   HB_Stream                      stream )
2547 {
2548   HB_Error error;
2549 
2550   HB_UShort               n = 0, m, count;
2551   HB_UInt                cur_offset, new_offset, base_offset;
2552 
2553   HB_ChainSubClassRule*  cscr;
2554 
2555 
2556   base_offset = FILE_Pos();
2557 
2558   if ( ACCESS_Frame( 2L ) )
2559     return error;
2560 
2561   count = cscs->ChainSubClassRuleCount = GET_UShort();
2562 
2563   FORGET_Frame();
2564 
2565   cscs->ChainSubClassRule = NULL;
2566 
2567   if ( ALLOC_ARRAY( cscs->ChainSubClassRule, count,
2568 		    HB_ChainSubClassRule ) )
2569     return error;
2570 
2571   cscr = cscs->ChainSubClassRule;
2572 
2573   for ( n = 0; n < count; n++ )
2574   {
2575     if ( ACCESS_Frame( 2L ) )
2576       goto Fail;
2577 
2578     new_offset = GET_UShort() + base_offset;
2579 
2580     FORGET_Frame();
2581 
2582     cur_offset = FILE_Pos();
2583     if ( FILE_Seek( new_offset ) ||
2584 	 ( error = Load_ChainSubClassRule( ccsf2, &cscr[n],
2585 					   stream ) ) != HB_Err_Ok )
2586       goto Fail;
2587     (void)FILE_Seek( cur_offset );
2588   }
2589 
2590   return HB_Err_Ok;
2591 
2592 Fail:
2593   for ( m = 0; m < n; m++ )
2594     Free_ChainSubClassRule( &cscr[m] );
2595 
2596   FREE( cscr );
2597   return error;
2598 }
2599 
2600 
Free_ChainSubClassSet(HB_ChainSubClassSet * cscs)2601 static void  Free_ChainSubClassSet( HB_ChainSubClassSet*  cscs )
2602 {
2603   HB_UShort               n, count;
2604 
2605   HB_ChainSubClassRule*  cscr;
2606 
2607 
2608   if ( cscs->ChainSubClassRule )
2609   {
2610     count = cscs->ChainSubClassRuleCount;
2611     cscr  = cscs->ChainSubClassRule;
2612 
2613     for ( n = 0; n < count; n++ )
2614       Free_ChainSubClassRule( &cscr[n] );
2615 
2616     FREE( cscr );
2617   }
2618 }
2619 
2620 
2621 /* ChainContextSubstFormat2 */
2622 
Load_ChainContextSubst2(HB_ChainContextSubstFormat2 * ccsf2,HB_Stream stream)2623 static HB_Error  Load_ChainContextSubst2(
2624 		   HB_ChainContextSubstFormat2*  ccsf2,
2625 		   HB_Stream                      stream )
2626 {
2627   HB_Error error;
2628 
2629   HB_UShort              n = 0, m, count;
2630   HB_UInt               cur_offset, new_offset, base_offset;
2631   HB_UInt               backtrack_offset, input_offset, lookahead_offset;
2632 
2633   HB_ChainSubClassSet*  cscs;
2634 
2635 
2636   base_offset = FILE_Pos() - 2;
2637 
2638   if ( ACCESS_Frame( 2L ) )
2639     return error;
2640 
2641   new_offset = GET_UShort() + base_offset;
2642 
2643   FORGET_Frame();
2644 
2645   cur_offset = FILE_Pos();
2646   if ( FILE_Seek( new_offset ) ||
2647        ( error = _HB_OPEN_Load_Coverage( &ccsf2->Coverage, stream ) ) != HB_Err_Ok )
2648     return error;
2649   (void)FILE_Seek( cur_offset );
2650 
2651   if ( ACCESS_Frame( 8L ) )
2652     goto Fail5;
2653 
2654   backtrack_offset = GET_UShort();
2655   input_offset     = GET_UShort();
2656   lookahead_offset = GET_UShort();
2657 
2658   /* `ChainSubClassSetCount' is the upper limit for input class values,
2659      thus we read it now to make an additional safety check. No limit
2660      is known or needed for the other two class definitions          */
2661 
2662   count = ccsf2->ChainSubClassSetCount = GET_UShort();
2663 
2664   FORGET_Frame();
2665 
2666   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->BacktrackClassDef, 65535,
2667 						       backtrack_offset, base_offset,
2668 						       stream ) ) != HB_Err_Ok )
2669       goto Fail5;
2670 
2671   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->InputClassDef, count,
2672 						       input_offset, base_offset,
2673 						       stream ) ) != HB_Err_Ok )
2674       goto Fail4;
2675   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->LookaheadClassDef, 65535,
2676 						       lookahead_offset, base_offset,
2677 						       stream ) ) != HB_Err_Ok )
2678     goto Fail3;
2679 
2680   ccsf2->ChainSubClassSet   = NULL;
2681   ccsf2->MaxBacktrackLength = 0;
2682   ccsf2->MaxInputLength     = 0;
2683   ccsf2->MaxLookaheadLength = 0;
2684 
2685   if ( ALLOC_ARRAY( ccsf2->ChainSubClassSet, count, HB_ChainSubClassSet ) )
2686     goto Fail2;
2687 
2688   cscs = ccsf2->ChainSubClassSet;
2689 
2690   for ( n = 0; n < count; n++ )
2691   {
2692     if ( ACCESS_Frame( 2L ) )
2693       goto Fail1;
2694 
2695     new_offset = GET_UShort() + base_offset;
2696 
2697     FORGET_Frame();
2698 
2699     if ( new_offset != base_offset )      /* not a NULL offset */
2700     {
2701       cur_offset = FILE_Pos();
2702       if ( FILE_Seek( new_offset ) ||
2703 	   ( error = Load_ChainSubClassSet( ccsf2, &cscs[n],
2704 					    stream ) ) != HB_Err_Ok )
2705 	goto Fail1;
2706       (void)FILE_Seek( cur_offset );
2707     }
2708     else
2709     {
2710       /* we create a ChainSubClassSet table with no entries */
2711 
2712       ccsf2->ChainSubClassSet[n].ChainSubClassRuleCount = 0;
2713       ccsf2->ChainSubClassSet[n].ChainSubClassRule      = NULL;
2714     }
2715   }
2716 
2717   return HB_Err_Ok;
2718 
2719 Fail1:
2720   for ( m = 0; m < n; m++ )
2721     Free_ChainSubClassSet( &cscs[m] );
2722 
2723   FREE( cscs );
2724 
2725 Fail2:
2726   _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef );
2727 
2728 Fail3:
2729   _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef );
2730 
2731 Fail4:
2732   _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef );
2733 
2734 Fail5:
2735   _HB_OPEN_Free_Coverage( &ccsf2->Coverage );
2736   return error;
2737 }
2738 
2739 
Free_ChainContextSubst2(HB_ChainContextSubstFormat2 * ccsf2)2740 static void  Free_ChainContextSubst2( HB_ChainContextSubstFormat2*  ccsf2 )
2741 {
2742   HB_UShort              n, count;
2743 
2744   HB_ChainSubClassSet*  cscs;
2745 
2746 
2747   if ( ccsf2->ChainSubClassSet )
2748   {
2749     count = ccsf2->ChainSubClassSetCount;
2750     cscs  = ccsf2->ChainSubClassSet;
2751 
2752     for ( n = 0; n < count; n++ )
2753       Free_ChainSubClassSet( &cscs[n] );
2754 
2755     FREE( cscs );
2756   }
2757 
2758   _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef );
2759   _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef );
2760   _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef );
2761 
2762   _HB_OPEN_Free_Coverage( &ccsf2->Coverage );
2763 }
2764 
2765 
2766 /* ChainContextSubstFormat3 */
2767 
Load_ChainContextSubst3(HB_ChainContextSubstFormat3 * ccsf3,HB_Stream stream)2768 static HB_Error  Load_ChainContextSubst3(
2769 		   HB_ChainContextSubstFormat3*  ccsf3,
2770 		   HB_Stream                      stream )
2771 {
2772   HB_Error error;
2773 
2774   HB_UShort               n, nb = 0, ni =0, nl = 0, m, count;
2775   HB_UShort               backtrack_count, input_count, lookahead_count;
2776   HB_UInt                cur_offset, new_offset, base_offset;
2777 
2778   HB_Coverage*           b;
2779   HB_Coverage*           i;
2780   HB_Coverage*           l;
2781   HB_SubstLookupRecord*  slr;
2782 
2783 
2784   base_offset = FILE_Pos() - 2L;
2785 
2786   if ( ACCESS_Frame( 2L ) )
2787     return error;
2788 
2789   ccsf3->BacktrackGlyphCount = GET_UShort();
2790 
2791   FORGET_Frame();
2792 
2793   ccsf3->BacktrackCoverage = NULL;
2794 
2795   backtrack_count = ccsf3->BacktrackGlyphCount;
2796 
2797   if ( ALLOC_ARRAY( ccsf3->BacktrackCoverage, backtrack_count,
2798 		    HB_Coverage ) )
2799     return error;
2800 
2801   b = ccsf3->BacktrackCoverage;
2802 
2803   for ( nb = 0; nb < backtrack_count; nb++ )
2804   {
2805     if ( ACCESS_Frame( 2L ) )
2806       goto Fail4;
2807 
2808     new_offset = GET_UShort() + base_offset;
2809 
2810     FORGET_Frame();
2811 
2812     cur_offset = FILE_Pos();
2813     if ( FILE_Seek( new_offset ) ||
2814 	 ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
2815       goto Fail4;
2816     (void)FILE_Seek( cur_offset );
2817   }
2818 
2819   if ( ACCESS_Frame( 2L ) )
2820     goto Fail4;
2821 
2822   ccsf3->InputGlyphCount = GET_UShort();
2823 
2824   FORGET_Frame();
2825 
2826   ccsf3->InputCoverage = NULL;
2827 
2828   input_count = ccsf3->InputGlyphCount;
2829 
2830   if ( ALLOC_ARRAY( ccsf3->InputCoverage, input_count, HB_Coverage ) )
2831     goto Fail4;
2832 
2833   i = ccsf3->InputCoverage;
2834 
2835   for ( ni = 0; ni < input_count; ni++ )
2836   {
2837     if ( ACCESS_Frame( 2L ) )
2838       goto Fail3;
2839 
2840     new_offset = GET_UShort() + base_offset;
2841 
2842     FORGET_Frame();
2843 
2844     cur_offset = FILE_Pos();
2845     if ( FILE_Seek( new_offset ) ||
2846 	 ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok )
2847       goto Fail3;
2848     (void)FILE_Seek( cur_offset );
2849   }
2850 
2851   if ( ACCESS_Frame( 2L ) )
2852     goto Fail3;
2853 
2854   ccsf3->LookaheadGlyphCount = GET_UShort();
2855 
2856   FORGET_Frame();
2857 
2858   ccsf3->LookaheadCoverage = NULL;
2859 
2860   lookahead_count = ccsf3->LookaheadGlyphCount;
2861 
2862   if ( ALLOC_ARRAY( ccsf3->LookaheadCoverage, lookahead_count,
2863 		    HB_Coverage ) )
2864     goto Fail3;
2865 
2866   l = ccsf3->LookaheadCoverage;
2867 
2868   for ( nl = 0; nl < lookahead_count; nl++ )
2869   {
2870     if ( ACCESS_Frame( 2L ) )
2871       goto Fail2;
2872 
2873     new_offset = GET_UShort() + base_offset;
2874 
2875     FORGET_Frame();
2876 
2877     cur_offset = FILE_Pos();
2878     if ( FILE_Seek( new_offset ) ||
2879 	 ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
2880       goto Fail2;
2881     (void)FILE_Seek( cur_offset );
2882   }
2883 
2884   if ( ACCESS_Frame( 2L ) )
2885     goto Fail2;
2886 
2887   ccsf3->SubstCount = GET_UShort();
2888 
2889   FORGET_Frame();
2890 
2891   ccsf3->SubstLookupRecord = NULL;
2892 
2893   count = ccsf3->SubstCount;
2894 
2895   if ( ALLOC_ARRAY( ccsf3->SubstLookupRecord, count,
2896 		    HB_SubstLookupRecord ) )
2897     goto Fail2;
2898 
2899   slr = ccsf3->SubstLookupRecord;
2900 
2901   if ( ACCESS_Frame( count * 4L ) )
2902     goto Fail1;
2903 
2904   for ( n = 0; n < count; n++ )
2905   {
2906     slr[n].SequenceIndex   = GET_UShort();
2907     slr[n].LookupListIndex = GET_UShort();
2908   }
2909 
2910   FORGET_Frame();
2911 
2912   return HB_Err_Ok;
2913 
2914 Fail1:
2915   FREE( slr );
2916 
2917 Fail2:
2918   for ( m = 0; m < nl; m++ )
2919     _HB_OPEN_Free_Coverage( &l[m] );
2920 
2921   FREE( l );
2922 
2923 Fail3:
2924   for ( m = 0; m < ni; m++ )
2925     _HB_OPEN_Free_Coverage( &i[m] );
2926 
2927   FREE( i );
2928 
2929 Fail4:
2930   for ( m = 0; m < nb; m++ )
2931     _HB_OPEN_Free_Coverage( &b[m] );
2932 
2933   FREE( b );
2934   return error;
2935 }
2936 
2937 
Free_ChainContextSubst3(HB_ChainContextSubstFormat3 * ccsf3)2938 static void  Free_ChainContextSubst3( HB_ChainContextSubstFormat3*  ccsf3 )
2939 {
2940   HB_UShort      n, count;
2941 
2942   HB_Coverage*  c;
2943 
2944 
2945   FREE( ccsf3->SubstLookupRecord );
2946 
2947   if ( ccsf3->LookaheadCoverage )
2948   {
2949     count = ccsf3->LookaheadGlyphCount;
2950     c     = ccsf3->LookaheadCoverage;
2951 
2952     for ( n = 0; n < count; n++ )
2953       _HB_OPEN_Free_Coverage( &c[n] );
2954 
2955     FREE( c );
2956   }
2957 
2958   if ( ccsf3->InputCoverage )
2959   {
2960     count = ccsf3->InputGlyphCount;
2961     c     = ccsf3->InputCoverage;
2962 
2963     for ( n = 0; n < count; n++ )
2964       _HB_OPEN_Free_Coverage( &c[n] );
2965 
2966     FREE( c );
2967   }
2968 
2969   if ( ccsf3->BacktrackCoverage )
2970   {
2971     count = ccsf3->BacktrackGlyphCount;
2972     c     = ccsf3->BacktrackCoverage;
2973 
2974     for ( n = 0; n < count; n++ )
2975       _HB_OPEN_Free_Coverage( &c[n] );
2976 
2977     FREE( c );
2978   }
2979 }
2980 
2981 
2982 /* ChainContextSubst */
2983 
Load_ChainContextSubst(HB_GSUB_SubTable * st,HB_Stream stream)2984 static HB_Error  Load_ChainContextSubst( HB_GSUB_SubTable* st,
2985 					 HB_Stream         stream )
2986 {
2987   HB_Error error;
2988   HB_ChainContextSubst*  ccs = &st->chain;
2989 
2990   if ( ACCESS_Frame( 2L ) )
2991     return error;
2992 
2993   ccs->SubstFormat = GET_UShort();
2994 
2995   FORGET_Frame();
2996 
2997   switch ( ccs->SubstFormat ) {
2998     case 1:  return Load_ChainContextSubst1( &ccs->ccsf.ccsf1, stream );
2999     case 2:  return Load_ChainContextSubst2( &ccs->ccsf.ccsf2, stream );
3000     case 3:  return Load_ChainContextSubst3( &ccs->ccsf.ccsf3, stream );
3001     default: return ERR(HB_Err_Invalid_SubTable_Format);
3002   }
3003 
3004   return HB_Err_Ok;               /* never reached */
3005 }
3006 
3007 
Free_ChainContextSubst(HB_GSUB_SubTable * st)3008 static void  Free_ChainContextSubst( HB_GSUB_SubTable* st )
3009 {
3010   HB_ChainContextSubst*  ccs = &st->chain;
3011 
3012   switch ( ccs->SubstFormat ) {
3013     case 1:  Free_ChainContextSubst1( &ccs->ccsf.ccsf1 ); break;
3014     case 2:  Free_ChainContextSubst2( &ccs->ccsf.ccsf2 ); break;
3015     case 3:  Free_ChainContextSubst3( &ccs->ccsf.ccsf3 ); break;
3016     default:							  break;
3017   }
3018 }
3019 
3020 
Lookup_ChainContextSubst1(HB_GSUBHeader * gsub,HB_ChainContextSubstFormat1 * ccsf1,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)3021 static HB_Error  Lookup_ChainContextSubst1( HB_GSUBHeader*               gsub,
3022 					    HB_ChainContextSubstFormat1* ccsf1,
3023 					    HB_Buffer                    buffer,
3024 					    HB_UShort                     flags,
3025 					    HB_UShort                     context_length,
3026 					    int                           nesting_level )
3027 {
3028   HB_UShort          index, property;
3029   HB_UShort          i, j, k, num_csr;
3030   HB_UShort          bgc, igc, lgc;
3031   HB_Error           error;
3032 
3033   HB_ChainSubRule*  csr;
3034   HB_ChainSubRule   curr_csr;
3035   HB_GDEFHeader*    gdef;
3036 
3037 
3038   gdef = gsub->gdef;
3039 
3040   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3041     return error;
3042 
3043   error = _HB_OPEN_Coverage_Index( &ccsf1->Coverage, IN_CURGLYPH(), &index );
3044   if ( error )
3045     return error;
3046 
3047   csr     = ccsf1->ChainSubRuleSet[index].ChainSubRule;
3048   num_csr = ccsf1->ChainSubRuleSet[index].ChainSubRuleCount;
3049 
3050   for ( k = 0; k < num_csr; k++ )
3051   {
3052     curr_csr = csr[k];
3053     bgc      = curr_csr.BacktrackGlyphCount;
3054     igc      = curr_csr.InputGlyphCount;
3055     lgc      = curr_csr.LookaheadGlyphCount;
3056 
3057     if ( context_length != 0xFFFF && context_length < igc )
3058       goto next_chainsubrule;
3059 
3060     /* check whether context is too long; it is a first guess only */
3061 
3062     if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
3063       goto next_chainsubrule;
3064 
3065     if ( bgc )
3066     {
3067       /* since we don't know in advance the number of glyphs to inspect,
3068 	 we search backwards for matches in the backtrack glyph array    */
3069 
3070       for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
3071       {
3072 	while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
3073 	{
3074 	  if ( error && error != HB_Err_Not_Covered )
3075 	    return error;
3076 
3077 	  if ( j + 1 == bgc - i )
3078 	    goto next_chainsubrule;
3079 	  j--;
3080 	}
3081 
3082 	/* In OpenType 1.3, it is undefined whether the offsets of
3083 	   backtrack glyphs is in logical order or not.  Version 1.4
3084 	   will clarify this:
3085 
3086 	     Logical order -      a  b  c  d  e  f  g  h  i  j
3087 					      i
3088 	     Input offsets -                  0  1
3089 	     Backtrack offsets -  3  2  1  0
3090 	     Lookahead offsets -                    0  1  2  3           */
3091 
3092 	if ( OUT_GLYPH( j ) != curr_csr.Backtrack[i] )
3093 	  goto next_chainsubrule;
3094       }
3095     }
3096 
3097     /* Start at 1 because [0] is implied */
3098 
3099     for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
3100     {
3101       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3102       {
3103 	if ( error && error != HB_Err_Not_Covered )
3104 	  return error;
3105 
3106 	if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
3107 	  goto next_chainsubrule;
3108 	j++;
3109       }
3110 
3111       if ( IN_GLYPH( j ) != curr_csr.Input[i - 1] )
3112 	  goto next_chainsubrule;
3113     }
3114 
3115     /* we are starting to check for lookahead glyphs right after the
3116        last context glyph                                            */
3117 
3118     for ( i = 0; i < lgc; i++, j++ )
3119     {
3120       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3121       {
3122 	if ( error && error != HB_Err_Not_Covered )
3123 	  return error;
3124 
3125 	if ( j + lgc - i == (HB_Int)buffer->in_length )
3126 	  goto next_chainsubrule;
3127 	j++;
3128       }
3129 
3130       if ( IN_GLYPH( j ) != curr_csr.Lookahead[i] )
3131 	goto next_chainsubrule;
3132     }
3133 
3134     return Do_ContextSubst( gsub, igc,
3135 			    curr_csr.SubstCount,
3136 			    curr_csr.SubstLookupRecord,
3137 			    buffer,
3138 			    nesting_level );
3139 
3140   next_chainsubrule:
3141     ;
3142   }
3143 
3144   return HB_Err_Not_Covered;
3145 }
3146 
3147 
Lookup_ChainContextSubst2(HB_GSUBHeader * gsub,HB_ChainContextSubstFormat2 * ccsf2,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)3148 static HB_Error  Lookup_ChainContextSubst2( HB_GSUBHeader*               gsub,
3149 					    HB_ChainContextSubstFormat2* ccsf2,
3150 					    HB_Buffer                    buffer,
3151 					    HB_UShort                     flags,
3152 					    HB_UShort                     context_length,
3153 					    int                           nesting_level )
3154 {
3155   HB_UShort              index, property;
3156   HB_Error               error;
3157   HB_UShort              i, j, k;
3158   HB_UShort              bgc, igc, lgc;
3159   HB_UShort              known_backtrack_classes,
3160 			 known_input_classes,
3161 			 known_lookahead_classes;
3162 
3163   HB_UShort*             backtrack_classes;
3164   HB_UShort*             input_classes;
3165   HB_UShort*             lookahead_classes;
3166 
3167   HB_UShort*             bc;
3168   HB_UShort*             ic;
3169   HB_UShort*             lc;
3170 
3171   HB_ChainSubClassSet*  cscs;
3172   HB_ChainSubClassRule  ccsr;
3173   HB_GDEFHeader*        gdef;
3174 
3175 
3176   gdef = gsub->gdef;
3177 
3178   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3179     return error;
3180 
3181   /* Note: The coverage table in format 2 doesn't give an index into
3182 	   anything.  It just lets us know whether or not we need to
3183 	   do any lookup at all.                                     */
3184 
3185   error = _HB_OPEN_Coverage_Index( &ccsf2->Coverage, IN_CURGLYPH(), &index );
3186   if ( error )
3187     return error;
3188 
3189   if ( ALLOC_ARRAY( backtrack_classes, ccsf2->MaxBacktrackLength, HB_UShort ) )
3190     return error;
3191   known_backtrack_classes = 0;
3192 
3193   if ( ALLOC_ARRAY( input_classes, ccsf2->MaxInputLength, HB_UShort ) )
3194     goto End3;
3195   known_input_classes = 1;
3196 
3197   if ( ALLOC_ARRAY( lookahead_classes, ccsf2->MaxLookaheadLength, HB_UShort ) )
3198     goto End2;
3199   known_lookahead_classes = 0;
3200 
3201   error = _HB_OPEN_Get_Class( &ccsf2->InputClassDef, IN_CURGLYPH(),
3202 		     &input_classes[0], NULL );
3203   if ( error && error != HB_Err_Not_Covered )
3204     goto End1;
3205 
3206   cscs = &ccsf2->ChainSubClassSet[input_classes[0]];
3207   if ( !cscs )
3208   {
3209     error = ERR(HB_Err_Invalid_SubTable);
3210     goto End1;
3211   }
3212 
3213   for ( k = 0; k < cscs->ChainSubClassRuleCount; k++ )
3214   {
3215     ccsr = cscs->ChainSubClassRule[k];
3216     bgc  = ccsr.BacktrackGlyphCount;
3217     igc  = ccsr.InputGlyphCount;
3218     lgc  = ccsr.LookaheadGlyphCount;
3219 
3220     if ( context_length != 0xFFFF && context_length < igc )
3221       goto next_chainsubclassrule;
3222 
3223     /* check whether context is too long; it is a first guess only */
3224 
3225     if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
3226       goto next_chainsubclassrule;
3227 
3228     if ( bgc )
3229     {
3230       /* Since we don't know in advance the number of glyphs to inspect,
3231 	 we search backwards for matches in the backtrack glyph array.
3232 	 Note that `known_backtrack_classes' starts at index 0.         */
3233 
3234       bc       = ccsr.Backtrack;
3235 
3236       for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
3237       {
3238 	while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
3239 	{
3240 	  if ( error && error != HB_Err_Not_Covered )
3241 	    goto End1;
3242 
3243 	  if ( j + 1 == bgc - i )
3244 	    goto next_chainsubclassrule;
3245 	  j--;
3246 	}
3247 
3248 	if ( i >= known_backtrack_classes )
3249 	{
3250 	  /* Keeps us from having to do this for each rule */
3251 
3252 	  error = _HB_OPEN_Get_Class( &ccsf2->BacktrackClassDef, OUT_GLYPH( j ),
3253 			     &backtrack_classes[i], NULL );
3254 	  if ( error && error != HB_Err_Not_Covered )
3255 	    goto End1;
3256 	  known_backtrack_classes = i;
3257 	}
3258 
3259 	if ( bc[i] != backtrack_classes[i] )
3260 	  goto next_chainsubclassrule;
3261       }
3262     }
3263 
3264     ic       = ccsr.Input;
3265 
3266     /* Start at 1 because [0] is implied */
3267 
3268     for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
3269     {
3270       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3271       {
3272 	if ( error && error != HB_Err_Not_Covered )
3273 	  goto End1;
3274 
3275 	if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
3276 	  goto next_chainsubclassrule;
3277 	j++;
3278       }
3279 
3280       if ( i >= known_input_classes )
3281       {
3282 	error = _HB_OPEN_Get_Class( &ccsf2->InputClassDef, IN_GLYPH( j ),
3283 			   &input_classes[i], NULL );
3284 	if ( error && error != HB_Err_Not_Covered )
3285 	  goto End1;
3286 	known_input_classes = i;
3287       }
3288 
3289       if ( ic[i - 1] != input_classes[i] )
3290 	goto next_chainsubclassrule;
3291     }
3292 
3293     /* we are starting to check for lookahead glyphs right after the
3294        last context glyph                                            */
3295 
3296     lc       = ccsr.Lookahead;
3297 
3298     for ( i = 0; i < lgc; i++, j++ )
3299     {
3300       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3301       {
3302 	if ( error && error != HB_Err_Not_Covered )
3303 	  goto End1;
3304 
3305 	if ( j + lgc - i == (HB_Int)buffer->in_length )
3306 	  goto next_chainsubclassrule;
3307 	j++;
3308       }
3309 
3310       if ( i >= known_lookahead_classes )
3311       {
3312 	error = _HB_OPEN_Get_Class( &ccsf2->LookaheadClassDef, IN_GLYPH( j ),
3313 			   &lookahead_classes[i], NULL );
3314 	if ( error && error != HB_Err_Not_Covered )
3315 	  goto End1;
3316 	known_lookahead_classes = i;
3317       }
3318 
3319       if ( lc[i] != lookahead_classes[i] )
3320 	goto next_chainsubclassrule;
3321     }
3322 
3323     error = Do_ContextSubst( gsub, igc,
3324 			     ccsr.SubstCount,
3325 			     ccsr.SubstLookupRecord,
3326 			     buffer,
3327 			     nesting_level );
3328     goto End1;
3329 
3330   next_chainsubclassrule:
3331     ;
3332   }
3333 
3334   error = HB_Err_Not_Covered;
3335 
3336 End1:
3337   FREE( lookahead_classes );
3338 
3339 End2:
3340   FREE( input_classes );
3341 
3342 End3:
3343   FREE( backtrack_classes );
3344   return error;
3345 }
3346 
3347 
Lookup_ChainContextSubst3(HB_GSUBHeader * gsub,HB_ChainContextSubstFormat3 * ccsf3,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)3348 static HB_Error  Lookup_ChainContextSubst3( HB_GSUBHeader*               gsub,
3349 					    HB_ChainContextSubstFormat3* ccsf3,
3350 					    HB_Buffer                    buffer,
3351 					    HB_UShort                     flags,
3352 					    HB_UShort                     context_length,
3353 					    int                           nesting_level )
3354 {
3355   HB_UShort        index, i, j, property;
3356   HB_UShort        bgc, igc, lgc;
3357   HB_Error         error;
3358 
3359   HB_Coverage*    bc;
3360   HB_Coverage*    ic;
3361   HB_Coverage*    lc;
3362   HB_GDEFHeader*  gdef;
3363 
3364 
3365   gdef = gsub->gdef;
3366 
3367   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3368     return error;
3369 
3370   bgc = ccsf3->BacktrackGlyphCount;
3371   igc = ccsf3->InputGlyphCount;
3372   lgc = ccsf3->LookaheadGlyphCount;
3373 
3374   if ( context_length != 0xFFFF && context_length < igc )
3375     return HB_Err_Not_Covered;
3376 
3377   /* check whether context is too long; it is a first guess only */
3378 
3379   if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
3380     return HB_Err_Not_Covered;
3381 
3382   if ( bgc )
3383   {
3384     /* Since we don't know in advance the number of glyphs to inspect,
3385        we search backwards for matches in the backtrack glyph array    */
3386 
3387     bc       = ccsf3->BacktrackCoverage;
3388 
3389     for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
3390     {
3391       while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
3392       {
3393 	if ( error && error != HB_Err_Not_Covered )
3394 	  return error;
3395 
3396 	if ( j + 1 == bgc - i )
3397 	  return HB_Err_Not_Covered;
3398 	j--;
3399       }
3400 
3401       error = _HB_OPEN_Coverage_Index( &bc[i], OUT_GLYPH( j ), &index );
3402       if ( error )
3403 	return error;
3404     }
3405   }
3406 
3407   ic       = ccsf3->InputCoverage;
3408 
3409   for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
3410   {
3411     /* We already called CHECK_Property for IN_GLYPH( buffer->in_pos ) */
3412     while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3413     {
3414       if ( error && error != HB_Err_Not_Covered )
3415 	return error;
3416 
3417       if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
3418 	return HB_Err_Not_Covered;
3419       j++;
3420     }
3421 
3422     error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index );
3423     if ( error )
3424       return error;
3425   }
3426 
3427   /* we are starting for lookahead glyphs right after the last context
3428      glyph                                                             */
3429 
3430   lc       = ccsf3->LookaheadCoverage;
3431 
3432   for ( i = 0; i < lgc; i++, j++ )
3433   {
3434     while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3435     {
3436       if ( error && error != HB_Err_Not_Covered )
3437 	return error;
3438 
3439       if ( j + lgc - i == (HB_Int)buffer->in_length )
3440 	return HB_Err_Not_Covered;
3441       j++;
3442     }
3443 
3444     error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
3445     if ( error )
3446       return error;
3447   }
3448 
3449   return Do_ContextSubst( gsub, igc,
3450 			  ccsf3->SubstCount,
3451 			  ccsf3->SubstLookupRecord,
3452 			  buffer,
3453 			  nesting_level );
3454 }
3455 
3456 
Lookup_ChainContextSubst(HB_GSUBHeader * gsub,HB_GSUB_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)3457 static HB_Error  Lookup_ChainContextSubst( HB_GSUBHeader*    gsub,
3458 					   HB_GSUB_SubTable* st,
3459 					   HB_Buffer         buffer,
3460 					   HB_UShort          flags,
3461 					   HB_UShort          context_length,
3462 					   int                nesting_level )
3463 {
3464   HB_ChainContextSubst*  ccs = &st->chain;
3465 
3466   switch ( ccs->SubstFormat ) {
3467     case 1:  return Lookup_ChainContextSubst1( gsub, &ccs->ccsf.ccsf1, buffer, flags, context_length, nesting_level );
3468     case 2:  return Lookup_ChainContextSubst2( gsub, &ccs->ccsf.ccsf2, buffer, flags, context_length, nesting_level );
3469     case 3:  return Lookup_ChainContextSubst3( gsub, &ccs->ccsf.ccsf3, buffer, flags, context_length, nesting_level );
3470     default: return ERR(HB_Err_Invalid_SubTable_Format);
3471   }
3472 }
3473 
3474 
Load_ReverseChainContextSubst(HB_GSUB_SubTable * st,HB_Stream stream)3475 static HB_Error  Load_ReverseChainContextSubst( HB_GSUB_SubTable* st,
3476 					        HB_Stream         stream )
3477 {
3478   HB_Error error;
3479   HB_ReverseChainContextSubst*  rccs = &st->reverse;
3480 
3481   HB_UShort               m, count;
3482 
3483   HB_UShort               nb = 0, nl = 0, n;
3484   HB_UShort               backtrack_count, lookahead_count;
3485   HB_UInt                cur_offset, new_offset, base_offset;
3486 
3487   HB_Coverage*           b;
3488   HB_Coverage*           l;
3489   HB_UShort*              sub;
3490 
3491   base_offset = FILE_Pos();
3492 
3493   if ( ACCESS_Frame( 2L ) )
3494     return error;
3495 
3496   rccs->SubstFormat = GET_UShort();
3497 
3498   if ( rccs->SubstFormat != 1 )
3499     return ERR(HB_Err_Invalid_SubTable_Format);
3500 
3501   FORGET_Frame();
3502 
3503   if ( ACCESS_Frame( 2L ) )
3504     return error;
3505 
3506   new_offset = GET_UShort() + base_offset;
3507 
3508   FORGET_Frame();
3509 
3510   cur_offset = FILE_Pos();
3511   if ( FILE_Seek( new_offset ) ||
3512        ( error = _HB_OPEN_Load_Coverage( &rccs->Coverage, stream ) ) != HB_Err_Ok )
3513     return error;
3514   (void)FILE_Seek( cur_offset );
3515 
3516 
3517   if ( ACCESS_Frame( 2L ) )
3518     goto Fail4;
3519 
3520   rccs->BacktrackGlyphCount = GET_UShort();
3521 
3522   FORGET_Frame();
3523 
3524   rccs->BacktrackCoverage = NULL;
3525 
3526   backtrack_count = rccs->BacktrackGlyphCount;
3527 
3528   if ( ALLOC_ARRAY( rccs->BacktrackCoverage, backtrack_count,
3529 		    HB_Coverage ) )
3530     goto Fail4;
3531 
3532   b = rccs->BacktrackCoverage;
3533 
3534   for ( nb = 0; nb < backtrack_count; nb++ )
3535   {
3536     if ( ACCESS_Frame( 2L ) )
3537       goto Fail3;
3538 
3539     new_offset = GET_UShort() + base_offset;
3540 
3541     FORGET_Frame();
3542 
3543     cur_offset = FILE_Pos();
3544     if ( FILE_Seek( new_offset ) ||
3545 	 ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
3546       goto Fail3;
3547     (void)FILE_Seek( cur_offset );
3548   }
3549 
3550 
3551   if ( ACCESS_Frame( 2L ) )
3552     goto Fail3;
3553 
3554   rccs->LookaheadGlyphCount = GET_UShort();
3555 
3556   FORGET_Frame();
3557 
3558   rccs->LookaheadCoverage = NULL;
3559 
3560   lookahead_count = rccs->LookaheadGlyphCount;
3561 
3562   if ( ALLOC_ARRAY( rccs->LookaheadCoverage, lookahead_count,
3563 		    HB_Coverage ) )
3564     goto Fail3;
3565 
3566   l = rccs->LookaheadCoverage;
3567 
3568   for ( nl = 0; nl < lookahead_count; nl++ )
3569   {
3570     if ( ACCESS_Frame( 2L ) )
3571       goto Fail2;
3572 
3573     new_offset = GET_UShort() + base_offset;
3574 
3575     FORGET_Frame();
3576 
3577     cur_offset = FILE_Pos();
3578     if ( FILE_Seek( new_offset ) ||
3579 	 ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
3580       goto Fail2;
3581     (void)FILE_Seek( cur_offset );
3582   }
3583 
3584   if ( ACCESS_Frame( 2L ) )
3585     goto Fail2;
3586 
3587   rccs->GlyphCount = GET_UShort();
3588 
3589   FORGET_Frame();
3590 
3591   rccs->Substitute = NULL;
3592 
3593   count = rccs->GlyphCount;
3594 
3595   if ( ALLOC_ARRAY( rccs->Substitute, count,
3596 		    HB_UShort ) )
3597     goto Fail2;
3598 
3599   sub = rccs->Substitute;
3600 
3601   if ( ACCESS_Frame( count * 2L ) )
3602     goto Fail1;
3603 
3604   for ( n = 0; n < count; n++ )
3605     sub[n] = GET_UShort();
3606 
3607   FORGET_Frame();
3608 
3609   return HB_Err_Ok;
3610 
3611 Fail1:
3612   FREE( sub );
3613 
3614 Fail2:
3615   for ( m = 0; m < nl; m++ )
3616     _HB_OPEN_Free_Coverage( &l[m] );
3617 
3618   FREE( l );
3619 
3620 Fail3:
3621   for ( m = 0; m < nb; m++ )
3622     _HB_OPEN_Free_Coverage( &b[m] );
3623 
3624   FREE( b );
3625 
3626 Fail4:
3627   _HB_OPEN_Free_Coverage( &rccs->Coverage );
3628   return error;
3629 }
3630 
3631 
Free_ReverseChainContextSubst(HB_GSUB_SubTable * st)3632 static void  Free_ReverseChainContextSubst( HB_GSUB_SubTable* st )
3633 {
3634   HB_UShort      n, count;
3635   HB_ReverseChainContextSubst*  rccs = &st->reverse;
3636 
3637   HB_Coverage*  c;
3638 
3639   _HB_OPEN_Free_Coverage( &rccs->Coverage );
3640 
3641   if ( rccs->LookaheadCoverage )
3642   {
3643     count = rccs->LookaheadGlyphCount;
3644     c     = rccs->LookaheadCoverage;
3645 
3646     for ( n = 0; n < count; n++ )
3647       _HB_OPEN_Free_Coverage( &c[n] );
3648 
3649     FREE( c );
3650   }
3651 
3652   if ( rccs->BacktrackCoverage )
3653   {
3654     count = rccs->BacktrackGlyphCount;
3655     c     = rccs->BacktrackCoverage;
3656 
3657     for ( n = 0; n < count; n++ )
3658       _HB_OPEN_Free_Coverage( &c[n] );
3659 
3660     FREE( c );
3661   }
3662 
3663   FREE ( rccs->Substitute );
3664 }
3665 
3666 
Lookup_ReverseChainContextSubst(HB_GSUBHeader * gsub,HB_GSUB_SubTable * st,HB_Buffer buffer,HB_UShort flags,HB_UShort context_length,int nesting_level)3667 static HB_Error  Lookup_ReverseChainContextSubst( HB_GSUBHeader*    gsub,
3668 						  HB_GSUB_SubTable* st,
3669 						  HB_Buffer         buffer,
3670 						  HB_UShort          flags,
3671 						  HB_UShort         context_length,
3672 						  int               nesting_level )
3673 {
3674   HB_UShort        index, input_index, i, j, property;
3675   HB_UShort        bgc, lgc;
3676   HB_Error         error;
3677 
3678   HB_ReverseChainContextSubst*  rccs = &st->reverse;
3679   HB_Coverage*    bc;
3680   HB_Coverage*    lc;
3681   HB_GDEFHeader*  gdef;
3682 
3683   if ( nesting_level != 1 || context_length != 0xFFFF )
3684     return HB_Err_Not_Covered;
3685 
3686   gdef = gsub->gdef;
3687 
3688   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
3689     return error;
3690 
3691   bgc = rccs->BacktrackGlyphCount;
3692   lgc = rccs->LookaheadGlyphCount;
3693 
3694   /* check whether context is too long; it is a first guess only */
3695 
3696   if ( bgc > buffer->in_pos || buffer->in_pos + 1 + lgc > buffer->in_length )
3697     return HB_Err_Not_Covered;
3698 
3699   if ( bgc )
3700   {
3701     /* Since we don't know in advance the number of glyphs to inspect,
3702        we search backwards for matches in the backtrack glyph array    */
3703 
3704     bc       = rccs->BacktrackCoverage;
3705 
3706     for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
3707     {
3708       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3709       {
3710 	if ( error && error != HB_Err_Not_Covered )
3711 	  return error;
3712 
3713 	if ( j + 1 == bgc - i )
3714 	  return HB_Err_Not_Covered;
3715 	j--;
3716       }
3717 
3718       error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
3719       if ( error )
3720 	return error;
3721     }
3722   }
3723 
3724   j = buffer->in_pos;
3725 
3726   error = _HB_OPEN_Coverage_Index( &rccs->Coverage, IN_GLYPH( j ), &input_index );
3727   if ( error )
3728       return error;
3729 
3730   lc       = rccs->LookaheadCoverage;
3731 
3732   for ( i = 0, j = buffer->in_pos + 1; i < lgc; i++, j++ )
3733   {
3734     while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
3735     {
3736       if ( error && error != HB_Err_Not_Covered )
3737 	return error;
3738 
3739       if ( j + lgc - i == (HB_Int)buffer->in_length )
3740 	return HB_Err_Not_Covered;
3741       j++;
3742     }
3743 
3744     error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
3745     if ( error )
3746       return error;
3747   }
3748 
3749   IN_CURGLYPH() = rccs->Substitute[input_index];
3750   buffer->in_pos--; /* Reverse! */
3751 
3752   return error;
3753 }
3754 
3755 
3756 
3757 /***********
3758  * GSUB API
3759  ***********/
3760 
3761 
3762 
HB_GSUB_Select_Script(HB_GSUBHeader * gsub,HB_UInt script_tag,HB_UShort * script_index)3763 HB_Error  HB_GSUB_Select_Script( HB_GSUBHeader*  gsub,
3764 				 HB_UInt         script_tag,
3765 				 HB_UShort*       script_index )
3766 {
3767   HB_UShort          n;
3768 
3769   HB_ScriptList*    sl;
3770   HB_ScriptRecord*  sr;
3771 
3772 
3773   if ( !gsub || !script_index )
3774     return ERR(HB_Err_Invalid_Argument);
3775 
3776   sl = &gsub->ScriptList;
3777   sr = sl->ScriptRecord;
3778 
3779   for ( n = 0; n < sl->ScriptCount; n++ )
3780     if ( script_tag == sr[n].ScriptTag )
3781     {
3782       *script_index = n;
3783 
3784       return HB_Err_Ok;
3785     }
3786 
3787   return HB_Err_Not_Covered;
3788 }
3789 
3790 
3791 
HB_GSUB_Select_Language(HB_GSUBHeader * gsub,HB_UInt language_tag,HB_UShort script_index,HB_UShort * language_index,HB_UShort * req_feature_index)3792 HB_Error  HB_GSUB_Select_Language( HB_GSUBHeader*  gsub,
3793 				   HB_UInt         language_tag,
3794 				   HB_UShort        script_index,
3795 				   HB_UShort*       language_index,
3796 				   HB_UShort*       req_feature_index )
3797 {
3798   HB_UShort           n;
3799 
3800   HB_ScriptList*     sl;
3801   HB_ScriptRecord*   sr;
3802   HB_ScriptTable*    s;
3803   HB_LangSysRecord*  lsr;
3804 
3805 
3806   if ( !gsub || !language_index || !req_feature_index )
3807     return ERR(HB_Err_Invalid_Argument);
3808 
3809   sl = &gsub->ScriptList;
3810   sr = sl->ScriptRecord;
3811 
3812   if ( script_index >= sl->ScriptCount )
3813     return ERR(HB_Err_Invalid_Argument);
3814 
3815   s   = &sr[script_index].Script;
3816   lsr = s->LangSysRecord;
3817 
3818   for ( n = 0; n < s->LangSysCount; n++ )
3819     if ( language_tag == lsr[n].LangSysTag )
3820     {
3821       *language_index = n;
3822       *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
3823 
3824       return HB_Err_Ok;
3825     }
3826 
3827   return HB_Err_Not_Covered;
3828 }
3829 
3830 
3831 /* selecting 0xFFFF for language_index asks for the values of the
3832    default language (DefaultLangSys)                              */
3833 
3834 
HB_GSUB_Select_Feature(HB_GSUBHeader * gsub,HB_UInt feature_tag,HB_UShort script_index,HB_UShort language_index,HB_UShort * feature_index)3835 HB_Error  HB_GSUB_Select_Feature( HB_GSUBHeader*  gsub,
3836 				  HB_UInt         feature_tag,
3837 				  HB_UShort        script_index,
3838 				  HB_UShort        language_index,
3839 				  HB_UShort*       feature_index )
3840 {
3841   HB_UShort           n;
3842 
3843   HB_ScriptList*     sl;
3844   HB_ScriptRecord*   sr;
3845   HB_ScriptTable*    s;
3846   HB_LangSysRecord*  lsr;
3847   HB_LangSys*        ls;
3848   HB_UShort*          fi;
3849 
3850   HB_FeatureList*    fl;
3851   HB_FeatureRecord*  fr;
3852 
3853 
3854   if ( !gsub || !feature_index )
3855     return ERR(HB_Err_Invalid_Argument);
3856 
3857   sl = &gsub->ScriptList;
3858   sr = sl->ScriptRecord;
3859 
3860   fl = &gsub->FeatureList;
3861   fr = fl->FeatureRecord;
3862 
3863   if ( script_index >= sl->ScriptCount )
3864     return ERR(HB_Err_Invalid_Argument);
3865 
3866   s   = &sr[script_index].Script;
3867   lsr = s->LangSysRecord;
3868 
3869   if ( language_index == 0xFFFF )
3870     ls = &s->DefaultLangSys;
3871   else
3872   {
3873     if ( language_index >= s->LangSysCount )
3874       return ERR(HB_Err_Invalid_Argument);
3875 
3876     ls = &lsr[language_index].LangSys;
3877   }
3878 
3879   fi = ls->FeatureIndex;
3880 
3881   for ( n = 0; n < ls->FeatureCount; n++ )
3882   {
3883     if ( fi[n] >= fl->FeatureCount )
3884       return ERR(HB_Err_Invalid_SubTable_Format);
3885 
3886     if ( feature_tag == fr[fi[n]].FeatureTag )
3887     {
3888       *feature_index = fi[n];
3889 
3890       return HB_Err_Ok;
3891     }
3892   }
3893 
3894   return HB_Err_Not_Covered;
3895 }
3896 
3897 
3898 /* The next three functions return a null-terminated list */
3899 
3900 
HB_GSUB_Query_Scripts(HB_GSUBHeader * gsub,HB_UInt ** script_tag_list)3901 HB_Error  HB_GSUB_Query_Scripts( HB_GSUBHeader*  gsub,
3902 				 HB_UInt**       script_tag_list )
3903 {
3904   HB_UShort          n;
3905   HB_Error           error;
3906   HB_UInt*          stl;
3907 
3908   HB_ScriptList*    sl;
3909   HB_ScriptRecord*  sr;
3910 
3911 
3912   if ( !gsub || !script_tag_list )
3913     return ERR(HB_Err_Invalid_Argument);
3914 
3915   sl = &gsub->ScriptList;
3916   sr = sl->ScriptRecord;
3917 
3918   if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) )
3919     return error;
3920 
3921   for ( n = 0; n < sl->ScriptCount; n++ )
3922     stl[n] = sr[n].ScriptTag;
3923   stl[n] = 0;
3924 
3925   *script_tag_list = stl;
3926 
3927   return HB_Err_Ok;
3928 }
3929 
3930 
3931 
HB_GSUB_Query_Languages(HB_GSUBHeader * gsub,HB_UShort script_index,HB_UInt ** language_tag_list)3932 HB_Error  HB_GSUB_Query_Languages( HB_GSUBHeader*  gsub,
3933 				   HB_UShort        script_index,
3934 				   HB_UInt**       language_tag_list )
3935 {
3936   HB_UShort           n;
3937   HB_Error            error;
3938   HB_UInt*           ltl;
3939 
3940   HB_ScriptList*     sl;
3941   HB_ScriptRecord*   sr;
3942   HB_ScriptTable*    s;
3943   HB_LangSysRecord*  lsr;
3944 
3945 
3946   if ( !gsub || !language_tag_list )
3947     return ERR(HB_Err_Invalid_Argument);
3948 
3949   sl = &gsub->ScriptList;
3950   sr = sl->ScriptRecord;
3951 
3952   if ( script_index >= sl->ScriptCount )
3953     return ERR(HB_Err_Invalid_Argument);
3954 
3955   s   = &sr[script_index].Script;
3956   lsr = s->LangSysRecord;
3957 
3958   if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) )
3959     return error;
3960 
3961   for ( n = 0; n < s->LangSysCount; n++ )
3962     ltl[n] = lsr[n].LangSysTag;
3963   ltl[n] = 0;
3964 
3965   *language_tag_list = ltl;
3966 
3967   return HB_Err_Ok;
3968 }
3969 
3970 
3971 /* selecting 0xFFFF for language_index asks for the values of the
3972    default language (DefaultLangSys)                              */
3973 
3974 
HB_GSUB_Query_Features(HB_GSUBHeader * gsub,HB_UShort script_index,HB_UShort language_index,HB_UInt ** feature_tag_list)3975 HB_Error  HB_GSUB_Query_Features( HB_GSUBHeader*  gsub,
3976 				  HB_UShort        script_index,
3977 				  HB_UShort        language_index,
3978 				  HB_UInt**       feature_tag_list )
3979 {
3980   HB_UShort           n;
3981   HB_Error            error;
3982   HB_UInt*           ftl;
3983 
3984   HB_ScriptList*     sl;
3985   HB_ScriptRecord*   sr;
3986   HB_ScriptTable*    s;
3987   HB_LangSysRecord*  lsr;
3988   HB_LangSys*        ls;
3989   HB_UShort*          fi;
3990 
3991   HB_FeatureList*    fl;
3992   HB_FeatureRecord*  fr;
3993 
3994 
3995   if ( !gsub || !feature_tag_list )
3996     return ERR(HB_Err_Invalid_Argument);
3997 
3998   sl = &gsub->ScriptList;
3999   sr = sl->ScriptRecord;
4000 
4001   fl = &gsub->FeatureList;
4002   fr = fl->FeatureRecord;
4003 
4004   if ( script_index >= sl->ScriptCount )
4005     return ERR(HB_Err_Invalid_Argument);
4006 
4007   s   = &sr[script_index].Script;
4008   lsr = s->LangSysRecord;
4009 
4010   if ( language_index == 0xFFFF )
4011     ls = &s->DefaultLangSys;
4012   else
4013   {
4014     if ( language_index >= s->LangSysCount )
4015       return ERR(HB_Err_Invalid_Argument);
4016 
4017     ls = &lsr[language_index].LangSys;
4018   }
4019 
4020   fi = ls->FeatureIndex;
4021 
4022   if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) )
4023     return error;
4024 
4025   for ( n = 0; n < ls->FeatureCount; n++ )
4026   {
4027     if ( fi[n] >= fl->FeatureCount )
4028     {
4029       FREE( ftl );
4030       return ERR(HB_Err_Invalid_SubTable_Format);
4031     }
4032     ftl[n] = fr[fi[n]].FeatureTag;
4033   }
4034   ftl[n] = 0;
4035 
4036   *feature_tag_list = ftl;
4037 
4038   return HB_Err_Ok;
4039 }
4040 
4041 
4042 /* Do an individual subtable lookup.  Returns HB_Err_Ok if substitution
4043    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)4044 static HB_Error  GSUB_Do_Glyph_Lookup( HB_GSUBHeader* gsub,
4045 				       HB_UShort       lookup_index,
4046 				       HB_Buffer      buffer,
4047 				       HB_UShort       context_length,
4048 				       int             nesting_level )
4049 {
4050   HB_Error               error = HB_Err_Not_Covered;
4051   HB_UShort              i, flags, lookup_count;
4052   HB_Lookup*             lo;
4053   int                    lookup_type;
4054 
4055   nesting_level++;
4056 
4057   if ( nesting_level > HB_MAX_NESTING_LEVEL )
4058     return ERR(HB_Err_Not_Covered); /* ERR() call intended */
4059 
4060   lookup_count = gsub->LookupList.LookupCount;
4061   if (lookup_index >= lookup_count)
4062     return error;
4063 
4064   lo    = &gsub->LookupList.Lookup[lookup_index];
4065   flags = lo->LookupFlag;
4066   lookup_type = lo->LookupType;
4067 
4068   for ( i = 0; i < lo->SubTableCount; i++ )
4069   {
4070     HB_GSUB_SubTable *st = &lo->SubTable[i].st.gsub;
4071 
4072     switch (lookup_type) {
4073       case HB_GSUB_LOOKUP_SINGLE:
4074 	error = Lookup_SingleSubst		( gsub, st, buffer, flags, context_length, nesting_level ); break;
4075       case HB_GSUB_LOOKUP_MULTIPLE:
4076 	error = Lookup_MultipleSubst		( gsub, st, buffer, flags, context_length, nesting_level ); break;
4077       case HB_GSUB_LOOKUP_ALTERNATE:
4078 	error = Lookup_AlternateSubst		( gsub, st, buffer, flags, context_length, nesting_level ); break;
4079       case HB_GSUB_LOOKUP_LIGATURE:
4080 	error = Lookup_LigatureSubst		( gsub, st, buffer, flags, context_length, nesting_level ); break;
4081       case HB_GSUB_LOOKUP_CONTEXT:
4082 	error = Lookup_ContextSubst		( gsub, st, buffer, flags, context_length, nesting_level ); break;
4083       case HB_GSUB_LOOKUP_CHAIN:
4084 	error = Lookup_ChainContextSubst	( gsub, st, buffer, flags, context_length, nesting_level ); break;
4085     /*case HB_GSUB_LOOKUP_EXTENSION:
4086 	error = Lookup_ExtensionSubst		( gsub, st, buffer, flags, context_length, nesting_level ); break;*/
4087       case HB_GSUB_LOOKUP_REVERSE_CHAIN:
4088 	error = Lookup_ReverseChainContextSubst	( gsub, st, buffer, flags, context_length, nesting_level ); break;
4089       default:
4090 	error = HB_Err_Not_Covered;
4091     };
4092 
4093     /* Check whether we have a successful substitution or an error other
4094        than HB_Err_Not_Covered                                          */
4095     if ( error != HB_Err_Not_Covered )
4096       return error;
4097   }
4098 
4099   return HB_Err_Not_Covered;
4100 }
4101 
4102 
4103 HB_INTERNAL HB_Error
_HB_GSUB_Load_SubTable(HB_GSUB_SubTable * st,HB_Stream stream,HB_UShort lookup_type)4104 _HB_GSUB_Load_SubTable( HB_GSUB_SubTable* st,
4105 			HB_Stream         stream,
4106 			HB_UShort         lookup_type )
4107 {
4108   switch (lookup_type) {
4109     case HB_GSUB_LOOKUP_SINGLE:		return Load_SingleSubst			( st, stream );
4110     case HB_GSUB_LOOKUP_MULTIPLE:	return Load_MultipleSubst		( st, stream );
4111     case HB_GSUB_LOOKUP_ALTERNATE:	return Load_AlternateSubst		( st, stream );
4112     case HB_GSUB_LOOKUP_LIGATURE:	return Load_LigatureSubst		( st, stream );
4113     case HB_GSUB_LOOKUP_CONTEXT:	return Load_ContextSubst		( st, stream );
4114     case HB_GSUB_LOOKUP_CHAIN:		return Load_ChainContextSubst		( st, stream );
4115   /*case HB_GSUB_LOOKUP_EXTENSION:	return Load_ExtensionSubst		( st, stream );*/
4116     case HB_GSUB_LOOKUP_REVERSE_CHAIN:	return Load_ReverseChainContextSubst	( st, stream );
4117     default:				return ERR(HB_Err_Invalid_SubTable_Format);
4118   };
4119 }
4120 
4121 
4122 HB_INTERNAL void
_HB_GSUB_Free_SubTable(HB_GSUB_SubTable * st,HB_UShort lookup_type)4123 _HB_GSUB_Free_SubTable( HB_GSUB_SubTable* st,
4124 			HB_UShort         lookup_type )
4125 {
4126   switch ( lookup_type ) {
4127     case HB_GSUB_LOOKUP_SINGLE:		Free_SingleSubst		( st ); return;
4128     case HB_GSUB_LOOKUP_MULTIPLE:	Free_MultipleSubst		( st ); return;
4129     case HB_GSUB_LOOKUP_ALTERNATE:	Free_AlternateSubst		( st ); return;
4130     case HB_GSUB_LOOKUP_LIGATURE:	Free_LigatureSubst		( st ); return;
4131     case HB_GSUB_LOOKUP_CONTEXT:	Free_ContextSubst		( st ); return;
4132     case HB_GSUB_LOOKUP_CHAIN:		Free_ChainContextSubst		( st ); return;
4133   /*case HB_GSUB_LOOKUP_EXTENSION:	Free_ExtensionSubst		( st ); return;*/
4134     case HB_GSUB_LOOKUP_REVERSE_CHAIN:	Free_ReverseChainContextSubst	( st ); return;
4135     default:									return;
4136   };
4137 }
4138 
4139 
4140 
4141 /* apply one lookup to the input string object */
4142 
GSUB_Do_String_Lookup(HB_GSUBHeader * gsub,HB_UShort lookup_index,HB_Buffer buffer)4143 static HB_Error  GSUB_Do_String_Lookup( HB_GSUBHeader*   gsub,
4144 				   HB_UShort         lookup_index,
4145 				   HB_Buffer        buffer )
4146 {
4147   HB_Error  error, retError = HB_Err_Not_Covered;
4148 
4149   HB_UInt*  properties = gsub->LookupList.Properties;
4150   int       lookup_type = gsub->LookupList.Lookup[lookup_index].LookupType;
4151 
4152   const int       nesting_level = 0;
4153   /* 0xFFFF indicates that we don't have a context length yet */
4154   const HB_UShort context_length = 0xFFFF;
4155 
4156   switch (lookup_type) {
4157 
4158     case HB_GSUB_LOOKUP_SINGLE:
4159     case HB_GSUB_LOOKUP_MULTIPLE:
4160     case HB_GSUB_LOOKUP_ALTERNATE:
4161     case HB_GSUB_LOOKUP_LIGATURE:
4162     case HB_GSUB_LOOKUP_CONTEXT:
4163     case HB_GSUB_LOOKUP_CHAIN:
4164       /* in/out forward substitution (implemented lazy) */
4165 
4166       _hb_buffer_clear_output ( buffer );
4167       buffer->in_pos = 0;
4168   while ( buffer->in_pos < buffer->in_length )
4169   {
4170     if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
4171     {
4172 	  error = GSUB_Do_Glyph_Lookup( gsub, lookup_index, buffer, context_length, nesting_level );
4173       if ( error )
4174       {
4175 	if ( error != HB_Err_Not_Covered )
4176 	  return error;
4177       }
4178       else
4179 	retError = error;
4180     }
4181     else
4182       error = HB_Err_Not_Covered;
4183 
4184     if ( error == HB_Err_Not_Covered )
4185 	  if ( COPY_Glyph ( buffer ) )
4186 	return error;
4187   }
4188       /* we shouldn't swap if error occurred.
4189        *
4190        * also don't swap if nothing changed (ie HB_Err_Not_Covered).
4191        * shouldn't matter in that case though.
4192        */
4193       if ( retError == HB_Err_Ok )
4194 	_hb_buffer_swap( buffer );
4195 
4196   return retError;
4197 
4198     case HB_GSUB_LOOKUP_REVERSE_CHAIN:
4199       /* in-place backward substitution */
4200 
4201       buffer->in_pos = buffer->in_length - 1;
4202     do
4203     {
4204       if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
4205 	{
4206 	  error = GSUB_Do_Glyph_Lookup( gsub, lookup_index, buffer, context_length, nesting_level );
4207 	  if ( error )
4208 	    {
4209 	      if ( error != HB_Err_Not_Covered )
4210 		return error;
4211 	    }
4212 	  else
4213 	    retError = error;
4214 	}
4215 	else
4216 	  error = HB_Err_Not_Covered;
4217 
4218 	if ( error == HB_Err_Not_Covered )
4219 	  buffer->in_pos--;
4220       }
4221       while ((HB_Int) buffer->in_pos >= 0);
4222 
4223       return retError;
4224 
4225   /*case HB_GSUB_LOOKUP_EXTENSION:*/
4226     default:
4227   return retError;
4228   };
4229 }
4230 
4231 
HB_GSUB_Add_Feature(HB_GSUBHeader * gsub,HB_UShort feature_index,HB_UInt property)4232 HB_Error  HB_GSUB_Add_Feature( HB_GSUBHeader*  gsub,
4233 			       HB_UShort        feature_index,
4234 			       HB_UInt          property )
4235 {
4236   HB_UShort    i;
4237 
4238   HB_Feature  feature;
4239   HB_UInt*     properties;
4240   HB_UShort*   index;
4241   HB_UShort    lookup_count;
4242 
4243   /* Each feature can only be added once */
4244 
4245   if ( !gsub ||
4246        feature_index >= gsub->FeatureList.FeatureCount ||
4247        gsub->FeatureList.ApplyCount == gsub->FeatureList.FeatureCount )
4248     return ERR(HB_Err_Invalid_Argument);
4249 
4250   gsub->FeatureList.ApplyOrder[gsub->FeatureList.ApplyCount++] = feature_index;
4251 
4252   properties = gsub->LookupList.Properties;
4253 
4254   feature = gsub->FeatureList.FeatureRecord[feature_index].Feature;
4255   index   = feature.LookupListIndex;
4256   lookup_count = gsub->LookupList.LookupCount;
4257 
4258   for ( i = 0; i < feature.LookupListCount; i++ )
4259   {
4260     HB_UShort lookup_index = index[i];
4261     if (lookup_index < lookup_count)
4262       properties[lookup_index] |= property;
4263   }
4264 
4265   return HB_Err_Ok;
4266 }
4267 
4268 
4269 
HB_GSUB_Clear_Features(HB_GSUBHeader * gsub)4270 HB_Error  HB_GSUB_Clear_Features( HB_GSUBHeader*  gsub )
4271 {
4272   HB_UShort i;
4273 
4274   HB_UInt*  properties;
4275 
4276 
4277   if ( !gsub )
4278     return ERR(HB_Err_Invalid_Argument);
4279 
4280   gsub->FeatureList.ApplyCount = 0;
4281 
4282   properties = gsub->LookupList.Properties;
4283 
4284   for ( i = 0; i < gsub->LookupList.LookupCount; i++ )
4285     properties[i] = 0;
4286 
4287   return HB_Err_Ok;
4288 }
4289 
4290 
4291 
HB_GSUB_Register_Alternate_Function(HB_GSUBHeader * gsub,HB_AltFunction altfunc,void * data)4292 HB_Error  HB_GSUB_Register_Alternate_Function( HB_GSUBHeader*  gsub,
4293 					       HB_AltFunction  altfunc,
4294 					       void*            data )
4295 {
4296   if ( !gsub )
4297     return ERR(HB_Err_Invalid_Argument);
4298 
4299   gsub->altfunc = altfunc;
4300   gsub->data    = data;
4301 
4302   return HB_Err_Ok;
4303 }
4304 
4305 /* returns error if one happened, otherwise returns HB_Err_Not_Covered if no
4306  * feature were applied, or HB_Err_Ok otherwise.
4307  */
HB_GSUB_Apply_String(HB_GSUBHeader * gsub,HB_Buffer buffer)4308 HB_Error  HB_GSUB_Apply_String( HB_GSUBHeader*   gsub,
4309 				HB_Buffer        buffer )
4310 {
4311   HB_Error          error, retError = HB_Err_Not_Covered;
4312   int               i, j, lookup_count, num_features;
4313 
4314   if ( !gsub ||
4315        !buffer)
4316     return ERR(HB_Err_Invalid_Argument);
4317 
4318   if ( buffer->in_length == 0 )
4319     return retError;
4320 
4321   lookup_count = gsub->LookupList.LookupCount;
4322   num_features = gsub->FeatureList.ApplyCount;
4323 
4324   for ( i = 0; i < num_features; i++)
4325   {
4326     HB_UShort  feature_index = gsub->FeatureList.ApplyOrder[i];
4327     HB_Feature feature = gsub->FeatureList.FeatureRecord[feature_index].Feature;
4328 
4329     for ( j = 0; j < feature.LookupListCount; j++ )
4330     {
4331       HB_UShort         lookup_index = feature.LookupListIndex[j];
4332 
4333       /* Skip nonexistant lookups */
4334       if (lookup_index >= lookup_count)
4335        continue;
4336 
4337 	error = GSUB_Do_String_Lookup( gsub, lookup_index, buffer );
4338       if ( error )
4339       {
4340 	if ( error != HB_Err_Not_Covered )
4341 	  return error;
4342       }
4343       else
4344 	retError = error;
4345     }
4346   }
4347 
4348   error = retError;
4349 
4350   return error;
4351 }
4352 
4353 
4354 /* END */
4355