- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# VobFile.cpp

    00001 #include "StdAfx.h"
    00002 #include <io.h>
    00003 #include "VobFile.h"
    00004 #include "CSSauth.h"
    00005 #include "CSSscramble.h"
    00006 #include "udf.h"
    00007
    00008 //
    00009 // CDVDSession
    00010 //
    00011
    00012 CDVDSession::CDVDSession()
    00013         : m_session(DVD_END_ALL_SESSIONS)
    00014         , m_hDrive(INVALID_HANDLE_VALUE)
    00015 {
    00016 }
    00017
    00018 CDVDSession::~CDVDSession()
    00019 {
    00020         EndSession();
    00021 }
    00022
    00023 bool CDVDSession::Open(LPCTSTR path)
    00024 {
    00025         Close();
    00026
    00027         CString fn = path;
    00028         CString drive = _T("\\\\.\\") + fn.Left(fn.Find(':')+1);
    00029
    00030         m_hDrive = CreateFile(drive, GENERIC_READ, FILE_SHARE_READ, NULL,
    00031                 OPEN_EXISTING, FILE_ATTRIBUTE_READONLY|FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)NULL);
    00032         if(m_hDrive == INVALID_HANDLE_VALUE)
    00033                 return(false);
    00034
    00035         return(true);
    00036 }
    00037
    00038 void CDVDSession::Close()
    00039 {
    00040         if(m_hDrive != INVALID_HANDLE_VALUE)
    00041         {
    00042                 CloseHandle(m_hDrive);
    00043                 m_hDrive = INVALID_HANDLE_VALUE;
    00044         }
    00045 }
    00046
    00047 bool CDVDSession::BeginSession()
    00048 {
    00049         EndSession();
    00050
    00051         if(m_hDrive == INVALID_HANDLE_VALUE)
    00052                 return(false);
    00053
    00054         DWORD BytesReturned;
    00055         if(!DeviceIoControl(m_hDrive, IOCTL_DVD_START_SESSION, NULL, 0, &m_session, sizeof(m_session), &BytesReturned, NULL))
    00056         {
    00057                 m_session = DVD_END_ALL_SESSIONS;
    00058                 if(!DeviceIoControl(m_hDrive, IOCTL_DVD_END_SESSION, &m_session, sizeof(m_session), NULL, 0, &BytesReturned, NULL)
    00059                 || !DeviceIoControl(m_hDrive, IOCTL_DVD_START_SESSION, NULL, 0, &m_session, sizeof(m_session), &BytesReturned, NULL))
    00060                 {
    00061                         CloseHandle(m_hDrive);
    00062                         DWORD err = GetLastError();
    00063                         return(false);
    00064                 }
    00065         }
    00066
    00067         return(true);
    00068 }
    00069
    00070 void CDVDSession::EndSession()
    00071 {
    00072         if(m_session != DVD_END_ALL_SESSIONS)
    00073         {
    00074                 DWORD BytesReturned;
    00075                 DeviceIoControl(m_hDrive, IOCTL_DVD_END_SESSION, &m_session, sizeof(m_session), NULL, 0, &BytesReturned, NULL);
    00076         m_session = DVD_END_ALL_SESSIONS;
    00077         }
    00078 }
    00079
    00080 bool CDVDSession::Authenticate()
    00081 {
    00082         if(m_session == DVD_END_ALL_SESSIONS)
    00083                 return(false);
    00084
    00085         BYTE Challenge[10], Key[10];
    00086
    00087         for(int i = 0; i < 10; i++) Challenge[i] = i;
    00088
    00089         if(!SendKey(DvdChallengeKey, Challenge))
    00090                 return(false);
    00091
    00092         if(!ReadKey(DvdBusKey1, Key))
    00093                 return(false);
    00094
    00095         int varient = -1;
    00096
    00097         for(int i = 31; i >= 0; i--)
    00098         {
    00099                 BYTE KeyCheck[5];
    00100                 CSSkey1(i, Challenge, KeyCheck);
    00101                 if(!memcmp(KeyCheck, Key, 5))
    00102                         varient = i;
    00103         }
    00104
    00105         if(!ReadKey(DvdChallengeKey, Challenge))
    00106                 return(false);
    00107
    00108         CSSkey2(varient, Challenge, &Key[5]);
    00109
    00110         if(!SendKey(DvdBusKey2, &Key[5]))
    00111                 return(false);
    00112
    00113         CSSbuskey(varient, Key, m_SessionKey);
    00114
    00115         return(true);
    00116 }
    00117
    00118 bool CDVDSession::GetDiscKey()
    00119 {
    00120         if(m_session == DVD_END_ALL_SESSIONS)
    00121                 return(false);
    00122
    00123         BYTE DiscKeys[2048];
    00124         if(!ReadKey(DvdDiskKey, DiscKeys))
    00125                 return(false);
    00126
    00127         for(int i = 0; i < g_nPlayerKeys; i++)
    00128         {
    00129                 for(int j = 1; j < 409; j++)
    00130                 {
    00131                         BYTE DiscKey[6];
    00132                         memcpy(DiscKey, &DiscKeys[j*5], 5);
    00133                         DiscKey[5] = 0;
    00134
    00135                         CSSdisckey(DiscKey, g_PlayerKeys[i]);
    00136
    00137                         BYTE Hash[6];
    00138                         memcpy(Hash, &DiscKeys[0], 5);
    00139                         Hash[5] = 0;
    00140
    00141                         CSSdisckey(Hash, DiscKey);
    00142
    00143                         if(!memcmp(Hash, DiscKey, 6))
    00144                         {
    00145                                 memcpy(m_DiscKey, DiscKey, 6);
    00146                                 return(true);
    00147                         }
    00148                 }
    00149         }
    00150
    00151         return(false);
    00152 }
    00153
    00154 bool CDVDSession::GetTitleKey(int lba, BYTE* pKey)
    00155 {
    00156         if(m_session == DVD_END_ALL_SESSIONS)
    00157                 return(false);
    00158
    00159         if(!ReadKey(DvdTitleKey, pKey, lba))
    00160                 return(false);
    00161
    00162         if(!(pKey[0]|pKey[1]|pKey[2]|pKey[3]|pKey[4]))
    00163                 return(false);
    00164
    00165         pKey[5] = 0;
    00166
    00167         CSStitlekey(pKey, m_DiscKey);
    00168
    00169         return(true);
    00170 }
    00171
    00172 static void Reverse(BYTE* d, BYTE* s, int len)
    00173 {
    00174         if(d == s)
    00175         {
    00176                 for(s += len-1; d < s; d++, s--)
    00177                         *d ^= *s, *s ^= *d, *d ^= *s;
    00178         }
    00179         else
    00180         {
    00181                 for(int i = 0; i < len; i++)
    00182                         d[i] = s[len-1 - i];
    00183         }
    00184 }
    00185
    00186 bool CDVDSession::SendKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData)
    00187 {
    00188         CAutoPtr<DVD_COPY_PROTECT_KEY> key;
    00189
    00190         switch(KeyType)
    00191         {
    00192                 case DvdChallengeKey:
    00193                         key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_CHALLENGE_KEY_LENGTH]);
    00194                         key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
    00195                         Reverse(key->KeyData, pKeyData, 10);
    00196                         break;
    00197                 case DvdBusKey2:
    00198                         key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_BUS_KEY_LENGTH]);
    00199                         key->KeyLength = DVD_BUS_KEY_LENGTH;
    00200                         Reverse(key->KeyData, pKeyData, 5);
    00201                         break;
    00202                 default:
    00203                         break;
    00204         }
    00205
    00206         if(!key)
    00207                 return(false);
    00208
    00209         key->SessionId = m_session;
    00210         key->KeyType = KeyType;
    00211         key->KeyFlags = 0;
    00212
    00213         DWORD BytesReturned;
    00214         return(!!DeviceIoControl(m_hDrive, IOCTL_DVD_SEND_KEY, key, key->KeyLength, NULL, 0, &BytesReturned, NULL));
    00215 }
    00216
    00217 bool CDVDSession::ReadKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData, int lba)
    00218 {
    00219         CAutoPtr<DVD_COPY_PROTECT_KEY> key;
    00220
    00221         switch(KeyType)
    00222         {
    00223                 case DvdChallengeKey:
    00224                         key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_CHALLENGE_KEY_LENGTH]);
    00225                         key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
    00226                         key->Parameters.TitleOffset.QuadPart = 0;
    00227                         break;
    00228                 case DvdBusKey1:
    00229                         key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_BUS_KEY_LENGTH]);
    00230                         key->KeyLength = DVD_BUS_KEY_LENGTH;
    00231                         key->Parameters.TitleOffset.QuadPart = 0;
    00232                         break;
    00233                 case DvdDiskKey:
    00234                         key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_DISK_KEY_LENGTH]);
    00235                         key->KeyLength = DVD_DISK_KEY_LENGTH;
    00236                         key->Parameters.TitleOffset.QuadPart = 0;
    00237                         break;
    00238                 case DvdTitleKey:
    00239                         key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_TITLE_KEY_LENGTH]);
    00240                         key->KeyLength = DVD_TITLE_KEY_LENGTH;
    00241                         key->Parameters.TitleOffset.QuadPart = 2048i64*lba;
    00242                         break;
    00243                 default:
    00244                         break;
    00245         }
    00246
    00247         if(!key)
    00248                 return(false);
    00249
    00250         key->SessionId = m_session;
    00251         key->KeyType = KeyType;
    00252         key->KeyFlags = 0;
    00253
    00254         DWORD BytesReturned;
    00255         if(!DeviceIoControl(m_hDrive, IOCTL_DVD_READ_KEY, key, key->KeyLength, key, key->KeyLength, &BytesReturned, NULL))
    00256         {
    00257                 DWORD err = GetLastError();
    00258                 return(false);
    00259         }
    00260
    00261         switch(KeyType)
    00262         {
    00263                 case DvdChallengeKey:
    00264                         Reverse(pKeyData, key->KeyData, 10);
    00265                         break;
    00266                 case DvdBusKey1:
    00267                         Reverse(pKeyData, key->KeyData, 5);
    00268                         break;
    00269                 case DvdDiskKey:
    00270                         memcpy(pKeyData, key->KeyData, 2048);
    00271                         for(int i = 0; i < 2048/5; i++)
    00272                                 pKeyData[i] ^= m_SessionKey[4-(i%5)];
    00273                         break;
    00274                 case DvdTitleKey:
    00275                         memcpy(pKeyData, key->KeyData, 5);
    00276                         for(int i = 0; i < 5; i++)
    00277                                 pKeyData[i] ^= m_SessionKey[4-(i%5)];
    00278                         break;
    00279                 default:
    00280                         break;
    00281         }
    00282
    00283         return(true);
    00284 }
    00285
    00286 //
    00287 // CLBAFile
    00288 //
    00289
    00290 CLBAFile::CLBAFile()
    00291 {
    00292 }
    00293
    00294 CLBAFile::~CLBAFile()
    00295 {
    00296 }
    00297
    00298 bool CLBAFile::IsOpen()
    00299 {
    00300         return(m_hFile != hFileNull);
    00301 }
    00302
    00303 bool CLBAFile::Open(LPCTSTR path)
    00304 {
    00305         Close();
    00306
    00307         return(!!CFile::Open(path, modeRead|typeBinary|shareDenyWrite|osSequentialScan));
    00308 }
    00309
    00310 void CLBAFile::Close()
    00311 {
    00312         if(m_hFile != hFileNull)
    00313                 CFile::Close();
    00314 }
    00315
    00316 int CLBAFile::GetLength()
    00317 {
    00318         return (int)(CFile::GetLength()/2048);
    00319 }
    00320
    00321 int CLBAFile::GetPosition()
    00322 {
    00323         return (int)(CFile::GetPosition()/2048);
    00324 }
    00325
    00326 int CLBAFile::Seek(int lba)
    00327 {
    00328         return (int)(CFile::Seek(2048i64*lba, CFile::begin)/2048);
    00329 }
    00330
    00331 bool CLBAFile::Read(BYTE* buff)
    00332 {
    00333         return CFile::Read(buff, 2048) == 2048;
    00334 }
    00335
    00336 //
    00337 // CVobFile
    00338 //
    00339
    00340 CVobFile::CVobFile()
    00341 {
    00342         Close();
    00343 }
    00344
    00345 CVobFile::~CVobFile()
    00346 {
    00347 }
    00348
    00349 bool CVobFile::IsDVD()
    00350 {
    00351         return m_fDVD;
    00352 }
    00353
    00354 bool CVobFile::HasDiscKey(BYTE* key)
    00355 {
    00356         if(key) memcpy(key, m_DiscKey, 5);
    00357         return m_fHasDiscKey;
    00358 }
    00359
    00360 bool CVobFile::HasTitleKey(BYTE* key)
    00361 {
    00362         if(key) memcpy(key, m_TitleKey, 5);
    00363         return m_fHasTitleKey;
    00364 }
    00365
    00366 bool CVobFile::Open(CString fn, CList<CString>& vobs)
    00367 {
    00368         CFile f;
    00369         if(!f.Open(fn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite))
    00370                 return(false);
    00371
    00372         char hdr[13];
    00373         f.Read(hdr, 12);
    00374         hdr[12] = 0;
    00375         if(strcmp(hdr, "DVDVIDEO-VTS"))
    00376                 return(false);
    00377
    00378         f.Close();
    00379
    00380         int offset = -1;
    00381
    00382         vobs.RemoveAll();
    00383
    00384         fn = fn.Left(fn.ReverseFind('.')+1);
    00385         fn.TrimRight(_T(".0123456789"));
    00386         for(int i = 0; i < 100; i++)
    00387         {
    00388                 CString vob;
    00389                 vob.Format(_T("%s%d.vob"), fn, i);
    00390
    00391                 CFileStatus status;
    00392                 if(!CFile::GetStatus(vob, status))
    00393                 {
    00394                         if(i == 0) continue;
    00395                         else break;
    00396                 }
    00397
    00398                 if(status.m_size&0x7ff)
    00399                 {
    00400                         vobs.RemoveAll();
    00401                         break;
    00402                 }
    00403
    00404                 if(status.m_size > 0)
    00405                         vobs.AddTail(vob);
    00406
    00407                 if(i == 0)
    00408                         offset = (int)(status.m_size/0x800);
    00409         }
    00410
    00411         return Open(vobs, offset);
    00412 }
    00413
    00414 bool CVobFile::Open(CList<CString>& vobs, int offset)
    00415 {
    00416         Close();
    00417
    00418         if(vobs.GetCount() == 0)
    00419                 return(false);
    00420
    00421         if(vobs.GetCount() == 1)
    00422                 offset = -1;
    00423
    00424         m_offset = offset;
    00425
    00426         POSITION pos = vobs.GetHeadPosition();
    00427         while(pos)
    00428         {
    00429                 CString fn = vobs.GetNext(pos);
    00430
    00431                 WIN32_FIND_DATA fd;
    00432                 HANDLE h = FindFirstFile(fn, &fd);
    00433                 if(h == INVALID_HANDLE_VALUE)
    00434                 {
    00435                         m_files.RemoveAll();
    00436                         return(false);
    00437                 }
    00438                 FindClose(h);
    00439
    00440                 file_t f;
    00441                 f.fn = fn;
    00442                 f.size = (int)(((__int64(fd.nFileSizeHigh)<<32)|fd.nFileSizeLow)/2048);
    00443                 m_files.Add(f);
    00444
    00445                 m_size += f.size;
    00446         }
    00447
    00448         if(m_files.GetCount() > 0 && CDVDSession::Open(m_files[0].fn))
    00449         {
    00450                 for(int i = 0; !m_fHasTitleKey && i < m_files.GetCount(); i++)
    00451                 {
    00452                         if(BeginSession())
    00453                         {
    00454                                 m_fDVD = true;
    00455                                 Authenticate();
    00456                                 m_fHasDiscKey = GetDiscKey();
    00457                                 EndSession();
    00458                         }
    00459                         else
    00460                         {
    00461                                 CString fn = m_files[0].fn;
    00462                                 fn.MakeLower();
    00463
    00464                                 if(fn.Find(_T(":\\video_ts")) == 1 && GetDriveType(fn.Left(3)) == DRIVE_CDROM)
    00465                                 {
    00466                                         m_fDVD = true;
    00467                                 }
    00468
    00469                                 break;
    00470                         }
    00471
    00472                         if(tp_udf_file f = udf_find_file(m_hDrive, 0, CStringA(m_files[i].fn.Mid(m_files[i].fn.Find(':')+1))))
    00473                         {
    00474                                 DWORD start, end;
    00475                                 if(udf_get_lba(m_hDrive, f, &start, &end))
    00476                                 {
    00477                                         if(BeginSession())
    00478                                         {
    00479                                                 Authenticate();
    00480                                                 m_fHasTitleKey = GetTitleKey(start + f->partition_lba, m_TitleKey);
    00481                                                 EndSession();
    00482                                         }
    00483                                 }
    00484
    00485                                 udf_free(f);
    00486                         }
    00487
    00488                         BYTE key[5];
    00489                         if(HasTitleKey(key) && i == 0 && offset >= 0)
    00490                         {
    00491                                 i++;
    00492
    00493                                 if(BeginSession())
    00494                                 {
    00495                                         m_fDVD = true;
    00496                                         Authenticate();
    00497                                         m_fHasDiscKey = GetDiscKey();
    00498                                         EndSession();
    00499                                 }
    00500                                 else
    00501                                 {
    00502                                         break;
    00503                                 }
    00504
    00505                                 if(tp_udf_file f = udf_find_file(m_hDrive, 0, CStringA(m_files[i].fn.Mid(m_files[i].fn.Find(':')+1))))
    00506                                 {
    00507                                         DWORD start, end;
    00508                                         if(udf_get_lba(m_hDrive, f, &start, &end))
    00509                                         {
    00510                                                 if(BeginSession())
    00511                                                 {
    00512                                                         Authenticate();
    00513                                                         m_fHasTitleKey = GetTitleKey(start + f->partition_lba, m_TitleKey);
    00514                                                         EndSession();
    00515                                                 }
    00516                                         }
    00517
    00518                                         udf_free(f);
    00519                                 }
    00520
    00521                                 if(!m_fHasTitleKey)
    00522                                 {
    00523                                         memcpy(m_TitleKey, key, 5);
    00524                                         m_fHasTitleKey = true;
    00525                                 }
    00526                         }
    00527                 }
    00528         }
    00529 /*
    00530         if(m_files.GetCount() > 0 && !m_fDVD)
    00531         {
    00532                 CString fn = m_files[0].fn;
    00533                 fn.MakeLower();
    00534
    00535                 if(fn.Find(_T(":\\video_ts")) == 1 && GetDriveType(fn.Left(3)) == DRIVE_CDROM)
    00536                 {
    00537                         m_fDVD = true;
    00538                 }
    00539         }
    00540 */
    00541         m_offset = max(offset, 0);
    00542
    00543         return(true);
    00544 }
    00545
    00546 void CVobFile::Close()
    00547 {
    00548         CDVDSession::Close();
    00549         m_files.RemoveAll();
    00550         m_iFile = -1;
    00551         m_pos = m_size = m_offset = 0;
    00552         m_file.Close();
    00553         m_fDVD = m_fHasDiscKey = m_fHasTitleKey = false;
    00554 }
    00555
    00556 int CVobFile::GetLength()
    00557 {
    00558         return(m_size - m_offset);
    00559 }
    00560
    00561 int CVobFile::GetPosition()
    00562 {
    00563         return(m_pos - m_offset);
    00564 }
    00565
    00566 int CVobFile::Seek(int pos)
    00567 {
    00568         pos = min(max(pos+m_offset, m_offset), m_size-1);
    00569
    00570         int i = -1;
    00571         int size = 0;
    00572
    00573         // this suxx, but won't take long
    00574         do size += m_files[++i].size;
    00575         while(i < m_files.GetSize() && pos >= size);
    00576
    00577         if(i != m_iFile && i < m_files.GetSize())
    00578         {
    00579                 if(!m_file.Open(m_files[i].fn))
    00580                         return(m_pos);
    00581
    00582                 m_iFile = i;
    00583         }
    00584
    00585         m_pos = pos;
    00586
    00587         pos -= (size - m_files[i].size);
    00588         m_file.Seek(pos);
    00589
    00590         return(GetPosition());
    00591 }
    00592
    00593 bool CVobFile::Read(BYTE* buff)
    00594 {
    00595         if(m_pos >= m_size) return(false);
    00596
    00597         if(m_file.IsOpen() && m_file.GetPosition() == m_file.GetLength())
    00598         {
    00599                 m_file.Close();
    00600         }
    00601
    00602         if(!m_file.IsOpen())
    00603         {
    00604                 if(m_iFile >= m_files.GetSize()-1)
    00605                 {
    00606                         return(false);
    00607                 }
    00608
    00609                 if(!m_file.Open(m_files[++m_iFile].fn))
    00610                 {
    00611                         m_iFile = -1;
    00612                         return(false);
    00613                 }
    00614         }
    00615
    00616         if(!m_file.Read(buff))
    00617         {
    00618                 // dvd still locked?
    00619                 return(false);
    00620         }
    00621
    00622         m_pos++;
    00623
    00624         if(buff[0x14] & 0x30)
    00625         {
    00626                 if(m_fHasTitleKey)
    00627                 {
    00628                         CSSdescramble(buff, m_TitleKey);
    00629                         buff[0x14] &= ~0x30;
    00630                 }
    00631                 else
    00632                 {
    00633                         // under win9x this is normal, but I'm not developing under win9x :P
    00634                         ASSERT(0);
    00635                 }
    00636         }
    00637
    00638         return(true);
    00639 }