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