1 /**************************************************************************** 2 * 3 * ftrfork.c 4 * 5 * Embedded resource forks accessor (body). 6 * 7 * Copyright 2004-2018 by 8 * Masatake YAMATO and Redhat K.K. 9 * 10 * FT_Raccess_Get_HeaderInfo() and raccess_guess_darwin_hfsplus() are 11 * derived from ftobjs.c. 12 * 13 * This file is part of the FreeType project, and may only be used, 14 * modified, and distributed under the terms of the FreeType project 15 * license, LICENSE.TXT. By continuing to use, modify, or distribute 16 * this file you indicate that you have read the license and 17 * understand and accept it fully. 18 * 19 */ 20 21 /**************************************************************************** 22 * Development of the code in this file is support of 23 * Information-technology Promotion Agency, Japan. 24 */ 25 26 27 #include <ft2build.h> 28 #include FT_INTERNAL_DEBUG_H 29 #include FT_INTERNAL_STREAM_H 30 #include FT_INTERNAL_RFORK_H 31 32 #include "ftbase.h" 33 34 #undef FT_COMPONENT 35 #define FT_COMPONENT trace_raccess 36 37 38 /*************************************************************************/ 39 /*************************************************************************/ 40 /*************************************************************************/ 41 /**** ****/ 42 /**** ****/ 43 /**** Resource fork directory access ****/ 44 /**** ****/ 45 /**** ****/ 46 /*************************************************************************/ 47 /*************************************************************************/ 48 /*************************************************************************/ 49 50 FT_BASE_DEF( FT_Error ) FT_Raccess_Get_HeaderInfo(FT_Library library,FT_Stream stream,FT_Long rfork_offset,FT_Long * map_offset,FT_Long * rdata_pos)51 FT_Raccess_Get_HeaderInfo( FT_Library library, 52 FT_Stream stream, 53 FT_Long rfork_offset, 54 FT_Long *map_offset, 55 FT_Long *rdata_pos ) 56 { 57 FT_Error error; 58 unsigned char head[16], head2[16]; 59 FT_Long map_pos, map_len, rdata_len; 60 int allzeros, allmatch, i; 61 FT_Long type_list; 62 63 FT_UNUSED( library ); 64 65 66 error = FT_Stream_Seek( stream, (FT_ULong)rfork_offset ); 67 if ( error ) 68 return error; 69 70 error = FT_Stream_Read( stream, (FT_Byte*)head, 16 ); 71 if ( error ) 72 return error; 73 74 /* ensure positive values */ 75 if ( head[0] >= 0x80 || 76 head[4] >= 0x80 || 77 head[8] >= 0x80 || 78 head[12] >= 0x80 ) 79 return FT_THROW( Unknown_File_Format ); 80 81 *rdata_pos = ( head[ 0] << 24 ) | 82 ( head[ 1] << 16 ) | 83 ( head[ 2] << 8 ) | 84 head[ 3]; 85 map_pos = ( head[ 4] << 24 ) | 86 ( head[ 5] << 16 ) | 87 ( head[ 6] << 8 ) | 88 head[ 7]; 89 rdata_len = ( head[ 8] << 24 ) | 90 ( head[ 9] << 16 ) | 91 ( head[10] << 8 ) | 92 head[11]; 93 map_len = ( head[12] << 24 ) | 94 ( head[13] << 16 ) | 95 ( head[14] << 8 ) | 96 head[15]; 97 98 /* the map must not be empty */ 99 if ( !map_pos ) 100 return FT_THROW( Unknown_File_Format ); 101 102 /* check whether rdata and map overlap */ 103 if ( *rdata_pos < map_pos ) 104 { 105 if ( *rdata_pos > map_pos - rdata_len ) 106 return FT_THROW( Unknown_File_Format ); 107 } 108 else 109 { 110 if ( map_pos > *rdata_pos - map_len ) 111 return FT_THROW( Unknown_File_Format ); 112 } 113 114 /* check whether end of rdata or map exceeds stream size */ 115 if ( FT_LONG_MAX - rdata_len < *rdata_pos || 116 FT_LONG_MAX - map_len < map_pos || 117 118 FT_LONG_MAX - ( *rdata_pos + rdata_len ) < rfork_offset || 119 FT_LONG_MAX - ( map_pos + map_len ) < rfork_offset || 120 121 (FT_ULong)( rfork_offset + *rdata_pos + rdata_len ) > stream->size || 122 (FT_ULong)( rfork_offset + map_pos + map_len ) > stream->size ) 123 return FT_THROW( Unknown_File_Format ); 124 125 *rdata_pos += rfork_offset; 126 map_pos += rfork_offset; 127 128 error = FT_Stream_Seek( stream, (FT_ULong)map_pos ); 129 if ( error ) 130 return error; 131 132 head2[15] = (FT_Byte)( head[15] + 1 ); /* make it be different */ 133 134 error = FT_Stream_Read( stream, (FT_Byte*)head2, 16 ); 135 if ( error ) 136 return error; 137 138 allzeros = 1; 139 allmatch = 1; 140 for ( i = 0; i < 16; i++ ) 141 { 142 if ( head2[i] != 0 ) 143 allzeros = 0; 144 if ( head2[i] != head[i] ) 145 allmatch = 0; 146 } 147 if ( !allzeros && !allmatch ) 148 return FT_THROW( Unknown_File_Format ); 149 150 /* If we have reached this point then it is probably a mac resource */ 151 /* file. Now, does it contain any interesting resources? */ 152 153 (void)FT_STREAM_SKIP( 4 /* skip handle to next resource map */ 154 + 2 /* skip file resource number */ 155 + 2 ); /* skip attributes */ 156 157 if ( FT_READ_SHORT( type_list ) ) 158 return error; 159 if ( type_list < 0 ) 160 return FT_THROW( Unknown_File_Format ); 161 162 error = FT_Stream_Seek( stream, (FT_ULong)( map_pos + type_list ) ); 163 if ( error ) 164 return error; 165 166 *map_offset = map_pos + type_list; 167 return FT_Err_Ok; 168 } 169 170 171 static int ft_raccess_sort_ref_by_id(FT_RFork_Ref * a,FT_RFork_Ref * b)172 ft_raccess_sort_ref_by_id( FT_RFork_Ref* a, 173 FT_RFork_Ref* b ) 174 { 175 if ( a->res_id < b->res_id ) 176 return -1; 177 else if ( a->res_id > b->res_id ) 178 return 1; 179 else 180 return 0; 181 } 182 183 184 FT_BASE_DEF( FT_Error ) FT_Raccess_Get_DataOffsets(FT_Library library,FT_Stream stream,FT_Long map_offset,FT_Long rdata_pos,FT_Long tag,FT_Bool sort_by_res_id,FT_Long ** offsets,FT_Long * count)185 FT_Raccess_Get_DataOffsets( FT_Library library, 186 FT_Stream stream, 187 FT_Long map_offset, 188 FT_Long rdata_pos, 189 FT_Long tag, 190 FT_Bool sort_by_res_id, 191 FT_Long **offsets, 192 FT_Long *count ) 193 { 194 FT_Error error; 195 int i, j, cnt, subcnt; 196 FT_Long tag_internal, rpos; 197 FT_Memory memory = library->memory; 198 FT_Long temp; 199 FT_Long *offsets_internal = NULL; 200 FT_RFork_Ref *ref = NULL; 201 202 203 FT_TRACE3(( "\n" )); 204 error = FT_Stream_Seek( stream, (FT_ULong)map_offset ); 205 if ( error ) 206 return error; 207 208 if ( FT_READ_SHORT( cnt ) ) 209 return error; 210 cnt++; 211 212 /* `rpos' is a signed 16bit integer offset to resource records; the */ 213 /* size of a resource record is 12 bytes. The map header is 28 bytes, */ 214 /* and a type list needs 10 bytes or more. If we assume that the name */ 215 /* list is empty and we have only a single entry in the type list, */ 216 /* there can be at most */ 217 /* */ 218 /* (32768 - 28 - 10) / 12 = 2727 */ 219 /* */ 220 /* resources. */ 221 /* */ 222 /* A type list starts with a two-byte counter, followed by 10-byte */ 223 /* type records. Assuming that there are no resources, the number of */ 224 /* type records can be at most */ 225 /* */ 226 /* (32768 - 28 - 2) / 8 = 4079 */ 227 /* */ 228 if ( cnt > 4079 ) 229 return FT_THROW( Invalid_Table ); 230 231 for ( i = 0; i < cnt; i++ ) 232 { 233 if ( FT_READ_LONG( tag_internal ) || 234 FT_READ_SHORT( subcnt ) || 235 FT_READ_SHORT( rpos ) ) 236 return error; 237 238 FT_TRACE2(( "Resource tags: %c%c%c%c\n", 239 (char)( 0xFF & ( tag_internal >> 24 ) ), 240 (char)( 0xFF & ( tag_internal >> 16 ) ), 241 (char)( 0xFF & ( tag_internal >> 8 ) ), 242 (char)( 0xFF & ( tag_internal >> 0 ) ) )); 243 FT_TRACE3(( " : subcount=%d, suboffset=0x%04x\n", 244 subcnt, rpos )); 245 246 if ( tag_internal == tag ) 247 { 248 *count = subcnt + 1; 249 rpos += map_offset; 250 251 /* a zero count might be valid in the resource specification, */ 252 /* however, it is completely useless to us */ 253 if ( *count < 1 || *count > 2727 ) 254 return FT_THROW( Invalid_Table ); 255 256 error = FT_Stream_Seek( stream, (FT_ULong)rpos ); 257 if ( error ) 258 return error; 259 260 if ( FT_NEW_ARRAY( ref, *count ) ) 261 return error; 262 263 for ( j = 0; j < *count; j++ ) 264 { 265 if ( FT_READ_SHORT( ref[j].res_id ) ) 266 goto Exit; 267 if ( FT_STREAM_SKIP( 2 ) ) /* resource name offset */ 268 goto Exit; 269 if ( FT_READ_LONG( temp ) ) /* attributes (8bit), offset (24bit) */ 270 goto Exit; 271 if ( FT_STREAM_SKIP( 4 ) ) /* mbz */ 272 goto Exit; 273 274 /* 275 * According to Inside Macintosh: More Macintosh Toolbox, 276 * "Resource IDs" (1-46), there are some reserved IDs. 277 * However, FreeType2 is not a font synthesizer, no need 278 * to check the acceptable resource ID. 279 */ 280 if ( temp < 0 ) 281 { 282 error = FT_THROW( Invalid_Table ); 283 goto Exit; 284 } 285 286 ref[j].offset = temp & 0xFFFFFFL; 287 288 FT_TRACE3(( " [%d]:" 289 " resource_id=0x%04x, offset=0x%08x\n", 290 j, (FT_UShort)ref[j].res_id, ref[j].offset )); 291 } 292 293 if ( sort_by_res_id ) 294 { 295 ft_qsort( ref, 296 (size_t)*count, 297 sizeof ( FT_RFork_Ref ), 298 ( int(*)(const void*, 299 const void*) )ft_raccess_sort_ref_by_id ); 300 301 FT_TRACE3(( " -- sort resources by their ids --\n" )); 302 303 for ( j = 0; j < *count; j++ ) 304 FT_TRACE3(( " [%d]:" 305 " resource_id=0x%04x, offset=0x%08x\n", 306 j, ref[j].res_id, ref[j].offset )); 307 } 308 309 if ( FT_NEW_ARRAY( offsets_internal, *count ) ) 310 goto Exit; 311 312 /* XXX: duplicated reference ID, 313 * gap between reference IDs are acceptable? 314 * further investigation on Apple implementation is needed. 315 */ 316 for ( j = 0; j < *count; j++ ) 317 offsets_internal[j] = rdata_pos + ref[j].offset; 318 319 *offsets = offsets_internal; 320 error = FT_Err_Ok; 321 322 Exit: 323 FT_FREE( ref ); 324 return error; 325 } 326 } 327 328 return FT_THROW( Cannot_Open_Resource ); 329 } 330 331 332 #ifdef FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK 333 334 /*************************************************************************/ 335 /*************************************************************************/ 336 /*************************************************************************/ 337 /**** ****/ 338 /**** ****/ 339 /**** Guessing functions ****/ 340 /**** ****/ 341 /**** When you add a new guessing function, ****/ 342 /**** update FT_RACCESS_N_RULES in ftrfork.h. ****/ 343 /**** ****/ 344 /*************************************************************************/ 345 /*************************************************************************/ 346 /*************************************************************************/ 347 348 static FT_Error 349 raccess_guess_apple_double( FT_Library library, 350 FT_Stream stream, 351 char *base_file_name, 352 char **result_file_name, 353 FT_Long *result_offset ); 354 355 static FT_Error 356 raccess_guess_apple_single( FT_Library library, 357 FT_Stream stream, 358 char *base_file_name, 359 char **result_file_name, 360 FT_Long *result_offset ); 361 362 static FT_Error 363 raccess_guess_darwin_ufs_export( FT_Library library, 364 FT_Stream stream, 365 char *base_file_name, 366 char **result_file_name, 367 FT_Long *result_offset ); 368 369 static FT_Error 370 raccess_guess_darwin_newvfs( FT_Library library, 371 FT_Stream stream, 372 char *base_file_name, 373 char **result_file_name, 374 FT_Long *result_offset ); 375 376 static FT_Error 377 raccess_guess_darwin_hfsplus( FT_Library library, 378 FT_Stream stream, 379 char *base_file_name, 380 char **result_file_name, 381 FT_Long *result_offset ); 382 383 static FT_Error 384 raccess_guess_vfat( FT_Library library, 385 FT_Stream stream, 386 char *base_file_name, 387 char **result_file_name, 388 FT_Long *result_offset ); 389 390 static FT_Error 391 raccess_guess_linux_cap( FT_Library library, 392 FT_Stream stream, 393 char *base_file_name, 394 char **result_file_name, 395 FT_Long *result_offset ); 396 397 static FT_Error 398 raccess_guess_linux_double( FT_Library library, 399 FT_Stream stream, 400 char *base_file_name, 401 char **result_file_name, 402 FT_Long *result_offset ); 403 404 static FT_Error 405 raccess_guess_linux_netatalk( FT_Library library, 406 FT_Stream stream, 407 char *base_file_name, 408 char **result_file_name, 409 FT_Long *result_offset ); 410 411 412 CONST_FT_RFORK_RULE_ARRAY_BEGIN(ft_raccess_guess_table, 413 ft_raccess_guess_rec) 414 CONST_FT_RFORK_RULE_ARRAY_ENTRY(apple_double, apple_double) 415 CONST_FT_RFORK_RULE_ARRAY_ENTRY(apple_single, apple_single) 416 CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_ufs_export, darwin_ufs_export) 417 CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_newvfs, darwin_newvfs) 418 CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_hfsplus, darwin_hfsplus) 419 CONST_FT_RFORK_RULE_ARRAY_ENTRY(vfat, vfat) 420 CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_cap, linux_cap) 421 CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_double, linux_double) 422 CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_netatalk, linux_netatalk) 423 CONST_FT_RFORK_RULE_ARRAY_END 424 425 426 /*************************************************************************/ 427 /**** ****/ 428 /**** Helper functions ****/ 429 /**** ****/ 430 /*************************************************************************/ 431 432 static FT_Error 433 raccess_guess_apple_generic( FT_Library library, 434 FT_Stream stream, 435 char *base_file_name, 436 FT_Int32 magic, 437 FT_Long *result_offset ); 438 439 static FT_Error 440 raccess_guess_linux_double_from_file_name( FT_Library library, 441 char* file_name, 442 FT_Long *result_offset ); 443 444 static char * 445 raccess_make_file_name( FT_Memory memory, 446 const char *original_name, 447 const char *insertion ); 448 449 FT_BASE_DEF( void ) FT_Raccess_Guess(FT_Library library,FT_Stream stream,char * base_name,char ** new_names,FT_Long * offsets,FT_Error * errors)450 FT_Raccess_Guess( FT_Library library, 451 FT_Stream stream, 452 char* base_name, 453 char **new_names, 454 FT_Long *offsets, 455 FT_Error *errors ) 456 { 457 FT_Int i; 458 459 460 for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) 461 { 462 new_names[i] = NULL; 463 if ( NULL != stream ) 464 errors[i] = FT_Stream_Seek( stream, 0 ); 465 else 466 errors[i] = FT_Err_Ok; 467 468 if ( errors[i] ) 469 continue; 470 471 errors[i] = ft_raccess_guess_table[i].func( library, 472 stream, base_name, 473 &(new_names[i]), 474 &(offsets[i]) ); 475 } 476 477 return; 478 } 479 480 481 #if defined( FT_CONFIG_OPTION_MAC_FONTS ) && !defined( FT_MACINTOSH ) 482 static FT_RFork_Rule raccess_get_rule_type_from_rule_index(FT_Library library,FT_UInt rule_index)483 raccess_get_rule_type_from_rule_index( FT_Library library, 484 FT_UInt rule_index ) 485 { 486 FT_UNUSED( library ); 487 488 if ( rule_index >= FT_RACCESS_N_RULES ) 489 return FT_RFork_Rule_invalid; 490 491 return ft_raccess_guess_table[rule_index].type; 492 } 493 494 495 /* 496 * For this function, refer ftbase.h. 497 */ 498 FT_LOCAL_DEF( FT_Bool ) ft_raccess_rule_by_darwin_vfs(FT_Library library,FT_UInt rule_index)499 ft_raccess_rule_by_darwin_vfs( FT_Library library, 500 FT_UInt rule_index ) 501 { 502 switch( raccess_get_rule_type_from_rule_index( library, rule_index ) ) 503 { 504 case FT_RFork_Rule_darwin_newvfs: 505 case FT_RFork_Rule_darwin_hfsplus: 506 return TRUE; 507 508 default: 509 return FALSE; 510 } 511 } 512 #endif 513 514 515 static FT_Error raccess_guess_apple_double(FT_Library library,FT_Stream stream,char * base_file_name,char ** result_file_name,FT_Long * result_offset)516 raccess_guess_apple_double( FT_Library library, 517 FT_Stream stream, 518 char *base_file_name, 519 char **result_file_name, 520 FT_Long *result_offset ) 521 { 522 FT_Int32 magic = ( 0x00 << 24 ) | 523 ( 0x05 << 16 ) | 524 ( 0x16 << 8 ) | 525 0x07; 526 527 528 *result_file_name = NULL; 529 if ( NULL == stream ) 530 return FT_THROW( Cannot_Open_Stream ); 531 532 return raccess_guess_apple_generic( library, stream, base_file_name, 533 magic, result_offset ); 534 } 535 536 537 static FT_Error raccess_guess_apple_single(FT_Library library,FT_Stream stream,char * base_file_name,char ** result_file_name,FT_Long * result_offset)538 raccess_guess_apple_single( FT_Library library, 539 FT_Stream stream, 540 char *base_file_name, 541 char **result_file_name, 542 FT_Long *result_offset ) 543 { 544 FT_Int32 magic = ( 0x00 << 24 ) | 545 ( 0x05 << 16 ) | 546 ( 0x16 << 8 ) | 547 0x00; 548 549 550 *result_file_name = NULL; 551 if ( NULL == stream ) 552 return FT_THROW( Cannot_Open_Stream ); 553 554 return raccess_guess_apple_generic( library, stream, base_file_name, 555 magic, result_offset ); 556 } 557 558 559 static FT_Error raccess_guess_darwin_ufs_export(FT_Library library,FT_Stream stream,char * base_file_name,char ** result_file_name,FT_Long * result_offset)560 raccess_guess_darwin_ufs_export( FT_Library library, 561 FT_Stream stream, 562 char *base_file_name, 563 char **result_file_name, 564 FT_Long *result_offset ) 565 { 566 char* newpath; 567 FT_Error error; 568 FT_Memory memory; 569 570 FT_UNUSED( stream ); 571 572 573 memory = library->memory; 574 newpath = raccess_make_file_name( memory, base_file_name, "._" ); 575 if ( !newpath ) 576 return FT_THROW( Out_Of_Memory ); 577 578 error = raccess_guess_linux_double_from_file_name( library, newpath, 579 result_offset ); 580 if ( !error ) 581 *result_file_name = newpath; 582 else 583 FT_FREE( newpath ); 584 585 return error; 586 } 587 588 589 static FT_Error raccess_guess_darwin_hfsplus(FT_Library library,FT_Stream stream,char * base_file_name,char ** result_file_name,FT_Long * result_offset)590 raccess_guess_darwin_hfsplus( FT_Library library, 591 FT_Stream stream, 592 char *base_file_name, 593 char **result_file_name, 594 FT_Long *result_offset ) 595 { 596 /* 597 Only meaningful on systems with hfs+ drivers (or Macs). 598 */ 599 FT_Error error; 600 char* newpath = NULL; 601 FT_Memory memory; 602 FT_Long base_file_len = (FT_Long)ft_strlen( base_file_name ); 603 604 FT_UNUSED( stream ); 605 606 607 memory = library->memory; 608 609 if ( base_file_len + 6 > FT_INT_MAX ) 610 return FT_THROW( Array_Too_Large ); 611 612 if ( FT_ALLOC( newpath, base_file_len + 6 ) ) 613 return error; 614 615 FT_MEM_COPY( newpath, base_file_name, base_file_len ); 616 FT_MEM_COPY( newpath + base_file_len, "/rsrc", 6 ); 617 618 *result_file_name = newpath; 619 *result_offset = 0; 620 621 return FT_Err_Ok; 622 } 623 624 625 static FT_Error raccess_guess_darwin_newvfs(FT_Library library,FT_Stream stream,char * base_file_name,char ** result_file_name,FT_Long * result_offset)626 raccess_guess_darwin_newvfs( FT_Library library, 627 FT_Stream stream, 628 char *base_file_name, 629 char **result_file_name, 630 FT_Long *result_offset ) 631 { 632 /* 633 Only meaningful on systems with Mac OS X (> 10.1). 634 */ 635 FT_Error error; 636 char* newpath = NULL; 637 FT_Memory memory; 638 FT_Long base_file_len = (FT_Long)ft_strlen( base_file_name ); 639 640 FT_UNUSED( stream ); 641 642 643 memory = library->memory; 644 645 if ( base_file_len + 18 > FT_INT_MAX ) 646 return FT_THROW( Array_Too_Large ); 647 648 if ( FT_ALLOC( newpath, base_file_len + 18 ) ) 649 return error; 650 651 FT_MEM_COPY( newpath, base_file_name, base_file_len ); 652 FT_MEM_COPY( newpath + base_file_len, "/..namedfork/rsrc", 18 ); 653 654 *result_file_name = newpath; 655 *result_offset = 0; 656 657 return FT_Err_Ok; 658 } 659 660 661 static FT_Error raccess_guess_vfat(FT_Library library,FT_Stream stream,char * base_file_name,char ** result_file_name,FT_Long * result_offset)662 raccess_guess_vfat( FT_Library library, 663 FT_Stream stream, 664 char *base_file_name, 665 char **result_file_name, 666 FT_Long *result_offset ) 667 { 668 char* newpath; 669 FT_Memory memory; 670 671 FT_UNUSED( stream ); 672 673 674 memory = library->memory; 675 676 newpath = raccess_make_file_name( memory, base_file_name, 677 "resource.frk/" ); 678 if ( !newpath ) 679 return FT_THROW( Out_Of_Memory ); 680 681 *result_file_name = newpath; 682 *result_offset = 0; 683 684 return FT_Err_Ok; 685 } 686 687 688 static FT_Error raccess_guess_linux_cap(FT_Library library,FT_Stream stream,char * base_file_name,char ** result_file_name,FT_Long * result_offset)689 raccess_guess_linux_cap( FT_Library library, 690 FT_Stream stream, 691 char *base_file_name, 692 char **result_file_name, 693 FT_Long *result_offset ) 694 { 695 char* newpath; 696 FT_Memory memory; 697 698 FT_UNUSED( stream ); 699 700 701 memory = library->memory; 702 703 newpath = raccess_make_file_name( memory, base_file_name, ".resource/" ); 704 if ( !newpath ) 705 return FT_THROW( Out_Of_Memory ); 706 707 *result_file_name = newpath; 708 *result_offset = 0; 709 710 return FT_Err_Ok; 711 } 712 713 714 static FT_Error raccess_guess_linux_double(FT_Library library,FT_Stream stream,char * base_file_name,char ** result_file_name,FT_Long * result_offset)715 raccess_guess_linux_double( FT_Library library, 716 FT_Stream stream, 717 char *base_file_name, 718 char **result_file_name, 719 FT_Long *result_offset ) 720 { 721 char* newpath; 722 FT_Error error; 723 FT_Memory memory; 724 725 FT_UNUSED( stream ); 726 727 728 memory = library->memory; 729 730 newpath = raccess_make_file_name( memory, base_file_name, "%" ); 731 if ( !newpath ) 732 return FT_THROW( Out_Of_Memory ); 733 734 error = raccess_guess_linux_double_from_file_name( library, newpath, 735 result_offset ); 736 if ( !error ) 737 *result_file_name = newpath; 738 else 739 FT_FREE( newpath ); 740 741 return error; 742 } 743 744 745 static FT_Error raccess_guess_linux_netatalk(FT_Library library,FT_Stream stream,char * base_file_name,char ** result_file_name,FT_Long * result_offset)746 raccess_guess_linux_netatalk( FT_Library library, 747 FT_Stream stream, 748 char *base_file_name, 749 char **result_file_name, 750 FT_Long *result_offset ) 751 { 752 char* newpath; 753 FT_Error error; 754 FT_Memory memory; 755 756 FT_UNUSED( stream ); 757 758 759 memory = library->memory; 760 761 newpath = raccess_make_file_name( memory, base_file_name, 762 ".AppleDouble/" ); 763 if ( !newpath ) 764 return FT_THROW( Out_Of_Memory ); 765 766 error = raccess_guess_linux_double_from_file_name( library, newpath, 767 result_offset ); 768 if ( !error ) 769 *result_file_name = newpath; 770 else 771 FT_FREE( newpath ); 772 773 return error; 774 } 775 776 777 static FT_Error raccess_guess_apple_generic(FT_Library library,FT_Stream stream,char * base_file_name,FT_Int32 magic,FT_Long * result_offset)778 raccess_guess_apple_generic( FT_Library library, 779 FT_Stream stream, 780 char *base_file_name, 781 FT_Int32 magic, 782 FT_Long *result_offset ) 783 { 784 FT_Int32 magic_from_stream; 785 FT_Error error; 786 FT_Int32 version_number = 0; 787 FT_UShort n_of_entries; 788 789 int i; 790 FT_Int32 entry_id, entry_offset, entry_length = 0; 791 792 const FT_Int32 resource_fork_entry_id = 0x2; 793 794 FT_UNUSED( library ); 795 FT_UNUSED( base_file_name ); 796 FT_UNUSED( version_number ); 797 FT_UNUSED( entry_length ); 798 799 800 if ( FT_READ_LONG( magic_from_stream ) ) 801 return error; 802 if ( magic_from_stream != magic ) 803 return FT_THROW( Unknown_File_Format ); 804 805 if ( FT_READ_LONG( version_number ) ) 806 return error; 807 808 /* filler */ 809 error = FT_Stream_Skip( stream, 16 ); 810 if ( error ) 811 return error; 812 813 if ( FT_READ_USHORT( n_of_entries ) ) 814 return error; 815 if ( n_of_entries == 0 ) 816 return FT_THROW( Unknown_File_Format ); 817 818 for ( i = 0; i < n_of_entries; i++ ) 819 { 820 if ( FT_READ_LONG( entry_id ) ) 821 return error; 822 if ( entry_id == resource_fork_entry_id ) 823 { 824 if ( FT_READ_LONG( entry_offset ) || 825 FT_READ_LONG( entry_length ) ) 826 continue; 827 *result_offset = entry_offset; 828 829 return FT_Err_Ok; 830 } 831 else 832 { 833 error = FT_Stream_Skip( stream, 4 + 4 ); /* offset + length */ 834 if ( error ) 835 return error; 836 } 837 } 838 839 return FT_THROW( Unknown_File_Format ); 840 } 841 842 843 static FT_Error raccess_guess_linux_double_from_file_name(FT_Library library,char * file_name,FT_Long * result_offset)844 raccess_guess_linux_double_from_file_name( FT_Library library, 845 char *file_name, 846 FT_Long *result_offset ) 847 { 848 FT_Open_Args args2; 849 FT_Stream stream2; 850 char* nouse = NULL; 851 FT_Error error; 852 853 854 args2.flags = FT_OPEN_PATHNAME; 855 args2.pathname = file_name; 856 error = FT_Stream_New( library, &args2, &stream2 ); 857 if ( error ) 858 return error; 859 860 error = raccess_guess_apple_double( library, stream2, file_name, 861 &nouse, result_offset ); 862 863 FT_Stream_Free( stream2, 0 ); 864 865 return error; 866 } 867 868 869 static char* raccess_make_file_name(FT_Memory memory,const char * original_name,const char * insertion)870 raccess_make_file_name( FT_Memory memory, 871 const char *original_name, 872 const char *insertion ) 873 { 874 char* new_name = NULL; 875 const char* tmp; 876 const char* slash; 877 size_t new_length; 878 FT_Error error = FT_Err_Ok; 879 880 FT_UNUSED( error ); 881 882 883 new_length = ft_strlen( original_name ) + ft_strlen( insertion ); 884 if ( FT_ALLOC( new_name, new_length + 1 ) ) 885 return NULL; 886 887 tmp = ft_strrchr( original_name, '/' ); 888 if ( tmp ) 889 { 890 ft_strncpy( new_name, 891 original_name, 892 (size_t)( tmp - original_name + 1 ) ); 893 new_name[tmp - original_name + 1] = '\0'; 894 slash = tmp + 1; 895 } 896 else 897 { 898 slash = original_name; 899 new_name[0] = '\0'; 900 } 901 902 ft_strcat( new_name, insertion ); 903 ft_strcat( new_name, slash ); 904 905 return new_name; 906 } 907 908 909 #else /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */ 910 911 912 /************************************************************************** 913 * Dummy function; just sets errors 914 */ 915 916 FT_BASE_DEF( void ) FT_Raccess_Guess(FT_Library library,FT_Stream stream,char * base_name,char ** new_names,FT_Long * offsets,FT_Error * errors)917 FT_Raccess_Guess( FT_Library library, 918 FT_Stream stream, 919 char *base_name, 920 char **new_names, 921 FT_Long *offsets, 922 FT_Error *errors ) 923 { 924 FT_Int i; 925 926 FT_UNUSED( library ); 927 FT_UNUSED( stream ); 928 FT_UNUSED( base_name ); 929 930 931 for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) 932 { 933 new_names[i] = NULL; 934 offsets[i] = 0; 935 errors[i] = FT_ERR( Unimplemented_Feature ); 936 } 937 } 938 939 940 #endif /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */ 941 942 943 /* END */ 944