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