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