1 | /**************************************************************************** |
2 | * |
3 | * ftrfork.c |
4 | * |
5 | * Embedded resource forks accessor (body). |
6 | * |
7 | * Copyright (C) 2004-2023 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 ) |
50 | ( 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 ) |
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 ) |
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 ) |
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 |
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 ) |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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* |
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; |
872 | |
873 | |
874 | new_length = ft_strlen( original_name ) + ft_strlen( insertion ); |
875 | if ( FT_QALLOC( new_name, new_length + 1 ) ) |
876 | return NULL; |
877 | |
878 | tmp = ft_strrchr( original_name, '/' ); |
879 | if ( tmp ) |
880 | { |
881 | ft_strncpy( new_name, |
882 | original_name, |
883 | (size_t)( tmp - original_name + 1 ) ); |
884 | new_name[tmp - original_name + 1] = '\0'; |
885 | slash = tmp + 1; |
886 | } |
887 | else |
888 | { |
889 | slash = original_name; |
890 | new_name[0] = '\0'; |
891 | } |
892 | |
893 | ft_strcat( new_name, insertion ); |
894 | ft_strcat( new_name, slash ); |
895 | |
896 | return new_name; |
897 | } |
898 | |
899 | |
900 | #else /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */ |
901 | |
902 | |
903 | /************************************************************************** |
904 | * Dummy function; just sets errors |
905 | */ |
906 | |
907 | FT_BASE_DEF( void ) |
908 | FT_Raccess_Guess( FT_Library library, |
909 | FT_Stream stream, |
910 | char *base_name, |
911 | char **new_names, |
912 | FT_Long *offsets, |
913 | FT_Error *errors ) |
914 | { |
915 | FT_Int i; |
916 | |
917 | FT_UNUSED( library ); |
918 | FT_UNUSED( stream ); |
919 | FT_UNUSED( base_name ); |
920 | |
921 | |
922 | for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) |
923 | { |
924 | new_names[i] = NULL; |
925 | offsets[i] = 0; |
926 | errors[i] = FT_ERR( Unimplemented_Feature ); |
927 | } |
928 | } |
929 | |
930 | |
931 | #endif /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */ |
932 | |
933 | |
934 | /* END */ |
935 | |