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
37static 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
76static void  Free_LangSys( HB_LangSys*  ls )
77{
78  FREE( ls->FeatureIndex );
79}
80
81
82/* Script */
83
84static 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
164Fail1:
165  for ( m = 0; m < n; m++ )
166    Free_LangSys( &lsr[m].LangSys );
167
168  FREE( s->LangSysRecord );
169
170Fail2:
171  Free_LangSys( &s->DefaultLangSys );
172  return error;
173}
174
175
176static 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
200HB_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
266Fail:
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
275HB_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
304static 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
344static void  Free_Feature( HB_Feature*  f )
345{
346  FREE( f->LookupListIndex );
347}
348
349
350/* FeatureList */
351
352HB_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
403Fail1:
404  for ( m = 0; m < n; m++ )
405    Free_Feature( &fr[m].Feature );
406
407  FREE( fl->ApplyOrder );
408
409Fail2:
410  FREE( fl->FeatureRecord );
411
412  return error;
413}
414
415
416HB_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
450static 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
462static 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
475static 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
545Fail:
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
554static 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
577HB_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
626Fail1:
627  FREE( ll->Properties );
628
629  for ( m = 0; m < n; m++ )
630    Free_Lookup( &l[m], type );
631
632Fail2:
633  FREE( ll->Lookup );
634  return error;
635}
636
637
638HB_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
670static 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
709static void  Free_Coverage1( HB_CoverageFormat1*  cf1)
710{
711  FREE( cf1->GlyphArray );
712}
713
714
715/* CoverageFormat2 */
716
717static 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
764Fail:
765  FREE( cf2->RangeRecord );
766  return error;
767}
768
769
770static void  Free_Coverage2( HB_CoverageFormat2*  cf2 )
771{
772  FREE( cf2->RangeRecord );
773}
774
775
776HB_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
800HB_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
812static 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
862static 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
912HB_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
936static 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
988Fail:
989  FREE( cva );
990
991  return error;
992}
993
994
995static void  Free_ClassDef1( HB_ClassDefFormat1*  cdf1 )
996{
997  FREE( cdf1->ClassValueArray );
998}
999
1000
1001/* ClassDefFormat2 */
1002
1003static 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
1062Fail:
1063  FREE( crr );
1064
1065  return error;
1066}
1067
1068
1069static void  Free_ClassDef2( HB_ClassDefFormat2*  cdf2 )
1070{
1071  FREE( cdf2->ClassRangeRecord );
1072}
1073
1074
1075/* ClassDefinition */
1076
1077HB_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
1107static 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
1122HB_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
1148HB_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
1163static 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
1191static 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
1261HB_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
1284HB_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
1355HB_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
1401HB_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 */
1434