home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 2: PC / frozenfish_august_1995.bin / bbs / d09xx / d0935.lha / AmiCDROM / hfs.c < prev    next >
C/C++ Source or Header  |  1993-12-20  |  21KB  |  828 lines

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