| OLD | NEW |
| (Empty) |
| 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 e
ntries 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 */ | |
| OLD | NEW |