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