sync with trunk r47346
[reactos.git] / lib / 3rdparty / freetype / src / base / ftrfork.c
1 /***************************************************************************/
2 /* */
3 /* ftrfork.c */
4 /* */
5 /* Embedded resource forks accessor (body). */
6 /* */
7 /* Copyright 2004, 2005, 2006 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
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
182 if ( FT_NEW_ARRAY( offsets_internal, *count ) )
183 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;
342 errors[i] = FT_Stream_Seek( stream, 0 );
343 if ( errors[i] )
344 continue ;
345
346 errors[i] = (funcs[i])( library, stream, base_name,
347 &(new_names[i]), &(offsets[i]) );
348 }
349
350 return;
351 }
352
353
354 static FT_Error
355 raccess_guess_apple_double( FT_Library library,
356 FT_Stream stream,
357 char * base_file_name,
358 char **result_file_name,
359 FT_Long *result_offset )
360 {
361 FT_Int32 magic = ( 0x00 << 24 | 0x05 << 16 | 0x16 << 8 | 0x07 );
362
363
364 *result_file_name = NULL;
365 return raccess_guess_apple_generic( library, stream, base_file_name,
366 magic, result_offset );
367 }
368
369
370 static FT_Error
371 raccess_guess_apple_single( FT_Library library,
372 FT_Stream stream,
373 char * base_file_name,
374 char **result_file_name,
375 FT_Long *result_offset )
376 {
377 FT_Int32 magic = (0x00 << 24 | 0x05 << 16 | 0x16 << 8 | 0x00);
378
379
380 *result_file_name = NULL;
381 return raccess_guess_apple_generic( library, stream, base_file_name,
382 magic, result_offset );
383 }
384
385
386 static FT_Error
387 raccess_guess_darwin_ufs_export( FT_Library library,
388 FT_Stream stream,
389 char * base_file_name,
390 char **result_file_name,
391 FT_Long *result_offset )
392 {
393 char* newpath;
394 FT_Error error;
395 FT_Memory memory;
396
397 FT_UNUSED( stream );
398
399
400 memory = library->memory;
401 newpath = raccess_make_file_name( memory, base_file_name, "._" );
402 if ( !newpath )
403 return FT_Err_Out_Of_Memory;
404
405 error = raccess_guess_linux_double_from_file_name( library, newpath,
406 result_offset );
407 if ( !error )
408 *result_file_name = newpath;
409 else
410 FT_FREE( newpath );
411
412 return error;
413 }
414
415
416 static FT_Error
417 raccess_guess_darwin_hfsplus( FT_Library library,
418 FT_Stream stream,
419 char * base_file_name,
420 char **result_file_name,
421 FT_Long *result_offset )
422 {
423 /*
424 Only meaningful on systems with hfs+ drivers (or Macs).
425 */
426 FT_Error error;
427 char* newpath;
428 FT_Memory memory;
429 FT_Long base_file_len = ft_strlen( base_file_name );
430
431 FT_UNUSED( stream );
432
433
434 memory = library->memory;
435
436 if ( base_file_len > FT_INT_MAX )
437 return FT_Err_Array_Too_Large;
438
439 if ( FT_ALLOC( newpath, base_file_len + 6 ) )
440 return error;
441
442 FT_MEM_COPY( newpath, base_file_name, base_file_len );
443 FT_MEM_COPY( newpath + base_file_len, "/rsrc", 6 );
444
445 *result_file_name = newpath;
446 *result_offset = 0;
447
448 return FT_Err_Ok;
449 }
450
451
452 static FT_Error
453 raccess_guess_vfat( FT_Library library,
454 FT_Stream stream,
455 char * base_file_name,
456 char **result_file_name,
457 FT_Long *result_offset )
458 {
459 char* newpath;
460 FT_Memory memory;
461
462 FT_UNUSED( stream );
463
464
465 memory = library->memory;
466
467 newpath = raccess_make_file_name( memory, base_file_name,
468 "resource.frk/" );
469 if ( !newpath )
470 return FT_Err_Out_Of_Memory;
471
472 *result_file_name = newpath;
473 *result_offset = 0;
474
475 return FT_Err_Ok;
476 }
477
478
479 static FT_Error
480 raccess_guess_linux_cap( FT_Library library,
481 FT_Stream stream,
482 char * base_file_name,
483 char **result_file_name,
484 FT_Long *result_offset )
485 {
486 char* newpath;
487 FT_Memory memory;
488
489 FT_UNUSED( stream );
490
491
492 memory = library->memory;
493
494 newpath = raccess_make_file_name( memory, base_file_name, ".resource/" );
495 if ( !newpath )
496 return FT_Err_Out_Of_Memory;
497
498 *result_file_name = newpath;
499 *result_offset = 0;
500
501 return FT_Err_Ok;
502 }
503
504
505 static FT_Error
506 raccess_guess_linux_double( FT_Library library,
507 FT_Stream stream,
508 char * base_file_name,
509 char **result_file_name,
510 FT_Long *result_offset )
511 {
512 char* newpath;
513 FT_Error error;
514 FT_Memory memory;
515
516 FT_UNUSED( stream );
517
518
519 memory = library->memory;
520
521 newpath = raccess_make_file_name( memory, base_file_name, "%" );
522 if ( !newpath )
523 return FT_Err_Out_Of_Memory;
524
525 error = raccess_guess_linux_double_from_file_name( library, newpath,
526 result_offset );
527 if ( !error )
528 *result_file_name = newpath;
529 else
530 FT_FREE( newpath );
531
532 return error;
533 }
534
535
536 static FT_Error
537 raccess_guess_linux_netatalk( FT_Library library,
538 FT_Stream stream,
539 char * base_file_name,
540 char **result_file_name,
541 FT_Long *result_offset )
542 {
543 char* newpath;
544 FT_Error error;
545 FT_Memory memory;
546
547 FT_UNUSED( stream );
548
549
550 memory = library->memory;
551
552 newpath = raccess_make_file_name( memory, base_file_name,
553 ".AppleDouble/" );
554 if ( !newpath )
555 return FT_Err_Out_Of_Memory;
556
557 error = raccess_guess_linux_double_from_file_name( library, newpath,
558 result_offset );
559 if ( !error )
560 *result_file_name = newpath;
561 else
562 FT_FREE( newpath );
563
564 return error;
565 }
566
567
568 static FT_Error
569 raccess_guess_apple_generic( FT_Library library,
570 FT_Stream stream,
571 char * base_file_name,
572 FT_Int32 magic,
573 FT_Long *result_offset )
574 {
575 FT_Int32 magic_from_stream;
576 FT_Error error;
577 FT_Int32 version_number = 0;
578 FT_UShort n_of_entries;
579
580 int i;
581 FT_UInt32 entry_id, entry_offset, entry_length = 0;
582
583 const FT_UInt32 resource_fork_entry_id = 0x2;
584
585 FT_UNUSED( library );
586 FT_UNUSED( base_file_name );
587 FT_UNUSED( version_number );
588 FT_UNUSED( entry_length );
589
590
591 if ( FT_READ_LONG( magic_from_stream ) )
592 return error;
593 if ( magic_from_stream != magic )
594 return FT_Err_Unknown_File_Format;
595
596 if ( FT_READ_LONG( version_number ) )
597 return error;
598
599 /* filler */
600 error = FT_Stream_Skip( stream, 16 );
601 if ( error )
602 return error;
603
604 if ( FT_READ_USHORT( n_of_entries ) )
605 return error;
606 if ( n_of_entries == 0 )
607 return FT_Err_Unknown_File_Format;
608
609 for ( i = 0; i < n_of_entries; i++ )
610 {
611 if ( FT_READ_LONG( entry_id ) )
612 return error;
613 if ( entry_id == resource_fork_entry_id )
614 {
615 if ( FT_READ_LONG( entry_offset ) ||
616 FT_READ_LONG( entry_length ) )
617 continue;
618 *result_offset = entry_offset;
619
620 return FT_Err_Ok;
621 }
622 else
623 FT_Stream_Skip( stream, 4 + 4 ); /* offset + length */
624 }
625
626 return FT_Err_Unknown_File_Format;
627 }
628
629
630 static FT_Error
631 raccess_guess_linux_double_from_file_name( FT_Library library,
632 char * file_name,
633 FT_Long *result_offset )
634 {
635 FT_Open_Args args2;
636 FT_Stream stream2;
637 char * nouse = NULL;
638 FT_Error error;
639
640
641 args2.flags = FT_OPEN_PATHNAME;
642 args2.pathname = file_name;
643 error = FT_Stream_New( library, &args2, &stream2 );
644 if ( error )
645 return error;
646
647 error = raccess_guess_apple_double( library, stream2, file_name,
648 &nouse, result_offset );
649
650 FT_Stream_Free( stream2, 0 );
651
652 return error;
653 }
654
655
656 static char*
657 raccess_make_file_name( FT_Memory memory,
658 const char *original_name,
659 const char *insertion )
660 {
661 char* new_name;
662 char* tmp;
663 const char* slash;
664 unsigned new_length;
665 FT_Error error = FT_Err_Ok;
666
667 FT_UNUSED( error );
668
669
670 new_length = ft_strlen( original_name ) + ft_strlen( insertion );
671 if ( FT_ALLOC( new_name, new_length + 1 ) )
672 return NULL;
673
674 tmp = ft_strrchr( original_name, '/' );
675 if ( tmp )
676 {
677 ft_strncpy( new_name, original_name, tmp - original_name + 1 );
678 new_name[tmp - original_name + 1] = '\0';
679 slash = tmp + 1;
680 }
681 else
682 {
683 slash = original_name;
684 new_name[0] = '\0';
685 }
686
687 ft_strcat( new_name, insertion );
688 ft_strcat( new_name, slash );
689
690 return new_name;
691 }
692
693
694 #else /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */
695
696
697 /*************************************************************************/
698 /* Dummy function; just sets errors */
699 /*************************************************************************/
700
701 FT_BASE_DEF( void )
702 FT_Raccess_Guess( FT_Library library,
703 FT_Stream stream,
704 char* base_name,
705 char **new_names,
706 FT_Long *offsets,
707 FT_Error *errors )
708 {
709 int i;
710
711 FT_UNUSED( library );
712 FT_UNUSED( stream );
713 FT_UNUSED( base_name );
714
715
716 for ( i = 0; i < FT_RACCESS_N_RULES; i++ )
717 {
718 new_names[i] = NULL;
719 offsets[i] = 0;
720 errors[i] = FT_Err_Unimplemented_Feature;
721 }
722 }
723
724
725 #endif /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */
726
727
728 /* END */