/*********************************************************************** Copyright 2002 Ben Rudiak-Gould. 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, or visit . ***********************************************************************/ #include "udfrecognize.h" #include "../include/dvdsynth-device.h" extern scsi_result_t KernelScsiCommand(DvsDeviceKernel* kdev, const unsigned char* cdb, int cdblen, unsigned char* buffer, unsigned long* pbuflen, int inout, SenseData* sense); #include #include bool Read(DvsDeviceKernel* device, int sector, int sectors, unsigned char* buf) { unsigned char cdb[10] = { 0x28, 0, sector>>24, sector>>16, sector>>8, sector, 0, sectors>>8, sectors, 0 }; unsigned long buflen = sectors*2048; static SenseData sense = { 0x70, 0, 0, {0,0,0,0}, 10, {0,0,0,0}, 0, 0, 0, {0,0,0} }; return SCSIRESULT_SUCCESS == KernelScsiCommand(device, cdb, 10, buf, &buflen, 1, &sense); } unsigned crc_ccitt(const unsigned char *buf, unsigned len) { const unsigned poly = 0x11021; static unsigned short lookup[256]; unsigned int r; unsigned int i; if (lookup[1] == 0) { unsigned int j,k; for (j = 0; j < 256; ++j) { unsigned int temp = j << 8; for (k = 0; k < 8; ++k) { unsigned int hibit = temp & 32768; temp <<= 1; if (hibit) temp ^= poly; } lookup[j] = temp; } } r = 0; for (i = 0; i < len; ++i) { r = (r << 8) ^ lookup[((r >> 8) ^ buf[i]) & 255]; } return r & 65535; } int check_descriptor(const unsigned char* buf, int type) { if (buf[0]+buf[1]*256 != type) { return -1; } // if (buf[12] != (location&255) || buf[13] != ((location>>8)&255) || buf[13] != ((location>>16)&255) || buf[13] != (location>>24)) { // return -2; // } int checksum = 0; for (int i=0; i<16; ++i) { checksum += buf[i]; } if ((checksum - buf[4]*2) & 255) { return -3; } /* int crc = crc_ccitt(buf+16, buf[10]+buf[11]*256); if (buf[8]*256 + buf[9] != crc) { return -4; } */ return 0; } unsigned get4(unsigned char* p) { return p[0] + p[1]*256 + p[2]*65536 + p[3]*16777216; } static unsigned char buf[2048]; int follow_icb(DvsDeviceKernel* device, unsigned partition_sector, unsigned sector, unsigned length, unsigned *psector, unsigned *plength) { if (!Read(device, sector, 1, buf)) { return -1; // sector read failed } if (check_descriptor(buf, 261) < 0) { return -4; } unsigned l_ea = get4(buf+168); if (l_ea > 2048-176-8) { return -5; // file entry longer than expected } *plength = get4(buf+176+l_ea); *psector = get4(buf+176+l_ea+4) + partition_sector; return 0; } int find_directory_entry(DvsDeviceKernel* device, unsigned partition_sector, unsigned sector, unsigned length, const char* name, bool dir, unsigned *psector, unsigned *plength) { int namelen = strlen(name); if (!Read(device, sector, 1, buf)) { return -1; } unsigned bufpos = 0; while (bufpos < 2048-38 && bufpos < length) { if (check_descriptor(buf, 257) < 0) { return -4; // bad descriptor } unsigned l_fi = buf[bufpos+19]; unsigned l_iu = buf[bufpos+36] + buf[bufpos+37]*256; if (bufpos+38+l_iu+l_fi > 2048) { return -7; } if ((buf[bufpos+18] & 30) == dir*2 && l_fi == namelen+1 && buf[bufpos+38+l_iu] == 8 && memcmp(buf+bufpos+38+l_iu+1, name, namelen) == 0) { *plength = get4(buf+bufpos+20); *psector = get4(buf+bufpos+24) + partition_sector; return 0; } bufpos += 38+l_iu+l_fi; bufpos = (bufpos+3) & ~3; } return -6; // couldn't find file in directory } int GetDvdVideoInfo(DvsDeviceKernel* device, DvdVideoInfo* info) { if (!Read(device, 256, 1, buf)) { return -1; // sector read failed } if (check_descriptor(buf, 2) < 0) { return -2; // no AVDP found } info->mvds_length = get4(buf+16); info->mvds_sector = get4(buf+20); info->partition_sector = 0; info->partition_sectors = 0; info->fsd_sector = 0; info->fsd_length = 0; for (unsigned i = 0; i*2048 < info->mvds_length; ++i) { if (!Read(device, info->mvds_sector + i, 1, buf)) { return -1; } if (check_descriptor(buf, 5) >= 0) { info->partition_sector = get4(buf+188); info->partition_sectors = get4(buf+192); } else if (check_descriptor(buf, 6) >= 0) { info->fsd_length = get4(buf+248); info->fsd_sector = get4(buf+252); } } if (info->partition_sectors == 0 || info->fsd_length == 0) { return -3; // no partition desc or logical volume desc found } info->fsd_sector += info->partition_sector; if (!Read(device, info->fsd_sector, 1, buf)) { return -1; } if (check_descriptor(buf, 256) < 0) { return -4; // bad descriptor } info->root_icb_length = get4(buf+400); info->root_icb_sector = get4(buf+404) + info->partition_sector; int result; unsigned unused_length; result = follow_icb(device, info->partition_sector, info->root_icb_sector, info->root_icb_length, &info->root_sector, &info->root_length); if (result < 0) return result; result = find_directory_entry(device, info->partition_sector, info->root_sector, info->root_length, "VIDEO_TS", true, &info->video_ts_icb_sector, &info->video_ts_icb_length); if (result < 0) return result; result = follow_icb(device, info->partition_sector, info->video_ts_icb_sector, info->video_ts_icb_length, &info->video_ts_sector, &info->video_ts_length); if (result < 0) return result; result = find_directory_entry(device, info->partition_sector, info->video_ts_sector, info->video_ts_length, "VIDEO_TS.IFO", false, &info->vmg_ifo_icb_sector, &info->vmg_ifo_icb_length); if (result < 0) return result; result = follow_icb(device, info->partition_sector, info->vmg_ifo_icb_sector, info->vmg_ifo_icb_length, &info->vmg_ifo_sector, &unused_length); return result; }