dvd_udf.c
上传用户:aoeyumen
上传日期:2007-01-06
资源大小:3329k
文件大小:16k
- /*
- * dvdudf: parse and read the UDF volume information of a DVD Video
- * Copyright (C) 1999 Christian Wolff for convergence integrated media GmbH
- *
- * 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, point your browser to http://www.gnu.org/copyleft/gpl.html
- *
- * The author can be reached at scarabaeus@convergence.de,
- * the project's page is at http://linuxtv.org/dvd/
- */
-
- /* This is needed for 64 bit file seek */
- #define _LARGEFILE64_SOURCE 1
- #include <stdio.h>
- #include <string.h>
- #include <sys/ioctl.h>
- #include <sys/types.h>
- #include <linux/cdrom.h>
- #include "dvd_udf.h"
- #ifndef u8
- #define u8 unsigned char
- #endif
- #ifndef u16
- #define u16 unsigned int
- #endif
- #ifndef u32
- #define u32 unsigned long int
- #endif
- #ifndef u64
- #define u64 unsigned long long int
- #endif
- #ifndef NULL
- #define NULL ((void *)0)
- #endif
- #define MAX_FILE_LEN 2048
- FILE* dvdromfile=NULL; // CD/DVD-ROM block device or image file
- struct Partition {
- int valid;
- char VolumeDesc[128];
- u16 Flags;
- u16 Number;
- char Contents[32];
- u32 AccessType;
- u32 Start;
- u32 Length;
- } partition;
- struct AD {
- u32 Location;
- u32 Length;
- u8 Flags;
- u16 Partition;
- };
- // for direct data access, LSB first
- #define GETN1(p) ((u8)data[p])
- #define GETN2(p) ((u16)data[p]|((u16)data[(p)+1]<<8))
- #define GETN3(p) ((u32)data[p]|((u32)data[(p)+1]<<8)|((u32)data[(p)+2]<<16))
- #define GETN4(p) ((u32)data[p]|((u32)data[(p)+1]<<8)|((u32)data[(p)+2]<<16)|((u32)data[(p)+3]<<24))
- #define GETN(p,n,target) memcpy(target,&data[p],n)
- // CSS structs
- #ifdef DVD_AUTH
- dvd_authinfo ai;
- dvd_struct dvds;
- #endif
- // reads absolute Logical Block of the disc
- // returns number of read bytes on success, 0 on error
- int UDFReadLB(unsigned long int lb_number, unsigned int block_count, unsigned char *data) {
- fpos64_t pos;
- if (dvdromfile==NULL) return 0;
- pos=(fpos64_t)lb_number*(fpos64_t)DVD_VIDEO_LB_LEN;
- if (fsetpos64(dvdromfile,&pos)<0) return 0; // position not found
- return fread(data,block_count*DVD_VIDEO_LB_LEN,1,dvdromfile);
- }
- int Unicodedecode(u8 *data, int len, char *target) {
- int p=1,i=0;
- if ((data[0]==8) || (data[0]==16)) do {
- if (data[0]==16) p++; // ignore MSB of unicode16
- if (p<len) {
- target[i++]=data[p++];
- }
- } while (p<len);
- target[i]='';
- return 0;
- }
- int UDFEntity(u8 *data, u8 *Flags, char *Identifier) {
- Flags[0]=data[0];
- strncpy(Identifier,&data[1],5);
- return 0;
- }
- int UDFDescriptor(u8 *data, u16 *TagID) {
- TagID[0]=GETN2(0);
- // TODO: check CRC 'n stuff
- return 0;
- }
- int UDFExtentAD(u8 *data, u32 *Length, u32 *Location) {
- Length[0] =GETN4(0);
- Location[0]=GETN4(4);
- return 0;
- }
- int UDFShortAD(u8 *data, struct AD *ad) {
- ad->Length=GETN4(0);
- ad->Flags=ad->Length>>30;
- ad->Length&=0x3FFFFFFF;
- ad->Location=GETN4(4);
- ad->Partition=partition.Number; // use number of current partition
- return 0;
- }
- int UDFLongAD(u8 *data, struct AD *ad) {
- ad->Length=GETN4(0);
- ad->Flags=ad->Length>>30;
- ad->Length&=0x3FFFFFFF;
- ad->Location=GETN4(4);
- ad->Partition=GETN2(8);
- //GETN(10,6,Use);
- return 0;
- }
- int UDFExtAD(u8 *data, struct AD *ad) {
- ad->Length=GETN4(0);
- ad->Flags=ad->Length>>30;
- ad->Length&=0x3FFFFFFF;
- ad->Location=GETN4(12);
- ad->Partition=GETN2(16);
- //GETN(10,6,Use);
- return 0;
- }
- int UDFICB(u8 *data, u8 *FileType, u16 *Flags) {
- FileType[0]=GETN1(11);
- Flags[0]=GETN2(18);
- return 0;
- }
- int UDFPartition(u8 *data, u16 *Flags, u16 *Number, char *Contents, u32 *Start, u32 *Length) {
- Flags[0]=GETN2(20);
- Number[0]=GETN2(22);
- GETN(24,32,Contents);
- Start[0]=GETN4(188);
- Length[0]=GETN4(192);
- return 0;
- }
- // reads the volume descriptor and checks the parameters
- // returns 0 on OK, 1 on error
- int UDFLogVolume(u8 *data, char *VolumeDescriptor) {
- u32 lbsize,MT_L,N_PM;
- //u8 type,PM_L;
- //u16 sequence;
- //int i,p;
- Unicodedecode(&data[84],128,VolumeDescriptor);
- lbsize=GETN4(212); // should be 2048
- MT_L=GETN4(264); // should be 6
- N_PM=GETN4(268); // should be 1
- if (lbsize!=DVD_VIDEO_LB_LEN) return 1;
- /*
- Partition1[0]=0;
- p=440;
- for (i=0; i<N_PM; i++) {
- type=GETN1(p);
- PM_L=GETN1(p+1);
- if (type==1) {
- sequence=GETN2(p+2);
- if (sequence==1) {
- Partition1[0]=GETN2(p+4);
- return 0;
- }
- }
- p+=PM_L;
- }
- return 1;
- */
- return 0;
- }
- int UDFFileEntry(u8 *data, u8 *FileType, struct AD *ad) {
- u8 filetype;
- u16 flags;
- u32 L_EA,L_AD;
- int p;
- UDFICB(&data[16],&filetype,&flags);
- FileType[0]=filetype;
- L_EA=GETN4(168);
- L_AD=GETN4(172);
- p=176+L_EA;
- while (p<176+L_EA+L_AD) {
- switch (flags&0x0007) {
- case 0: UDFShortAD(&data[p],ad); p+=8; break;
- case 1: UDFLongAD(&data[p],ad); p+=16; break;
- case 2: UDFExtAD(&data[p],ad); p+=20; break;
- case 3:
- switch (L_AD) {
- case 8: UDFShortAD(&data[p],ad); break;
- case 16: UDFLongAD(&data[p],ad); break;
- case 20: UDFExtAD(&data[p],ad); break;
- }
- p+=L_AD;
- break;
- default: p+=L_AD; break;
- }
- }
- return 0;
- }
- int UDFFileIdentifier(u8 *data, u8 *FileCharacteristics, char *FileName, struct AD *FileICB) {
- u8 L_FI;
- u16 L_IU;
-
- FileCharacteristics[0]=GETN1(18);
- L_FI=GETN1(19);
- UDFLongAD(&data[20],FileICB);
- L_IU=GETN2(36);
- if (L_FI) Unicodedecode(&data[38+L_IU],L_FI,FileName);
- else FileName[0]='';
- return 4*((38+L_FI+L_IU+3)/4);
- }
- // Maps ICB to FileAD
- // ICB: Location of ICB of directory to scan
- // FileType: Type of the file
- // File: Location of file the ICB is pointing to
- // return 1 on success, 0 on error;
- int UDFMapICB(struct AD ICB, u8 *FileType, struct AD *File) {
- u8 LogBlock[DVD_VIDEO_LB_LEN];
- u32 lbnum;
- u16 TagID;
- lbnum=partition.Start+ICB.Location;
- do {
- if (!UDFReadLB(lbnum++,1,LogBlock)) TagID=0;
- else UDFDescriptor(LogBlock,&TagID);
- if (TagID==261) {
- UDFFileEntry(LogBlock,FileType,File);
- //printf("Found File entry type %d at LB %ld, %ld bytes longn",FileType[0],File->Location,File->Length);
- return 1;
- };
- } while ((lbnum<=partition.Start+ICB.Location+(ICB.Length-1)/DVD_VIDEO_LB_LEN) && (TagID!=261));
- return 0;
- }
-
- // Dir: Location of directory to scan
- // FileName: Name of file to look for
- // FileICB: Location of ICB of the found file
- // return 1 on success, 0 on error;
- int UDFScanDir(struct AD Dir, char *FileName, struct AD *FileICB) {
- u8 LogBlock[DVD_VIDEO_LB_LEN];
- u32 lbnum;
- u16 TagID;
- u8 filechar;
- char filename[MAX_FILE_LEN];
- int p;
-
- // Scan dir for ICB of file
- lbnum=partition.Start+Dir.Location;
- do {
- if (!UDFReadLB(lbnum++,1,LogBlock)) TagID=0;
- else {
- p=0;
- while (p<DVD_VIDEO_LB_LEN) {
- UDFDescriptor(&LogBlock[p],&TagID);
- if (TagID==257) {
- p+=UDFFileIdentifier(&LogBlock[p],&filechar,filename,FileICB);
- //printf("Found ICB for file '%s' at LB %ld, %ld bytes longn",filename,FileICB->Location,FileICB->Length);
- if (!strcasecmp(FileName,filename)) return 1;
- } else p=DVD_VIDEO_LB_LEN;
- }
- }
- } while (lbnum<=partition.Start+Dir.Location+(Dir.Length-1)/DVD_VIDEO_LB_LEN);
- return 0;
- }
- // looks for partition on the disc
- // partnum: number of the partition, starting at 0
- // part: structure to fill with the partition information
- // return 1 if partition found, 0 on error;
- int UDFFindPartition(int partnum, struct Partition *part) {
- u8 LogBlock[DVD_VIDEO_LB_LEN],Anchor[DVD_VIDEO_LB_LEN];
- u32 lbnum,MVDS_location,MVDS_length;
- u16 TagID;
- //u8 Flags;
- //char Identifier[6];
- u32 lastsector;
- int i,terminate,volvalid;
- // Recognize Volume
- /*
- lbnum=16;
- do {
- if (!UDFReadLB(lbnum++,1,LogBlock)) strcpy(Identifier,"");
- else UDFEntity(LogBlock,&Flags,Identifier);
- printf("Looking for NSR02 at LB %ld, found %sn",lbnum-1,Identifier);
- } while ((lbnum<=256) && strcmp("NSR02",Identifier));
- if (strcmp("NSR02",Identifier)) printf("Could not recognize volume. Bad.n");
- else printf("Found %s at LB %ld. Good.n",Identifier,lbnum-1);
- */
- // Find Anchor
- lastsector=0;
- lbnum=256; // try #1, prime anchor
- terminate=0;
- while (1) { // loop da loop
- if (UDFReadLB(lbnum,1,Anchor)) {
- UDFDescriptor(Anchor,&TagID);
- } else TagID=0;
- if (TagID!=2) { // not an anchor?
- if (terminate) return 0; // final try failed
- if (lastsector) { // we already found the last sector
- lbnum=lastsector; // try #3, alternative backup anchor
- terminate=1; // but that's just about enough, then!
- } else {
- // TODO: find last sector of the disc (this is optional)
- if (lastsector) lbnum=lastsector-256; // try #2, backup anchor
- else return 0; // unable to find last sector
- }
- } else break; // it is an anchor! continue...
- }
- UDFExtentAD(&Anchor[16],&MVDS_length,&MVDS_location); // main volume descriptor
- //printf("MVDS at LB %ld thru %ldn",MVDS_location,MVDS_location+(MVDS_length-1)/DVD_VIDEO_LB_LEN);
-
- part->valid=0;
- volvalid=0;
- part->VolumeDesc[0]='';
- i=1;
- do {
- // Find Volume Descriptor
- lbnum=MVDS_location;
- do {
- if (!UDFReadLB(lbnum++,1,LogBlock)) TagID=0;
- else UDFDescriptor(LogBlock,&TagID);
- //printf("Looking for Descripors at LB %ld, found %dn",lbnum-1,TagID);
- if ((TagID==5) && (!part->valid)) { // Partition Descriptor
- //printf("Partition Descriptor at LB %ldn",lbnum-1);
- UDFPartition(LogBlock,&part->Flags,&part->Number,part->Contents,&part->Start,&part->Length);
- part->valid=(partnum==part->Number);
- //printf("Partition %d at LB %ld thru %ldn",part->Number,part->Start,part->Start+part->Length-1);
- } else if ((TagID==6) && (!volvalid)) { // Logical Volume Descriptor
- //printf("Logical Volume Descriptor at LB %ldn",lbnum-1);
- if (UDFLogVolume(LogBlock,part->VolumeDesc)) {
- //TODO: sector size wrong!
- } else volvalid=1;
- //printf("Logical Volume Descriptor: %sn",part->VolumeDesc); // name of the disc
- }
- } while ((lbnum<=MVDS_location+(MVDS_length-1)/DVD_VIDEO_LB_LEN) && (TagID!=8) && ((!part->valid) || (!volvalid)));
- if ((!part->valid) || (!volvalid)) UDFExtentAD(&Anchor[24],&MVDS_length,&MVDS_location); // backup volume descriptor
- } while (i-- && ((!part->valid) || (!volvalid)));
- return (part->valid); // we only care for the partition, not the volume
- }
- // looks for a file on the UDF disc/imagefile
- // filename has to be the absolute pathname on the UDF filesystem, starting with /
- // returns absolute LB number, or 0 on error
- unsigned long int UDFFindFile(char *filename) {
- u8 LogBlock[DVD_VIDEO_LB_LEN];
- u32 lbnum;
- u16 TagID;
- struct AD RootICB,File,ICB;
- char tokenline[MAX_FILE_LEN];
- char *token;
- u8 filetype;
-
- int Partition=0; // this is the standard location for DVD Video
-
- tokenline[0]='';
- // Very DVD-Video specific:
- //if (filename[0]!='/') strcat(tokenline,"/VIDEO_TS/");
- strcat(tokenline,filename);
- // Find partition
- if (!UDFFindPartition(Partition,&partition)) return 0;
-
- // Find root dir ICB
- lbnum=partition.Start;
- do {
- if (!UDFReadLB(lbnum++,1,LogBlock)) TagID=0;
- else UDFDescriptor(LogBlock,&TagID);
- //printf("Found TagID %d at LB %ldn",TagID,lbnum-1);
- if (TagID==256) { // File Set Descriptor
- UDFLongAD(&LogBlock[400],&RootICB);
- }
- } while ((lbnum<partition.Start+partition.Length) && (TagID!=8) && (TagID!=256));
- if (TagID!=256) return 0;
- if (RootICB.Partition!=Partition) return 0;
-
- // Find root dir
- if (!UDFMapICB(RootICB,&filetype,&File)) return 0;
- if (filetype!=4) return 0; // root dir should be dir
- //printf("Root Dir found at %ldn",File.Location);
- // Tokenize filepath
- token=strtok(tokenline,"/");
- while (token != NULL) {
- //printf("looking for token %sn",token);
- if (!UDFScanDir(File,token,&ICB)) return 0;
- if (!UDFMapICB(ICB,&filetype,&File)) return 0;
- token=strtok(NULL,"/");
- }
- return partition.Start+File.Location;
- }
- // Initializes the CSS process with the drive
- // returns positive AGID on success, -1 on error, -2 if no CSS support in CD-ROM driver
- int UDFCSSRequestAGID(void) {
- #ifdef DVD_AUTH
- int i,err;
-
- // clear struct
- memset(&ai,0,sizeof(ai));
- // the DVD drive parts of this process are from Andrew T. Veliath or Jens Axboe
- /*
- ai.type=DVD_LU_SEND_ASF;
- ai.lsasf.agid=0;
- ai.lsasf.asf=0;
- if (ioctl(fileno(dvdromfile),DVD_AUTH,&ai)<0) return -1;
- if (ai.lsasf.asf) {
- // if (verbosity>1) { fprintf(debugf,"CSS - DVD is authenticatedn"); fflush(debugf); }
- } else {
- // if (verbosity>0) { fprintf(debugf,"CSS - DVD authentication failedn"); fflush(debugf); }
- }
- */
- // Init sequence, request AGID (authentication grant ID)
- err=-1;
- for (i=1; i<=2; i++) {
- // if (verbosity>1) { fprintf(debugf,"CSS - Request AGID[%d]...n", i); fflush(debugf); }
- ai.type=DVD_LU_SEND_AGID;
- ai.lsa.agid=0;
- if ((err=ioctl(fileno(dvdromfile),DVD_AUTH,&ai))<0) {
- ai.type=DVD_INVALIDATE_AGID;
- ai.lsa.agid=0;
- ioctl(fileno(dvdromfile),DVD_AUTH,&ai);
- } else break;
- }
- if (err<0) return -1;
- return ai.lsa.agid;
- #else
- return -2;
- #endif
- }
- // Post host challenge (10 bytes) into drive
- // and retreive drive response (5 bytes) for host
- // returns 0 on success, -1 on error, -2 if no CSS support in CD-ROM driver
- int UDFCSSDriveAuth(char *data) {
- #ifdef DVD_AUTH
- memcpy(ai.hsc.chal,data,10);
- ai.type=DVD_HOST_SEND_CHALLENGE;
- if (ioctl(fileno(dvdromfile),DVD_AUTH,&ai)<0) return -1;
- ai.type=DVD_LU_SEND_KEY1;
- if (ioctl(fileno(dvdromfile),DVD_AUTH,&ai)<0) return -1;
- memcpy(data,ai.lsk.key,5);
- return 0;
- #else
- return -2;
- #endif
- }
- // Retreive drive challenge (10 bytes)
- // returns 0 on success, -1 on error, -2 if no CSS support in CD-ROM driver
- int UDFCSSHostAuthChallenge(char *data) {
- #ifdef DVD_AUTH
- ai.type=DVD_LU_SEND_CHALLENGE;
- if (ioctl(fileno(dvdromfile),DVD_AUTH,&ai)<0) return -1;
- memcpy(data,ai.lsc.chal,10);
- return 0;
- #else
- return -2;
- #endif
- }
- // Post host response (5 bytes) into drive
- // returns 0 on success, -1 on error, -2 if no CSS support in CD-ROM driver
- int UDFCSSHostAuthResponse(char *data) {
- #ifdef DVD_AUTH
- memcpy(ai.hsk.key,data,5);
- ai.type=DVD_HOST_SEND_KEY2;
- if (ioctl(fileno(dvdromfile),DVD_AUTH,&ai)<0) return -1;
- else return 0;
- #else
- return -2;
- #endif
- }
- // Retreive disc key (2048 byte) from drive
- // returns 0 on success, -1 on error, -2 if no CSS support in CD-ROM driver
- int UDFCSSDiscKey(char *data) {
- #ifdef DVD_AUTH
- // clear struct
- memset(&dvds,0,sizeof(dvds));
- dvds.type = DVD_STRUCT_DISCKEY;
- dvds.disckey.agid=ai.lsa.agid;
- memset(dvds.disckey.value,0,2048);
- if (ioctl(fileno(dvdromfile),DVD_READ_STRUCT,&dvds)<0) return -1;
- memcpy(data,dvds.disckey.value,2048);
- return 0;
- #else
- return -2;
- #endif
- }
- // Retreive title key (5 byte) from drive
- // lba: absolute number of logical block containing the title key
- // returns 0 on success, -1 on error, -2 if no CSS support in CD-ROM driver
- int UDFCSSTitleKey(unsigned long int lba, char *data) {
- #ifdef DVD_AUTH
- ai.type=DVD_LU_SEND_TITLE_KEY;
- ai.lstk.lba=lba; // logical block address of title on disc
- if (ioctl(fileno(dvdromfile),DVD_AUTH,&ai)<0) return -1;
- memcpy(data,ai.lstk.title_key,5);
- return 0;
- #else
- return -2;
- #endif
- }
- // open block device or image file
- // returns fileno() of the file on success, or -1 on error
- int UDFOpenDisc(char *filename) {
- if ((dvdromfile=fopen(filename,"r"))==NULL) return -1;
- return fileno(dvdromfile);
- }