blob: 120c2f803fac8cebe71fcaa7f17165fd12427606 [file] [log] [blame]
Werner Lemberg75435332004-02-25 12:58:54 +00001/***************************************************************************/
2/* */
3/* ftrfork.c */
4/* */
5/* Embedded resource forks accessor (body). */
6/* */
Werner Lembergbe3c9812006-01-27 14:16:16 +00007/* Copyright 2004, 2005, 2006 by */
Werner Lemberg75435332004-02-25 12:58:54 +00008/* 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
33#undef FT_COMPONENT
34#define FT_COMPONENT trace_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 )
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, 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, 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 *rdata_pos = rfork_offset + ( ( head[0] << 24 ) |
74 ( head[1] << 16 ) |
75 ( head[2] << 8 ) |
76 head[3] );
77 map_pos = rfork_offset + ( ( head[4] << 24 ) |
78 ( head[5] << 16 ) |
79 ( head[6] << 8 ) |
80 head[7] );
81 rdata_len = ( head[ 8] << 24 ) |
82 ( head[ 9] << 16 ) |
83 ( head[10] << 8 ) |
84 head[11];
85
86 /* map_len = head[12] .. head[15] */
87
88 if ( *rdata_pos + rdata_len != map_pos || map_pos == rfork_offset )
89 return FT_Err_Unknown_File_Format;
90
91 error = FT_Stream_Seek( stream, map_pos );
92 if ( error )
93 return error;
94
95 head2[15] = (FT_Byte)( head[15] + 1 ); /* make it be different */
96
97 error = FT_Stream_Read( stream, (FT_Byte*)head2, 16 );
98 if ( error )
99 return error;
100
101 allzeros = 1;
102 allmatch = 1;
103 for ( i = 0; i < 16; ++i )
104 {
105 if ( head2[i] != 0 )
106 allzeros = 0;
107 if ( head2[i] != head[i] )
108 allmatch = 0;
109 }
110 if ( !allzeros && !allmatch )
111 return FT_Err_Unknown_File_Format;
112
113 /* If we have reached this point then it is probably a mac resource */
114 /* file. Now, does it contain any interesting resources? */
115 /* Skip handle to next resource map, the file resource number, and */
116 /* attributes. */
117 (void)FT_STREAM_SKIP( 4 /* skip handle to next resource map */
118 + 2 /* skip file resource number */
119 + 2 ); /* skip attributes */
120
121 if ( FT_READ_USHORT( type_list ) )
122 return error;
123 if ( type_list == -1 )
124 return FT_Err_Unknown_File_Format;
125
126 error = FT_Stream_Seek( stream, map_pos + type_list );
127 if ( error )
128 return error;
129
130 *map_offset = map_pos + type_list;
131 return FT_Err_Ok;
132 }
133
134
135 FT_BASE_DEF( FT_Error )
136 FT_Raccess_Get_DataOffsets( FT_Library library,
137 FT_Stream stream,
138 FT_Long map_offset,
139 FT_Long rdata_pos,
140 FT_Long tag,
141 FT_Long **offsets,
142 FT_Long *count )
143 {
144 FT_Error error;
145 int i, j, cnt, subcnt;
146 FT_Long tag_internal, rpos;
147 FT_Memory memory = library->memory;
148 FT_Long temp;
149 FT_Long *offsets_internal;
150
151
152 error = FT_Stream_Seek( stream, map_offset );
153 if ( error )
154 return error;
155
156 if ( FT_READ_USHORT( cnt ) )
157 return error;
158 cnt++;
159
160 for ( i = 0; i < cnt; ++i )
161 {
162 if ( FT_READ_LONG( tag_internal ) ||
163 FT_READ_USHORT( subcnt ) ||
164 FT_READ_USHORT( rpos ) )
165 return error;
166
167 FT_TRACE2(( "Resource tags: %c%c%c%c\n",
168 (char)( 0xff & ( tag_internal >> 24 ) ),
169 (char)( 0xff & ( tag_internal >> 16 ) ),
170 (char)( 0xff & ( tag_internal >> 8 ) ),
171 (char)( 0xff & ( tag_internal >> 0 ) ) ));
172
173 if ( tag_internal == tag )
174 {
175 *count = subcnt + 1;
176 rpos += map_offset;
177
178 error = FT_Stream_Seek( stream, rpos );
179 if ( error )
180 return error;
181
David Turner9ca78252006-05-02 09:00:29 +0000182 if ( FT_NEW_ARRAY( offsets_internal, *count ) )
Werner Lemberg75435332004-02-25 12:58:54 +0000183 return error;
184
185 for ( j = 0; j < *count; ++j )
186 {
187 (void)FT_STREAM_SKIP( 2 ); /* resource id */
188 (void)FT_STREAM_SKIP( 2 ); /* rsource name */
189
190 if ( FT_READ_LONG( temp ) )
191 {
192 FT_FREE( offsets_internal );
193 return error;
194 }
195
196 offsets_internal[j] = rdata_pos + ( temp & 0xFFFFFFL );
197
198 (void)FT_STREAM_SKIP( 4 ); /* mbz */
199 }
200
201 *offsets = offsets_internal;
202
203 return FT_Err_Ok;
204 }
205 }
206
207 return FT_Err_Cannot_Open_Resource;
208 }
209
210
211#ifdef FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK
212
213 /*************************************************************************/
214 /*************************************************************************/
215 /*************************************************************************/
216 /**** ****/
217 /**** ****/
218 /**** Guessing functions ****/
219 /**** ****/
220 /**** When you add a new guessing function, ****/
221 /**** update FT_RACCESS_N_RULES in ftrfork.h. ****/
222 /**** ****/
223 /*************************************************************************/
224 /*************************************************************************/
225 /*************************************************************************/
226
227 typedef FT_Error
228 (*raccess_guess_func)( FT_Library library,
229 FT_Stream stream,
230 char * base_file_name,
231 char **result_file_name,
232 FT_Long *result_offset );
233
234
235 static FT_Error
236 raccess_guess_apple_double( FT_Library library,
237 FT_Stream stream,
238 char * base_file_name,
239 char **result_file_name,
240 FT_Long *result_offset );
241
242 static FT_Error
243 raccess_guess_apple_single( FT_Library library,
244 FT_Stream stream,
245 char * base_file_name,
246 char **result_file_name,
247 FT_Long *result_offset );
248
249 static FT_Error
250 raccess_guess_darwin_ufs_export( FT_Library library,
251 FT_Stream stream,
252 char * base_file_name,
253 char **result_file_name,
254 FT_Long *result_offset );
255
256 static FT_Error
257 raccess_guess_darwin_hfsplus( FT_Library library,
258 FT_Stream stream,
259 char * base_file_name,
260 char **result_file_name,
261 FT_Long *result_offset );
262
263 static FT_Error
264 raccess_guess_vfat( FT_Library library,
265 FT_Stream stream,
266 char * base_file_name,
267 char **result_file_name,
268 FT_Long *result_offset );
269
270 static FT_Error
271 raccess_guess_linux_cap( FT_Library library,
272 FT_Stream stream,
273 char * base_file_name,
274 char **result_file_name,
275 FT_Long *result_offset );
276
277 static FT_Error
278 raccess_guess_linux_double( FT_Library library,
279 FT_Stream stream,
280 char * base_file_name,
281 char **result_file_name,
282 FT_Long *result_offset );
283
284 static FT_Error
285 raccess_guess_linux_netatalk( FT_Library library,
286 FT_Stream stream,
287 char * base_file_name,
288 char **result_file_name,
289 FT_Long *result_offset );
290
291
292 /*************************************************************************/
293 /**** ****/
294 /**** Helper functions ****/
295 /**** ****/
296 /*************************************************************************/
297
298 static FT_Error
299 raccess_guess_apple_generic( FT_Library library,
300 FT_Stream stream,
301 char * base_file_name,
302 FT_Int32 magic,
303 FT_Long *result_offset );
304
305 static FT_Error
306 raccess_guess_linux_double_from_file_name( FT_Library library,
307 char * file_name,
308 FT_Long *result_offset );
309
310 static char *
311 raccess_make_file_name( FT_Memory memory,
312 const char *original_name,
313 const char *insertion );
314
315
316 FT_BASE_DEF( void )
317 FT_Raccess_Guess( FT_Library library,
318 FT_Stream stream,
319 char* base_name,
320 char **new_names,
321 FT_Long *offsets,
322 FT_Error *errors )
323 {
324 FT_Long i;
325
326
327 raccess_guess_func funcs[FT_RACCESS_N_RULES] =
328 {
329 raccess_guess_apple_double,
330 raccess_guess_apple_single,
331 raccess_guess_darwin_ufs_export,
332 raccess_guess_darwin_hfsplus,
333 raccess_guess_vfat,
334 raccess_guess_linux_cap,
335 raccess_guess_linux_double,
336 raccess_guess_linux_netatalk,
337 };
338
339 for ( i = 0; i < FT_RACCESS_N_RULES; i++ )
340 {
341 new_names[i] = NULL;
Suzuki, Toshiya (鈴木俊哉)86c0f902007-11-20 14:00:17 +0000342 if ( NULL != stream )
343 errors[i] = FT_Stream_Seek( stream, 0 );
344 else
345 errors[i] = FT_Err_Ok;
346
Werner Lemberg75435332004-02-25 12:58:54 +0000347 if ( errors[i] )
348 continue ;
349
350 errors[i] = (funcs[i])( library, stream, base_name,
351 &(new_names[i]), &(offsets[i]) );
352 }
353
354 return;
355 }
356
357
358 static FT_Error
359 raccess_guess_apple_double( FT_Library library,
360 FT_Stream stream,
361 char * base_file_name,
362 char **result_file_name,
363 FT_Long *result_offset )
364 {
365 FT_Int32 magic = ( 0x00 << 24 | 0x05 << 16 | 0x16 << 8 | 0x07 );
366
367
368 *result_file_name = NULL;
Suzuki, Toshiya (鈴木俊哉)86c0f902007-11-20 14:00:17 +0000369 if ( NULL == stream )
370 return FT_Err_Cannot_Open_Stream;
371
Werner Lemberg75435332004-02-25 12:58:54 +0000372 return raccess_guess_apple_generic( library, stream, base_file_name,
373 magic, result_offset );
374 }
375
376
377 static FT_Error
378 raccess_guess_apple_single( FT_Library library,
379 FT_Stream stream,
380 char * base_file_name,
381 char **result_file_name,
382 FT_Long *result_offset )
383 {
384 FT_Int32 magic = (0x00 << 24 | 0x05 << 16 | 0x16 << 8 | 0x00);
385
386
387 *result_file_name = NULL;
Suzuki, Toshiya (鈴木俊哉)86c0f902007-11-20 14:00:17 +0000388 if ( NULL == stream )
389 return FT_Err_Cannot_Open_Stream;
390
Werner Lemberg75435332004-02-25 12:58:54 +0000391 return raccess_guess_apple_generic( library, stream, base_file_name,
392 magic, result_offset );
393 }
394
395
396 static FT_Error
397 raccess_guess_darwin_ufs_export( FT_Library library,
398 FT_Stream stream,
399 char * base_file_name,
400 char **result_file_name,
401 FT_Long *result_offset )
402 {
403 char* newpath;
404 FT_Error error;
405 FT_Memory memory;
406
407 FT_UNUSED( stream );
408
409
410 memory = library->memory;
411 newpath = raccess_make_file_name( memory, base_file_name, "._" );
412 if ( !newpath )
413 return FT_Err_Out_Of_Memory;
414
415 error = raccess_guess_linux_double_from_file_name( library, newpath,
416 result_offset );
417 if ( !error )
418 *result_file_name = newpath;
419 else
420 FT_FREE( newpath );
421
422 return error;
423 }
424
425
426 static FT_Error
427 raccess_guess_darwin_hfsplus( FT_Library library,
428 FT_Stream stream,
429 char * base_file_name,
430 char **result_file_name,
431 FT_Long *result_offset )
432 {
433 /*
434 Only meaningful on systems with hfs+ drivers (or Macs).
435 */
436 FT_Error error;
437 char* newpath;
438 FT_Memory memory;
David Turner9ca78252006-05-02 09:00:29 +0000439 FT_Long base_file_len = ft_strlen( base_file_name );
Werner Lemberg75435332004-02-25 12:58:54 +0000440
441 FT_UNUSED( stream );
442
443
444 memory = library->memory;
445
David Turner9ca78252006-05-02 09:00:29 +0000446 if ( base_file_len > FT_INT_MAX )
447 return FT_Err_Array_Too_Large;
448
449 if ( FT_ALLOC( newpath, base_file_len + 6 ) )
Werner Lemberg75435332004-02-25 12:58:54 +0000450 return error;
451
David Turner9ca78252006-05-02 09:00:29 +0000452 FT_MEM_COPY( newpath, base_file_name, base_file_len );
453 FT_MEM_COPY( newpath + base_file_len, "/rsrc", 6 );
454
Werner Lemberg75435332004-02-25 12:58:54 +0000455 *result_file_name = newpath;
David Turner9ca78252006-05-02 09:00:29 +0000456 *result_offset = 0;
457
Werner Lemberg75435332004-02-25 12:58:54 +0000458 return FT_Err_Ok;
459 }
460
461
462 static FT_Error
463 raccess_guess_vfat( FT_Library library,
464 FT_Stream stream,
465 char * base_file_name,
466 char **result_file_name,
467 FT_Long *result_offset )
468 {
469 char* newpath;
470 FT_Memory memory;
471
472 FT_UNUSED( stream );
473
474
475 memory = library->memory;
476
477 newpath = raccess_make_file_name( memory, base_file_name,
478 "resource.frk/" );
479 if ( !newpath )
480 return FT_Err_Out_Of_Memory;
481
482 *result_file_name = newpath;
483 *result_offset = 0;
484
485 return FT_Err_Ok;
486 }
487
488
489 static FT_Error
490 raccess_guess_linux_cap( FT_Library library,
491 FT_Stream stream,
492 char * base_file_name,
493 char **result_file_name,
494 FT_Long *result_offset )
495 {
496 char* newpath;
497 FT_Memory memory;
498
499 FT_UNUSED( stream );
500
501
502 memory = library->memory;
503
504 newpath = raccess_make_file_name( memory, base_file_name, ".resource/" );
505 if ( !newpath )
506 return FT_Err_Out_Of_Memory;
507
508 *result_file_name = newpath;
509 *result_offset = 0;
510
511 return FT_Err_Ok;
512 }
513
514
515 static FT_Error
516 raccess_guess_linux_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 char* newpath;
523 FT_Error error;
524 FT_Memory memory;
525
526 FT_UNUSED( stream );
527
528
529 memory = library->memory;
530
531 newpath = raccess_make_file_name( memory, base_file_name, "%" );
532 if ( !newpath )
533 return FT_Err_Out_Of_Memory;
534
535 error = raccess_guess_linux_double_from_file_name( library, newpath,
536 result_offset );
537 if ( !error )
538 *result_file_name = newpath;
539 else
540 FT_FREE( newpath );
541
542 return error;
543 }
544
545
546 static FT_Error
547 raccess_guess_linux_netatalk( FT_Library library,
548 FT_Stream stream,
549 char * base_file_name,
550 char **result_file_name,
551 FT_Long *result_offset )
552 {
553 char* newpath;
554 FT_Error error;
555 FT_Memory memory;
556
557 FT_UNUSED( stream );
558
559
560 memory = library->memory;
561
562 newpath = raccess_make_file_name( memory, base_file_name,
563 ".AppleDouble/" );
564 if ( !newpath )
565 return FT_Err_Out_Of_Memory;
566
567 error = raccess_guess_linux_double_from_file_name( library, newpath,
568 result_offset );
569 if ( !error )
570 *result_file_name = newpath;
571 else
572 FT_FREE( newpath );
573
574 return error;
575 }
576
577
578 static FT_Error
579 raccess_guess_apple_generic( FT_Library library,
580 FT_Stream stream,
581 char * base_file_name,
582 FT_Int32 magic,
583 FT_Long *result_offset )
584 {
585 FT_Int32 magic_from_stream;
586 FT_Error error;
Werner Lembergf814f682005-05-22 20:33:09 +0000587 FT_Int32 version_number = 0;
Werner Lemberg75435332004-02-25 12:58:54 +0000588 FT_UShort n_of_entries;
589
590 int i;
Werner Lembergf814f682005-05-22 20:33:09 +0000591 FT_UInt32 entry_id, entry_offset, entry_length = 0;
Werner Lemberg75435332004-02-25 12:58:54 +0000592
593 const FT_UInt32 resource_fork_entry_id = 0x2;
594
595 FT_UNUSED( library );
596 FT_UNUSED( base_file_name );
Werner Lembergf814f682005-05-22 20:33:09 +0000597 FT_UNUSED( version_number );
598 FT_UNUSED( entry_length );
Werner Lemberg75435332004-02-25 12:58:54 +0000599
600
Werner Lembergf814f682005-05-22 20:33:09 +0000601 if ( FT_READ_LONG( magic_from_stream ) )
Werner Lemberg75435332004-02-25 12:58:54 +0000602 return error;
603 if ( magic_from_stream != magic )
604 return FT_Err_Unknown_File_Format;
605
606 if ( FT_READ_LONG( version_number ) )
607 return error;
608
609 /* filler */
610 error = FT_Stream_Skip( stream, 16 );
611 if ( error )
612 return error;
613
614 if ( FT_READ_USHORT( n_of_entries ) )
615 return error;
616 if ( n_of_entries == 0 )
617 return FT_Err_Unknown_File_Format;
618
619 for ( i = 0; i < n_of_entries; i++ )
620 {
621 if ( FT_READ_LONG( entry_id ) )
622 return error;
623 if ( entry_id == resource_fork_entry_id )
624 {
625 if ( FT_READ_LONG( entry_offset ) ||
626 FT_READ_LONG( entry_length ) )
627 continue;
628 *result_offset = entry_offset;
629
630 return FT_Err_Ok;
631 }
632 else
633 FT_Stream_Skip( stream, 4 + 4 ); /* offset + length */
634 }
635
636 return FT_Err_Unknown_File_Format;
637 }
638
639
640 static FT_Error
641 raccess_guess_linux_double_from_file_name( FT_Library library,
642 char * file_name,
643 FT_Long *result_offset )
644 {
Werner Lemberg75435332004-02-25 12:58:54 +0000645 FT_Open_Args args2;
646 FT_Stream stream2;
647 char * nouse = NULL;
648 FT_Error error;
649
650
Werner Lemberg75435332004-02-25 12:58:54 +0000651 args2.flags = FT_OPEN_PATHNAME;
652 args2.pathname = file_name;
653 error = FT_Stream_New( library, &args2, &stream2 );
654 if ( error )
655 return error;
656
657 error = raccess_guess_apple_double( library, stream2, file_name,
658 &nouse, result_offset );
659
Suzuki, Toshiya (鈴木俊哉)de0a96c2006-05-19 23:16:12 +0000660 FT_Stream_Free( stream2, 0 );
Werner Lemberg75435332004-02-25 12:58:54 +0000661
662 return error;
663 }
664
665
666 static char*
667 raccess_make_file_name( FT_Memory memory,
668 const char *original_name,
669 const char *insertion )
670 {
671 char* new_name;
672 char* tmp;
673 const char* slash;
674 unsigned new_length;
David Turner6a681fa2006-01-27 12:11:22 +0000675 FT_Error error = FT_Err_Ok;
Werner Lembergf814f682005-05-22 20:33:09 +0000676
677 FT_UNUSED( error );
678
Werner Lemberg75435332004-02-25 12:58:54 +0000679
680 new_length = ft_strlen( original_name ) + ft_strlen( insertion );
681 if ( FT_ALLOC( new_name, new_length + 1 ) )
682 return NULL;
683
684 tmp = ft_strrchr( original_name, '/' );
685 if ( tmp )
686 {
687 ft_strncpy( new_name, original_name, tmp - original_name + 1 );
688 new_name[tmp - original_name + 1] = '\0';
689 slash = tmp + 1;
690 }
691 else
692 {
693 slash = original_name;
694 new_name[0] = '\0';
695 }
696
697 ft_strcat( new_name, insertion );
698 ft_strcat( new_name, slash );
699
700 return new_name;
701 }
702
703
704#else /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */
705
706
707 /*************************************************************************/
708 /* Dummy function; just sets errors */
709 /*************************************************************************/
710
711 FT_BASE_DEF( void )
712 FT_Raccess_Guess( FT_Library library,
713 FT_Stream stream,
714 char* base_name,
715 char **new_names,
716 FT_Long *offsets,
717 FT_Error *errors )
718 {
719 int i;
720
Werner Lemberg17439422004-08-11 05:25:37 +0000721 FT_UNUSED( library );
722 FT_UNUSED( stream );
723 FT_UNUSED( base_name );
724
Werner Lemberg75435332004-02-25 12:58:54 +0000725
726 for ( i = 0; i < FT_RACCESS_N_RULES; i++ )
727 {
728 new_names[i] = NULL;
729 offsets[i] = 0;
730 errors[i] = FT_Err_Unimplemented_Feature;
731 }
732 }
733
734
735#endif /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */
736
737
738/* END */