/**************************************************************************** * Genesis Plus 1.2a * * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * DVD ISO9660/Joliet Parsing * * This is not intended as a complete guide to ISO9660. * Here I use the bare minimum! ***************************************************************************/ #include "shared.h" #include "dvd.h" #include "iso9660.h" /** Minimal ISO Directory Definition **/ #define RECLEN 0 /* Record length */ #define EXTENT 6 /* Extent */ #define FILE_LENGTH 14 /* File length (BIG ENDIAN) */ #define FILE_FLAGS 25 /* File flags */ #define FILENAME_LENGTH 32 /* Filename length */ #define FILENAME 33 /* ASCIIZ filename */ /** Minimal Primary Volume Descriptor **/ #define PVDROOT 0x9c static int IsJoliet = 0; u64 rootdir = 0; u64 basedir = 0; int rootdirlength = 0; /** Global file entry table **/ FILEENTRIES filelist[MAXFILES]; static char dvdbuffer[2048]; /**************************************************************************** * Primary Volume Descriptor * * The PVD should reside between sector 16 and 31. * This is for single session DVD only. ****************************************************************************/ int getpvd () { int sector = 16; u32 rootdir32; basedir = rootdirlength = 0; IsJoliet = -1; /** Look for Joliet PVD first **/ while (sector < 32) { if (dvd_read (&dvdbuffer, 2048, (u64)(sector << 11))) { if (memcmp (&dvdbuffer, "\2CD001\1", 8) == 0) { memcpy(&rootdir32, &dvdbuffer[PVDROOT + EXTENT], 4); basedir = (u64)rootdir32; memcpy (&rootdirlength, &dvdbuffer[PVDROOT + FILE_LENGTH], 4); basedir <<= 11; IsJoliet = 1; break; } } else return 0; /*** Can't read sector! ***/ sector++; } if (IsJoliet > 0) return 1; /*** Joliet PVD Found ? ***/ /*** Look for standard ISO9660 PVD ***/ sector = 16; while (sector < 32) { if (dvd_read (&dvdbuffer, 2048, (u64)(sector << 11))) { if (memcmp (&dvdbuffer, "\1CD001\1", 8) == 0) { memcpy (&rootdir32, &dvdbuffer[PVDROOT + EXTENT], 4); basedir = (u64)rootdir32; memcpy (&rootdirlength, &dvdbuffer[PVDROOT + FILE_LENGTH], 4); IsJoliet = 0; basedir <<= 11; break; } } else return 0; /*** Can't read sector! ***/ sector++; } return (IsJoliet == 0); } /**************************************************************************** * getentry * * Support function to return the next file entry, if any * Declared static to avoid accidental external entry. ****************************************************************************/ static int diroffset = 0; static int getentry (int entrycount) { char fname[512]; /* Huge, but experience has determined this */ char *ptr; char *filename; char *filenamelength; char *rr; int j; u32 offset32; /* Basic checks */ if (entrycount >= MAXFILES) return 0; if (diroffset >= 2048) return 0; /** Decode this entry **/ if (dvdbuffer[diroffset]) /* Record length available */ { /* Update offsets into sector buffer */ ptr = (char *) &dvdbuffer[0]; ptr += diroffset; filename = ptr + FILENAME; filenamelength = ptr + FILENAME_LENGTH; /* Check for wrap round - illegal in ISO spec, * but certain crap writers do it! */ if ((diroffset + dvdbuffer[diroffset]) > 2048) return 0; if (*filenamelength) { memset (&fname, 0, 512); /*** Do ISO 9660 first ***/ if (!IsJoliet) strcpy (fname, filename); else { /*** The more tortuous unicode joliet entries ***/ for (j = 0; j < (*filenamelength >> 1); j++) { fname[j] = filename[j * 2 + 1]; } fname[j] = 0; if (strlen (fname) >= MAXJOLIET) fname[MAXJOLIET - 1] = 0; if (strlen (fname) == 0) fname[0] = filename[0]; } if (strlen (fname) == 0) strcpy (fname, "."); else { if (fname[0] == 1) strcpy (fname, ".."); else { /* * Move *filenamelength to t, * Only to stop gcc warning for noobs :) */ int t = *filenamelength; fname[t] = 0; } } /** Rockridge Check **/ rr = strstr (fname, ";"); if (rr != NULL) *rr = 0; strcpy (filelist[entrycount].filename, fname); memcpy (&offset32, &dvdbuffer[diroffset + EXTENT], 4); filelist[entrycount].offset = (u64)offset32; memcpy (&filelist[entrycount].length, &dvdbuffer[diroffset + FILE_LENGTH], 4); memcpy (&filelist[entrycount].flags, &dvdbuffer[diroffset + FILE_FLAGS], 1); filelist[entrycount].offset <<= 11; filelist[entrycount].flags = filelist[entrycount].flags & 2; filelist[entrycount].filename_offset = 0; /*** Prepare for next entry ***/ diroffset += dvdbuffer[diroffset]; return 1; } } return 0; } /**************************************************************************** * parsedirectory * * This function will parse the directory tree. * It relies on rootdir and rootdirlength being pre-populated by a call to * getpvd, a previous parse or a menu selection. * * The return value is number of files collected, or 0 on failure. ****************************************************************************/ int parsedirectory () { int pdlength; u64 pdoffset; u64 rdoffset; int len = 0; int filecount = 0; pdoffset = rdoffset = rootdir; pdlength = rootdirlength; filecount = 0; /** Clear any existing values ***/ memset (&filelist, 0, sizeof (FILEENTRIES) * MAXFILES); /*** Get as many files as possible ***/ while (len < pdlength) { if (dvd_read (&dvdbuffer, 2048, pdoffset) == 0) return 0; diroffset = 0; while (getentry (filecount)) { if (filecount < MAXFILES) filecount++; } len += 2048; pdoffset = rdoffset + len; } return filecount; }