home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / cdrom / amicdrom / src / hfs.c < prev    next >
C/C++ Source or Header  |  1977-12-31  |  22KB  |  865 lines

  1. /* hfs.c:
  2.  *
  3.  * Support for the Macintosh HFS filing system.
  4.  *
  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:
  12.  * 
  13.  * 03-Nov-94   fmu   - Fixed bug in HFS_Read_From_File().
  14.  *                   - Truncate file names to 30 characters.
  15.  * 15-Apr-93   fmu   - Improved conversion routines.
  16.  *                   - Fixed bug in HFS_Find_Parent().
  17.  *                   - Fixed bug in date conversion routine.
  18.  * 02-Jan-93   fmu   Improved search method for master directory block.
  19.  * 03-Dec-93   fmu   - Fixed bug in HFS_Find_Leaf_Record().
  20.  *                   - Convert ':' and '/' characters.
  21.  *                   - Also convert volume names.
  22.  * 29-Nov-93   fmu   New function HFS_Block_Size().
  23.  * 15-Nov-93   fmu   Corrected some typing mistakes in the HFS->ISO conversion
  24.  *                   table.
  25.  */
  26.  
  27. #include <stdlib.h>
  28. #include <string.h>
  29.  
  30. #include <clib/exec_protos.h>
  31. #include <clib/utility_protos.h>
  32.  
  33. #ifdef LATTICE
  34. #include <pragmas/exec_pragmas.h>
  35. #include <pragmas/utility_pragmas.h>
  36.  
  37. extern struct ExecBase *SysBase;
  38. extern struct Library *UtilityBase;
  39. #endif
  40.  
  41. #include "cdrom.h"
  42. #include "generic.h"
  43. #include "hfs.h"
  44. #include "params.h"
  45.  
  46. char g_data_fork_extension[17] = { 0, };
  47. char g_resource_fork_extension[17] = { 0, };
  48. t_bool g_convert_hfs_filenames = FALSE;
  49. t_bool g_convert_hfs_spaces = FALSE;
  50.  
  51. typedef struct hfs_vol_info {
  52.   t_mdb            mdb;
  53.   int            start_block;
  54.   t_ulong        root_node;
  55. } t_hfs_vol_info;
  56.  
  57. typedef struct hfs_obj_info {
  58.   t_bool        data_fork;
  59.   t_ulong        parent_id;
  60.   char            name[50];
  61.   t_catalog_record    cat_rec;
  62. } t_hfs_obj_info;
  63.  
  64. typedef struct leaf_record_pos {
  65.   t_ulong        node;
  66.   t_ushort        record;
  67.   t_node_descr        node_descr;
  68.   t_catalog_record    cat_rec;
  69.   t_leaf_record        leaf_rec;
  70.   char            pad[32]; /* space for name from t_leaf_record */
  71. } t_leaf_record_pos;
  72.  
  73. #define VOL(vol,tag) (((t_hfs_vol_info *)(vol->vol_info))->tag)
  74. #define OBJ(obj,tag) (((t_hfs_obj_info *)(obj->obj_info))->tag)
  75.  
  76. /* Number of seconds betweem 01-Jan-1904 and 01-Jan-1978: */
  77.  
  78. #define TIME_DIFF ((74 * 365 + 19) * 24 * 60 * 60)
  79.  
  80. static char g_conv_table[128] = {
  81.   'Ä', 'Å', 'Ç', 'É', 'Ñ', 'Ö', 'Ü',
  82.   'á', 'à', 'â', 'ä', 'ã', 'å', 'ç',
  83.   'é', 'è', 'ê', 'ë', 'í', 'ì', 'î',
  84.   'ï', 'ñ', 'ó', 'ò', 'ô', 'ö', 'õ',
  85.   'ú', 'ù', 'û', 'ü', '¿', '°', '¢',
  86.   '£', '§', '·', '¶', 'ß', '®', '©',
  87.   '¿', '´', '¨', '¿', 'Æ', 'Ø', '¿',
  88.   '±', '¿', '¿', '¥', 'µ', 'ð', '¿',
  89.   '¿', '¿', '¿', 'ª', 'º', '¿', 'æ',
  90.   'ø', '¿', '¡', '¬', '¿', '¿', '¿',
  91.   '¿', '«', '»', '¿', ' ', 'À', 'Ã',
  92.   'Õ', '¿', '¿', '­', '-', '\"', '\"',
  93.   '`', '´', '÷', '¿', 'ÿ', '¿', '/',
  94.   '¤', '¿', '¿', '¿', '¿', '¿', '.',
  95.   '¸', '¿', '¿', 'Â', 'Ê', 'Á', 'Ë',
  96.   'È', 'Í', 'Î', 'Ï', 'Ì', 'Ó', 'Ô',
  97.   '¿', 'Ò', 'Ú', 'Û', 'Ù', '¿', '^',
  98.   '~', '­', '¿', '·', '°', '¿', '\"',
  99.   '.', '¿'
  100. };
  101.  
  102. void Convert_Mac_Characters (char *p_buf, int p_buf_len)
  103. {
  104.   unsigned char *cp = (unsigned char *) p_buf;
  105.   int i;
  106.   
  107.   for (i=0; i<p_buf_len; i++, cp++)
  108.     if (*cp >= 128)
  109.       *cp = g_conv_table[*cp-128];
  110.     else if (*cp == ':')
  111.       *cp = '.';
  112.     else if (*cp == '/')
  113.       *cp = '-';
  114.     else if (*cp < 32)
  115.       *cp = 0xBF /* ¿ */;
  116. }
  117.  
  118. void Convert_HFS_Spaces (char *p_buf, int p_buf_len)
  119. {
  120.   unsigned char *cp = (unsigned char *) p_buf;
  121.   int i;
  122.   
  123.   for (i=0; i<p_buf_len; i++, cp++)
  124.     if (*cp == ' ' || *cp == 0xA0)
  125.       *cp = '_';
  126. }
  127.  
  128. t_uchar *Read_Block (CDROM *p_cdrom, t_ulong p_block)
  129. {
  130.   if (!Read_Sector (p_cdrom, p_block >> 2))
  131.     return NULL;
  132.   
  133.   return p_cdrom->buffer + ((p_block & 3) << 9);
  134. }
  135.  
  136. t_uchar *Read_Contiguous_Blocks (CDROM *p_cdrom, t_ulong p_block,
  137.                  t_ulong p_last_block)
  138. {
  139.   if (!Read_Contiguous_Sectors (p_cdrom, p_block >> 2, p_last_block >> 2))
  140.     return NULL;
  141.  
  142.   return p_cdrom->buffer + ((p_block & 3) << 9);
  143. }
  144.  
  145. /* Convert allocation block number into 512 byte block number.
  146.  */
  147.  
  148. t_ulong AB_to_Block (VOLUME *p_volume, t_ulong p_alloc_block)
  149. {
  150.   return p_alloc_block * (VOL(p_volume,mdb).AlBlkSiz >> 9) +
  151.        VOL(p_volume,mdb).AlBlSt + VOL(p_volume,start_block);
  152. }
  153.  
  154. int HFS_Find_Master_Directory_Block (CDROM *p_cd, t_mdb *p_mdb)
  155. {
  156.   t_uchar *block;
  157.   typedef struct partition_map {
  158.     t_ushort    pmSig;
  159.     t_ushort    reSigPad;
  160.     t_ulong    pmMapBlkCnt;
  161.     t_ulong    pmPyPartStart;
  162.     t_ulong    pmPartBlkCnt;
  163.     char    pmPartName[32];
  164.     char    pmPartType[32];
  165.   } t_partition_map;
  166.   int i, entries;
  167.   int result;
  168.     
  169.   block = Read_Block (p_cd, 1);
  170.   if (!block || block[0] != 0x50 || block[1] != 0x4D)
  171.     return -1;
  172.  
  173.   entries = ((t_partition_map *) block)->pmMapBlkCnt;
  174.   for (i=0; i<entries; i++) {
  175.     block = Read_Block (p_cd, i+1);
  176.     if (!block || block[0] != 0x50 || block[1] != 0x4D)
  177.       return -1;
  178.     if (memcmp (((t_partition_map *) block)->pmPartType,
  179.             "Apple_HFS", 9) == 0) {
  180.       result = ((t_partition_map *) block)->pmPyPartStart + 2;
  181.       block = Read_Block (p_cd, result);
  182.       if (!block || block[0] != 0x42 || block[1] != 0x44)
  183.         return -1;
  184.       else {
  185.         memcpy (p_mdb, block, sizeof (*p_mdb));
  186.         return result;
  187.       }
  188.     }
  189.   }
  190.  
  191.   return -1;
  192. }
  193.  
  194. t_bool Uses_HFS_Protocol (CDROM *p_cd, int *p_skip)
  195. {
  196.   t_mdb mdb;
  197.   int blk;
  198.  
  199.   blk = HFS_Find_Master_Directory_Block (p_cd, &mdb);
  200.   if (blk == -1)
  201.     return FALSE;
  202.   
  203.   *p_skip = blk - 2; /* *p_skip holds the start block of the volume */
  204.   return TRUE;
  205. }
  206.  
  207. t_bool HFS_Get_Header_Node (CDROM *p_cd, t_ulong p_mdb_pos,
  208.                 t_mdb *p_mdb, t_hdr_node *p_hdr_node)
  209. {
  210.   t_ulong pos = (p_mdb_pos - 2 + p_mdb->AlBlSt +
  211.            p_mdb->CTExtRec[0].StABN * (p_mdb->AlBlkSiz >> 9));
  212.   t_hdr_node *hdr;
  213.   
  214.   hdr = (t_hdr_node *) Read_Block (p_cd, pos);
  215.   if (!hdr)
  216.     return FALSE;
  217.   
  218.   memcpy (p_hdr_node, hdr, sizeof (t_hdr_node));
  219.   return TRUE;
  220. }
  221.  
  222. t_node_descr *HFS_Get_Node (CDROM *p_cd, t_ulong p_mdb_pos, t_mdb *p_mdb,
  223.                 t_ulong p_node)
  224. {
  225.   t_ulong first_node;
  226.   t_ulong pos;
  227.   t_ulong max = 0;
  228.   t_ulong sub = 0;
  229.   int i;
  230.  
  231.   for (i=0; i<3; i++) {
  232.     max += p_mdb->CTExtRec[i].NumABlks * (p_mdb->AlBlkSiz >> 9);
  233.     if (p_node < max)
  234.       break;
  235.     sub = max;
  236.   }
  237.   
  238.   if (i==3)
  239.     return NULL;
  240.  
  241.   first_node = (p_mdb_pos - 2 + p_mdb->AlBlSt +
  242.           p_mdb->CTExtRec[i].StABN * (p_mdb->AlBlkSiz >> 9));
  243.  
  244.   pos = first_node + (p_node - sub);
  245.  
  246.   return (t_node_descr *) Read_Block (p_cd, pos);
  247. }
  248.  
  249. t_node_descr *HFS_Node (VOLUME *p_volume, t_ulong p_node)
  250. {
  251.   return HFS_Get_Node (p_volume->cd, VOL(p_volume,start_block) + 2,
  252.                  &VOL(p_volume,mdb), p_node);
  253. }
  254.  
  255. void HFS_Load_Catalog_Record (t_catalog_record *p_cat_rec,
  256.                   char *p_node, int p_record)
  257. {
  258.   short *sp = (short *) p_node;
  259.   int len;
  260.   int start;
  261.  
  262.   start = sp[255-p_record];
  263.   start += p_node[start] + 1;
  264.   if (start & 1)
  265.     start++;
  266.  
  267.   len = sp[254-p_record] - start;
  268.   memcpy (p_cat_rec, p_node + start, len);
  269. }
  270.  
  271.  
  272. t_bool HFS_Find_Next_Leaf (VOLUME *p_volume, t_leaf_record_pos *p_leaf)
  273. {
  274.   t_node_descr *node;
  275.   short *sp;
  276.   int pos;
  277.  
  278.   node = HFS_Node (p_volume, p_leaf->node);
  279.   if (!node)
  280.     return FALSE;
  281.  
  282.   p_leaf->record++;
  283.   if (p_leaf->record == node->NRecs) {
  284.     if (node->FLink) {
  285.       node = HFS_Node (p_volume, p_leaf->node = node->FLink);
  286.       if (!node)
  287.         return FALSE;
  288.       p_leaf->record = 0;
  289.     } else
  290.       return FALSE;
  291.   }
  292.  
  293.   sp = (short *) node;
  294.   pos = sp[255-p_leaf->record];
  295.   memcpy (&p_leaf->node_descr, node, sizeof (t_node_descr));
  296.   memcpy (&p_leaf->leaf_rec, (char *) node + pos, ((char *) node)[pos] + 1);
  297.   HFS_Load_Catalog_Record (&p_leaf->cat_rec, (char *) node, p_leaf->record);
  298.  
  299.   if (p_leaf->leaf_rec.name_length > 30) {
  300.     p_leaf->leaf_rec.name_length = 30;
  301.     p_leaf->leaf_rec.name[30] = 0;
  302.   }
  303.  
  304.   return TRUE;
  305. }
  306.  
  307. /* Find leaf record p_leaf->record in node p_leaf->node.
  308.  * Store the result in *p_leaf.
  309.  */
  310.  
  311. t_bool HFS_Find_This_Leaf (VOLUME *p_volume, t_leaf_record_pos *p_leaf)
  312. {
  313.   t_node_descr *node;
  314.   short *sp;
  315.   int pos;
  316.  
  317.   node = HFS_Node (p_volume, p_leaf->node);
  318.   if (!node)
  319.     return FALSE;
  320.  
  321.   sp = (short *) node;
  322.   pos = sp[255-p_leaf->record];
  323.   memcpy (&p_leaf->node_descr, node, sizeof (t_node_descr));
  324.   memcpy (&p_leaf->leaf_rec, (char *) node + pos, ((char *) node)[pos] + 1);
  325.   HFS_Load_Catalog_Record (&p_leaf->cat_rec, (char *) node, p_leaf->record);
  326.  
  327.   return TRUE;
  328. }
  329.  
  330. /* Find the first leaf record with parent ID p_parent_id.
  331.  * If the leaf node is found, TRUE is returned and *p_cat_rec will be
  332.  * loaded with the catalog record. Otherwise, FALSE is returned.
  333.  */
  334.  
  335. t_bool HFS_Find_Leaf_Record (VOLUME *p_volume, t_leaf_record_pos *p_leaf,
  336.                  t_ulong p_parent_id)
  337. {
  338.   t_node_descr *node;
  339.   short *sp;
  340.   int i;
  341.   t_ulong this_node = VOL(p_volume,root_node);
  342.   t_ulong next_node;
  343.  
  344.   node = HFS_Node (p_volume, VOL(p_volume,root_node));
  345.   if (!node) {
  346.     iso_errno = ISOERR_SCSI_ERROR;
  347.     return FALSE;
  348.   }
  349.  
  350.   for (;;) {
  351.     if (node->Type == 0) { /* index node */
  352.       sp = (short *) node;
  353.       next_node = -1;
  354.       for (i=0; i<node->NRecs; i++) {
  355.         t_idx_record *idx = (t_idx_record *) ((char *) node + sp[255-i]);
  356.     if (idx->length != 0) {
  357.           if (idx->parent_id >= p_parent_id)
  358.         break;
  359.       next_node = idx->pointer;
  360.     }
  361.       }
  362.     } else if (node->Type == 0xff) { /* leaf node */
  363.       break;
  364.     } else {
  365.       iso_errno = ISOERR_INTERNAL;
  366.       return FALSE;
  367.     }
  368.  
  369.     if (next_node == -1) {
  370.       iso_errno = ISOERR_INTERNAL;
  371.       return FALSE;
  372.     }
  373.  
  374.     node = HFS_Node (p_volume, next_node);
  375.     if (!node) {
  376.       iso_errno = ISOERR_SCSI_ERROR;
  377.       return FALSE;
  378.     }
  379.     this_node = next_node;
  380.   }
  381.  
  382.   p_leaf->node = this_node;
  383.   p_leaf->record = 0;
  384.   memcpy (&p_leaf->node_descr, node, sizeof (t_node_descr));
  385.   memcpy (&p_leaf->leaf_rec, (char *) node + 0xe, ((char *) node)[0xe] + 1);
  386.   HFS_Load_Catalog_Record (&p_leaf->cat_rec, (char *) node, 0);
  387.  
  388.   /* walk forwards until the same key is found: */
  389.   for (;;) {
  390.     if (p_leaf->leaf_rec.parent_id == p_parent_id)
  391.       break;
  392.     if (p_leaf->leaf_rec.parent_id > p_parent_id) {
  393.       iso_errno = ISOERR_INTERNAL;
  394.       return FALSE;
  395.     }
  396.  
  397.     if (!HFS_Find_Next_Leaf (p_volume, p_leaf)) {
  398.       iso_errno = ISOERR_INTERNAL;
  399.       return FALSE;
  400.     }
  401.  
  402.   }
  403.   
  404.   if (p_leaf->leaf_rec.name_length > 30) {
  405.     p_leaf->leaf_rec.name_length = 30;
  406.     p_leaf->leaf_rec.name[30] = 0;
  407.   }
  408.   
  409.   return TRUE;
  410. }
  411.  
  412. t_bool HFS_Init_Vol_Info (VOLUME *p_volume, int p_start_block)
  413. {
  414.   extern t_handler g_hfs_handler;
  415.   t_uchar *block;
  416.   t_hdr_node hdr;
  417.  
  418.   /* Here is a good place to check whether the values of the variables
  419.    * g_data_fork_extension and g_resource_fork_extension are OK.
  420.    */
  421.  
  422.   if (g_data_fork_extension[0] == 0 &&
  423.       g_resource_fork_extension[0] == 0)
  424.     strcpy (g_resource_fork_extension, ".rsrc");
  425.  
  426.   /*
  427.    * Volume info initialization:
  428.    */
  429.  
  430.   p_volume->handler = &g_hfs_handler;
  431.   
  432.   p_volume->vol_info = AllocMem (sizeof (t_hfs_vol_info), MEMF_PUBLIC);
  433.   if (!p_volume->vol_info) {
  434.     iso_errno = ISOERR_NO_MEMORY;
  435.     return FALSE;
  436.   }
  437.   
  438.   VOL(p_volume,start_block) = p_start_block;
  439.  
  440.   if (!(block = Read_Block (p_volume->cd, p_start_block + 2))) {
  441.     iso_errno = ISOERR_SCSI_ERROR;
  442.     FreeMem (p_volume->vol_info, sizeof (t_hfs_vol_info));
  443.     return FALSE;
  444.   }
  445.  
  446.   memcpy (&VOL(p_volume,mdb), block, sizeof (t_mdb));
  447.  
  448.   if (!HFS_Get_Header_Node (p_volume->cd, p_start_block + 2,
  449.                   &VOL(p_volume,mdb), &hdr)) {
  450.     iso_errno = ISOERR_SCSI_ERROR;
  451.     FreeMem (p_volume->vol_info, sizeof (t_hfs_vol_info));
  452.     return FALSE;
  453.   }
  454.  
  455.   VOL(p_volume,root_node) = hdr.Root;
  456.  
  457.   p_volume->mixed_char_filenames = TRUE;
  458.  
  459.   return TRUE;
  460. }
  461.  
  462. void HFS_Close_Vol_Info (VOLUME *p_volume)
  463. {
  464.   FreeMem (p_volume->vol_info, sizeof (t_hfs_vol_info));
  465. }
  466.  
  467. CDROM_OBJ *HFS_Alloc_Obj (void)
  468. {
  469.   CDROM_OBJ *obj = AllocMem (sizeof (CDROM_OBJ), MEMF_PUBLIC | MEMF_CLEAR);
  470.   
  471.   if (!obj) {
  472.     iso_errno = ISOERR_NO_MEMORY;
  473.     return NULL;
  474.   }
  475.  
  476.   obj->obj_info = AllocMem (sizeof (t_hfs_obj_info), MEMF_PUBLIC | MEMF_CLEAR);
  477.   if (!obj->obj_info) {
  478.     FreeMem (obj, sizeof (CDROM_OBJ));
  479.     return NULL;
  480.   }
  481.  
  482.   return obj;
  483. }
  484.  
  485. CDROM_OBJ *HFS_Open_Top_Level_Directory (VOLUME *p_volume)
  486. {
  487.   CDROM_OBJ *obj = HFS_Alloc_Obj ();
  488.  
  489.   if (!obj)
  490.     return NULL;
  491.  
  492.   obj->directory_f = TRUE;
  493.   obj->volume = p_volume;
  494.  
  495.   OBJ(obj,parent_id) = 1;
  496.   strcpy (OBJ(obj,name), ":");
  497.   OBJ(obj,cat_rec).d.DirID = 2;
  498.  
  499.   return obj;
  500. }
  501.  
  502. CDROM_OBJ *HFS_Open_Object (VOLUME *p_volume, char *p_name, t_ulong p_parent)
  503. {
  504.   t_leaf_record_pos leaf;
  505.   CDROM_OBJ *obj;
  506.   char name[50];
  507.   char type;
  508.   t_bool data_fork;
  509.  
  510.   if (!HFS_Find_Leaf_Record (p_volume, &leaf, p_parent))
  511.     return NULL;
  512.  
  513.   for (;;) {
  514.     type = leaf.cat_rec.d.type;
  515.     if (type == 1 || type == 2) {
  516.       if (leaf.leaf_rec.parent_id != p_parent) {
  517.         iso_errno = ISOERR_NOT_FOUND;
  518.         return NULL;
  519.       }
  520.  
  521.       memcpy (name, leaf.leaf_rec.name, leaf.leaf_rec.name_length);
  522.       name[leaf.leaf_rec.name_length] = 0;
  523.  
  524.       if (g_convert_hfs_filenames)
  525.         Convert_Mac_Characters (name, leaf.leaf_rec.name_length);
  526.       if (g_convert_hfs_spaces)
  527.         Convert_HFS_Spaces (name, leaf.leaf_rec.name_length);
  528.  
  529.       if (type == 1) {
  530.         if (Stricmp ((UBYTE *) p_name, (UBYTE *) name) == 0)
  531.       break;
  532.       } else {
  533.         strcat (name, g_data_fork_extension);
  534.     if (Stricmp ((UBYTE *) p_name, (UBYTE *) name) == 0) {
  535.       data_fork = TRUE;
  536.       break;
  537.     }
  538.         name[leaf.leaf_rec.name_length] = 0;
  539.     strcat (name, g_resource_fork_extension);
  540.     if (Stricmp ((UBYTE *) p_name, (UBYTE *) name) == 0) {
  541.       data_fork = FALSE;
  542.       break;
  543.     }
  544.       }
  545.     }
  546.     if (!HFS_Find_Next_Leaf (p_volume, &leaf))
  547.       return NULL;
  548.   }
  549.  
  550.   obj = HFS_Alloc_Obj ();
  551.   obj->directory_f = (type == 1);
  552.   obj->volume = p_volume;
  553.  
  554.   OBJ(obj,data_fork) = data_fork;
  555.   OBJ(obj,parent_id) = p_parent;
  556.   strcpy (OBJ(obj,name), name);
  557.   memcpy (&OBJ(obj,cat_rec), &leaf.cat_rec, sizeof (t_catalog_record));
  558.  
  559.   return obj;
  560. }
  561.  
  562. /* Open the object with name p_name in the directory p_dir.
  563.  * p_name must not contain '/' or ':' characters.
  564.  */
  565.  
  566. CDROM_OBJ *HFS_Open_Obj_In_Directory (CDROM_OBJ *p_dir, char *p_name)
  567. {
  568.   return HFS_Open_Object (p_dir->volume, p_name, OBJ(p_dir,cat_rec).d.DirID);
  569. }
  570.  
  571. CDROM_OBJ *HFS_Find_Parent (CDROM_OBJ *p_obj)
  572. {
  573.   t_leaf_record_pos leaf;
  574.  
  575.   if (OBJ(p_obj,parent_id) == 2)
  576.     return HFS_Open_Top_Level_Directory (p_obj->volume);
  577.  
  578.   if (!HFS_Find_Leaf_Record (p_obj->volume, &leaf, OBJ(p_obj,parent_id)))
  579.     return NULL;
  580.  
  581.   for (;;) {
  582.     if (leaf.leaf_rec.parent_id != OBJ(p_obj,parent_id)) {
  583.       iso_errno = ISOERR_INTERNAL;
  584.       return NULL;
  585.     } 
  586.     if (leaf.cat_rec.d.type == 3) {
  587.       char buf[50];
  588.       memcpy (buf, leaf.cat_rec.dt.CName, leaf.cat_rec.dt.CNameLen);
  589.       buf[leaf.cat_rec.dt.CNameLen] = 0;
  590.       if (g_convert_hfs_filenames)
  591.         Convert_Mac_Characters (buf, leaf.cat_rec.dt.CNameLen);
  592.       if (g_convert_hfs_spaces)
  593.         Convert_HFS_Spaces (buf, leaf.cat_rec.dt.CNameLen);
  594.       return HFS_Open_Object (p_obj->volume, buf, leaf.cat_rec.dt.ParID);
  595.     }
  596.     if (!HFS_Find_Next_Leaf (p_obj->volume, &leaf))
  597.       return NULL;
  598.   }
  599. }
  600.  
  601. void HFS_Close_Obj (CDROM_OBJ *p_obj)
  602. {
  603.   FreeMem (p_obj->obj_info, sizeof (t_hfs_obj_info));
  604.   FreeMem (p_obj, sizeof (CDROM_OBJ));
  605. }
  606.  
  607. int HFS_Read_From_File (CDROM_OBJ *p_file, char *p_buffer, int p_buffer_length)
  608. {
  609.   unsigned long block;
  610.   int remain_block, remain_file, remain;
  611.   int len;
  612.   CDROM *cd;
  613.   int pos;
  614.   int buf_pos = 0;
  615.   int todo;
  616.   t_bool data_fork = OBJ(p_file,data_fork);
  617.   t_ulong first_block;
  618.   t_ulong last_block;
  619.   t_ulong data_length = (data_fork ? OBJ(p_file,cat_rec).f.LgLen :
  620.                OBJ(p_file,cat_rec).f.RLgLen);
  621.  
  622.   if (p_file->pos == data_length)
  623.     /* at end of file: */
  624.     return 0;
  625.  
  626.   cd = p_file->volume->cd;
  627.   first_block = AB_to_Block (p_file->volume,
  628.                    data_fork ?
  629.                    OBJ(p_file,cat_rec).f.ExtRec[0].StABN :
  630.                  OBJ(p_file,cat_rec).f.RExtRec[0].StABN);
  631.   block = first_block + (p_file->pos >> 9);
  632.   last_block = first_block + ((data_length-1) >> 9);
  633.   todo = p_buffer_length;
  634.  
  635.   while (todo) {
  636.     t_uchar *data;
  637.     
  638.     if (!(data = Read_Contiguous_Blocks (cd, block, last_block))) {
  639.       iso_errno = ISOERR_SCSI_ERROR;
  640.       return -1;
  641.     }
  642.  
  643.     remain_block = 512 - (pos = (p_file->pos & 511));
  644.     remain_file = data_length - p_file->pos;
  645.     remain = (remain_block < remain_file) ? remain_block : remain_file;
  646.     len = (todo < remain) ? todo : remain;
  647.     CopyMem ((APTR) (data + pos), (APTR) (p_buffer + buf_pos), len);
  648.     buf_pos += len;
  649.     p_file->pos += len;
  650.     todo -= len;
  651.  
  652.     if (p_file->pos >= data_length)
  653.       break;
  654.  
  655.     block++;
  656.   }
  657.  
  658.   return buf_pos;
  659. }
  660.  
  661. t_bool HFS_Cdrom_Info (CDROM_OBJ *p_obj, CDROM_INFO *p_info)
  662. {
  663.   p_info->symlink_f = 0;
  664.   p_info->directory_f = p_obj->directory_f;
  665.   p_info->name_length = strlen (OBJ(p_obj,name));
  666.   memcpy (p_info->name, OBJ(p_obj,name), p_info->name_length);
  667.   if (p_info->directory_f) {
  668.     p_info->file_length = 0;
  669.     p_info->date = OBJ(p_obj,cat_rec).d.CrDat - TIME_DIFF;
  670.   } else {
  671.     if (OBJ(p_obj,data_fork))
  672.       p_info->file_length = OBJ(p_obj,cat_rec).f.LgLen;
  673.     else
  674.       p_info->file_length = OBJ(p_obj,cat_rec).f.RLgLen;
  675.     p_info->date = OBJ(p_obj,cat_rec).f.CrDat - TIME_DIFF;
  676.   }
  677.   
  678.   return TRUE;
  679. }
  680.  
  681. /*  The 'offset' is a long integer coded like this:
  682.  *
  683.  *  Bit:      |    31 ... 8  | 7   6 | 5   4   3   2   1   0
  684.  *            |              |       |
  685.  *  Contents: |  Node number |  Fork |    Record number
  686.  *
  687.  *  The "Fork" value is encoded as follows:
  688.  *
  689.  *   0 - data fork
  690.  *   1 - resource fork
  691.  *   2 - directory
  692.  *   3 - illegal
  693.  */
  694.  
  695. t_bool HFS_Examine_Next (CDROM_OBJ *p_obj, CDROM_INFO *p_info,
  696.              unsigned long *p_offset)
  697. {
  698.   t_leaf_record_pos leaf;
  699.   short fork = 3;
  700.  
  701.   while (fork == 3) {
  702.     if (*p_offset == 0) {
  703.       if (!HFS_Find_Leaf_Record (p_obj->volume, &leaf, OBJ(p_obj,cat_rec).d.DirID))
  704.         return FALSE;
  705.     } else {
  706.       leaf.node = *p_offset >> 8;
  707.       leaf.record = *p_offset & 63;
  708.       fork = (*p_offset & 0xC0) >> 6;
  709.  
  710.       if (fork == 0) {
  711.         if (!HFS_Find_This_Leaf (p_obj->volume, &leaf))
  712.       return FALSE;
  713.       } else {
  714.         if (!HFS_Find_Next_Leaf (p_obj->volume, &leaf))
  715.           return FALSE;
  716.         if (leaf.leaf_rec.parent_id != OBJ(p_obj,cat_rec).d.DirID)
  717.           return FALSE;
  718.       }
  719.     }
  720.     if (leaf.cat_rec.d.type == 1)
  721.       fork = 2;
  722.     else if (leaf.cat_rec.d.type != 2)
  723.       fork = 3;
  724.     else if (fork != 0 && leaf.cat_rec.f.LgLen > 0)
  725.       fork = 0;
  726.     else if (leaf.cat_rec.f.RLgLen > 0)
  727.       fork = 1;
  728.     else
  729.       fork = 3;
  730.  
  731.     *p_offset = ((leaf.node << 8) + (fork << 6) + leaf.record);
  732.  
  733.   }
  734.  
  735.   p_info->symlink_f = 0;
  736.   p_info->directory_f = (leaf.cat_rec.d.type == 1);
  737.   p_info->name_length = leaf.leaf_rec.name_length;
  738.   memcpy (p_info->name, leaf.leaf_rec.name, leaf.leaf_rec.name_length);
  739.   if (g_convert_hfs_filenames)
  740.     Convert_Mac_Characters (p_info->name, p_info->name_length);
  741.   if (g_convert_hfs_spaces)
  742.     Convert_HFS_Spaces (p_info->name, p_info->name_length);
  743.   if (p_info->directory_f) {
  744.     p_info->file_length = 0;
  745.     p_info->date = leaf.cat_rec.d.CrDat - TIME_DIFF;
  746.   } else {
  747.     if (fork == 0) {
  748.       memcpy (p_info->name + p_info->name_length, g_data_fork_extension,
  749.                 strlen (g_data_fork_extension));
  750.       p_info->name_length += strlen (g_data_fork_extension);
  751.       p_info->file_length = leaf.cat_rec.f.LgLen;
  752.     } else {
  753.       memcpy (p_info->name + p_info->name_length, g_resource_fork_extension,
  754.                 strlen (g_resource_fork_extension));
  755.       p_info->name_length += strlen (g_resource_fork_extension);
  756.       p_info->file_length = leaf.cat_rec.f.RLgLen;
  757.     }
  758.     p_info->date = leaf.cat_rec.f.CrDat - TIME_DIFF;
  759.   }
  760.   p_info->suppl_info = NULL;
  761.  
  762.   return TRUE;
  763. }
  764.  
  765. void *HFS_Clone_Obj_Info (void *p_info)
  766. {
  767.   t_hfs_obj_info *info = (t_hfs_obj_info *) p_info;
  768.   t_hfs_obj_info *new;
  769.   
  770.   new = AllocMem (sizeof (t_hfs_obj_info), MEMF_PUBLIC);
  771.   if (!new)
  772.     return NULL;
  773.  
  774.   memcpy (new, info, sizeof (t_hfs_obj_info));
  775.   
  776.   return new;
  777. }
  778.  
  779. t_bool HFS_Is_Top_Level_Obj (CDROM_OBJ *p_obj)
  780. {
  781.   return OBJ(p_obj,parent_id) == 1;
  782. }
  783.  
  784. t_bool HFS_Same_Objects (CDROM_OBJ *p_obj1, CDROM_OBJ *p_obj2)
  785. {
  786.   if (OBJ(p_obj1,cat_rec).d.type != OBJ(p_obj2,cat_rec).d.type)
  787.     return FALSE;
  788.  
  789.   if (OBJ(p_obj1,cat_rec).d.type == 1)
  790.     return OBJ(p_obj1,cat_rec).d.DirID == OBJ(p_obj2,cat_rec).d.DirID;
  791.   else
  792.     return OBJ(p_obj1,cat_rec).f.FlNum == OBJ(p_obj2,cat_rec).f.FlNum;
  793. }
  794.  
  795. t_ulong HFS_Creation_Date (VOLUME *p_volume)
  796. {
  797.   return VOL(p_volume,mdb).CrDate - TIME_DIFF;
  798. }
  799.  
  800. /* Return volume size in 2048 byte blocks:
  801.  */
  802.  
  803. t_ulong HFS_Volume_Size (VOLUME *p_volume)
  804. {
  805.   return (VOL(p_volume,mdb).NmAlBlks * (VOL(p_volume,mdb).AlBlkSiz >> 9));
  806. }
  807.  
  808. t_ulong HFS_Block_Size (VOLUME *p_volume)
  809. {
  810.   return 512;
  811. }
  812.  
  813. void HFS_Volume_Id (VOLUME *p_volume, char *p_buf, int p_buf_length)
  814. {
  815.   int len = p_buf_length - 1;
  816.  
  817.   if (len > VOL(p_volume,mdb).VolNameLen)
  818.     len = VOL(p_volume,mdb).VolNameLen;
  819.   
  820.   memcpy (p_buf, VOL(p_volume,mdb).VolName, len);
  821.   p_buf[len] = 0;
  822.  
  823.   if (g_convert_hfs_filenames)
  824.     Convert_Mac_Characters (p_buf, len);
  825.   if (g_convert_hfs_spaces)
  826.     Convert_HFS_Spaces (p_buf, len);
  827. }
  828.  
  829. t_ulong HFS_Location (CDROM_OBJ *p_obj)
  830. {
  831.  if (p_obj->directory_f) {
  832.    if (Is_Top_Level_Object (p_obj))
  833.      return FALSE;
  834.    return OBJ(p_obj,cat_rec).d.DirID;
  835.  } else
  836.    return OBJ(p_obj,cat_rec).f.FlNum;
  837. }
  838.  
  839. t_ulong HFS_File_Length (CDROM_OBJ *p_obj)
  840. {
  841.   return (OBJ(p_obj,data_fork) ?
  842.         OBJ(p_obj,cat_rec).f.LgLen :
  843.       OBJ(p_obj,cat_rec).f.RLgLen);
  844. }
  845.  
  846. t_handler g_hfs_handler = {
  847.   HFS_Close_Vol_Info,
  848.   HFS_Open_Top_Level_Directory,
  849.   HFS_Open_Obj_In_Directory,
  850.   HFS_Find_Parent,
  851.   HFS_Close_Obj,
  852.   HFS_Read_From_File,
  853.   HFS_Cdrom_Info,
  854.   HFS_Examine_Next,
  855.   HFS_Clone_Obj_Info,
  856.   HFS_Is_Top_Level_Obj,
  857.   HFS_Same_Objects,
  858.   HFS_Creation_Date,
  859.   HFS_Volume_Size,
  860.   HFS_Volume_Id,
  861.   HFS_Location,
  862.   HFS_File_Length,
  863.   HFS_Block_Size
  864. };
  865.