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 
Load_LangSys(HB_LangSys * ls,HB_Stream stream)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 
Free_LangSys(HB_LangSys * ls)76 static void  Free_LangSys( HB_LangSys*  ls )
77 {
78   FREE( ls->FeatureIndex );
79 }
80 
81 
82 /* Script */
83 
Load_Script(HB_ScriptTable * s,HB_Stream stream)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 
Free_Script(HB_ScriptTable * s)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
_HB_OPEN_Load_ScriptList(HB_ScriptList * sl,HB_Stream stream)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
_HB_OPEN_Free_ScriptList(HB_ScriptList * sl)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 
Load_Feature(HB_Feature * f,HB_Stream stream)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 
Free_Feature(HB_Feature * f)344 static void  Free_Feature( HB_Feature*  f )
345 {
346   FREE( f->LookupListIndex );
347 }
348 
349 
350 /* FeatureList */
351 
352 HB_INTERNAL HB_Error
_HB_OPEN_Load_FeatureList(HB_FeatureList * fl,HB_Stream stream)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
_HB_OPEN_Free_FeatureList(HB_FeatureList * fl)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 
Load_SubTable(HB_SubTable * st,HB_Stream stream,HB_Type table_type,HB_UShort lookup_type)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 
Free_SubTable(HB_SubTable * st,HB_Type table_type,HB_UShort lookup_type)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 
Load_Lookup(HB_Lookup * l,HB_Stream stream,HB_Type type)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 
Free_Lookup(HB_Lookup * l,HB_Type type)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
_HB_OPEN_Load_LookupList(HB_LookupList * ll,HB_Stream stream,HB_Type type)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
_HB_OPEN_Free_LookupList(HB_LookupList * ll,HB_Type type)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 
Load_Coverage1(HB_CoverageFormat1 * cf1,HB_Stream stream)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 
Free_Coverage1(HB_CoverageFormat1 * cf1)709 static void  Free_Coverage1( HB_CoverageFormat1*  cf1)
710 {
711   FREE( cf1->GlyphArray );
712 }
713 
714 
715 /* CoverageFormat2 */
716 
Load_Coverage2(HB_CoverageFormat2 * cf2,HB_Stream stream)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 
Free_Coverage2(HB_CoverageFormat2 * cf2)770 static void  Free_Coverage2( HB_CoverageFormat2*  cf2 )
771 {
772   FREE( cf2->RangeRecord );
773 }
774 
775 
776 HB_INTERNAL HB_Error
_HB_OPEN_Load_Coverage(HB_Coverage * c,HB_Stream stream)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
_HB_OPEN_Free_Coverage(HB_Coverage * c)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 
Coverage_Index1(HB_CoverageFormat1 * cf1,HB_UShort glyphID,HB_UShort * index)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 
Coverage_Index2(HB_CoverageFormat2 * cf2,HB_UShort glyphID,HB_UShort * index)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
_HB_OPEN_Coverage_Index(HB_Coverage * c,HB_UShort glyphID,HB_UShort * index)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 
Load_ClassDef1(HB_ClassDefinition * cd,HB_UShort limit,HB_Stream stream)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 
Free_ClassDef1(HB_ClassDefFormat1 * cdf1)995 static void  Free_ClassDef1( HB_ClassDefFormat1*  cdf1 )
996 {
997   FREE( cdf1->ClassValueArray );
998 }
999 
1000 
1001 /* ClassDefFormat2 */
1002 
Load_ClassDef2(HB_ClassDefinition * cd,HB_UShort limit,HB_Stream stream)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 
Free_ClassDef2(HB_ClassDefFormat2 * cdf2)1069 static void  Free_ClassDef2( HB_ClassDefFormat2*  cdf2 )
1070 {
1071   FREE( cdf2->ClassRangeRecord );
1072 }
1073 
1074 
1075 /* ClassDefinition */
1076 
1077 HB_INTERNAL HB_Error
_HB_OPEN_Load_ClassDefinition(HB_ClassDefinition * cd,HB_UShort limit,HB_Stream stream)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
_HB_OPEN_Load_EmptyClassDefinition(HB_ClassDefinition * cd)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
_HB_OPEN_Load_EmptyOrClassDefinition(HB_ClassDefinition * cd,HB_UShort limit,HB_UInt class_offset,HB_UInt base_offset,HB_Stream stream)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
_HB_OPEN_Free_ClassDefinition(HB_ClassDefinition * cd)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 
Get_Class1(HB_ClassDefFormat1 * cdf1,HB_UShort glyphID,HB_UShort * klass,HB_UShort * index)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 
Get_Class2(HB_ClassDefFormat2 * cdf2,HB_UShort glyphID,HB_UShort * klass,HB_UShort * index)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
_HB_OPEN_Get_Class(HB_ClassDefinition * cd,HB_UShort glyphID,HB_UShort * klass,HB_UShort * index)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
_HB_OPEN_Load_Device(HB_Device ** device,HB_Stream stream)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
_HB_OPEN_Free_Device(HB_Device * d)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
_HB_OPEN_Get_Device(HB_Device * d,HB_UShort size,HB_Short * value)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 */
1434