home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 7 / FreshFishVol7.bin / new / disk / cdrom / amicdfs / src / iso9660.c < prev    next >
C/C++ Source or Header  |  1994-10-03  |  20KB  |  836 lines

  1. /* iso9660.c:
  2.  *
  3.  * Support for the ISO-9660 filing system.
  4.  *
  5.  * Modified by Nicola Salmoria.
  6.  *
  7.  * ----------------------------------------------------------------------
  8.  * This code is (C) Copyright 1993,1994 by Frank Munkert.
  9.  * All rights reserved.
  10.  * This software may be freely distributed and redistributed for
  11.  * non-commercial purposes, provided this notice is included.
  12.  * ----------------------------------------------------------------------
  13.  * [History removed]
  14.  */
  15.  
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <ctype.h>
  19.  
  20. #include <exec/types.h>
  21. #include <exec/memory.h>
  22. #include <dos/dos.h>
  23. #include <proto/exec.h>
  24. #include <proto/dos.h>
  25. #include <proto/utility.h>
  26.  
  27. #include "cdrom.h"
  28. #include "iso9660.h"
  29. #include "rock.h"
  30.  
  31.  
  32. t_bool Iso_Is_Top_Level_Object (VOLUME *,CDROM_OBJ *);
  33. CDROM_OBJ *Iso_Open_Top_Level_Directory (VOLUME *p_volume);
  34. LONG Iso_Examine_Next (VOLUME *p_volume,CDROM_OBJ *p_dir, CDROM_INFO *p_info,
  35.               unsigned long *p_offset);
  36. void Iso_Close_Obj (CDROM_OBJ *p_object);
  37.  
  38.  
  39. #define VOL(vol,tag) (((t_iso_vol_info *)(vol->vol_info))->tag)
  40. #define OBJ(obj,tag) (((t_iso_obj_info *)(obj->obj_info))->tag)
  41.  
  42. /* Check whether the given volume uses the ISO 9660 Protocol.
  43.  * The protocol is identified by the sequence
  44.  *            'C' 'D' '0' '0' '1'
  45.  * in the 2nd..6th byte of sector 16 of a track.
  46.  *
  47.  * All data tracks on the disk are examined.
  48.  *
  49.  * Returns TRUE iff the ISO protocol is used; FALSE otherwise.
  50.  */
  51.  
  52. t_bool Uses_Iso_Protocol (CDROM *p_cdrom, t_ulong *p_offset)
  53. {
  54.   int i, len;
  55.   t_ulong *buf;
  56.  
  57.  
  58.   SetIoErr(ERROR_NOT_A_DOS_DISK);    /* initialize error code (Read_Sector() */
  59.                                     /* will change it if needed) */
  60.  
  61.   /* If Data_Tracks() returns -1, then the drive probably doesn't support
  62.    * the SCSI-2 READ TOC command.
  63.    */
  64.   if (p_cdrom->use_trackdisk ||
  65.       (len = Data_Tracks (p_cdrom, &buf)) < 0) {
  66.     *p_offset = 0;
  67.     if (!Read_Sector (p_cdrom, 16))
  68.       return FALSE;
  69.     return strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0;
  70.   }
  71.  
  72.   if (len == 0)
  73.     return FALSE;
  74.  
  75.   /* Use a vendor-specific command to find the offset of the last
  76.    * session:
  77.    */
  78.   if (Find_Last_Session (p_cdrom, p_offset) &&
  79.       Read_Sector (p_cdrom, 16 + *p_offset) &&
  80.       strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0) {
  81.     FreeVec (buf);
  82.     return TRUE;
  83.   }
  84.  
  85.   /* Search all data tracks for valid primary volume descriptors: */
  86.   for (i=len-1; i>=0; i--) {
  87.     *p_offset = buf[i];
  88.     if (!Read_Sector (p_cdrom, 16 + *p_offset))
  89.       continue;
  90.     if (strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0) {
  91.       FreeVec (buf);
  92.       return TRUE;
  93.     }
  94.   }
  95.  
  96.   FreeVec (buf);
  97.  
  98.   /* On some disks, the information in the TOC may not be valid. Therefore
  99.    * also check sector 16:
  100.    */
  101.   if (!Read_Sector (p_cdrom, 16))
  102.     return FALSE;
  103.   if (strncmp ((char *) p_cdrom->buffer + 1, "CD001", 5) == 0) {
  104.     *p_offset = 0;
  105.     return TRUE;
  106.   }
  107.  
  108.   return FALSE;
  109. }
  110.  
  111. /* Check whether the given volume uses the High Sierra Protocol.
  112.  * The protocol is identified by the sequence
  113.  *            'C' 'D' 'R' 'O' 'M'
  114.  * in the 10th..14th byte of sector 16.
  115.  *
  116.  * Returns TRUE iff the High Sierra protocol is used; FALSE otherwise.
  117.  */
  118.  
  119. t_bool Uses_High_Sierra_Protocol (CDROM *p_cdrom)
  120. {
  121.   SetIoErr(ERROR_NOT_A_DOS_DISK);    /* initialize error code (Read_Sector() */
  122.                                     /* will change it if needed) */
  123.  
  124.   if (!Read_Sector (p_cdrom, 16))
  125.     return FALSE;
  126.  
  127.   return strncmp ((char *) p_cdrom->buffer + 9, "CDROM", 5) == 0;
  128. }
  129.  
  130.  
  131.  
  132. t_bool Iso_Init_Vol_Info (VOLUME *p_volume, int p_skip, t_ulong p_offset,
  133.         t_bool lowercase)
  134. {
  135.   long loc = 16 + p_offset;
  136.   extern t_handler g_iso_handler;
  137.  
  138.   p_volume->handler = &g_iso_handler;
  139.  
  140.   p_volume->vol_info = AllocMem (sizeof (t_iso_vol_info), MEMF_PUBLIC | MEMF_CLEAR);
  141.   if (!p_volume->vol_info) {
  142.     SetIoErr(ERROR_NO_FREE_STORE);
  143.     return FALSE;
  144.   }
  145.  
  146.   for (;;) {
  147.     if (!Read_Sector (p_volume->cd, loc)) {
  148.       FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
  149.       return FALSE;
  150.     }
  151.  
  152.     if (p_volume->cd->buffer[0] == 1) {
  153.       memcpy (&VOL(p_volume,pvd), p_volume->cd->buffer, sizeof (prim_vol_desc));
  154.       break;
  155.     }
  156.  
  157.     if (p_volume->cd->buffer[0] == 255 || loc > 1000) {
  158.       SetIoErr(ISOERR_NO_PVD);
  159.       FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
  160.       return FALSE;
  161.     }
  162.  
  163.     loc++;
  164.   }
  165.  
  166.   VOL(p_volume,skip) = p_skip;
  167.  
  168.   switch (VOL(p_volume,pvd).block_size_m) {
  169.   case 512:
  170.     VOL(p_volume,blockshift) = 2;
  171.     break;
  172.   case 1024:
  173.     VOL(p_volume,blockshift) = 1;
  174.     break;
  175.   case 2048:
  176.   default:
  177.     VOL(p_volume,blockshift) = 0;
  178.     break;
  179.   }
  180.  
  181.   if (lowercase)
  182.   {
  183.     /* Look at the system ID to find out if the CD is supposed
  184.      * to feature proper file names. These are CDs made for use
  185.      * with the CDTV and the CD³² (both share the "CDTV" system ID)
  186.      * and the "Fresh Fish", "Frozen Fish" and "Gold Fish" CDs
  187.      * created by Mkisofs. If any of these IDs is found the
  188.      * file name to lower case conversion is disabled.
  189.      */
  190.  
  191.     if (!strncmp(VOL(p_volume,pvd).system_id,"CDTV",4) ||
  192.         !strncmp(VOL(p_volume,pvd).system_id,"AMIGA",5))
  193.     {
  194.         lowercase = 0;
  195.     }
  196.   }
  197.  
  198.   VOL(p_volume,lowercase) = lowercase;
  199.  
  200.   return TRUE;
  201. }
  202.  
  203. void Iso_Close_Vol_Info (VOLUME *p_volume)
  204. {
  205.   FreeMem (p_volume->vol_info, sizeof (t_iso_vol_info));
  206. }
  207.  
  208. CDROM_OBJ *Iso_Alloc_Obj (int p_length_of_dir_record)
  209. {
  210. CDROM_OBJ *obj;
  211.  
  212.  
  213. if (obj = AllocMem(sizeof(CDROM_OBJ),MEMF_PUBLIC | MEMF_CLEAR))
  214. {
  215.     if (obj->obj_info = AllocMem(sizeof (t_iso_obj_info),MEMF_PUBLIC))
  216.     {
  217.         if (OBJ(obj,dir) = AllocMem(p_length_of_dir_record,MEMF_PUBLIC))
  218.             return(obj);
  219.  
  220.         FreeMem(obj->obj_info, sizeof (t_iso_obj_info));
  221.     }
  222.  
  223.     FreeMem(obj,sizeof(CDROM_OBJ));
  224. }
  225.  
  226. SetIoErr(ERROR_NO_FREE_STORE);
  227. return(NULL);
  228. }
  229.  
  230. /* Get the "CDROM object" for the root directory of the volume.
  231.  */
  232.  
  233. CDROM_OBJ *Iso_Open_Top_Level_Directory (VOLUME *p_volume)
  234. {
  235.   CDROM_OBJ *obj;
  236.  
  237.   obj = Iso_Alloc_Obj (VOL(p_volume,pvd).root.length);
  238.   if (!obj)
  239.     return NULL;
  240.  
  241.   obj->directory_f = TRUE;
  242.   obj->handler = p_volume->handler;
  243.   obj->pos = 0;
  244.   memcpy (OBJ(obj,dir), &VOL(p_volume,pvd).root, VOL(p_volume,pvd).root.length);
  245.  
  246.   return obj;
  247. }
  248.  
  249.  
  250. /* Compare the name of the directory entry p_iso_name
  251.  * with the C string p_name, and return 1 iff strings are equal.
  252.  * NOTE: p_iso_name may be a file name (with version number) or a directory
  253.  *       name (without version number).
  254.  * NOTE: may *TRASH* p_iso_name
  255.  */
  256.  
  257. int Names_Equal (char *p_iso_name, char *p_name)
  258. {
  259.   int pos;
  260.  
  261.  
  262.   if (!Stricmp(p_iso_name, p_name))
  263.     return TRUE;
  264.  
  265.   /* compare without version number: */
  266.  
  267.   for (pos=strlen(p_iso_name)-1; pos>=0; pos--)
  268.     if (p_iso_name[pos] == ';')
  269.       break;
  270.  
  271.   if (pos>=0)
  272.   {
  273.     p_iso_name[pos] = 0;
  274.     return(!Stricmp(p_iso_name,p_name));
  275.   }
  276.   else
  277.     return FALSE;
  278. }
  279.  
  280. /* Get a record from a directory.
  281.  * p_location is a LOGICAL BLOCK number.
  282.  * the record will be stored in buffer, which must be 256 bytes long.
  283.  */
  284.  
  285. directory_record *Get_Directory_Record (VOLUME *p_volume,struct directory_record *p_dir,
  286.                     unsigned long p_location,
  287.                     unsigned long p_offset)
  288. {
  289.   int len;
  290.   int loc;
  291.  
  292.   loc = (p_location >> VOL(p_volume,blockshift)) + (p_offset >> 11);
  293.   if (!Read_Sector (p_volume->cd, loc)) {
  294.     return NULL;
  295.   }
  296.  
  297.   len = p_volume->cd->buffer[p_offset & 2047];
  298.   if (len)
  299.     memcpy (p_dir, p_volume->cd->buffer + (p_offset & 2047), len);
  300.   else
  301.     p_dir->length = 0;  /* mark as last record */
  302.  
  303.   return(p_dir);
  304. }
  305.  
  306.  
  307.  
  308. /* store the name of an object into buffer, which must be 32 bytes long */
  309. VOID Convert_Iso_Name(VOLUME *p_volume,struct directory_record *p_dir,UBYTE *buffer)
  310. {
  311. int len;
  312.  
  313.  
  314. len = -1;
  315. if (p_volume->protocol == PRO_ROCK)
  316.     len = Get_RR_File_Name(p_volume,p_dir,buffer,30);
  317.  
  318. if (len < 0)
  319. {
  320.     len = p_dir->file_id_length;
  321. /* make sure that the name doesn't exceed AmigaDOS limit (30 characters) */
  322.     if (len > 30) len = 30;
  323.  
  324.     memcpy(buffer,p_dir->file_id,len);
  325.     if (VOL(p_volume,lowercase))
  326.     {
  327. /* convert file name to lowercase if the user requested it */
  328.         WORD i;
  329.  
  330.  
  331.         for (i = 0;i < len;i++)
  332.             buffer[i] = ToLower(buffer[i]);
  333.     }
  334. }
  335.  
  336. /* NULL terminate the string */
  337. buffer[len] = 0;
  338. }
  339.  
  340.  
  341.  
  342. /* Create a "CDROM object" for the directory which is located
  343.  * at s