Imported Upstream version 0.9.12
[platform/upstream/harfbuzz.git] / src / hb-old / harfbuzz-open.c
1 /*
2  * Copyright (C) 1998-2004  David Turner and Werner Lemberg
3  * Copyright (C) 2006  Behdad Esfahbod
4  *
5  * This is part of HarfBuzz, an OpenType Layout engine library.
6  *
7  * Permission is hereby granted, without written agreement and without
8  * license or royalty fees, to use, copy, modify, and distribute this
9  * software and its documentation for any purpose, provided that the
10  * above copyright notice and the following two paragraphs appear in
11  * all copies of this software.
12  *
13  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17  * DAMAGE.
18  *
19  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24  */
25
26 #include "harfbuzz-impl.h"
27 #include "harfbuzz-open-private.h"
28
29
30 /***************************
31  * Script related functions
32  ***************************/
33
34
35 /* LangSys */
36
37 static HB_Error  Load_LangSys( HB_LangSys*  ls,
38                                HB_Stream     stream )
39 {
40   HB_Error   error;
41   HB_UShort  n, count;
42   HB_UShort* fi;
43
44
45   if ( ACCESS_Frame( 6L ) )
46     return error;
47
48   ls->LookupOrderOffset    = GET_UShort();    /* should be 0 */
49   ls->ReqFeatureIndex      = GET_UShort();
50   count = ls->FeatureCount = GET_UShort();
51
52   FORGET_Frame();
53
54   ls->FeatureIndex = NULL;
55
56   if ( ALLOC_ARRAY( ls->FeatureIndex, count, HB_UShort ) )
57     return error;
58
59   if ( ACCESS_Frame( count * 2L ) )
60   {
61     FREE( ls->FeatureIndex );
62     return error;
63   }
64
65   fi = ls->FeatureIndex;
66
67   for ( n = 0; n < count; n++ )
68     fi[n] = GET_UShort();
69
70   FORGET_Frame();
71
72   return HB_Err_Ok;
73 }
74
75
76 static void  Free_LangSys( HB_LangSys*  ls )
77 {
78   FREE( ls->FeatureIndex );
79 }
80
81
82 /* Script */
83
84 static HB_Error  Load_Script( HB_ScriptTable*  s,
85                               HB_Stream    stream )
86 {
87   HB_Error   error;
88   HB_UShort  n, m, count;
89   HB_UInt   cur_offset, new_offset, base_offset;
90
91   HB_LangSysRecord*  lsr;
92
93
94   base_offset = FILE_Pos();
95
96   if ( ACCESS_Frame( 2L ) )
97     return error;
98
99   new_offset = GET_UShort() + base_offset;
100
101   FORGET_Frame();
102
103   if ( new_offset != base_offset )        /* not a NULL offset */
104   {
105     cur_offset = FILE_Pos();
106     if ( FILE_Seek( new_offset ) ||
107          ( error = Load_LangSys( &s->DefaultLangSys,
108                                  stream ) ) != HB_Err_Ok )
109       return error;
110     (void)FILE_Seek( cur_offset );
111   }
112   else
113   {
114     /* we create a DefaultLangSys table with no entries */
115
116     s->DefaultLangSys.LookupOrderOffset = 0;
117     s->DefaultLangSys.ReqFeatureIndex   = 0xFFFF;
118     s->DefaultLangSys.FeatureCount      = 0;
119     s->DefaultLangSys.FeatureIndex      = NULL;
120   }
121
122   if ( ACCESS_Frame( 2L ) )
123     goto Fail2;
124
125   count = s->LangSysCount = GET_UShort();
126
127   /* safety check; otherwise the official handling of TrueType Open
128      fonts won't work */
129
130   if ( s->LangSysCount == 0 && s->DefaultLangSys.FeatureCount == 0 )
131   {
132     error = HB_Err_Not_Covered;
133     goto Fail2;
134   }
135
136   FORGET_Frame();
137
138   s->LangSysRecord = NULL;
139
140   if ( ALLOC_ARRAY( s->LangSysRecord, count, HB_LangSysRecord ) )
141     goto Fail2;
142
143   lsr = s->LangSysRecord;
144
145   for ( n = 0; n < count; n++ )
146   {
147     if ( ACCESS_Frame( 6L ) )
148       goto Fail1;
149
150     lsr[n].LangSysTag = GET_ULong();
151     new_offset = GET_UShort() + base_offset;
152
153     FORGET_Frame();
154
155     cur_offset = FILE_Pos();
156     if ( FILE_Seek( new_offset ) ||
157          ( error = Load_LangSys( &lsr[n].LangSys, stream ) ) != HB_Err_Ok )
158       goto Fail1;
159     (void)FILE_Seek( cur_offset );
160   }
161
162   return HB_Err_Ok;
163
164 Fail1:
165   for ( m = 0; m < n; m++ )
166     Free_LangSys( &lsr[m].LangSys );
167
168   FREE( s->LangSysRecord );
169
170 Fail2:
171   Free_LangSys( &s->DefaultLangSys );
172   return error;
173 }
174
175
176 static void  Free_Script( HB_ScriptTable*  s )
177 {
178   HB_UShort           n, count;
179
180   HB_LangSysRecord*  lsr;
181
182
183   Free_LangSys( &s->DefaultLangSys );
184
185   if ( s->LangSysRecord )
186   {
187     count = s->LangSysCount;
188     lsr   = s->LangSysRecord;
189
190     for ( n = 0; n < count; n++ )
191       Free_LangSys( &lsr[n].LangSys );
192
193     FREE( lsr );
194   }
195 }
196
197
198 /* ScriptList */
199
200 HB_INTERNAL HB_Error
201 _HB_OPEN_Load_ScriptList( HB_ScriptList* sl,
202                            HB_Stream        stream )
203 {
204   HB_Error   error;
205
206   HB_UShort          n, script_count;
207   HB_UInt           cur_offset, new_offset, base_offset;
208
209   HB_ScriptRecord*  sr;
210
211
212   base_offset = FILE_Pos();
213
214   if ( ACCESS_Frame( 2L ) )
215     return error;
216
217   script_count = GET_UShort();
218
219   FORGET_Frame();
220
221   sl->ScriptRecord = NULL;
222
223   if ( ALLOC_ARRAY( sl->ScriptRecord, script_count, HB_ScriptRecord ) )
224     return error;
225
226   sr = sl->ScriptRecord;
227
228   sl->ScriptCount= 0;
229   for ( n = 0; n < script_count; n++ )
230   {
231     if ( ACCESS_Frame( 6L ) )
232       goto Fail;
233
234     sr[sl->ScriptCount].ScriptTag = GET_ULong();
235     new_offset = GET_UShort() + base_offset;
236
237     FORGET_Frame();
238
239     cur_offset = FILE_Pos();
240
241     if ( FILE_Seek( new_offset ) )
242       goto Fail;
243
244     error = Load_Script( &sr[sl->ScriptCount].Script, stream );
245     if ( error == HB_Err_Ok )
246       sl->ScriptCount += 1;
247     else if ( error != HB_Err_Not_Covered )
248       goto Fail;
249
250     (void)FILE_Seek( cur_offset );
251   }
252
253   /* Empty tables are harmless and generated by fontforge.
254    * See http://bugzilla.gnome.org/show_bug.cgi?id=347073
255    */
256 #if 0
257   if ( sl->ScriptCount == 0 )
258   {
259     error = ERR(HB_Err_Invalid_SubTable);
260     goto Fail;
261   }
262 #endif
263   
264   return HB_Err_Ok;
265
266 Fail:
267   for ( n = 0; n < sl->ScriptCount; n++ )
268     Free_Script( &sr[n].Script );
269
270   FREE( sl->ScriptRecord );
271   return error;
272 }
273
274
275 HB_INTERNAL void
276 _HB_OPEN_Free_ScriptList( HB_ScriptList* sl )
277 {
278   HB_UShort          n, count;
279
280   HB_ScriptRecord*  sr;
281
282
283   if ( sl->ScriptRecord )
284   {
285     count = sl->ScriptCount;
286     sr    = sl->ScriptRecord;
287
288     for ( n = 0; n < count; n++ )
289       Free_Script( &sr[n].Script );
290
291     FREE( sr );
292   }
293 }
294
295
296
297 /*********************************
298  * Feature List related functions
299  *********************************/
300
301
302 /* Feature */
303
304 static HB_Error  Load_Feature( HB_Feature*  f,
305                                HB_Stream     stream )
306 {
307   HB_Error   error;
308
309   HB_UShort   n, count;
310
311   HB_UShort*  lli;
312
313
314   if ( ACCESS_Frame( 4L ) )
315     return error;
316
317   f->FeatureParams           = GET_UShort();    /* should be 0 */
318   count = f->LookupListCount = GET_UShort();
319
320   FORGET_Frame();
321
322   f->LookupListIndex = NULL;
323
324   if ( ALLOC_ARRAY( f->LookupListIndex, count, HB_UShort ) )
325     return error;
326
327   lli = f->LookupListIndex;
328
329   if ( ACCESS_Frame( count * 2L ) )
330   {
331     FREE( f->LookupListIndex );
332     return error;
333   }
334
335   for ( n = 0; n < count; n++ )
336     lli[n] = GET_UShort();
337
338   FORGET_Frame();
339
340   return HB_Err_Ok;
341 }
342
343
344 static void  Free_Feature( HB_Feature*  f )
345 {
346   FREE( f->LookupListIndex );
347 }
348
349
350 /* FeatureList */
351
352 HB_INTERNAL HB_Error
353 _HB_OPEN_Load_FeatureList( HB_FeatureList* fl,
354                             HB_Stream         stream )
355 {
356   HB_Error   error;
357
358   HB_UShort           n, m, count;
359   HB_UInt            cur_offset, new_offset, base_offset;
360
361   HB_FeatureRecord*  fr;
362
363
364   base_offset = FILE_Pos();
365
366   if ( ACCESS_Frame( 2L ) )
367     return error;
368
369   count = fl->FeatureCount = GET_UShort();
370
371   FORGET_Frame();
372
373   fl->FeatureRecord = NULL;
374
375   if ( ALLOC_ARRAY( fl->FeatureRecord, count, HB_FeatureRecord ) )
376     return error;
377   if ( ALLOC_ARRAY( fl->ApplyOrder, count, HB_UShort ) )
378     goto Fail2;
379   
380   fl->ApplyCount = 0;
381
382   fr = fl->FeatureRecord;
383
384   for ( n = 0; n < count; n++ )
385   {
386     if ( ACCESS_Frame( 6L ) )
387       goto Fail1;
388
389     fr[n].FeatureTag = GET_ULong();
390     new_offset = GET_UShort() + base_offset;
391
392     FORGET_Frame();
393
394     cur_offset = FILE_Pos();
395     if ( FILE_Seek( new_offset ) ||
396          ( error = Load_Feature( &fr[n].Feature, stream ) ) != HB_Err_Ok )
397       goto Fail1;
398     (void)FILE_Seek( cur_offset );
399   }
400
401   return HB_Err_Ok;
402
403 Fail1:
404   for ( m = 0; m < n; m++ )
405     Free_Feature( &fr[m].Feature );
406
407   FREE( fl->ApplyOrder );
408
409 Fail2:
410   FREE( fl->FeatureRecord );
411
412   return error;
413 }
414
415
416 HB_INTERNAL void
417 _HB_OPEN_Free_FeatureList( HB_FeatureList*  fl )
418 {
419   HB_UShort           n, count;
420
421   HB_FeatureRecord*  fr;
422
423
424   if ( fl->FeatureRecord )
425   {
426     count = fl->FeatureCount;
427     fr    = fl->FeatureRecord;
428
429     for ( n = 0; n < count; n++ )
430       Free_Feature( &fr[n].Feature );
431
432     FREE( fr );
433   }
434   
435   FREE( fl->ApplyOrder );
436 }
437
438
439
440 /********************************
441  * Lookup List related functions
442  ********************************/
443
444 /* the subroutines of the following two functions are defined in
445    ftxgsub.c and ftxgpos.c respectively                          */
446
447
448 /* SubTable */
449
450 static HB_Error  Load_SubTable( HB_SubTable*  st,
451                                 HB_Stream     stream,
452                                 HB_Type       table_type,
453                                 HB_UShort     lookup_type )
454 {
455   if ( table_type == HB_Type_GSUB )
456     return _HB_GSUB_Load_SubTable ( &st->st.gsub, stream, lookup_type );
457   else
458     return _HB_GPOS_Load_SubTable ( &st->st.gpos, stream, lookup_type );
459 }
460
461
462 static void  Free_SubTable( HB_SubTable*  st,
463                             HB_Type       table_type,
464                             HB_UShort      lookup_type )
465 {
466   if ( table_type == HB_Type_GSUB )
467     _HB_GSUB_Free_SubTable ( &st->st.gsub, lookup_type );
468   else
469     _HB_GPOS_Free_SubTable ( &st->st.gpos, lookup_type );
470 }
471
472
473 /* Lookup */
474
475 static HB_Error  Load_Lookup( HB_Lookup*   l,
476                               HB_Stream     stream,
477                               HB_Type      type )
478 {
479   HB_Error   error;
480
481   HB_UShort      n, m, count;
482   HB_UInt       cur_offset, new_offset, base_offset;
483
484   HB_SubTable*  st;
485
486   HB_Bool        is_extension = FALSE;
487
488
489   base_offset = FILE_Pos();
490
491   if ( ACCESS_Frame( 6L ) )
492     return error;
493
494   l->LookupType            = GET_UShort();
495   l->LookupFlag            = GET_UShort();
496   count = l->SubTableCount = GET_UShort();
497
498   FORGET_Frame();
499
500   l->SubTable = NULL;
501
502   if ( ALLOC_ARRAY( l->SubTable, count, HB_SubTable ) )
503     return error;
504
505   st = l->SubTable;
506
507   if ( ( type == HB_Type_GSUB && l->LookupType == HB_GSUB_LOOKUP_EXTENSION ) ||
508        ( type == HB_Type_GPOS && l->LookupType == HB_GPOS_LOOKUP_EXTENSION ) )
509     is_extension = TRUE;
510
511   for ( n = 0; n < count; n++ )
512   {
513     if ( ACCESS_Frame( 2L ) )
514       goto Fail;
515
516     new_offset = GET_UShort() + base_offset;
517
518     FORGET_Frame();
519
520     cur_offset = FILE_Pos();
521
522     if ( is_extension )
523     {
524       if ( FILE_Seek( new_offset ) || ACCESS_Frame( 8L ) )
525         goto Fail;
526
527       if (GET_UShort() != 1) /* format should be 1 */
528         goto Fail;
529
530       l->LookupType = GET_UShort();
531       new_offset += GET_ULong();
532
533       FORGET_Frame();
534     }
535
536     if ( FILE_Seek( new_offset ) ||
537          ( error = Load_SubTable( &st[n], stream,
538                                   type, l->LookupType ) ) != HB_Err_Ok )
539       goto Fail;
540     (void)FILE_Seek( cur_offset );
541   }
542
543   return HB_Err_Ok;
544
545 Fail:
546   for ( m = 0; m < n; m++ )
547     Free_SubTable( &st[m], type, l->LookupType );
548
549   FREE( l->SubTable );
550   return error;
551 }
552
553
554 static void  Free_Lookup( HB_Lookup*   l,
555                           HB_Type      type)
556 {
557   HB_UShort      n, count;
558
559   HB_SubTable*  st;
560
561
562   if ( l->SubTable )
563   {
564     count = l->SubTableCount;
565     st    = l->SubTable;
566
567     for ( n = 0; n < count; n++ )
568       Free_SubTable( &st[n], type, l->LookupType );
569
570     FREE( st );
571   }
572 }
573
574
575 /* LookupList */
576
577 HB_INTERNAL HB_Error
578 _HB_OPEN_Load_LookupList( HB_LookupList* ll,
579                            HB_Stream        stream,
580                            HB_Type         type )
581 {
582   HB_Error   error;
583
584   HB_UShort    n, m, count;
585   HB_UInt     cur_offset, new_offset, base_offset;
586
587   HB_Lookup*  l;
588
589
590   base_offset = FILE_Pos();
591
592   if ( ACCESS_Frame( 2L ) )
593     return error;
594
595   count = ll->LookupCount = GET_UShort();
596
597   FORGET_Frame();
598
599   ll->Lookup = NULL;
600
601   if ( ALLOC_ARRAY( ll->Lookup, count, HB_Lookup ) )
602     return error;
603   if ( ALLOC_ARRAY( ll->Properties, count, HB_UInt ) )
604     goto Fail2;
605
606   l = ll->Lookup;
607
608   for ( n = 0; n < count; n++ )
609   {
610     if ( ACCESS_Frame( 2L ) )
611       goto Fail1;
612
613     new_offset = GET_UShort() + base_offset;
614
615     FORGET_Frame();
616
617     cur_offset = FILE_Pos();
618     if ( FILE_Seek( new_offset ) ||
619          ( error = Load_Lookup( &l[n], stream, type ) ) != HB_Err_Ok )
620       goto Fail1;
621     (void)FILE_Seek( cur_offset );
622   }
623
624   return HB_Err_Ok;
625
626 Fail1:
627   FREE( ll->Properties );
628
629   for ( m = 0; m < n; m++ )
630     Free_Lookup( &l[m], type );
631
632 Fail2:
633   FREE( ll->Lookup );
634   return error;
635 }
636
637
638 HB_INTERNAL void
639 _HB_OPEN_Free_LookupList( HB_LookupList* ll,
640                        HB_Type         type )
641 {
642   HB_UShort    n, count;
643
644   HB_Lookup*  l;
645
646
647   FREE( ll->Properties );
648
649   if ( ll->Lookup )
650   {
651     count = ll->LookupCount;
652     l     = ll->Lookup;
653
654     for ( n = 0; n < count; n++ )
655       Free_Lookup( &l[n], type );
656
657     FREE( l );
658   }
659 }
660
661
662
663 /*****************************
664  * Coverage related functions
665  *****************************/
666
667
668 /* CoverageFormat1 */
669
670 static HB_Error  Load_Coverage1( HB_CoverageFormat1*  cf1,
671                                  HB_Stream             stream )
672 {
673   HB_Error   error;
674
675   HB_UShort  n, count;
676
677   HB_UShort* ga;
678
679
680   if ( ACCESS_Frame( 2L ) )
681     return error;
682
683   count = cf1->GlyphCount = GET_UShort();
684
685   FORGET_Frame();
686
687   cf1->GlyphArray = NULL;
688
689   if ( ALLOC_ARRAY( cf1->GlyphArray, count, HB_UShort ) )
690     return error;
691
692   ga = cf1->GlyphArray;
693
694   if ( ACCESS_Frame( count * 2L ) )
695   {
696     FREE( cf1->GlyphArray );
697     return error;
698   }
699
700   for ( n = 0; n < count; n++ )
701     ga[n] = GET_UShort();
702
703   FORGET_Frame();
704
705   return HB_Err_Ok;
706 }
707
708
709 static void  Free_Coverage1( HB_CoverageFormat1*  cf1)
710 {
711   FREE( cf1->GlyphArray );
712 }
713
714
715 /* CoverageFormat2 */
716
717 static HB_Error  Load_Coverage2( HB_CoverageFormat2*  cf2,
718                                  HB_Stream             stream )
719 {
720   HB_Error   error;
721
722   HB_UShort         n, count;
723
724   HB_RangeRecord*  rr;
725
726
727   if ( ACCESS_Frame( 2L ) )
728     return error;
729
730   count = cf2->RangeCount = GET_UShort();
731
732   FORGET_Frame();
733
734   cf2->RangeRecord = NULL;
735
736   if ( ALLOC_ARRAY( cf2->RangeRecord, count, HB_RangeRecord ) )
737     return error;
738
739   rr = cf2->RangeRecord;
740
741   if ( ACCESS_Frame( count * 6L ) )
742     goto Fail;
743
744   for ( n = 0; n < count; n++ )
745   {
746     rr[n].Start              = GET_UShort();
747     rr[n].End                = GET_UShort();
748     rr[n].StartCoverageIndex = GET_UShort();
749
750     /* sanity check; we are limited to 16bit integers */
751     if ( rr[n].Start > rr[n].End ||
752          ( rr[n].End - rr[n].Start + (long)rr[n].StartCoverageIndex ) >=
753            0x10000L )
754     {
755       error = ERR(HB_Err_Invalid_SubTable);
756       goto Fail;
757     }
758   }
759
760   FORGET_Frame();
761
762   return HB_Err_Ok;
763
764 Fail:
765   FREE( cf2->RangeRecord );
766   return error;
767 }
768
769
770 static void  Free_Coverage2( HB_CoverageFormat2*  cf2 )
771 {
772   FREE( cf2->RangeRecord );
773 }
774
775
776 HB_INTERNAL HB_Error
777 _HB_OPEN_Load_Coverage( HB_Coverage* c,
778                          HB_Stream      stream )
779 {
780   HB_Error   error;
781
782   if ( ACCESS_Frame( 2L ) )
783     return error;
784
785   c->CoverageFormat = GET_UShort();
786
787   FORGET_Frame();
788
789   switch ( c->CoverageFormat )
790   {
791   case 1:  return Load_Coverage1( &c->cf.cf1, stream );
792   case 2:  return Load_Coverage2( &c->cf.cf2, stream );
793   default: return ERR(HB_Err_Invalid_SubTable_Format);
794   }
795
796   return HB_Err_Ok;               /* never reached */
797 }
798
799
800 HB_INTERNAL void
801 _HB_OPEN_Free_Coverage( HB_Coverage* c )
802 {
803   switch ( c->CoverageFormat )
804   {
805   case 1:  Free_Coverage1( &c->cf.cf1 ); break;
806   case 2:  Free_Coverage2( &c->cf.cf2 ); break;
807   default:                                       break;
808   }
809 }
810
811
812 static HB_Error  Coverage_Index1( HB_CoverageFormat1*  cf1,
813                                   HB_UShort             glyphID,
814                                   HB_UShort*            index )
815 {
816   HB_UShort min, max, new_min, new_max, middle;
817
818   HB_UShort*  array = cf1->GlyphArray;
819
820
821   /* binary search */
822
823   if ( cf1->GlyphCount == 0 )
824     return HB_Err_Not_Covered;
825
826   new_min = 0;
827   new_max = cf1->GlyphCount - 1;
828
829   do
830   {
831     min = new_min;
832     max = new_max;
833
834     /* we use (min + max) / 2 = max - (max - min) / 2  to avoid
835        overflow and rounding errors                             */
836
837     middle = max - ( ( max - min ) >> 1 );
838
839     if ( glyphID == array[middle] )
840     {
841       *index = middle;
842       return HB_Err_Ok;
843     }
844     else if ( glyphID < array[middle] )
845     {
846       if ( middle == min )
847         break;
848       new_max = middle - 1;
849     }
850     else
851     {
852       if ( middle == max )
853         break;
854       new_min = middle + 1;
855     }
856   } while ( min < max );
857
858   return HB_Err_Not_Covered;
859 }
860
861
862 static HB_Error  Coverage_Index2( HB_CoverageFormat2*  cf2,
863                                   HB_UShort             glyphID,
864                                   HB_UShort*            index )
865 {
866   HB_UShort         min, max, new_min, new_max, middle;
867
868   HB_RangeRecord*  rr = cf2->RangeRecord;
869
870
871   /* binary search */
872
873   if ( cf2->RangeCount == 0 )
874     return HB_Err_Not_Covered;
875
876   new_min = 0;
877   new_max = cf2->RangeCount - 1;
878
879   do
880   {
881     min = new_min;
882     max = new_max;
883
884     /* we use (min + max) / 2 = max - (max - min) / 2  to avoid
885        overflow and rounding errors                             */
886
887     middle = max - ( ( max - min ) >> 1 );
888
889     if ( glyphID >= rr[middle].Start && glyphID <= rr[middle].End )
890     {
891       *index = rr[middle].StartCoverageIndex + glyphID - rr[middle].Start;
892       return HB_Err_Ok;
893     }
894     else if ( glyphID < rr[middle].Start )
895     {
896       if ( middle == min )
897         break;
898       new_max = middle - 1;
899     }
900     else
901     {
902       if ( middle == max )
903         break;
904       new_min = middle + 1;
905     }
906   } while ( min < max );
907
908   return HB_Err_Not_Covered;
909 }
910
911
912 HB_INTERNAL HB_Error
913 _HB_OPEN_Coverage_Index( HB_Coverage* c,
914                           HB_UShort      glyphID,
915                           HB_UShort*     index )
916 {
917   switch ( c->CoverageFormat )
918   {
919   case 1:  return Coverage_Index1( &c->cf.cf1, glyphID, index );
920   case 2:  return Coverage_Index2( &c->cf.cf2, glyphID, index );
921   default: return ERR(HB_Err_Invalid_SubTable_Format);
922   }
923
924   return HB_Err_Ok;               /* never reached */
925 }
926
927
928
929 /*************************************
930  * Class Definition related functions
931  *************************************/
932
933
934 /* ClassDefFormat1 */
935
936 static HB_Error  Load_ClassDef1( HB_ClassDefinition*  cd,
937                                  HB_UShort             limit,
938                                  HB_Stream             stream )
939 {
940   HB_Error   error;
941
942   HB_UShort             n, count;
943
944   HB_UShort*            cva;
945
946   HB_ClassDefFormat1*  cdf1;
947
948
949   cdf1 = &cd->cd.cd1;
950
951   if ( ACCESS_Frame( 4L ) )
952     return error;
953
954   cdf1->StartGlyph         = GET_UShort();
955   count = cdf1->GlyphCount = GET_UShort();
956
957   FORGET_Frame();
958
959   /* sanity check; we are limited to 16bit integers */
960
961   if ( cdf1->StartGlyph + (long)count >= 0x10000L )
962     return ERR(HB_Err_Invalid_SubTable);
963
964   cdf1->ClassValueArray = NULL;
965
966   if ( ALLOC_ARRAY( cdf1->ClassValueArray, count, HB_UShort ) )
967     return error;
968
969   cva = cdf1->ClassValueArray;
970
971   if ( ACCESS_Frame( count * 2L ) )
972     goto Fail;
973
974   for ( n = 0; n < count; n++ )
975   {
976     cva[n] = GET_UShort();
977     if ( cva[n] >= limit )
978     {
979       error = ERR(HB_Err_Invalid_SubTable);
980       goto Fail;
981     }
982   }
983
984   FORGET_Frame();
985
986   return HB_Err_Ok;
987
988 Fail:
989   FREE( cva );
990
991   return error;
992 }
993
994
995 static void  Free_ClassDef1( HB_ClassDefFormat1*  cdf1 )
996 {
997   FREE( cdf1->ClassValueArray );
998 }
999
1000
1001 /* ClassDefFormat2 */
1002
1003 static HB_Error  Load_ClassDef2( HB_ClassDefinition*  cd,
1004                                  HB_UShort             limit,
1005                                  HB_Stream             stream )
1006 {
1007   HB_Error   error;
1008
1009   HB_UShort              n, count;
1010
1011   HB_ClassRangeRecord*  crr;
1012
1013   HB_ClassDefFormat2*   cdf2;
1014
1015
1016   cdf2 = &cd->cd.cd2;
1017
1018   if ( ACCESS_Frame( 2L ) )
1019     return error;
1020
1021   count = GET_UShort();
1022   cdf2->ClassRangeCount = 0; /* zero for now.  we fill with the number of good entries later */
1023
1024   FORGET_Frame();
1025
1026   cdf2->ClassRangeRecord = NULL;
1027
1028   if ( ALLOC_ARRAY( cdf2->ClassRangeRecord, count, HB_ClassRangeRecord ) )
1029     return error;
1030
1031   crr = cdf2->ClassRangeRecord;
1032
1033   if ( ACCESS_Frame( count * 6L ) )
1034     goto Fail;
1035
1036   for ( n = 0; n < count; n++ )
1037   {
1038     crr[n].Start = GET_UShort();
1039     crr[n].End   = GET_UShort();
1040     crr[n].Class = GET_UShort();
1041
1042     /* sanity check */
1043
1044     if ( crr[n].Start > crr[n].End ||
1045          crr[n].Class >= limit )
1046     {
1047       /* XXX
1048        * Corrupt entry.  Skip it.
1049        * This is hit by Nafees Nastaliq font for example
1050        */
1051        n--;
1052        count--;
1053     }
1054   }
1055
1056   FORGET_Frame();
1057
1058   cdf2->ClassRangeCount = count;
1059
1060   return HB_Err_Ok;
1061
1062 Fail:
1063   FREE( crr );
1064
1065   return error;
1066 }
1067
1068
1069 static void  Free_ClassDef2( HB_ClassDefFormat2*  cdf2 )
1070 {
1071   FREE( cdf2->ClassRangeRecord );
1072 }
1073
1074
1075 /* ClassDefinition */
1076
1077 HB_INTERNAL HB_Error
1078 _HB_OPEN_Load_ClassDefinition( HB_ClassDefinition* cd,
1079                                 HB_UShort             limit,
1080                                 HB_Stream             stream )
1081 {
1082   HB_Error   error;
1083
1084   if ( ACCESS_Frame( 2L ) )
1085     return error;
1086
1087   cd->ClassFormat = GET_UShort();
1088
1089   FORGET_Frame();
1090
1091   switch ( cd->ClassFormat )
1092   {
1093   case 1:  error = Load_ClassDef1( cd, limit, stream ); break;
1094   case 2:  error = Load_ClassDef2( cd, limit, stream ); break;
1095   default: error = ERR(HB_Err_Invalid_SubTable_Format); break;
1096   }
1097
1098   if ( error )
1099     return error;
1100
1101   cd->loaded = TRUE;
1102
1103   return HB_Err_Ok;
1104 }
1105
1106
1107 static HB_Error
1108 _HB_OPEN_Load_EmptyClassDefinition( HB_ClassDefinition*  cd )
1109 {
1110   HB_Error   error;
1111
1112   cd->ClassFormat = 1; /* Meaningless */
1113
1114   if ( ALLOC_ARRAY( cd->cd.cd1.ClassValueArray, 1, HB_UShort ) )
1115     return error;
1116
1117   cd->loaded = TRUE;
1118
1119   return HB_Err_Ok;
1120 }
1121
1122 HB_INTERNAL HB_Error
1123 _HB_OPEN_Load_EmptyOrClassDefinition( HB_ClassDefinition* cd,
1124                                                HB_UShort             limit,
1125                                                HB_UInt              class_offset,
1126                                                HB_UInt              base_offset,
1127                                                HB_Stream             stream )
1128 {
1129   HB_Error error;
1130   HB_UInt               cur_offset;
1131
1132   cur_offset = FILE_Pos();
1133
1134   if ( class_offset )
1135     {
1136       if ( !FILE_Seek( class_offset + base_offset ) )
1137         error = _HB_OPEN_Load_ClassDefinition( cd, limit, stream );
1138     }
1139   else
1140      error = _HB_OPEN_Load_EmptyClassDefinition ( cd );
1141
1142   if (error == HB_Err_Ok)
1143     (void)FILE_Seek( cur_offset ); /* Changes error as a side-effect */
1144
1145   return error;
1146 }
1147
1148 HB_INTERNAL void
1149 _HB_OPEN_Free_ClassDefinition( HB_ClassDefinition*  cd )
1150 {
1151   if ( !cd->loaded )
1152     return;
1153
1154   switch ( cd->ClassFormat )
1155   {
1156   case 1:  Free_ClassDef1( &cd->cd.cd1 ); break;
1157   case 2:  Free_ClassDef2( &cd->cd.cd2 ); break;
1158   default:                                break;
1159   }
1160 }
1161
1162
1163 static HB_Error  Get_Class1( HB_ClassDefFormat1*  cdf1,
1164                              HB_UShort             glyphID,
1165                              HB_UShort*            klass,
1166                              HB_UShort*            index )
1167 {
1168   HB_UShort*  cva = cdf1->ClassValueArray;
1169
1170
1171   if ( index )
1172     *index = 0;
1173
1174   if ( glyphID >= cdf1->StartGlyph &&
1175        glyphID < cdf1->StartGlyph + cdf1->GlyphCount )
1176   {
1177     *klass = cva[glyphID - cdf1->StartGlyph];
1178     return HB_Err_Ok;
1179   }
1180   else
1181   {
1182     *klass = 0;
1183     return HB_Err_Not_Covered;
1184   }
1185 }
1186
1187
1188 /* we need the index value of the last searched class range record
1189    in case of failure for constructed GDEF tables                  */
1190
1191 static HB_Error  Get_Class2( HB_ClassDefFormat2*  cdf2,
1192                              HB_UShort             glyphID,
1193                              HB_UShort*            klass,
1194                              HB_UShort*            index )
1195 {
1196   HB_Error               error = HB_Err_Ok;
1197   HB_UShort              min, max, new_min, new_max, middle;
1198
1199   HB_ClassRangeRecord*  crr = cdf2->ClassRangeRecord;
1200
1201
1202   /* binary search */
1203
1204   if ( cdf2->ClassRangeCount == 0 )
1205     {
1206       *klass = 0;
1207       if ( index )
1208         *index = 0;
1209       
1210       return HB_Err_Not_Covered;
1211     }
1212
1213   new_min = 0;
1214   new_max = cdf2->ClassRangeCount - 1;
1215
1216   do
1217   {
1218     min = new_min;
1219     max = new_max;
1220
1221     /* we use (min + max) / 2 = max - (max - min) / 2  to avoid
1222        overflow and rounding errors                             */
1223
1224     middle = max - ( ( max - min ) >> 1 );
1225
1226     if ( glyphID >= crr[middle].Start && glyphID <= crr[middle].End )
1227     {
1228       *klass = crr[middle].Class;
1229       error  = HB_Err_Ok;
1230       break;
1231     }
1232     else if ( glyphID < crr[middle].Start )
1233     {
1234       if ( middle == min )
1235       {
1236         *klass = 0;
1237         error  = HB_Err_Not_Covered;
1238         break;
1239       }
1240       new_max = middle - 1;
1241     }
1242     else
1243     {
1244       if ( middle == max )
1245       {
1246         *klass = 0;
1247         error  = HB_Err_Not_Covered;
1248         break;
1249       }
1250       new_min = middle + 1;
1251     }
1252   } while ( min < max );
1253
1254   if ( index )
1255     *index = middle;
1256
1257   return error;
1258 }
1259
1260
1261 HB_INTERNAL HB_Error
1262 _HB_OPEN_Get_Class( HB_ClassDefinition* cd,
1263                      HB_UShort             glyphID,
1264                     HB_UShort*          klass,
1265                      HB_UShort*            index )
1266 {
1267   switch ( cd->ClassFormat )
1268   {
1269   case 1:  return Get_Class1( &cd->cd.cd1, glyphID, klass, index );
1270   case 2:  return Get_Class2( &cd->cd.cd2, glyphID, klass, index );
1271   default: return ERR(HB_Err_Invalid_SubTable_Format);
1272   }
1273
1274   return HB_Err_Ok;               /* never reached */
1275 }
1276
1277
1278
1279 /***************************
1280  * Device related functions
1281  ***************************/
1282
1283
1284 HB_INTERNAL HB_Error
1285 _HB_OPEN_Load_Device( HB_Device** device,
1286                        HB_Stream    stream )
1287 {
1288   HB_Device*  d;
1289   HB_Error   error;
1290
1291   HB_UShort   n, count;
1292
1293   HB_UShort*  dv;
1294
1295
1296   if ( ACCESS_Frame( 6L ) )
1297     return error;
1298
1299   if ( ALLOC( *device, sizeof(HB_Device)) )
1300   {
1301     *device = 0;
1302     return error;
1303   }
1304
1305   d = *device;
1306
1307   d->StartSize   = GET_UShort();
1308   d->EndSize     = GET_UShort();
1309   d->DeltaFormat = GET_UShort();
1310
1311   FORGET_Frame();
1312
1313   d->DeltaValue = NULL;
1314
1315   if ( d->StartSize > d->EndSize ||
1316        d->DeltaFormat == 0 || d->DeltaFormat > 3 )
1317     {
1318       /* XXX
1319        * I've seen fontforge generate DeltaFormat == 0.
1320        * Just return Ok and let the NULL DeltaValue disable
1321        * this table.
1322        */
1323       return HB_Err_Ok;
1324     }
1325
1326   count = ( ( d->EndSize - d->StartSize + 1 ) >>
1327               ( 4 - d->DeltaFormat ) ) + 1;
1328
1329   if ( ALLOC_ARRAY( d->DeltaValue, count, HB_UShort ) )
1330   {
1331     FREE( *device );
1332     *device = 0;
1333     return error;
1334   }
1335
1336   if ( ACCESS_Frame( count * 2L ) )
1337   {
1338     FREE( d->DeltaValue );
1339     FREE( *device );
1340     *device = 0;
1341     return error;
1342   }
1343
1344   dv = d->DeltaValue;
1345
1346   for ( n = 0; n < count; n++ )
1347     dv[n] = GET_UShort();
1348
1349   FORGET_Frame();
1350
1351   return HB_Err_Ok;
1352 }
1353
1354
1355 HB_INTERNAL void
1356 _HB_OPEN_Free_Device( HB_Device* d )
1357 {
1358   if ( d )
1359   {
1360     FREE( d->DeltaValue );
1361     FREE( d );
1362   }
1363 }
1364
1365
1366 /* Since we have the delta values stored in compressed form, we must
1367    uncompress it now.  To simplify the interface, the function always
1368    returns a meaningful value in `value'; the error is just for
1369    information.
1370                                |                |
1371    format = 1: 0011223344556677|8899101112131415|...
1372                                |                |
1373                     byte 1           byte 2
1374
1375      00: (byte >> 14) & mask
1376      11: (byte >> 12) & mask
1377      ...
1378
1379      mask = 0x0003
1380                                |                |
1381    format = 2: 0000111122223333|4444555566667777|...
1382                                |                |
1383                     byte 1           byte 2
1384
1385      0000: (byte >> 12) & mask
1386      1111: (byte >>  8) & mask
1387      ...
1388
1389      mask = 0x000F
1390                                |                |
1391    format = 3: 0000000011111111|2222222233333333|...
1392                                |                |
1393                     byte 1           byte 2
1394
1395      00000000: (byte >> 8) & mask
1396      11111111: (byte >> 0) & mask
1397      ....
1398
1399      mask = 0x00FF                                    */
1400
1401 HB_INTERNAL HB_Error
1402 _HB_OPEN_Get_Device( HB_Device* d,
1403                       HB_UShort    size,
1404                       HB_Short*    value )
1405 {
1406   HB_UShort  byte, bits, mask, s;
1407
1408   if ( d && d->DeltaValue && size >= d->StartSize && size <= d->EndSize )
1409   {
1410     HB_UShort f = d->DeltaFormat;
1411     s    = size - d->StartSize;
1412     byte = d->DeltaValue[s >> ( 4 - f )];
1413     bits = byte >> ( 16 - ( ( s % ( 1 << ( 4 - f ) ) + 1 ) << f ) );
1414     mask = 0xFFFF >> ( 16 - ( 1 << f ) );
1415
1416     *value = (HB_Short)( bits & mask );
1417
1418     /* conversion to a signed value */
1419
1420     if ( *value >= ( ( mask + 1 ) >> 1 ) )
1421       *value -= mask + 1;
1422
1423     return HB_Err_Ok;
1424   }
1425   else
1426   {
1427     *value = 0;
1428     return HB_Err_Not_Covered;
1429   }
1430 }
1431
1432
1433 /* END */