dvd_udf.c
上传用户:aoeyumen
上传日期:2007-01-06
资源大小:3329k
文件大小:16k
源码类别:

DVD

开发平台:

Unix_Linux

  1. /*
  2.  * dvdudf: parse and read the UDF volume information of a DVD Video
  3.  * Copyright (C) 1999 Christian Wolff for convergence integrated media GmbH
  4.  * 
  5.  * This program is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU General Public License
  7.  * as published by the Free Software Foundation; either version 2
  8.  * of the License, or (at your option) any later version.
  9.  * 
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  * 
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  19.  * 
  20.  * The author can be reached at scarabaeus@convergence.de, 
  21.  * the project's page is at http://linuxtv.org/dvd/
  22.  */
  23.  
  24. /* This is needed for 64 bit file seek */
  25. #define _LARGEFILE64_SOURCE 1
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include <sys/ioctl.h>
  29. #include <sys/types.h>
  30. #include <linux/cdrom.h>
  31. #include "dvd_udf.h"
  32. #ifndef u8
  33. #define u8 unsigned char
  34. #endif
  35. #ifndef u16
  36. #define u16 unsigned int
  37. #endif
  38. #ifndef u32
  39. #define u32 unsigned long int
  40. #endif
  41. #ifndef u64
  42. #define u64 unsigned long long int
  43. #endif
  44. #ifndef NULL
  45. #define NULL ((void *)0)
  46. #endif
  47. #define MAX_FILE_LEN 2048
  48. FILE* dvdromfile=NULL;  // CD/DVD-ROM block device or image file
  49. struct Partition {
  50.   int valid;
  51.   char VolumeDesc[128];
  52.   u16 Flags;
  53.   u16 Number;
  54.   char Contents[32];
  55.   u32 AccessType;
  56.   u32 Start;
  57.   u32 Length;
  58. } partition;
  59. struct AD {
  60.   u32 Location;
  61.   u32 Length;
  62.   u8 Flags;
  63.   u16 Partition;
  64. };
  65. // for direct data access, LSB first
  66. #define GETN1(p) ((u8)data[p])
  67. #define GETN2(p) ((u16)data[p]|((u16)data[(p)+1]<<8))
  68. #define GETN3(p) ((u32)data[p]|((u32)data[(p)+1]<<8)|((u32)data[(p)+2]<<16))
  69. #define GETN4(p) ((u32)data[p]|((u32)data[(p)+1]<<8)|((u32)data[(p)+2]<<16)|((u32)data[(p)+3]<<24))
  70. #define GETN(p,n,target) memcpy(target,&data[p],n)
  71. // CSS structs
  72. #ifdef DVD_AUTH
  73.   dvd_authinfo ai;
  74.   dvd_struct dvds;
  75. #endif
  76. // reads absolute Logical Block of the disc
  77. // returns number of read bytes on success, 0 on error
  78. int UDFReadLB(unsigned long int lb_number, unsigned int block_count, unsigned char *data) {
  79.   fpos64_t pos;
  80.   if (dvdromfile==NULL) return 0;
  81.   pos=(fpos64_t)lb_number*(fpos64_t)DVD_VIDEO_LB_LEN;
  82.   if (fsetpos64(dvdromfile,&pos)<0) return 0; // position not found
  83.   return fread(data,block_count*DVD_VIDEO_LB_LEN,1,dvdromfile);
  84. }
  85. int Unicodedecode(u8 *data, int len, char *target) {
  86.   int p=1,i=0;
  87.   if ((data[0]==8) || (data[0]==16)) do {
  88.     if (data[0]==16) p++;  // ignore MSB of unicode16
  89.     if (p<len) {
  90.       target[i++]=data[p++];
  91.     }
  92.   } while (p<len);
  93.   target[i]='';
  94.   return 0;
  95. }
  96. int UDFEntity(u8 *data, u8 *Flags, char *Identifier) {
  97.   Flags[0]=data[0];
  98.   strncpy(Identifier,&data[1],5);
  99.   return 0;
  100. }
  101. int UDFDescriptor(u8 *data, u16 *TagID) {
  102.   TagID[0]=GETN2(0);
  103.   // TODO: check CRC 'n stuff
  104.   return 0;
  105. }
  106. int UDFExtentAD(u8 *data, u32 *Length, u32 *Location) {
  107.   Length[0]  =GETN4(0);
  108.   Location[0]=GETN4(4);
  109.   return 0;
  110. }
  111. int UDFShortAD(u8 *data, struct AD *ad) {
  112.   ad->Length=GETN4(0);
  113.   ad->Flags=ad->Length>>30;
  114.   ad->Length&=0x3FFFFFFF;
  115.   ad->Location=GETN4(4);
  116.   ad->Partition=partition.Number;  // use number of current partition
  117.   return 0;
  118. }
  119. int UDFLongAD(u8 *data, struct AD *ad) {
  120.   ad->Length=GETN4(0);
  121.   ad->Flags=ad->Length>>30;
  122.   ad->Length&=0x3FFFFFFF;
  123.   ad->Location=GETN4(4);
  124.   ad->Partition=GETN2(8);
  125.   //GETN(10,6,Use);
  126.   return 0;
  127. }
  128. int UDFExtAD(u8 *data, struct AD *ad) {
  129.   ad->Length=GETN4(0);
  130.   ad->Flags=ad->Length>>30;
  131.   ad->Length&=0x3FFFFFFF;
  132.   ad->Location=GETN4(12);
  133.   ad->Partition=GETN2(16);
  134.   //GETN(10,6,Use);
  135.   return 0;
  136. }
  137. int UDFICB(u8 *data, u8 *FileType, u16 *Flags) {
  138.   FileType[0]=GETN1(11);
  139.   Flags[0]=GETN2(18);
  140.   return 0;
  141. }
  142. int UDFPartition(u8 *data, u16 *Flags, u16 *Number, char *Contents, u32 *Start, u32 *Length) {
  143.   Flags[0]=GETN2(20);
  144.   Number[0]=GETN2(22);
  145.   GETN(24,32,Contents);
  146.   Start[0]=GETN4(188);
  147.   Length[0]=GETN4(192);
  148.   return 0;
  149. }
  150. // reads the volume descriptor and checks the parameters
  151. // returns 0 on OK, 1 on error
  152. int UDFLogVolume(u8 *data, char *VolumeDescriptor) {
  153.   u32 lbsize,MT_L,N_PM;
  154.   //u8 type,PM_L;
  155.   //u16 sequence;
  156.   //int i,p;
  157.   Unicodedecode(&data[84],128,VolumeDescriptor);
  158.   lbsize=GETN4(212);  // should be 2048
  159.   MT_L=GETN4(264);  // should be 6
  160.   N_PM=GETN4(268);  // should be 1
  161.   if (lbsize!=DVD_VIDEO_LB_LEN) return 1;
  162.   /*
  163.   Partition1[0]=0;
  164.   p=440;
  165.   for (i=0; i<N_PM; i++) {
  166.     type=GETN1(p);
  167.     PM_L=GETN1(p+1);
  168.     if (type==1) {
  169.       sequence=GETN2(p+2);
  170.       if (sequence==1) {
  171.         Partition1[0]=GETN2(p+4);
  172.         return 0;
  173.       }
  174.     }
  175.     p+=PM_L;
  176.   }
  177.   return 1;
  178.   */
  179.   return 0;
  180. }
  181. int UDFFileEntry(u8 *data, u8 *FileType, struct AD *ad) {
  182.   u8 filetype;
  183.   u16 flags;
  184.   u32 L_EA,L_AD;
  185.   int p;
  186.   UDFICB(&data[16],&filetype,&flags);
  187.   FileType[0]=filetype;
  188.   L_EA=GETN4(168);
  189.   L_AD=GETN4(172);
  190.   p=176+L_EA;
  191.   while (p<176+L_EA+L_AD) {
  192.     switch (flags&0x0007) {
  193.       case 0: UDFShortAD(&data[p],ad); p+=8;  break;
  194.       case 1: UDFLongAD(&data[p],ad);  p+=16; break;
  195.       case 2: UDFExtAD(&data[p],ad);   p+=20; break;
  196.       case 3:
  197.         switch (L_AD) {
  198.           case 8:  UDFShortAD(&data[p],ad); break;
  199.           case 16: UDFLongAD(&data[p],ad);  break;
  200.           case 20: UDFExtAD(&data[p],ad);   break;
  201.         }
  202.         p+=L_AD;
  203.         break;
  204.       default: p+=L_AD; break;
  205.     }
  206.   }
  207.   return 0;
  208. }
  209. int UDFFileIdentifier(u8 *data, u8 *FileCharacteristics, char *FileName, struct AD *FileICB) {
  210.   u8 L_FI;
  211.   u16 L_IU;
  212.   
  213.   FileCharacteristics[0]=GETN1(18);
  214.   L_FI=GETN1(19);
  215.   UDFLongAD(&data[20],FileICB);
  216.   L_IU=GETN2(36);
  217.   if (L_FI) Unicodedecode(&data[38+L_IU],L_FI,FileName);
  218.   else FileName[0]='';
  219.   return 4*((38+L_FI+L_IU+3)/4);
  220. }
  221. // Maps ICB to FileAD
  222. // ICB: Location of ICB of directory to scan
  223. // FileType: Type of the file
  224. // File: Location of file the ICB is pointing to
  225. // return 1 on success, 0 on error;
  226. int UDFMapICB(struct AD ICB, u8 *FileType, struct AD *File) {
  227.   u8 LogBlock[DVD_VIDEO_LB_LEN];
  228.   u32 lbnum;
  229.   u16 TagID;
  230.   lbnum=partition.Start+ICB.Location;
  231.   do {
  232.     if (!UDFReadLB(lbnum++,1,LogBlock)) TagID=0;
  233.     else UDFDescriptor(LogBlock,&TagID);
  234.     if (TagID==261) {
  235.       UDFFileEntry(LogBlock,FileType,File);
  236.       //printf("Found File entry type %d at LB %ld, %ld bytes longn",FileType[0],File->Location,File->Length);
  237.       return 1;
  238.     };
  239.   } while ((lbnum<=partition.Start+ICB.Location+(ICB.Length-1)/DVD_VIDEO_LB_LEN) && (TagID!=261));
  240.   return 0;
  241. }
  242.   
  243. // Dir: Location of directory to scan
  244. // FileName: Name of file to look for
  245. // FileICB: Location of ICB of the found file
  246. // return 1 on success, 0 on error;
  247. int UDFScanDir(struct AD Dir, char *FileName, struct AD *FileICB) {
  248.   u8 LogBlock[DVD_VIDEO_LB_LEN];
  249.   u32 lbnum;
  250.   u16 TagID;
  251.   u8 filechar;
  252.   char filename[MAX_FILE_LEN];
  253.   int p;
  254.   
  255.   // Scan dir for ICB of file
  256.   lbnum=partition.Start+Dir.Location;
  257.   do {
  258.     if (!UDFReadLB(lbnum++,1,LogBlock)) TagID=0;
  259.     else {
  260.       p=0;
  261.       while (p<DVD_VIDEO_LB_LEN) {
  262.         UDFDescriptor(&LogBlock[p],&TagID);
  263.         if (TagID==257) {
  264.           p+=UDFFileIdentifier(&LogBlock[p],&filechar,filename,FileICB);
  265.           //printf("Found ICB for file '%s' at LB %ld, %ld bytes longn",filename,FileICB->Location,FileICB->Length);
  266.           if (!strcasecmp(FileName,filename)) return 1;
  267.         } else p=DVD_VIDEO_LB_LEN;
  268.       }
  269.     }
  270.   } while (lbnum<=partition.Start+Dir.Location+(Dir.Length-1)/DVD_VIDEO_LB_LEN);
  271.   return 0;
  272. }
  273. // looks for partition on the disc
  274. //   partnum: number of the partition, starting at 0
  275. //   part: structure to fill with the partition information
  276. //   return 1 if partition found, 0 on error;
  277. int UDFFindPartition(int partnum, struct Partition *part) {
  278.   u8 LogBlock[DVD_VIDEO_LB_LEN],Anchor[DVD_VIDEO_LB_LEN];
  279.   u32 lbnum,MVDS_location,MVDS_length;
  280.   u16 TagID;
  281.   //u8 Flags;
  282.   //char Identifier[6];
  283.   u32 lastsector;
  284.   int i,terminate,volvalid;
  285.   // Recognize Volume
  286.   /*
  287.   lbnum=16;
  288.   do {
  289.     if (!UDFReadLB(lbnum++,1,LogBlock)) strcpy(Identifier,"");
  290.     else UDFEntity(LogBlock,&Flags,Identifier);
  291.     printf("Looking for NSR02 at LB %ld, found %sn",lbnum-1,Identifier);
  292.   } while ((lbnum<=256) && strcmp("NSR02",Identifier));
  293.   if (strcmp("NSR02",Identifier))  printf("Could not recognize volume. Bad.n");
  294.   else printf("Found %s at LB %ld. Good.n",Identifier,lbnum-1);
  295.   */
  296.   // Find Anchor
  297.   lastsector=0;
  298.   lbnum=256;   // try #1, prime anchor
  299.   terminate=0;
  300.   while (1) {  // loop da loop
  301.     if (UDFReadLB(lbnum,1,Anchor)) {
  302.       UDFDescriptor(Anchor,&TagID);
  303.     } else TagID=0;
  304.     if (TagID!=2) {             // not an anchor?
  305.       if (terminate) return 0;  // final try failed 
  306.       if (lastsector) {         // we already found the last sector
  307.         lbnum=lastsector;       // try #3, alternative backup anchor
  308.         terminate=1;            // but that's just about enough, then!
  309.       } else {
  310.         // TODO: find last sector of the disc (this is optional)
  311.         if (lastsector) lbnum=lastsector-256; // try #2, backup anchor
  312.         else return 0;          // unable to find last sector
  313.       }
  314.     } else break;               // it is an anchor! continue...
  315.   }
  316.   UDFExtentAD(&Anchor[16],&MVDS_length,&MVDS_location);  // main volume descriptor
  317.   //printf("MVDS at LB %ld thru %ldn",MVDS_location,MVDS_location+(MVDS_length-1)/DVD_VIDEO_LB_LEN);
  318.   
  319.   part->valid=0;
  320.   volvalid=0;
  321.   part->VolumeDesc[0]='';
  322.   i=1;
  323.   do {
  324.     // Find Volume Descriptor
  325.     lbnum=MVDS_location;
  326.     do {
  327.       if (!UDFReadLB(lbnum++,1,LogBlock)) TagID=0;
  328.       else UDFDescriptor(LogBlock,&TagID);
  329.       //printf("Looking for Descripors at LB %ld, found %dn",lbnum-1,TagID);
  330.       if ((TagID==5) && (!part->valid)) {  // Partition Descriptor
  331.         //printf("Partition Descriptor at LB %ldn",lbnum-1);
  332.         UDFPartition(LogBlock,&part->Flags,&part->Number,part->Contents,&part->Start,&part->Length);
  333.         part->valid=(partnum==part->Number);
  334.         //printf("Partition %d at LB %ld thru %ldn",part->Number,part->Start,part->Start+part->Length-1);
  335.       } else if ((TagID==6) && (!volvalid)) {  // Logical Volume Descriptor
  336.         //printf("Logical Volume Descriptor at LB %ldn",lbnum-1);
  337.         if (UDFLogVolume(LogBlock,part->VolumeDesc)) {  
  338.           //TODO: sector size wrong!
  339.         } else volvalid=1;
  340. //printf("Logical Volume Descriptor: %sn",part->VolumeDesc);  // name of the disc
  341.       }
  342.     } while ((lbnum<=MVDS_location+(MVDS_length-1)/DVD_VIDEO_LB_LEN) && (TagID!=8) && ((!part->valid) || (!volvalid)));
  343.     if ((!part->valid) || (!volvalid)) UDFExtentAD(&Anchor[24],&MVDS_length,&MVDS_location);  // backup volume descriptor
  344.   } while (i-- && ((!part->valid) || (!volvalid)));
  345.   return (part->valid);  // we only care for the partition, not the volume
  346. }
  347. // looks for a file on the UDF disc/imagefile
  348. // filename has to be the absolute pathname on the UDF filesystem, starting with /
  349. // returns absolute LB number, or 0 on error
  350. unsigned long int UDFFindFile(char *filename) {
  351.   u8 LogBlock[DVD_VIDEO_LB_LEN];
  352.   u32 lbnum;
  353.   u16 TagID;
  354.   struct AD RootICB,File,ICB;
  355.   char tokenline[MAX_FILE_LEN];
  356.   char *token;
  357.   u8 filetype;
  358.   
  359.   int Partition=0;  // this is the standard location for DVD Video
  360.   
  361.   tokenline[0]='';
  362.   // Very DVD-Video specific:
  363.   //if (filename[0]!='/') strcat(tokenline,"/VIDEO_TS/");
  364.   strcat(tokenline,filename);
  365.   // Find partition
  366.   if (!UDFFindPartition(Partition,&partition)) return 0;
  367.   
  368.   // Find root dir ICB
  369.   lbnum=partition.Start;
  370.   do {
  371.     if (!UDFReadLB(lbnum++,1,LogBlock)) TagID=0;
  372.     else UDFDescriptor(LogBlock,&TagID);
  373.     //printf("Found TagID %d at LB %ldn",TagID,lbnum-1);
  374.     if (TagID==256) {  // File Set Descriptor
  375.       UDFLongAD(&LogBlock[400],&RootICB);
  376.     }
  377.   } while ((lbnum<partition.Start+partition.Length) && (TagID!=8) && (TagID!=256));
  378.   if (TagID!=256) return 0;
  379.   if (RootICB.Partition!=Partition) return 0;
  380.   
  381.   // Find root dir
  382.   if (!UDFMapICB(RootICB,&filetype,&File)) return 0;
  383.   if (filetype!=4) return 0;  // root dir should be dir
  384.   //printf("Root Dir found at %ldn",File.Location);
  385.   // Tokenize filepath
  386.   token=strtok(tokenline,"/");
  387.   while (token != NULL) {
  388.     //printf("looking for token %sn",token);
  389.     if (!UDFScanDir(File,token,&ICB)) return 0;
  390.     if (!UDFMapICB(ICB,&filetype,&File)) return 0;
  391.     token=strtok(NULL,"/");
  392.   }
  393.   return partition.Start+File.Location;
  394. }
  395. // Initializes the CSS process with the drive
  396. // returns positive AGID on success, -1 on error, -2 if no CSS support in CD-ROM driver
  397. int UDFCSSRequestAGID(void) {
  398. #ifdef DVD_AUTH
  399.   int i,err;
  400.   
  401.   // clear struct
  402.   memset(&ai,0,sizeof(ai));
  403.   // the DVD drive parts of this process are from Andrew T. Veliath or Jens Axboe
  404. /*
  405.   ai.type=DVD_LU_SEND_ASF;
  406.   ai.lsasf.agid=0;
  407.   ai.lsasf.asf=0;
  408.   if (ioctl(fileno(dvdromfile),DVD_AUTH,&ai)<0) return -1;
  409.   if (ai.lsasf.asf) {
  410. //    if (verbosity>1) { fprintf(debugf,"CSS - DVD is authenticatedn"); fflush(debugf); }
  411.   } else {
  412. //    if (verbosity>0) { fprintf(debugf,"CSS - DVD authentication failedn"); fflush(debugf); }
  413.   }
  414. */
  415.     // Init sequence, request AGID (authentication grant ID)
  416.     err=-1;
  417.     for (i=1; i<=2; i++) {
  418. //      if (verbosity>1) { fprintf(debugf,"CSS - Request AGID[%d]...n", i); fflush(debugf); }
  419.       ai.type=DVD_LU_SEND_AGID;
  420.       ai.lsa.agid=0;
  421.       if ((err=ioctl(fileno(dvdromfile),DVD_AUTH,&ai))<0) {
  422.         ai.type=DVD_INVALIDATE_AGID;
  423.         ai.lsa.agid=0;
  424.         ioctl(fileno(dvdromfile),DVD_AUTH,&ai);
  425.       } else break;
  426.     }
  427.     if (err<0) return -1;
  428.   return ai.lsa.agid;
  429. #else
  430.   return -2;
  431. #endif
  432. }
  433. // Post host challenge (10 bytes) into drive
  434. // and retreive drive response (5 bytes) for host
  435. // returns 0 on success, -1 on error, -2 if no CSS support in CD-ROM driver
  436. int UDFCSSDriveAuth(char *data) {
  437. #ifdef DVD_AUTH
  438.   memcpy(ai.hsc.chal,data,10);
  439.   ai.type=DVD_HOST_SEND_CHALLENGE;
  440.   if (ioctl(fileno(dvdromfile),DVD_AUTH,&ai)<0) return -1;
  441.   ai.type=DVD_LU_SEND_KEY1;
  442.   if (ioctl(fileno(dvdromfile),DVD_AUTH,&ai)<0) return -1;
  443.   memcpy(data,ai.lsk.key,5);
  444.   return 0;
  445. #else
  446.   return -2;
  447. #endif
  448. }
  449. // Retreive drive challenge (10 bytes) 
  450. // returns 0 on success, -1 on error, -2 if no CSS support in CD-ROM driver
  451. int UDFCSSHostAuthChallenge(char *data) {
  452. #ifdef DVD_AUTH
  453.   ai.type=DVD_LU_SEND_CHALLENGE;
  454.   if (ioctl(fileno(dvdromfile),DVD_AUTH,&ai)<0) return -1;
  455.   memcpy(data,ai.lsc.chal,10);
  456.   return 0;
  457. #else
  458.   return -2;
  459. #endif
  460. }
  461. // Post host response (5 bytes) into drive
  462. // returns 0 on success, -1 on error, -2 if no CSS support in CD-ROM driver
  463. int UDFCSSHostAuthResponse(char *data) {
  464. #ifdef DVD_AUTH
  465.   memcpy(ai.hsk.key,data,5);
  466.   ai.type=DVD_HOST_SEND_KEY2;
  467.   if (ioctl(fileno(dvdromfile),DVD_AUTH,&ai)<0) return -1;
  468.   else return 0;
  469. #else
  470.   return -2;
  471. #endif
  472. }
  473. // Retreive disc key (2048 byte) from drive
  474. // returns 0 on success, -1 on error, -2 if no CSS support in CD-ROM driver
  475. int UDFCSSDiscKey(char *data) {
  476. #ifdef DVD_AUTH
  477.   // clear struct
  478.   memset(&dvds,0,sizeof(dvds));
  479.   dvds.type = DVD_STRUCT_DISCKEY;
  480.   dvds.disckey.agid=ai.lsa.agid;
  481.   memset(dvds.disckey.value,0,2048);
  482.   if (ioctl(fileno(dvdromfile),DVD_READ_STRUCT,&dvds)<0) return -1;
  483.   memcpy(data,dvds.disckey.value,2048);
  484.   return 0;
  485. #else
  486.   return -2;
  487. #endif
  488. }
  489. // Retreive title key (5 byte) from drive
  490. // lba: absolute number of logical block containing the title key
  491. // returns 0 on success, -1 on error, -2 if no CSS support in CD-ROM driver
  492. int UDFCSSTitleKey(unsigned long int lba, char *data) {
  493. #ifdef DVD_AUTH
  494.   ai.type=DVD_LU_SEND_TITLE_KEY;
  495.   ai.lstk.lba=lba;  // logical block address of title on disc
  496.   if (ioctl(fileno(dvdromfile),DVD_AUTH,&ai)<0) return -1;
  497.   memcpy(data,ai.lstk.title_key,5);
  498.   return 0;
  499. #else
  500.   return -2;
  501. #endif
  502. }
  503. // open block device or image file
  504. // returns fileno() of the file on success, or -1 on error
  505. int UDFOpenDisc(char *filename) {
  506.   if ((dvdromfile=fopen(filename,"r"))==NULL) return -1;
  507.   return fileno(dvdromfile);
  508. }