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