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