VobFile.cpp
上传用户:xjjlds
上传日期:2015-12-05
资源大小:22823k
文件大小:12k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. #include "StdAfx.h"
  2. #include <io.h>
  3. #include "VobFile.h"
  4. #include "CSSauth.h"
  5. #include "CSSscramble.h"
  6. #include "udf.h"
  7. //
  8. // CDVDSession
  9. //
  10. CDVDSession::CDVDSession()
  11. : m_session(DVD_END_ALL_SESSIONS)
  12. , m_hDrive(INVALID_HANDLE_VALUE)
  13. {
  14. }
  15. CDVDSession::~CDVDSession()
  16. {
  17. EndSession();
  18. }
  19. bool CDVDSession::Open(LPCTSTR path)
  20. {
  21. Close();
  22. CString fn = path;
  23. CString drive = _T("\\.\") + fn.Left(fn.Find(':')+1);
  24. m_hDrive = CreateFile(drive, GENERIC_READ, FILE_SHARE_READ, NULL, 
  25. OPEN_EXISTING, FILE_ATTRIBUTE_READONLY|FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)NULL);
  26. if(m_hDrive == INVALID_HANDLE_VALUE)
  27. return(false);
  28. return(true);
  29. }
  30. void CDVDSession::Close()
  31. {
  32. if(m_hDrive != INVALID_HANDLE_VALUE)
  33. {
  34. CloseHandle(m_hDrive);
  35. m_hDrive = INVALID_HANDLE_VALUE;
  36. }
  37. }
  38. bool CDVDSession::BeginSession()
  39. {
  40. EndSession();
  41. if(m_hDrive == INVALID_HANDLE_VALUE)
  42. return(false);
  43. DWORD BytesReturned;
  44. if(!DeviceIoControl(m_hDrive, IOCTL_DVD_START_SESSION, NULL, 0, &m_session, sizeof(m_session), &BytesReturned, NULL))
  45. {
  46. m_session = DVD_END_ALL_SESSIONS;
  47. if(!DeviceIoControl(m_hDrive, IOCTL_DVD_END_SESSION, &m_session, sizeof(m_session), NULL, 0, &BytesReturned, NULL)
  48. || !DeviceIoControl(m_hDrive, IOCTL_DVD_START_SESSION, NULL, 0, &m_session, sizeof(m_session), &BytesReturned, NULL))
  49. {
  50. CloseHandle(m_hDrive);
  51. DWORD err = GetLastError();
  52. return(false);
  53. }
  54. }
  55. return(true);
  56. }
  57. void CDVDSession::EndSession()
  58. {
  59. if(m_session != DVD_END_ALL_SESSIONS)
  60. {
  61. DWORD BytesReturned;
  62. DeviceIoControl(m_hDrive, IOCTL_DVD_END_SESSION, &m_session, sizeof(m_session), NULL, 0, &BytesReturned, NULL);
  63.         m_session = DVD_END_ALL_SESSIONS;
  64. }
  65. }
  66. bool CDVDSession::Authenticate()
  67. {
  68. if(m_session == DVD_END_ALL_SESSIONS) 
  69. return(false);
  70. BYTE Challenge[10], Key[10];
  71. for(int i = 0; i < 10; i++) Challenge[i] = i;
  72. if(!SendKey(DvdChallengeKey, Challenge))
  73. return(false);
  74. if(!ReadKey(DvdBusKey1, Key))
  75. return(false);
  76. int varient = -1;
  77. for(int i = 31; i >= 0; i--)
  78. {
  79. BYTE KeyCheck[5];
  80. CSSkey1(i, Challenge, KeyCheck);
  81. if(!memcmp(KeyCheck, Key, 5))
  82. varient = i;
  83. }
  84. if(!ReadKey(DvdChallengeKey, Challenge))
  85. return(false);
  86. CSSkey2(varient, Challenge, &Key[5]);
  87. if(!SendKey(DvdBusKey2, &Key[5]))
  88. return(false);
  89. CSSbuskey(varient, Key, m_SessionKey);
  90. return(true);
  91. }
  92. bool CDVDSession::GetDiscKey()
  93. {
  94. if(m_session == DVD_END_ALL_SESSIONS) 
  95. return(false);
  96. BYTE DiscKeys[2048];
  97. if(!ReadKey(DvdDiskKey, DiscKeys))
  98. return(false);
  99. for(int i = 0; i < g_nPlayerKeys; i++)
  100. {
  101. for(int j = 1; j < 409; j++)
  102. {
  103. BYTE DiscKey[6];
  104. memcpy(DiscKey, &DiscKeys[j*5], 5);
  105. DiscKey[5] = 0;
  106. CSSdisckey(DiscKey, g_PlayerKeys[i]);
  107. BYTE Hash[6];
  108. memcpy(Hash, &DiscKeys[0], 5);
  109. Hash[5] = 0;
  110. CSSdisckey(Hash, DiscKey);
  111. if(!memcmp(Hash, DiscKey, 6))
  112. {
  113. memcpy(m_DiscKey, DiscKey, 6);
  114. return(true);
  115. }
  116. }
  117. }
  118. return(false);
  119. }
  120. bool CDVDSession::GetTitleKey(int lba, BYTE* pKey)
  121. {
  122. if(m_session == DVD_END_ALL_SESSIONS) 
  123. return(false);
  124. if(!ReadKey(DvdTitleKey, pKey, lba))
  125. return(false);
  126. if(!(pKey[0]|pKey[1]|pKey[2]|pKey[3]|pKey[4]))
  127. return(false);
  128. pKey[5] = 0;
  129. CSStitlekey(pKey, m_DiscKey);
  130. return(true);
  131. }
  132. static void Reverse(BYTE* d, BYTE* s, int len)
  133. {
  134. if(d == s)
  135. {
  136. for(s += len-1; d < s; d++, s--)
  137. *d ^= *s, *s ^= *d, *d ^= *s;
  138. }
  139. else
  140. {
  141. for(int i = 0; i < len; i++)
  142. d[i] = s[len-1 - i];
  143. }
  144. }
  145. bool CDVDSession::SendKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData)
  146. {
  147. CAutoPtr<DVD_COPY_PROTECT_KEY> key;
  148. switch(KeyType)
  149. {
  150. case DvdChallengeKey: 
  151. key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_CHALLENGE_KEY_LENGTH]);
  152. key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
  153. Reverse(key->KeyData, pKeyData, 10);
  154. break;
  155. case DvdBusKey2:
  156. key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_BUS_KEY_LENGTH]);
  157. key->KeyLength = DVD_BUS_KEY_LENGTH;
  158. Reverse(key->KeyData, pKeyData, 5);
  159. break;
  160. default: 
  161. break;
  162. }
  163. if(!key)
  164. return(false);
  165. key->SessionId = m_session;
  166. key->KeyType = KeyType;
  167. key->KeyFlags = 0;
  168. DWORD BytesReturned;
  169. return(!!DeviceIoControl(m_hDrive, IOCTL_DVD_SEND_KEY, key, key->KeyLength, NULL, 0, &BytesReturned, NULL));
  170. }
  171. bool CDVDSession::ReadKey(DVD_KEY_TYPE KeyType, BYTE* pKeyData, int lba)
  172. {
  173. CAutoPtr<DVD_COPY_PROTECT_KEY> key;
  174. switch(KeyType)
  175. {
  176. case DvdChallengeKey: 
  177. key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_CHALLENGE_KEY_LENGTH]);
  178. key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
  179. key->Parameters.TitleOffset.QuadPart = 0;
  180. break;
  181. case DvdBusKey1:
  182. key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_BUS_KEY_LENGTH]);
  183. key->KeyLength = DVD_BUS_KEY_LENGTH;
  184. key->Parameters.TitleOffset.QuadPart = 0;
  185. break;
  186. case DvdDiskKey:
  187. key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_DISK_KEY_LENGTH]);
  188. key->KeyLength = DVD_DISK_KEY_LENGTH;
  189. key->Parameters.TitleOffset.QuadPart = 0;
  190. break;
  191. case DvdTitleKey:
  192. key.Attach((DVD_COPY_PROTECT_KEY*)new BYTE[DVD_TITLE_KEY_LENGTH]);
  193. key->KeyLength = DVD_TITLE_KEY_LENGTH;
  194. key->Parameters.TitleOffset.QuadPart = 2048i64*lba;
  195. break;
  196. default: 
  197. break;
  198. }
  199. if(!key)
  200. return(false);
  201. key->SessionId = m_session;
  202. key->KeyType = KeyType;
  203. key->KeyFlags = 0;
  204. DWORD BytesReturned;
  205. if(!DeviceIoControl(m_hDrive, IOCTL_DVD_READ_KEY, key, key->KeyLength, key, key->KeyLength, &BytesReturned, NULL))
  206. {
  207. DWORD err = GetLastError();
  208. return(false);
  209. }
  210. switch(KeyType)
  211. {
  212. case DvdChallengeKey:
  213. Reverse(pKeyData, key->KeyData, 10);
  214. break;
  215. case DvdBusKey1:
  216. Reverse(pKeyData, key->KeyData, 5);
  217. break;
  218. case DvdDiskKey:
  219. memcpy(pKeyData, key->KeyData, 2048);
  220. for(int i = 0; i < 2048/5; i++)
  221. pKeyData[i] ^= m_SessionKey[4-(i%5)];
  222. break;
  223. case DvdTitleKey:
  224. memcpy(pKeyData, key->KeyData, 5);
  225. for(int i = 0; i < 5; i++)
  226. pKeyData[i] ^= m_SessionKey[4-(i%5)];
  227. break;
  228. default: 
  229. break;
  230. }
  231. return(true);
  232. }
  233. //
  234. // CLBAFile
  235. //
  236. CLBAFile::CLBAFile()
  237. {
  238. }
  239. CLBAFile::~CLBAFile()
  240. {
  241. }
  242. bool CLBAFile::IsOpen()
  243. {
  244. return(m_hFile != hFileNull);
  245. }
  246. bool CLBAFile::Open(LPCTSTR path)
  247. {
  248. Close();
  249. return(!!CFile::Open(path, modeRead|typeBinary|shareDenyWrite|osSequentialScan));
  250. }
  251. void CLBAFile::Close()
  252. {
  253. if(m_hFile != hFileNull) 
  254. CFile::Close();
  255. }
  256. int CLBAFile::GetLength()
  257. {
  258. return (int)(CFile::GetLength()/2048);
  259. }
  260. int CLBAFile::GetPosition()
  261. {
  262. return (int)(CFile::GetPosition()/2048);
  263. }
  264. int CLBAFile::Seek(int lba)
  265. {
  266. return (int)(CFile::Seek(2048i64*lba, CFile::begin)/2048);
  267. }
  268. bool CLBAFile::Read(BYTE* buff)
  269. {
  270. return CFile::Read(buff, 2048) == 2048;
  271. }
  272. //
  273. // CVobFile
  274. //
  275. CVobFile::CVobFile()
  276. {
  277. Close();
  278. }
  279. CVobFile::~CVobFile()
  280. {
  281. }
  282. bool CVobFile::IsDVD()
  283. {
  284. return m_fDVD;
  285. }
  286. bool CVobFile::HasDiscKey(BYTE* key)
  287. {
  288. if(key) memcpy(key, m_DiscKey, 5);
  289. return m_fHasDiscKey;
  290. }
  291. bool CVobFile::HasTitleKey(BYTE* key)
  292. {
  293. if(key) memcpy(key, m_TitleKey, 5);
  294. return m_fHasTitleKey;
  295. }
  296. bool CVobFile::Open(CString fn, CList<CString>& vobs)
  297. {
  298. CFile f;
  299. if(!f.Open(fn, CFile::modeRead|CFile::typeBinary|CFile::shareDenyWrite))
  300. return(false);
  301. char hdr[13];
  302. f.Read(hdr, 12);
  303. hdr[12] = 0;
  304. if(strcmp(hdr, "DVDVIDEO-VTS"))
  305. return(false);
  306. f.Close();
  307. int offset = -1;
  308. vobs.RemoveAll();
  309. fn = fn.Left(fn.ReverseFind('.')+1);
  310. fn.TrimRight(_T(".0123456789"));
  311. for(int i = 0; i < 100; i++)
  312. {
  313. CString vob;
  314. vob.Format(_T("%s%d.vob"), fn, i);
  315. CFileStatus status;
  316. if(!CFile::GetStatus(vob, status))
  317. {
  318. if(i == 0) continue;
  319. else break;
  320. }
  321. if(status.m_size&0x7ff)
  322. {
  323. vobs.RemoveAll();
  324. break;
  325. }
  326. if(status.m_size > 0)
  327. vobs.AddTail(vob);
  328. if(i == 0)
  329. offset = (int)(status.m_size/0x800);
  330. }
  331. return Open(vobs, offset);
  332. }
  333. bool CVobFile::Open(CList<CString>& vobs, int offset)
  334. {
  335. Close();
  336. if(vobs.GetCount() == 0)
  337. return(false);
  338. if(vobs.GetCount() == 1)
  339. offset = -1;
  340. m_offset = offset;
  341. POSITION pos = vobs.GetHeadPosition();
  342. while(pos)
  343. {
  344. CString fn = vobs.GetNext(pos);
  345. WIN32_FIND_DATA fd;
  346. HANDLE h = FindFirstFile(fn, &fd);
  347. if(h == INVALID_HANDLE_VALUE)
  348. {
  349. m_files.RemoveAll();
  350. return(false);
  351. }
  352. FindClose(h);
  353. file_t f;
  354. f.fn = fn;
  355. f.size = (int)(((__int64(fd.nFileSizeHigh)<<32)|fd.nFileSizeLow)/2048);
  356. m_files.Add(f);
  357. m_size += f.size;
  358. }
  359. if(m_files.GetCount() > 0 && CDVDSession::Open(m_files[0].fn))
  360. {
  361. for(int i = 0; !m_fHasTitleKey && i < m_files.GetCount(); i++)
  362. {
  363. if(BeginSession())
  364. {
  365. m_fDVD = true;
  366. Authenticate();
  367. m_fHasDiscKey = GetDiscKey();
  368. EndSession();
  369. }
  370. else
  371. {
  372. CString fn = m_files[0].fn;
  373. fn.MakeLower();
  374. if(fn.Find(_T(":\video_ts")) == 1 && GetDriveType(fn.Left(3)) == DRIVE_CDROM)
  375. {
  376. m_fDVD = true;
  377. }
  378. break;
  379. }
  380. if(tp_udf_file f = udf_find_file(m_hDrive, 0, CStringA(m_files[i].fn.Mid(m_files[i].fn.Find(':')+1))))
  381. {
  382. DWORD start, end;
  383. if(udf_get_lba(m_hDrive, f, &start, &end))
  384. {
  385. if(BeginSession())
  386. {
  387. Authenticate();
  388. m_fHasTitleKey = GetTitleKey(start + f->partition_lba, m_TitleKey);
  389. EndSession();
  390. }
  391. }
  392. udf_free(f);
  393. }
  394. BYTE key[5];
  395. if(HasTitleKey(key) && i == 0 && offset >= 0)
  396. {
  397. i++;
  398. if(BeginSession())
  399. {
  400. m_fDVD = true;
  401. Authenticate();
  402. m_fHasDiscKey = GetDiscKey();
  403. EndSession();
  404. }
  405. else
  406. {
  407. break;
  408. }
  409. if(tp_udf_file f = udf_find_file(m_hDrive, 0, CStringA(m_files[i].fn.Mid(m_files[i].fn.Find(':')+1))))
  410. {
  411. DWORD start, end;
  412. if(udf_get_lba(m_hDrive, f, &start, &end))
  413. {
  414. if(BeginSession())
  415. {
  416. Authenticate();
  417. m_fHasTitleKey = GetTitleKey(start + f->partition_lba, m_TitleKey);
  418. EndSession();
  419. }
  420. }
  421. udf_free(f);
  422. }
  423. if(!m_fHasTitleKey)
  424. {
  425. memcpy(m_TitleKey, key, 5);
  426. m_fHasTitleKey = true;
  427. }
  428. }
  429. }
  430. }
  431. /*
  432. if(m_files.GetCount() > 0 && !m_fDVD)
  433. {
  434. CString fn = m_files[0].fn;
  435. fn.MakeLower();
  436. if(fn.Find(_T(":\video_ts")) == 1 && GetDriveType(fn.Left(3)) == DRIVE_CDROM)
  437. {
  438. m_fDVD = true;
  439. }
  440. }
  441. */
  442. m_offset = max(offset, 0);
  443. return(true);
  444. }
  445. void CVobFile::Close()
  446. {
  447. CDVDSession::Close();
  448. m_files.RemoveAll();
  449. m_iFile = -1;
  450. m_pos = m_size = m_offset = 0;
  451. m_file.Close();
  452. m_fDVD = m_fHasDiscKey = m_fHasTitleKey = false;
  453. }
  454. int CVobFile::GetLength()
  455. {
  456. return(m_size - m_offset);
  457. }
  458. int CVobFile::GetPosition()
  459. {
  460. return(m_pos - m_offset);
  461. }
  462. int CVobFile::Seek(int pos)
  463. {
  464. pos = min(max(pos+m_offset, m_offset), m_size-1);
  465. int i = -1;
  466. int size = 0;
  467. // this suxx, but won't take long
  468. do size += m_files[++i].size;
  469. while(i < m_files.GetSize() && pos >= size);
  470. if(i != m_iFile && i < m_files.GetSize())
  471. {
  472. if(!m_file.Open(m_files[i].fn))
  473. return(m_pos);
  474. m_iFile = i;
  475. }
  476. m_pos = pos;
  477. pos -= (size - m_files[i].size);
  478. m_file.Seek(pos);
  479. return(GetPosition());
  480. }
  481. bool CVobFile::Read(BYTE* buff)
  482. {
  483. if(m_pos >= m_size) return(false);
  484. if(m_file.IsOpen() && m_file.GetPosition() == m_file.GetLength())
  485. {
  486. m_file.Close();
  487. }
  488. if(!m_file.IsOpen())
  489. {
  490. if(m_iFile >= m_files.GetSize()-1)
  491. {
  492. return(false);
  493. }
  494. if(!m_file.Open(m_files[++m_iFile].fn))
  495. {
  496. m_iFile = -1; 
  497. return(false);
  498. }
  499. }
  500. if(!m_file.Read(buff))
  501. {
  502. // dvd still locked?
  503. return(false);
  504. }
  505. m_pos++;
  506. if(buff[0x14] & 0x30)
  507. {
  508. if(m_fHasTitleKey)
  509. {
  510. CSSdescramble(buff, m_TitleKey);
  511. buff[0x14] &= ~0x30;
  512. }
  513. else
  514. {
  515. // under win9x this is normal, but I'm not developing under win9x :P
  516. ASSERT(0);
  517. }
  518. }
  519. return(true);
  520. }