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