Support unrar64.dll
[xy_vsfilter.git] / src / decss / VobFile.cpp
blob9215c0c484b3c20d5c5abfe9b49879d152500c4d
1 #include "StdAfx.h"
2 #include <io.h>
3 #include "VobFile.h"
4 #include "CSSauth.h"
5 #include "CSSscramble.h"
6 #include "udf.h"
8 //
9 // CDVDSession
12 CDVDSession::CDVDSession()
13 : m_session(DVD_END_ALL_SESSIONS)
14 , m_hDrive(INVALID_HANDLE_VALUE)
18 CDVDSession::~CDVDSession()
20 EndSession();
23 bool CDVDSession::Open(LPCTSTR path)
25 Close();
27 CString fn = path;
28 CString drive = _T("\\\\.\\") + fn.Left(fn.Find(':')+1);
30 m_hDrive = CreateFile(drive, GENERIC_READ, FILE_SHARE_READ, NULL,
31 OPEN_EXISTING, FILE_ATTRIBUTE_READONLY|FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)NULL);
32 if(m_hDrive == INVALID_HANDLE_VALUE)
33 return(false);
35 return(true);
38 void CDVDSession::Close()
40 if(m_hDrive != INVALID_HANDLE_VALUE)
42 CloseHandle(m_hDrive);
43 m_hDrive = INVALID_HANDLE_VALUE;
47 bool CDVDSession::BeginSession()
49 EndSession();
51 if(m_hDrive == INVALID_HANDLE_VALUE)
52 return(false);
54 DWORD BytesReturned;
55 if(!DeviceIoControl(m_hDrive, IOCTL_DVD_START_SESSION, NULL, 0, &m_session, sizeof(m_session), &BytesReturned, NULL))
57 m_session = DVD_END_ALL_SESSIONS;
58 if(!DeviceIoControl(m_hDrive, IOCTL_DVD_END_SESSION, &m_session, sizeof(m_session), NULL, 0, &BytesReturned, NULL)
59 || !DeviceIoControl(m_hDrive, IOCTL_DVD_START_SESSION, NULL, 0, &m_session, sizeof(m_session), &BytesReturned, NULL))
61 CloseHandle(m_hDrive);
62 DWORD err = GetLastError();
63 return(false);
67 return(true);
70 void CDVDSession::EndSession()
72 if(m_session != DVD_END_ALL_SESSIONS)
74 DWORD BytesReturned;
75 DeviceIoControl(m_hDrive, IOCTL_DVD_END_SESSION, &m_session, sizeof(m_session), NULL, 0, &BytesReturned, NULL);
76 m_session = DVD_END_ALL_SESSIONS;
80 bool CDVDSession::Authenticate()
82 if(m_session == DVD_END_ALL_SESSIONS)
83 return(false);
85 BYTE Challenge[10], Key[10];
87 for(int i = 0; i < 10; i++) Challenge[i] = i;
89 if(!SendKey(DvdChallengeKey, Challenge))
90 return(false);
92 if(!ReadKey(DvdBusKey1, Key))
93 return(false);
95 int varient = -1;
97 for(int i = 31; i >= 0; i--)
99 BYTE KeyCheck[5];
100 CSSkey1(i, Challenge, KeyCheck);
101 if(!memcmp(KeyCheck, Key, 5))
102 varient = i;
105 if(!ReadKey(DvdChallengeKey, Challenge))
106 return(false);
108 CSSkey2(varient, Challenge, &Key[5]);
110 if(!SendKey(DvdBusKey2, &Key[5]))
111 return(false);
113 CSSbuskey(varient, Key, m_SessionKey);
115 return(true);
118 bool CDVDSession::GetDiscKey()
120 if(m_session == DVD_END_ALL_SESSIONS)
121 return(false);
123 BYTE DiscKeys[2048];
124 if(!ReadKey(DvdDiskKey, DiscKeys))
125 return(false);
127 for(int i = 0; i < g_nPlayerKeys; i++)
129 for(int j = 1; j < 409; j++)
131 BYTE DiscKey[6];
132 memcpy(DiscKey, &DiscKeys[j*5], 5);
133 DiscKey[5] = 0;
135 CSSdisckey(DiscKey, g_PlayerKeys[i]);
137 BYTE Hash[6];
138 memcpy(Hash, &DiscKeys[0], 5);
139 Hash[5] = 0;
141 CSSdisckey(Hash, DiscKey);
143 if(!memcmp(Hash, DiscKey, 6))
145 memcpy(m_DiscKey, DiscKey, 6);
146 return(true);
151 return(false);
154 bool CDVDSession::GetTitleKey(int lba, BYTE* pKey)
156 if(m_session == DVD_END_ALL_SESSIONS)
157 return(false);
159 if(!ReadKey(DvdTitleKey, pKey, lba))
160 return(false);
162 if(!(pKey[0]|pKey[1]|pKey[2]|pKey[3]|pKey[4]))
163 return(false);
165 pKey[5] = 0;
167 CSStitlekey(pKey, m_DiscKey);
169 return(true);
172 static void Reverse(BYTE* d, BYTE* s, int len)
174 if(d == s)
176 for(s += len-1; d < s; d++, s--)
177 *d ^= *s, *s ^= *d, *d ^= *s;
179 else
181 for(int i = 0; i < len; i++)
182 d[i] = s[len-1 - i];
186 bool CDVDSession::SendKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData)
188 CAutoPtr<DVD_COPY_PROTECT_KEY> key;
190 switch(KeyType)
192 case DvdChallengeKey:
193 key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_CHALLENGE_KEY_LENGTH]);
194 key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
195 Reverse(key->KeyData, pKeyData, 10);
196 break;
197 case DvdBusKey2:
198 key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_BUS_KEY_LENGTH]);
199 key->KeyLength = DVD_BUS_KEY_LENGTH;
200 Reverse(key->KeyData, pKeyData, 5);
201 break;
202 default:
203 break;
206 if(!key)
207 return(false);
209 key->SessionId = m_session;
210 key->KeyType = KeyType;
211 key->KeyFlags = 0;
213 DWORD BytesReturned;
214 return(!!DeviceIoControl(m_hDrive, IOCTL_DVD_SEND_KEY, key, key->KeyLength, NULL, 0, &BytesReturned, NULL));
217 bool CDVDSession::ReadKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData, int lba)
219 CAutoPtr<DVD_COPY_PROTECT_KEY> key;
221 switch(KeyType)
223 case DvdChallengeKey:
224 key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_CHALLENGE_KEY_LENGTH]);
225 key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
226 key->Parameters.TitleOffset.QuadPart = 0;
227 break;
228 case DvdBusKey1:
229 key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_BUS_KEY_LENGTH]);
230 key->KeyLength = DVD_BUS_KEY_LENGTH;
231 key->Parameters.TitleOffset.QuadPart = 0;
232 break;
233 case DvdDiskKey:
234 key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_DISK_KEY_LENGTH]);
235 key->KeyLength = DVD_DISK_KEY_LENGTH;
236 key->Parameters.TitleOffset.QuadPart = 0;
237 break;
238 case DvdTitleKey:
239 key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_TITLE_KEY_LENGTH]);
240 key->KeyLength = DVD_TITLE_KEY_LENGTH;
241 key->Parameters.TitleOffset.QuadPart = 2048i64*lba;
242 break;
243 default:
244 break;
247 if(!key)
248 return(false);
250 key->SessionId = m_session;
251 key->KeyType = KeyType;
252 key->KeyFlags = 0;
254 DWORD BytesReturned;
255 if(!DeviceIoControl(m_hDrive, IOCTL_DVD_READ_KEY, key, key->KeyLength, key, key->KeyLength, &BytesReturned, NULL))
257 DWORD err = GetLastError();
258 return(false);
261 switch(KeyType)
263 case DvdChallengeKey:
264 Reverse(pKeyData, key->KeyData, 10);
265 break;
266 case DvdBusKey1:
267 Reverse(pKeyData, key->KeyData, 5);
268 break;
269 case DvdDiskKey:
270 memcpy(pKeyData, key->KeyData, 2048);
271 for(int i = 0; i < 2048/5; i++)
272 pKeyData[i] ^= m_SessionKey[4-(i%5)];
273 break;
274 case DvdTitleKey:
275 memcpy(pKeyData, key->KeyData, 5);
276 for(int i = 0; i < 5; i++)
277 pKeyData[i] ^= m_SessionKey[4-(i%5)];
278 break;
279 default:
280 break;
283 return(true);
287 // CLBAFile
290 CLBAFile::CLBAFile()
294 CLBAFile::~CLBAFile()
298 bool CLBAFile::IsOpen()
300 return(m_hFile != hFileNull);
303 bool CLBAFile::Open(LPCTSTR path)
305 Close();
307 return(!!CFile::Open(path, modeRead|typeBinary|shareDenyWrite|osSequentialScan));
310 void CLBAFile::Close()
312 if(m_hFile != hFileNull)
313 CFile::Close();
316 int CLBAFile::GetLength()
318 return (int)(CFile::GetLength()/2048);
321 int CLBAFile::GetPosition()
323 return (int)(CFile::GetPosition()/2048);
326 int CLBAFile::Seek(int lba)
328 return (int)(CFile::Seek(2048i64*lba, CFile::begin)/2048);
331 bool CLBAFile::Read(BYTE* buff)
333 return CFile::Read(buff, 2048) == 2048;
337 // CVobFile
340 CVobFile::CVobFile()
342 Close();
345 CVobFile::~CVobFile()
349 bool CVobFile::IsDVD()
351 return m_fDVD;
354 bool CVobFile::HasDiscKey(BYTE* key)
356 if(key) memcpy(key, m_DiscKey, 5);
357 return m_fHasDiscKey;
360 bool CVobFile::HasTitleKey(BYTE* key)
362 if(key) memcpy(key, m_TitleKey, 5);
363 return m_fHasTitleKey;
366 bool CVobFile::Open(CString fn, CAtlList<CString>& vobs)
368 CFile f;
369 if(!f.Open(fn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite))
370 return(false);
372 char hdr[13];
373 f.Read(hdr, 12);
374 hdr[12] = 0;
375 if(strcmp(hdr, "DVDVIDEO-VTS"))
376 return(false);
378 f.Close();
380 int offset = -1;
382 vobs.RemoveAll();
384 fn = fn.Left(fn.ReverseFind('.')+1);
385 fn.TrimRight(_T(".0123456789"));
386 for(int i = 0; i < 100; i++)
388 CString vob;
389 vob.Format(_T("%s%d.vob"), fn, i);
391 CFileStatus status;
392 if(!CFile::GetStatus(vob, status))
394 if(i == 0) continue;
395 else break;
398 if(status.m_size&0x7ff)
400 vobs.RemoveAll();
401 break;
404 if(status.m_size > 0)
405 vobs.AddTail(vob);
407 if(i == 0)
408 offset = (int)(status.m_size/0x800);
411 return Open(vobs, offset);
414 bool CVobFile::Open(CAtlList<CString>& vobs, int offset)
416 Close();
418 if(vobs.GetCount() == 0)
419 return(false);
421 if(vobs.GetCount() == 1)
422 offset = -1;
424 m_offset = offset;
426 POSITION pos = vobs.GetHeadPosition();
427 while(pos)
429 CString fn = vobs.GetNext(pos);
431 WIN32_FIND_DATA fd;
432 HANDLE h = FindFirstFile(fn, &fd);
433 if(h == INVALID_HANDLE_VALUE)
435 m_files.RemoveAll();
436 return(false);
438 FindClose(h);
440 file_t f;
441 f.fn = fn;
442 f.size = (int)(((__int64(fd.nFileSizeHigh)<<32)|fd.nFileSizeLow)/2048);
443 m_files.Add(f);
445 m_size += f.size;
448 if(m_files.GetCount() > 0 && CDVDSession::Open(m_files[0].fn))
450 for(int i = 0; !m_fHasTitleKey && i < m_files.GetCount(); i++)
452 if(BeginSession())
454 m_fDVD = true;
455 Authenticate();
456 m_fHasDiscKey = GetDiscKey();
457 EndSession();
459 else
461 CString fn = m_files[0].fn;
462 fn.MakeLower();
464 if(fn.Find(_T(":\\video_ts")) == 1 && GetDriveType(fn.Left(3)) == DRIVE_CDROM)
466 m_fDVD = true;
469 break;
472 if(tp_udf_file f = udf_find_file(m_hDrive, 0, CStringA(m_files[i].fn.Mid(m_files[i].fn.Find(':')+1))))
474 DWORD start, end;
475 if(udf_get_lba(m_hDrive, f, &start, &end))
477 if(BeginSession())
479 Authenticate();
480 m_fHasTitleKey = GetTitleKey(start + f->partition_lba, m_TitleKey);
481 EndSession();
485 udf_free(f);
488 BYTE key[5];
489 if(HasTitleKey(key) && i == 0 && offset >= 0)
491 i++;
493 if(BeginSession())
495 m_fDVD = true;
496 Authenticate();
497 m_fHasDiscKey = GetDiscKey();
498 EndSession();
500 else
502 break;
505 if(tp_udf_file f = udf_find_file(m_hDrive, 0, CStringA(m_files[i].fn.Mid(m_files[i].fn.Find(':')+1))))
507 DWORD start, end;
508 if(udf_get_lba(m_hDrive, f, &start, &end))
510 if(BeginSession())
512 Authenticate();
513 m_fHasTitleKey = GetTitleKey(start + f->partition_lba, m_TitleKey);
514 EndSession();
518 udf_free(f);
521 if(!m_fHasTitleKey)
523 memcpy(m_TitleKey, key, 5);
524 m_fHasTitleKey = true;
530 if(m_files.GetCount() > 0 && !m_fDVD)
532 CString fn = m_files[0].fn;
533 fn.MakeLower();
535 if(fn.Find(_T(":\\video_ts")) == 1 && GetDriveType(fn.Left(3)) == DRIVE_CDROM)
537 m_fDVD = true;
541 m_offset = max(offset, 0);
543 return(true);
546 void CVobFile::Close()
548 CDVDSession::Close();
549 m_files.RemoveAll();
550 m_iFile = -1;
551 m_pos = m_size = m_offset = 0;
552 m_file.Close();
553 m_fDVD = m_fHasDiscKey = m_fHasTitleKey = false;
556 int CVobFile::GetLength()
558 return(m_size - m_offset);
561 int CVobFile::GetPosition()
563 return(m_pos - m_offset);
566 int CVobFile::Seek(int pos)
568 pos = min(max(pos+m_offset, m_offset), m_size-1);
570 int i = -1;
571 int size = 0;
573 // this suxx, but won't take long
574 do size += m_files[++i].size;
575 while(i < m_files.GetCount() && pos >= size);
577 if(i != m_iFile && i < m_files.GetCount())
579 if(!m_file.Open(m_files[i].fn))
580 return(m_pos);
582 m_iFile = i;
585 m_pos = pos;
587 pos -= (size - m_files[i].size);
588 m_file.Seek(pos);
590 return(GetPosition());
593 bool CVobFile::Read(BYTE* buff)
595 if(m_pos >= m_size) return(false);
597 if(m_file.IsOpen() && m_file.GetPosition() == m_file.GetLength())
599 m_file.Close();
602 if(!m_file.IsOpen())
604 if(m_iFile >= m_files.GetCount()-1)
606 return(false);
609 if(!m_file.Open(m_files[++m_iFile].fn))
611 m_iFile = -1;
612 return(false);
616 if(!m_file.Read(buff))
618 // dvd still locked?
619 return(false);
622 m_pos++;
624 if(buff[0x14] & 0x30)
626 if(m_fHasTitleKey)
628 CSSdescramble(buff, m_TitleKey);
629 buff[0x14] &= ~0x30;
631 else
633 // under win9x this is normal, but I'm not developing under win9x :P
634 ASSERT(0);
638 return(true);