Fixed compatibility of output.
[AROS.git] / rom / filesys / CDVDFS / src / hfs.c
blob5e3359113ceeea26309d0d57d9a6f4ffc8c160c6
1 /* hfs.c:
3 * Support for the Macintosh HFS filing system.
5 * ----------------------------------------------------------------------
6 * This code is (C) Copyright 1993,1994 by Frank Munkert.
7 * All rights reserved.
8 * This software may be freely distributed and redistributed for
9 * non-commercial purposes, provided this notice is included.
10 * ----------------------------------------------------------------------
11 * History:
13 * 06-Mar-09 error - Removed madness, fixed insanity. Cleanup started
14 * 03-Nov-94 fmu - Fixed bug in HFS_Read_From_File().
15 * - Truncate file names to 30 characters.
16 * 15-Apr-93 fmu - Improved conversion routines.
17 * - Fixed bug in HFS_Find_Parent().
18 * - Fixed bug in date conversion routine.
19 * 02-Jan-93 fmu Improved search method for master directory block.
20 * 03-Dec-93 fmu - Fixed bug in HFS_Find_Leaf_Record().
21 * - Convert ':' and '/' characters.
22 * - Also convert volume names.
23 * 29-Nov-93 fmu New function HFS_Block_Size().
24 * 15-Nov-93 fmu Corrected some typing mistakes in the HFS->ISO conversion
25 * table.
26 * 07-Jul-02 sheutlin various changes when porting to AROS
27 * - global variables are now in a struct Globals *global
28 * - moved some definitions into hfs.h
31 #include <proto/exec.h>
32 #include <proto/utility.h>
33 #include <stdlib.h>
34 #include <string.h>
36 #include "cdrom.h"
37 #include "generic.h"
38 #include "hfs.h"
39 #include "params.h"
40 #include "globals.h"
42 #include "clib_stuff.h"
44 #define VOL(vol,tag) (((t_hfs_vol_info *)(vol->vol_info))->tag)
45 #define OBJ(obj,tag) (((t_hfs_obj_info *)(obj->obj_info))->tag)
47 /* Number of seconds betweem 01-Jan-1904 and 01-Jan-1978: */
49 #define TIME_DIFF ((74UL * 365 + 19) * 24 * 60 * 60)
51 static char const g_conv_table[128] = {
52 'Ä', 'Å', 'Ç', 'É', 'Ñ', 'Ö', 'Ü',
53 'á', 'à', 'â', 'ä', 'ã', 'å', 'ç',
54 'é', 'è', 'ê', 'ë', 'í', 'ì', 'î',
55 'ï', 'ñ', 'ó', 'ò', 'ô', 'ö', 'õ',
56 'ú', 'ù', 'û', 'ü', '¿', '°', '¢',
57 '£', '§', '·', '¶', 'ß', '®', '©',
58 '¿', '´', '¨', '¿', 'Æ', 'Ø', '¿',
59 '±', '¿', '¿', '¥', 'µ', 'ð', '¿',
60 '¿', '¿', '¿', 'ª', 'º', '¿', 'æ',
61 'ø', '¿', '¡', '¬', '¿', '¿', '¿',
62 '¿', '«', '»', '¿', ' ', 'À', 'Ã',
63 'Õ', '¿', '¿', '­', '-', '\"', '\"',
64 '`', '´', '÷', '¿', 'ÿ', '¿', '/',
65 '¤', '¿', '¿', '¿', '¿', '¿', '.',
66 '¸', '¿', '¿', 'Â', 'Ê', 'Á', 'Ë',
67 'È', 'Í', 'Î', 'Ï', 'Ì', 'Ó', 'Ô',
68 '¿', 'Ò', 'Ú', 'Û', 'Ù', '¿', '^',
69 '~', '­', '¿', '·', '°', '¿', '\"',
70 '.', '¿'
73 void Convert_Mac_Characters (char *p_buf, int p_buf_len)
75 unsigned char *cp = (unsigned char *) p_buf;
76 int i;
78 for (i=0; i<p_buf_len; i++, cp++)
79 if (*cp >= 128)
80 *cp = g_conv_table[*cp-128];
81 else if (*cp == ':')
82 *cp = '.';
83 else if (*cp == '/')
84 *cp = '-';
85 else if (*cp < 32)
86 *cp = 0xBF /* ¿ */;
89 void Convert_HFS_Spaces (char *p_buf, int p_buf_len)
91 unsigned char *cp = (unsigned char *) p_buf;
92 int i;
94 for (i=0; i<p_buf_len; i++, cp++)
95 if (*cp == ' ' || *cp == 0xA0)
96 *cp = '_';
99 t_uchar *Read_Block(CDROM *p_cdrom, t_ulong p_block) {
100 if (!Read_Chunk(p_cdrom, p_block >> 2))
101 return NULL;
103 return p_cdrom->buffer + ((p_block & 3) << 9);
106 /* Convert allocation block number into 512 byte block number.
109 t_ulong AB_to_Block (VOLUME *p_volume, t_ulong p_alloc_block)
111 return p_alloc_block * (VOL(p_volume,mdb).AlBlkSiz >> 9) +
112 VOL(p_volume,mdb).AlBlSt + VOL(p_volume,start_block);
115 int HFS_Find_Master_Directory_Block(CDROM *p_cd, t_mdb *p_mdb) {
116 t_uchar *block;
117 typedef struct partition_map
119 t_ushort pmSig;
120 t_ushort reSigPad;
121 t_ulong pmMapBlkCnt;
122 t_ulong pmPyPartStart;
123 t_ulong pmPartBlkCnt;
124 char pmPartName[32];
125 char pmPartType[32];
126 } t_partition_map;
127 int i, entries;
128 int result;
130 block = Read_Block(p_cd, 1);
131 if (!block || block[0] != 0x50 || block[1] != 0x4D)
132 return -1;
134 entries = ((t_partition_map *) block)->pmMapBlkCnt;
135 for (i=0; i<entries; i++)
137 block = Read_Block(p_cd, i+1);
138 if (!block || block[0] != 0x50 || block[1] != 0x4D)
139 return -1;
140 if (
141 MemCmp
143 ((t_partition_map *) block)->pmPartType,
144 "Apple_HFS", 9
145 ) == 0
148 result = ((t_partition_map *) block)->pmPyPartStart + 2;
149 block = Read_Block(p_cd, result);
150 if (!block || block[0] != 0x42 || block[1] != 0x44)
151 return -1;
152 else
154 CopyMem(block, p_mdb, sizeof (*p_mdb));
155 return result;
160 return -1;
163 t_bool Uses_HFS_Protocol(CDROM *p_cd, int *p_skip) {
164 t_mdb mdb;
165 int blk;
167 blk = HFS_Find_Master_Directory_Block(p_cd, &mdb);
168 if (blk == -1)
169 return FALSE;
171 *p_skip = blk - 2; /* *p_skip holds the start block of the volume */
172 return TRUE;
175 t_bool HFS_Get_Header_Node
176 (CDROM *p_cd, t_ulong p_mdb_pos, t_mdb *p_mdb, t_hdr_node *p_hdr_node)
178 t_ulong pos =
180 p_mdb_pos - 2 + p_mdb->AlBlSt +
181 p_mdb->CTExtRec[0].StABN * (p_mdb->AlBlkSiz >> 9)
183 t_hdr_node *hdr;
185 hdr = (t_hdr_node *) Read_Block(p_cd, pos);
186 if (!hdr)
187 return FALSE;
189 CopyMem(hdr, p_hdr_node, sizeof (t_hdr_node));
190 return TRUE;
193 t_node_descr *HFS_Get_Node
194 (CDROM *p_cd, t_ulong p_mdb_pos, t_mdb *p_mdb, t_ulong p_node)
196 t_ulong first_node;
197 t_ulong pos;
198 t_ulong max = 0;
199 t_ulong sub = 0;
200 int i;
202 for (i=0; i<3; i++)
204 max += p_mdb->CTExtRec[i].NumABlks * (p_mdb->AlBlkSiz >> 9);
205 if (p_node < max)
206 break;
207 sub = max;
210 if (i==3)
211 return NULL;
213 first_node = (p_mdb_pos - 2 + p_mdb->AlBlSt +
214 p_mdb->CTExtRec[i].StABN * (p_mdb->AlBlkSiz >> 9));
216 pos = first_node + (p_node - sub);
218 return (t_node_descr *) Read_Block(p_cd, pos);
221 t_node_descr *HFS_Node(VOLUME *p_volume, t_ulong p_node) {
222 return HFS_Get_Node (p_volume->cd, VOL(p_volume,start_block) + 2,
223 &VOL(p_volume,mdb), p_node);
226 void HFS_Load_Catalog_Record
227 (t_catalog_record *p_cat_rec, char *p_node, int p_record)
229 short *sp = (short *) p_node;
230 int len;
231 int start;
233 start = sp[255-p_record];
234 start += p_node[start] + 1;
235 if (start & 1)
236 start++;
238 len = sp[254-p_record] - start;
239 CopyMem(p_node + start, p_cat_rec, len);
243 t_bool HFS_Find_Next_Leaf(VOLUME *p_volume, t_leaf_record_pos *p_leaf) {
244 t_node_descr *node;
245 short *sp;
246 int pos;
248 node = HFS_Node(p_volume, p_leaf->node);
249 if (!node)
250 return FALSE;
252 p_leaf->record++;
253 if (p_leaf->record == node->NRecs)
255 if (node->FLink)
257 node = HFS_Node(p_volume, p_leaf->node = node->FLink);
258 if (!node)
259 return FALSE;
260 p_leaf->record = 0;
262 else
263 return FALSE;
266 sp = (short *) node;
267 pos = sp[255-p_leaf->record];
268 CopyMem(node, &p_leaf->node_descr, sizeof (t_node_descr));
269 CopyMem((char *)node+pos, &p_leaf->leaf_rec, ((char *) node)[pos] + 1);
270 HFS_Load_Catalog_Record(&p_leaf->cat_rec, (char *) node, p_leaf->record);
272 if (p_leaf->leaf_rec.name_length > 30)
274 p_leaf->leaf_rec.name_length = 30;
275 *((char *)&p_leaf->leaf_rec.name[0] + 30) = '\0';
278 return TRUE;
281 /* Find leaf record p_leaf->record in node p_leaf->node.
282 * Store the result in *p_leaf.
285 t_bool HFS_Find_This_Leaf(VOLUME *p_volume, t_leaf_record_pos *p_leaf) {
286 t_node_descr *node;
287 short *sp;
288 int pos;
290 node = HFS_Node(p_volume, p_leaf->node);
291 if (!node)
292 return FALSE;
294 sp = (short *) node;
295 pos = sp[255-p_leaf->record];
296 CopyMem(node, &p_leaf->node_descr, sizeof (t_node_descr));
297 CopyMem((char *)node+pos, &p_leaf->leaf_rec, ((char *) node)[pos] + 1);
298 HFS_Load_Catalog_Record(&p_leaf->cat_rec, (char *) node, p_leaf->record);
300 return TRUE;
303 /* Find the first leaf record with parent ID p_parent_id.
304 * If the leaf node is found, TRUE is returned and *p_cat_rec will be
305 * loaded with the catalog record. Otherwise, FALSE is returned.
308 t_bool HFS_Find_Leaf_Record
309 (VOLUME *p_volume, t_leaf_record_pos *p_leaf, t_ulong p_parent_id)
311 struct CDVDBase *global = p_volume->global;
312 t_node_descr *node;
313 short *sp;
314 int i;
315 t_ulong this_node = VOL(p_volume,root_node);
316 t_ulong next_node;
318 node = HFS_Node(p_volume, VOL(p_volume,root_node));
319 if (!node)
321 global->iso_errno = ISOERR_SCSI_ERROR;
322 return FALSE;
325 for (;;)
327 if (node->Type == 0)
329 /* index node */
330 sp = (short *) node;
331 next_node = -1;
332 for (i=0; i<node->NRecs; i++)
334 t_idx_record *idx = (t_idx_record *) ((char *) node + sp[255-i]);
335 if (idx->length != 0)
337 if (idx->parent_id >= p_parent_id)
338 break;
339 next_node = idx->pointer;
343 else if (node->Type == 0xff)
345 /* leaf node */
346 break;
348 else
350 global->iso_errno = ISOERR_INTERNAL;
351 return FALSE;
354 if (next_node == -1)
356 global->iso_errno = ISOERR_INTERNAL;
357 return FALSE;
360 node = HFS_Node(p_volume, next_node);
361 if (!node)
363 global->iso_errno = ISOERR_SCSI_ERROR;
364 return FALSE;
366 this_node = next_node;
369 p_leaf->node = this_node;
370 p_leaf->record = 0;
371 CopyMem(node, &p_leaf->node_descr, sizeof (t_node_descr));
372 CopyMem((char *)node +0xE, &p_leaf->leaf_rec, ((char *) node)[0xe] + 1);
373 HFS_Load_Catalog_Record(&p_leaf->cat_rec, (char *) node, 0);
375 /* walk forwards until the same key is found: */
376 for (;;)
378 if (p_leaf->leaf_rec.parent_id == p_parent_id)
379 break;
380 if (p_leaf->leaf_rec.parent_id > p_parent_id)
382 global->iso_errno = ISOERR_INTERNAL;
383 return FALSE;
386 if (!HFS_Find_Next_Leaf(p_volume, p_leaf))
388 global->iso_errno = ISOERR_INTERNAL;
389 return FALSE;
394 if (p_leaf->leaf_rec.name_length > 30)
396 p_leaf->leaf_rec.name_length = 30;
397 *((char *)&p_leaf->leaf_rec.name[0] + 30) = '\0';
400 return TRUE;
403 static t_handler const g_hfs_handler;
405 t_bool HFS_Init_Vol_Info
406 (VOLUME *p_volume, int p_start_block) {
407 struct CDVDBase *global = p_volume->global;
408 t_uchar *block;
409 t_hdr_node hdr;
412 Here is a good place to check whether the values of the variables
413 g_data_fork_extension and g_resource_fork_extension are OK.
416 if (
417 global->g_data_fork_extension[0] == 0 &&
418 (global->g_resource_fork_extension[0] == 0)
420 StrCpy (global->g_resource_fork_extension, ".rsrc");
423 Volume info initialization:
426 p_volume->handler = &g_hfs_handler;
428 p_volume->vol_info = AllocMem (sizeof (t_hfs_vol_info), MEMF_PUBLIC);
429 if (!p_volume->vol_info)
431 global->iso_errno = ISOERR_NO_MEMORY;
432 return FALSE;
435 VOL(p_volume,start_block) = p_start_block;
437 if (!(block = Read_Block(p_volume->cd, p_start_block + 2)))
439 global->iso_errno = ISOERR_SCSI_ERROR;
440 FreeMem (p_volume->vol_info, sizeof (t_hfs_vol_info));
441 return FALSE;
444 CopyMem(block, &VOL(p_volume,mdb), sizeof (t_mdb));
446 if (
447 !HFS_Get_Header_Node
448 (p_volume->cd, p_start_block + 2, &VOL(p_volume,mdb), &hdr)
451 global->iso_errno = ISOERR_SCSI_ERROR;
452 FreeMem (p_volume->vol_info, sizeof (t_hfs_vol_info));
453 return FALSE;
456 VOL(p_volume,root_node) = hdr.Root;
458 p_volume->mixed_char_filenames = TRUE;
460 return TRUE;
463 void HFS_Close_Vol_Info(VOLUME *p_volume)
465 FreeMem (p_volume->vol_info, sizeof (t_hfs_vol_info));
468 CDROM_OBJ *HFS_Alloc_Obj(struct CDVDBase *global) {
469 CDROM_OBJ *obj = AllocMem (sizeof (CDROM_OBJ), MEMF_PUBLIC | MEMF_CLEAR);
471 if (!obj)
473 global->iso_errno = ISOERR_NO_MEMORY;
474 return NULL;
477 obj->global = global;
478 obj->obj_info = AllocMem (sizeof (t_hfs_obj_info), MEMF_PUBLIC | MEMF_CLEAR);
479 if (!obj->obj_info)
481 FreeMem (obj, sizeof (CDROM_OBJ));
482 return NULL;
485 obj->global = global;
487 return obj;
490 CDROM_OBJ *HFS_Open_Top_Level_Directory(VOLUME *p_volume) {
491 struct CDVDBase *global = p_volume->global;
492 CDROM_OBJ *obj = HFS_Alloc_Obj(global);
494 if (!obj)
495 return NULL;
497 obj->directory_f = TRUE;
498 obj->volume = p_volume;
500 OBJ(obj,parent_id) = 1;
501 StrCpy (OBJ(obj,name), ":");
502 OBJ(obj,cat_rec).d.DirID = 2;
504 return obj;
507 CDROM_OBJ *HFS_Open_Object(VOLUME *p_volume, char *p_name, t_ulong p_parent) {
508 t_leaf_record_pos leaf;
509 struct CDVDBase *global = p_volume->global;
510 CDROM_OBJ *obj;
511 char name[50];
512 char type;
513 t_bool data_fork = FALSE;
515 if (!HFS_Find_Leaf_Record(p_volume, &leaf, p_parent))
516 return NULL;
518 for (;;)
520 type = leaf.cat_rec.d.type;
521 if (type == 1 || type == 2)
523 if (leaf.leaf_rec.parent_id != p_parent)
525 global->iso_errno = ISOERR_NOT_FOUND;
526 return NULL;
529 CopyMem(leaf.leaf_rec.name, name, leaf.leaf_rec.name_length);
530 name[leaf.leaf_rec.name_length] = 0;
532 if (global->g_convert_hfs_filenames)
533 Convert_Mac_Characters (name, leaf.leaf_rec.name_length);
534 if (global->g_convert_hfs_spaces)
535 Convert_HFS_Spaces (name, leaf.leaf_rec.name_length);
537 if (type == 1)
539 if (Stricmp ((UBYTE *) p_name, (UBYTE *) name) == 0)
540 break;
542 else
544 StrCat (name, global->g_data_fork_extension);
545 if (Stricmp ((UBYTE *) p_name, (UBYTE *) name) == 0)
547 data_fork = TRUE;
548 break;
550 name[leaf.leaf_rec.name_length] = 0;
551 StrCat (name, global->g_resource_fork_extension);
552 if (Stricmp ((UBYTE *) p_name, (UBYTE *) name) == 0)
554 data_fork = FALSE;
555 break;
559 if (!HFS_Find_Next_Leaf(p_volume, &leaf))
560 return NULL;
563 obj = HFS_Alloc_Obj(global);
564 obj->directory_f = (type == 1);
565 obj->volume = p_volume;
567 OBJ(obj,data_fork) = data_fork;
568 OBJ(obj,parent_id) = p_parent;
569 StrCpy (OBJ(obj,name), name);
570 CopyMem(&leaf.cat_rec, &OBJ(obj,cat_rec), sizeof (t_catalog_record));
572 return obj;
575 /* Open the object with name p_name in the directory p_dir.
576 * p_name must not contain '/' or ':' characters.
579 CDROM_OBJ *HFS_Open_Obj_In_Directory(CDROM_OBJ *p_dir, char *p_name) {
580 return HFS_Open_Object(p_dir->volume, p_name, OBJ(p_dir,cat_rec).d.DirID);
583 CDROM_OBJ *HFS_Find_Parent(CDROM_OBJ *p_obj) {
584 struct CDVDBase *global = p_obj->global;
585 t_leaf_record_pos leaf;
587 if (OBJ(p_obj,parent_id) == 2)
588 return HFS_Open_Top_Level_Directory(p_obj->volume);
590 if (!HFS_Find_Leaf_Record(p_obj->volume, &leaf, OBJ(p_obj,parent_id)))
591 return NULL;
593 for (;;)
595 if (leaf.leaf_rec.parent_id != OBJ(p_obj,parent_id))
597 global->iso_errno = ISOERR_INTERNAL;
598 return NULL;
600 if (leaf.cat_rec.d.type == 3)
602 char buf[50];
603 CopyMem(leaf.cat_rec.dt.CName, buf, leaf.cat_rec.dt.CNameLen);
604 buf[leaf.cat_rec.dt.CNameLen] = 0;
605 if (global->g_convert_hfs_filenames)
606 Convert_Mac_Characters (buf, leaf.cat_rec.dt.CNameLen);
607 if (global->g_convert_hfs_spaces)
608 Convert_HFS_Spaces (buf, leaf.cat_rec.dt.CNameLen);
609 return HFS_Open_Object(p_obj->volume, buf, leaf.cat_rec.dt.ParID);
611 if (!HFS_Find_Next_Leaf(p_obj->volume, &leaf))
612 return NULL;
616 void HFS_Close_Obj(CDROM_OBJ *p_obj)
618 FreeMem (p_obj->obj_info, sizeof (t_hfs_obj_info));
619 FreeMem (p_obj, sizeof (CDROM_OBJ));
622 int HFS_Read_From_File(CDROM_OBJ *p_file, char *p_buffer, int p_buffer_length)
624 struct CDVDBase *global = p_file->global;
625 uint32_t block;
626 int remain_block, remain_file, remain;
627 int len;
628 CDROM *cd;
629 int pos;
630 int buf_pos = 0;
631 int todo;
632 t_bool data_fork = OBJ(p_file,data_fork);
633 t_ulong first_block;
634 t_ulong data_length = (data_fork ? OBJ(p_file,cat_rec).f.LgLen :
635 OBJ(p_file,cat_rec).f.RLgLen);
637 if (p_file->pos == data_length)
639 /* at end of file: */
640 return 0;
643 cd = p_file->volume->cd;
644 first_block = AB_to_Block
646 p_file->volume,
647 data_fork ?
648 OBJ(p_file,cat_rec).f.ExtRec[0].StABN :
649 OBJ(p_file,cat_rec).f.RExtRec[0].StABN
651 block = first_block + (p_file->pos >> 9);
652 todo = p_buffer_length;
654 while (todo)
656 t_uchar *data;
658 if (0 == Read_Chunk(cd, block >> 2))
660 global->iso_errno = ISOERR_SCSI_ERROR;
661 return -1;
664 data = cd->buffer + ((block & 3) << 9);
667 * this is offset within first block
669 pos = p_file->pos & 511;
672 * depending on logical block location, we will have up to 32kB of data here.
673 * we always read in 32768bytes chunks, so the first of 16 sectors in group yields largest amount
675 remain_block = (SCSI_BUFSIZE << 4) - ((block << 9) & ((SCSI_BUFSIZE << 4) - 1)) - pos;
678 * how much data left in a file do we have?
680 remain_file = data_length - p_file->pos;
683 * and how much can we read (file vs block)
685 remain = (remain_block < remain_file) ? remain_block : remain_file;
688 * last: how much the *user* wants to read?
690 len = (todo < remain) ? todo : remain;
693 * copy memory block
695 CopyMem ((APTR) (data + pos), (APTR) (p_buffer + buf_pos), len);
698 * update position in user buffer
699 * and file offset
700 * reduce amount of bytes to be read
702 buf_pos += len;
703 p_file->pos += len;
704 todo -= len;
707 * fin?
709 if (p_file->pos >= data_length)
710 break;
713 * here's the trick:
714 * - HFS block size is 512bytes (so we have up to 64 such blocks in a chunk)
715 * - block + 64 moves us to next chunk, while
716 * - &~63 puts us at the beginning of it.
718 block = (block + 64) &~ 63 ;
721 return buf_pos;
724 t_bool HFS_Cdrom_Info(CDROM_OBJ *p_obj, CDROM_INFO *p_info) {
725 p_info->symlink_f = 0;
726 p_info->directory_f = p_obj->directory_f;
727 p_info->name_length = StrLen (OBJ(p_obj,name));
728 CopyMem(OBJ(p_obj,name), p_info->name, p_info->name_length);
729 if (p_info->directory_f)
731 p_info->file_length = 0;
732 p_info->date = OBJ(p_obj,cat_rec).d.CrDat - TIME_DIFF;
734 else
736 if (OBJ(p_obj,data_fork))
737 p_info->file_length = OBJ(p_obj,cat_rec).f.LgLen;
738 else
739 p_info->file_length = OBJ(p_obj,cat_rec).f.RLgLen;
740 p_info->date = OBJ(p_obj,cat_rec).f.CrDat - TIME_DIFF;
743 return TRUE;
746 /* The 'offset' is a long integer coded like this:
748 * Bit: | 31 ... 8 | 7 6 | 5 4 3 2 1 0
749 * | | |
750 * Contents: | Node number | Fork | Record number
752 * The "Fork" value is encoded as follows:
754 * 0 - data fork
755 * 1 - resource fork
756 * 2 - directory
757 * 3 - illegal
760 t_bool HFS_Examine_Next
761 (CDROM_OBJ *p_obj, CDROM_INFO *p_info, uint32_t *p_offset)
763 struct CDVDBase *global = p_obj->global;
764 t_leaf_record_pos leaf;
765 short fork = 3;
767 while (fork == 3)
769 if (*p_offset == 0)
771 if (
772 !HFS_Find_Leaf_Record
773 (p_obj->volume, &leaf, OBJ(p_obj,cat_rec).d.DirID)
775 return FALSE;
777 else
779 leaf.node = *p_offset >> 8;
780 leaf.record = *p_offset & 63;
781 fork = (*p_offset & 0xC0) >> 6;
783 if (fork == 0)
785 if (!HFS_Find_This_Leaf(p_obj->volume, &leaf))
786 return FALSE;
788 else
790 if (!HFS_Find_Next_Leaf(p_obj->volume, &leaf))
791 return FALSE;
792 if (leaf.leaf_rec.parent_id != OBJ(p_obj,cat_rec).d.DirID)
793 return FALSE;
796 if (leaf.cat_rec.d.type == 1)
797 fork = 2;
798 else if (leaf.cat_rec.d.type != 2)
799 fork = 3;
800 else if (fork != 0 && leaf.cat_rec.f.LgLen > 0)
801 fork = 0;
802 else if (leaf.cat_rec.f.RLgLen > 0)
803 fork = 1;
804 else
805 fork = 3;
807 *p_offset = ((leaf.node << 8) + (fork << 6) + leaf.record);
811 p_info->symlink_f = 0;
812 p_info->directory_f = (leaf.cat_rec.d.type == 1);
813 p_info->name_length = leaf.leaf_rec.name_length;
814 CopyMem(leaf.leaf_rec.name, p_info->name, leaf.leaf_rec.name_length);
815 if (global->g_convert_hfs_filenames)
816 Convert_Mac_Characters (p_info->name, p_info->name_length);
817 if (global->g_convert_hfs_spaces)
818 Convert_HFS_Spaces (p_info->name, p_info->name_length);
819 if (p_info->directory_f)
821 p_info->file_length = 0;
822 p_info->date = leaf.cat_rec.d.CrDat - TIME_DIFF;
824 else
826 if (fork == 0)
828 CopyMem
830 global->g_data_fork_extension,
831 p_info->name + p_info->name_length,
832 StrLen (global->g_data_fork_extension)
834 p_info->name_length += StrLen (global->g_data_fork_extension);
835 p_info->file_length = leaf.cat_rec.f.LgLen;
837 else
839 CopyMem
841 global->g_resource_fork_extension,
842 p_info->name + p_info->name_length,
843 StrLen (global->g_resource_fork_extension)
845 p_info->name_length += StrLen (global->g_resource_fork_extension);
846 p_info->file_length = leaf.cat_rec.f.RLgLen;
848 p_info->date = leaf.cat_rec.f.CrDat - TIME_DIFF;
850 p_info->suppl_info = NULL;
852 return TRUE;
855 void *HFS_Clone_Obj_Info(void *p_info) {
856 t_hfs_obj_info *info = (t_hfs_obj_info *) p_info;
857 t_hfs_obj_info *new;
859 new = AllocMem (sizeof (t_hfs_obj_info), MEMF_PUBLIC);
860 if (!new)
861 return NULL;
863 CopyMem(info, new, sizeof (t_hfs_obj_info));
865 return new;
868 t_bool HFS_Is_Top_Level_Obj (CDROM_OBJ *p_obj)
870 return OBJ(p_obj,parent_id) == 1;
873 t_bool HFS_Same_Objects (CDROM_OBJ *p_obj1, CDROM_OBJ *p_obj2)
875 if (OBJ(p_obj1,cat_rec).d.type != OBJ(p_obj2,cat_rec).d.type)
876 return FALSE;
878 if (OBJ(p_obj1,cat_rec).d.type == 1)
879 return OBJ(p_obj1,cat_rec).d.DirID == OBJ(p_obj2,cat_rec).d.DirID;
880 else
881 return OBJ(p_obj1,cat_rec).f.FlNum == OBJ(p_obj2,cat_rec).f.FlNum;
884 t_ulong HFS_Creation_Date(VOLUME *p_volume)
886 return VOL(p_volume,mdb).CrDate - TIME_DIFF;
889 /* Return volume size in 2048 byte blocks:
892 t_ulong HFS_Volume_Size (VOLUME *p_volume)
894 return (VOL(p_volume,mdb).NmAlBlks * (VOL(p_volume,mdb).AlBlkSiz >> 9));
897 t_ulong HFS_Block_Size (VOLUME *p_volume)
899 return 512;
902 void HFS_Volume_Id(VOLUME *p_volume, char *p_buf, int p_buf_length) {
903 struct CDVDBase *global = p_volume->global;
904 int len = p_buf_length - 1;
906 if (len > VOL(p_volume,mdb).VolNameLen)
907 len = VOL(p_volume,mdb).VolNameLen;
909 CopyMem(VOL(p_volume,mdb).VolName, p_buf, len);
910 p_buf[len] = 0;
912 if (global->g_convert_hfs_filenames)
913 Convert_Mac_Characters (p_buf, len);
914 if (global->g_convert_hfs_spaces)
915 Convert_HFS_Spaces (p_buf, len);
918 t_ulong HFS_Location (CDROM_OBJ *p_obj)
920 if (p_obj->directory_f) {
921 if (Is_Top_Level_Object (p_obj))
922 return FALSE;
923 return OBJ(p_obj,cat_rec).d.DirID;
924 } else
925 return OBJ(p_obj,cat_rec).f.FlNum;
928 t_ulong HFS_File_Length (CDROM_OBJ *p_obj)
930 return (OBJ(p_obj,data_fork) ?
931 OBJ(p_obj,cat_rec).f.LgLen :
932 OBJ(p_obj,cat_rec).f.RLgLen);
935 static t_handler const g_hfs_handler = {
936 HFS_Close_Vol_Info,
937 HFS_Open_Top_Level_Directory,
938 HFS_Open_Obj_In_Directory,
939 HFS_Find_Parent,
940 HFS_Close_Obj,
941 HFS_Read_From_File,
942 HFS_Cdrom_Info,
943 HFS_Examine_Next,
944 HFS_Clone_Obj_Info,
945 HFS_Is_Top_Level_Obj,
946 HFS_Same_Objects,
947 HFS_Creation_Date,
948 HFS_Volume_Size,
949 HFS_Volume_Id,
950 HFS_Location,
951 HFS_File_Length,
952 HFS_Block_Size