Fix stuff

This commit is contained in:
Li 2023-03-17 21:23:19 +13:00
parent f83e7addef
commit ab8bd004fd
12 changed files with 231 additions and 66 deletions

View File

@ -33,13 +33,17 @@ namespace Li::Dvd {
}
std::byte* DvdRipper::GetDiscKey() {
return this->discKey;
return this->drive->DiscKey();
}
std::byte* DvdRipper::GetTitleKey() {
return this->titleKey;
}
bool DvdRipper::Decrypt() {
return this->decrypt;
}
bool DvdRipper::Done() {
return this->done;
}
@ -54,12 +58,12 @@ namespace Li::Dvd {
for (int i = 0; i < toRead; i++) {
for (int retry = 0; retry < 10; retry++) {
memset(this->tmpBuffer, 0x00, DVDCSS_BLOCK_SIZE);
int dataRd = dvdcss_read(driveIoCtl->GetDvdCssHandle(), this->tmpBuffer, 1, DVDCSS_READ_DECRYPT);
int dataRd = dvdcss_read(driveIoCtl->GetDvdCssHandle(), this->tmpBuffer, 1, (this->decrypt ? DVDCSS_READ_DECRYPT : DVDCSS_NOFLAGS));
if (dataRd < 0) {
dvdcss_seek(driveIoCtl->GetDvdCssHandle(), this->sectorsReadSoFar, DVDCSS_SEEK_KEY);
dvdcss_seek(driveIoCtl->GetDvdCssHandle(), this->sectorsReadSoFar, (this->decrypt ? DVDCSS_SEEK_KEY : DVDCSS_NOFLAGS) );
if (retry+1 >= 10)
dvdcss_seek(driveIoCtl->GetDvdCssHandle(), this->sectorsReadSoFar + 1, DVDCSS_SEEK_KEY);
dvdcss_seek(driveIoCtl->GetDvdCssHandle(), this->sectorsReadSoFar + 1, (this->decrypt ? DVDCSS_SEEK_KEY : DVDCSS_NOFLAGS));
continue; // retry
}
@ -80,7 +84,7 @@ namespace Li::Dvd {
}
void DvdRipper::readSectors() {
void DvdRipper::readCssSectors() {
do {
int toRead = this->sectorsAtOnce;
if ((this->fileReadSoFar + toRead) > this->fileRemain) {
@ -120,7 +124,7 @@ namespace Li::Dvd {
this->fileReadSoFar = 0;
this->readSectors();
this->readCssSectors();
}
void DvdRipper::readFileSectors() {
@ -135,21 +139,63 @@ namespace Li::Dvd {
this->fileReadSoFar = 0;
this->readSectors();
this->readCssSectors();
}
void DvdRipper::readUnprotectedSectors() {
do {
int toRead = this->sectorsAtOnce;
if ((this->sectorsReadSoFar + toRead) > this->drive->Sectors()) {
toRead = this->drive->Sectors() - this->sectorsReadSoFar;
}
int numRead = dvdcss_read(this->driveIoCtl->GetDvdCssHandle(), this->tmpBuffer, toRead, DVDCSS_NOFLAGS);
if (dvdcss_was_error(driveIoCtl->GetDvdCssHandle())) {
this->errorMsg = std::string(dvdcss_error(driveIoCtl->GetDvdCssHandle()));
}
if (numRead < 0) { // Handle bad sectors
dvdcss_seek(driveIoCtl->GetDvdCssHandle(), this->sectorsReadSoFar, DVDCSS_NOFLAGS);
read1SectorATimeSkippingBadSectors(toRead);
}
else {
this->iso->write((const char*)this->tmpBuffer, DVDCSS_BLOCK_SIZE * numRead);
this->sectorsReadSoFar += numRead;
this->fileReadSoFar += numRead;
}
} while (this->sectorsReadSoFar < this->drive->Sectors() && this->keepRunning);
}
void DvdRipper::ripThread() {
this->sectorsReadSoFar = 0;
Li::Dvd::TitleKey::GetTitleKeys(driveIoCtl->GetDvdCssHandle());
dvdcss_seek(driveIoCtl->GetDvdCssHandle(), 0, DVDCSS_SEEK_KEY);
this->inFile = Li::Dvd::TitleKey::IsSectorInFile(this->sectorsReadSoFar);
// due to how libdvdcss works, you can only actually decrypt a dvd sector
// if you seek directly at it or call dvdcss_title on the sector containing the start of the encrypted title file
// so, i have to actually parse the disc file system, in order to find all those
//
if (this->decrypt) {
Li::Dvd::TitleKey::FindTitleKeys(driveIoCtl->GetDvdCssHandle());
dvdcss_seek(driveIoCtl->GetDvdCssHandle(), 0, DVDCSS_SEEK_KEY);
this->inFile = Li::Dvd::TitleKey::IsSectorInFile(this->sectorsReadSoFar);
}
do {
if (this->inFile)
this->readFileSectors(); // read & decrypt all files (including those associated w the filesystem)
else
this->readNonFileSectors(); // read the data not associated with any file on the filesystem.
if (this->decrypt) {
if (this->inFile) {
// read & decrypt all files (including those associated w the filesystem)
this->readFileSectors();
}
else {
// read the data not associated with any file on the filesystem.
this->readNonFileSectors();
}
}
else {
// for non scrambled dvds, just read every sector one after another.
this->readUnprotectedSectors();
}
} while (this->sectorsReadSoFar < this->drive->Sectors() && this->keepRunning);
@ -190,16 +236,22 @@ namespace Li::Dvd {
}
}
void DvdRipper::StartRip(uint32_t driveSpeed) {
void DvdRipper::StartRip(uint32_t driveSpeed, bool cssDecrypt) {
this->driveIoCtl = new Li::Scsi::IoCtl(this->drive->DrivePath());
this->driveIoCtl->AllowReadingPastDisc();
this->driveIoCtl->SetDriveSpeed(driveSpeed, driveSpeed);
this->driveIoCtl->ExclusiveLockDrive();
this->discKey = (std::byte*)dvdcss_get_cur_disckey(this->driveIoCtl->GetDvdCssHandle());
dvdcss_title(this->driveIoCtl->GetDvdCssHandle(), 0);
this->titleKey = (std::byte*)dvdcss_get_cur_titlekey(this->driveIoCtl->GetDvdCssHandle());
this->decrypt = cssDecrypt;
if (!dvdcss_is_scrambled(this->driveIoCtl->GetDvdCssHandle())) {
this->decrypt = false;
}
if (this->decrypt) {
dvdcss_title(this->driveIoCtl->GetDvdCssHandle(), 0);
this->titleKey = (std::byte*)dvdcss_get_cur_titlekey(this->driveIoCtl->GetDvdCssHandle());
}
this->iso = new std::ofstream(this->outputPath, std::ios::binary);
this->keepRunning = true;

View File

@ -27,12 +27,12 @@ namespace Li::Dvd {
std::thread* ripinThread;
bool keepRunning;
bool decrypt;
std::ofstream* iso;
std::byte* tmpBuffer;
std::byte* titleKey;
std::byte* discKey;
Li::Scsi::IoCtl* driveIoCtl;
Li::Scsi::OpticalDrive* drive;
@ -40,7 +40,9 @@ namespace Li::Dvd {
void readNonFileSectors();
void readFileSectors();
void readSectors();
void readUnprotectedSectors();
void readCssSectors();
int read1SectorATimeSkippingBadSectors(int toRead);
public:
DvdRipper(Li::Scsi::OpticalDrive* opticalDrive, std::string outputISO, uint32_t sectorsAtOnce);
@ -53,6 +55,7 @@ namespace Li::Dvd {
uint32_t FileSoFar();
uint32_t FileLen();
bool Decrypt();
std::byte* GetTitleKey();
std::byte* GetDiscKey();
@ -60,7 +63,7 @@ namespace Li::Dvd {
bool Error();
std::string ErrorMessage();
void StartRip(uint32_t driveSpeed);
void StartRip(uint32_t driveSpeed, bool decryptCss);
void EndRip();
};
}

View File

@ -11,6 +11,8 @@ namespace Li::Dvd {
static std::vector<sectorInfo*> sectorsList;
static dvdcss_t drv;
static int depth = 0;
bool TitleKey::readSector(l9660_fs* fs, void* buf, uint32_t sector) {
dvdcss_seek(drv, sector, DVDCSS_SEEK_KEY);
@ -58,10 +60,16 @@ namespace Li::Dvd {
}
void readDir(l9660_dir* dir) {
while (true) {
bool TitleKey::readDir(l9660_dir* dir, int depth=0) {
if (depth > 10) return false;
bool success = true;
for(int cnt = 0; cnt < 90000; ++cnt) {
if (cnt >= 90000) return false;
l9660_dirent* dent;
l9660_status status = l9660_readdir(dir, &dent);
if (l9660_readdir(dir, &dent) != L9660_OK) return false;
if (dent == nullptr)
break;
@ -69,13 +77,12 @@ namespace Li::Dvd {
if (dent->name_len < 2)
continue;
uint32_t cSector = *(uint32_t*)dent->sector.le;
if ((dent->flags & DENT_ISDIR) != 0) {
l9660_dir ndir;
l9660_opendirat(&ndir, dir, dent->name);
readDir(&ndir);
if (l9660_opendirat(&ndir, dir, dent->name) != L9660_OK) return false;
success = readDir(&ndir, depth + 1);
}
else if (TitleKey::GetSectorInfo(cSector) == nullptr) {
sectorInfo* file = new sectorInfo();
@ -98,11 +105,14 @@ namespace Li::Dvd {
delete file;
}
}
}
return success;
}
std::vector<sectorInfo*> TitleKey::GetTitleKeys(dvdcss_t drive) {
bool TitleKey::FindTitleKeys(dvdcss_t drive) {
drv = drive;
sectorsList = std::vector<sectorInfo*>();
@ -110,11 +120,13 @@ namespace Li::Dvd {
l9660_fs isoFs;
l9660_status status;
status = l9660_openfs(&isoFs, TitleKey::readSector);
status = l9660_fs_open_root(&rootDir, &isoFs);
readDir(&rootDir);
if (l9660_openfs(&isoFs, TitleKey::readSector) == L9660_OK) {
if (l9660_fs_open_root(&rootDir, &isoFs) == L9660_OK) {
return TitleKey::readDir(&rootDir);
}
}
return sectorsList;
return false;
}
void TitleKey::FreeMemory() {

View File

@ -13,8 +13,9 @@ namespace Li::Dvd {
class TitleKey {
private:
static bool readSector(l9660_fs* fs, void* buf, uint32_t sector);
static bool readDir(l9660_dir* dir, int depth);
public:
static std::vector<sectorInfo*> GetTitleKeys(dvdcss_t drive);
static bool FindTitleKeys(dvdcss_t drive);
static uint32_t GetDistanceToNextFile(uint32_t currentSector);
static bool IsSectorInFile(uint32_t currentSector);
static sectorInfo* GetSectorInfo(uint32_t currentSector);

View File

@ -1,14 +1,7 @@
#include "DumpDVD.hpp"
#include <imgui.h>
#include <SDL.h>
#ifdef _WIN32
#include <Windows.h>
#include <shlobj.h>
#endif
#include <portable-file-dialogs.h>
#include <mutex>
#include <thread>
#include <filesystem>
@ -63,6 +56,10 @@ namespace Li::Gui {
this->lock->lock();
this->freeOldDriveList();
this->drivesList = pollDrives;
if (this->selectedDrive >= this->drivesList->size())
this->reset();
this->lock->unlock();
}
@ -84,21 +81,17 @@ namespace Li::Gui {
}
void DumpDVD::reset() {
if (this->GetCurrentSelectedDrive()->DiscInDrive())
if (this->GetCurrentSelectedDrive()->DiscInDrive()) {
this->selectedDriveSpeed = this->GetCurrentSelectedDrive()->SupportedSpeeds()->size();
else
if (this->GetCurrentSelectedDrive()->HasCss()) {
this->decrypt = true;
}
}
else {
this->selectedDriveSpeed = 0;
}
std::string documentsFolder = "";
#ifdef _WIN32
WCHAR documents[MAX_PATH];
HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documents);
std::wstring wDocuments = std::wstring(documents);
documentsFolder = std::string(wDocuments.begin(), wDocuments.end());
#endif
std::filesystem::path p = std::filesystem::path(documentsFolder);
std::filesystem::path p = std::filesystem::path(Utils::GetDocumentsFolder());
p = p.append(GetCurrentSelectedDrive()->VolumeName()).replace_extension(".iso");
strncpy(this->outputFile, p.string().c_str(), sizeof(DumpDVD::outputFile)-1);
}
@ -120,7 +113,7 @@ namespace Li::Gui {
}
this->dvdRipper = new Li::Dvd::DvdRipper(this->GetCurrentSelectedDrive(), std::string(this->outputFile), this->sectorsAtOnce);
this->dvdRipper->StartRip(speed);
this->dvdRipper->StartRip(speed, this->decrypt);
this->imRippinIt = true;
}
@ -147,24 +140,32 @@ namespace Li::Gui {
ImGui::ProgressBar(this->dvdRipper->PercentDone());
ImGui::Text("Sector %i / %i", this->dvdRipper->SectorsReadSoFar(), this->GetCurrentSelectedDrive()->Sectors());
ImGui::Text("File: %i / %i", this->dvdRipper->FileSoFar(), this->dvdRipper->FileLen());
uint64_t szSoFar = (uint64_t)(this->dvdRipper->SectorsReadSoFar()) * (uint64_t)(DVDCSS_BLOCK_SIZE);
uint64_t szTotal = (uint64_t)(this->GetCurrentSelectedDrive()->Sectors()) * (uint64_t)(DVDCSS_BLOCK_SIZE);
ImGui::Text("Total %s / %s", Utils::HumanReadableByteStr(szSoFar).c_str(), Utils::HumanReadableByteStr(szTotal).c_str());
ImGui::SeparatorText("Content Scrambling System (CSS)");
ImGui::SeparatorText("Copy Protection");
std::byte* discKey = this->dvdRipper->GetDiscKey();
std::byte* titleKey = this->dvdRipper->GetTitleKey();
if (discKey != nullptr)
ImGui::Text("Disc Key: %02X%02X%02X%02X%02X", discKey[0], discKey[1], discKey[2], discKey[3], discKey[4]);
if (titleKey != nullptr)
ImGui::Text("Title Key: %02X%02X%02X%02X%02X", titleKey[0], titleKey[1], titleKey[2], titleKey[3], titleKey[4]);
if (this->GetCurrentSelectedDrive()->HasCss()) {
ImGui::Text("Copy Protection: \"Content Scrambling System\" (CSS)");
ImGui::Text("Decrypt Enabled? %s", this->decrypt ? "Yes" : "No");
if (this->decrypt) {
std::byte* discKey = this->dvdRipper->GetDiscKey();
std::byte* titleKey = this->dvdRipper->GetTitleKey();
if (discKey != nullptr)
ImGui::Text("Disc Key: %02X%02X%02X%02X%02X", discKey[0], discKey[1], discKey[2], discKey[3], discKey[4]);
if (titleKey != nullptr)
ImGui::Text("Title Key: %02X%02X%02X%02X%02X", titleKey[0], titleKey[1], titleKey[2], titleKey[3], titleKey[4]);
}
}
else {
ImGui::Text("Copy Protection: None Detected.");
}
ImGui::SeparatorText("Output");
ImGui::Text("Output file: \"%s\"", this->outputFile);
@ -209,7 +210,6 @@ namespace Li::Gui {
this->reset();
}
if (!GetCurrentSelectedDrive()->DiscInDrive()) {
ImGui::Text("Put a disc in the drive to continue ...");
this->discInserted = false;
@ -248,6 +248,15 @@ namespace Li::Gui {
ImGui::InputInt("##bufferSize", &this->sectorsAtOnce, 1, 100);
if (this->sectorsAtOnce <= 0) this->sectorsAtOnce = 1;
ImGui::SeparatorText("Copy Protection");
if (this->GetCurrentSelectedDrive()->HasCss()) {
ImGui::Text("Copy Protection: \"Content Scrambling System\" (CSS)");
ImGui::Checkbox("Decrypt/Remove CSS", &this->decrypt);
}
else {
ImGui::Text("Copy Protection: None Detected.\n(This doesn't completely confirm there isn't any ...)");
}
ImGui::SeparatorText("Output");
ImGui::Text("Output file: ");

View File

@ -20,6 +20,7 @@ namespace Li::Gui {
std::mutex* lock;
int sectorsAtOnce;
bool decrypt;
bool discInserted;
int selectedDrive;
int selectedDriveSpeed;

View File

@ -1,9 +1,12 @@
#include "SDL.hpp"
#ifdef _WIN32
#include "D3D.hpp"
#include <windows.h>
#include <imgui_impl_dx11.h>
#endif
#include <SDL.h>
#include <imgui_impl_sdl2.h>
#include <imgui.h>
@ -14,7 +17,7 @@ namespace Li::Gui {
SDL::SDL(std::string windowTitle, int windowWidth, int windowHeight) {
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0)
{
std::cout << "Error: " << SDL_GetError() << std::endl;
std::cerr << "Error: " << SDL_GetError() << std::endl;
return;
}
@ -29,6 +32,8 @@ namespace Li::Gui {
#ifdef _WIN32
HWND hwnd = (HWND)this->wmInfo.info.win.window;
this->renderer = new D3D(hwnd);
#else
#error no renderer for this platform
#endif
IMGUI_CHECKVERSION();
@ -42,6 +47,8 @@ namespace Li::Gui {
#ifdef _WIN32
ImGui_ImplSDL2_InitForD3D(this->window);
this->renderer->InitImgui();
#else
#error No imgui renderer backend provided for this platform
#endif
isExiting = false;
}
@ -63,6 +70,8 @@ namespace Li::Gui {
#ifdef _WIN32
D3D* d3d = (D3D*)this->renderer;
d3d->Resize();
#else
#error No resize method provided for this platform
#endif
}
}

View File

@ -83,6 +83,9 @@ namespace Li::Scsi {
}
delete buffer;
#else
#error no way to get all supported read speeds on this platform
#endif
return speeds;
}
@ -98,6 +101,8 @@ namespace Li::Scsi {
std::cerr << "Error getting geometry: " << std::to_string(GetLastError()) << std::endl;
}
return (uint64_t)(geometry.DiskSize.QuadPart / DVDCSS_BLOCK_SIZE);
#else
#error no way to get total sector count of disc on this platform ..
#endif
}
bool IoCtl::AllowReadingPastDisc() {
@ -110,6 +115,8 @@ namespace Li::Scsi {
std::cerr << "Error enabling DASD I/O: " << std::to_string(GetLastError()) << std::endl;
}
return success;
#else
#error no way to disable bounds checks (DASHD) i/o on this platform (maybe not required?)
#endif
}
@ -121,6 +128,8 @@ namespace Li::Scsi {
std::cerr << "Error unmounting drive: " << std::to_string(GetLastError()) << std::endl;
}
return success;
#else
#error no way to unmount drive on this platform
#endif
}
@ -132,6 +141,8 @@ namespace Li::Scsi {
std::cerr << "Error mounting drive: " << std::to_string(GetLastError()) << std::endl;
}
return success;
#else
#error no way to mount drive on this platform
#endif
}
@ -154,6 +165,8 @@ namespace Li::Scsi {
std::cerr << "Error Locking the drive: " << std::to_string(GetLastError()) << std::endl;
}
return success;
#else
#error no way to exclusive lock drive on this platform.
#endif
}
@ -171,6 +184,8 @@ namespace Li::Scsi {
this->MountVolume();
return success;
#else
#error no way to exclusive unlock drive on this platform.
#endif
}
@ -191,6 +206,8 @@ namespace Li::Scsi {
std::cerr << "Error setting speed: " << std::to_string(GetLastError()) << std::endl;
}
return success;
#else
#error no way to set drive speed folder on this platform.
#endif
}

View File

@ -1,5 +1,6 @@
#include "OpticalDrive.hpp"
#include "IoCtl.hpp"
#include "SDL.h"
#ifdef _WIN32
#include <Windows.h>
@ -30,6 +31,8 @@ namespace Li::Scsi {
}
delete wChrVolumeName;
#else
#error no way to get optical drive information on this platform
#endif
}
@ -40,6 +43,15 @@ namespace Li::Scsi {
IoCtl* ctl = new IoCtl(this->drivePath);
this->supportedSpeeds = ctl->GetSupportedReadSpeeds();
this->sectors = ctl->GetTotalSectors();
this->hasCss = dvdcss_is_scrambled(ctl->GetDvdCssHandle());
if (this->hasCss) {
this->discKey = (std::byte*)dvdcss_get_cur_disckey(ctl->GetDvdCssHandle());
}
else {
this->discKey = nullptr;
}
delete ctl;
}
}
@ -60,6 +72,14 @@ namespace Li::Scsi {
return this->drivePath;
}
bool OpticalDrive::HasCss() {
return this->hasCss;
}
std::byte* OpticalDrive::DiscKey() {
return this->discKey;
}
uint32_t OpticalDrive::Sectors() {
return this->sectors;
}
@ -88,6 +108,20 @@ namespace Li::Scsi {
}
delete drivesList;
#else
/*
* Looks like SDL cdrom support got removed at some point .. oh well
*
// Use SDL
int numCdDrives = SDL_CDNumDrives();
for (int i = 0; i < numCdDrives; i++) {
OpticalDrive* opticalDrive = new OpticalDrive(SDL_CDName(i));
drives->push_back(opticalDrive);
}
*/
#error No way to list optical drives on this platform!
#endif
return drives;
}

View File

@ -8,6 +8,9 @@ namespace Li::Scsi {
std::string drivePath;
std::string volumeName;
bool hasCss;
std::byte* discKey;
bool discInDrive;
std::vector<uint32_t>* supportedSpeeds;
uint32_t sectors;
@ -21,6 +24,8 @@ namespace Li::Scsi {
std::string DrivePath();
std::string VolumeName();
uint32_t Sectors();
std::byte* DiscKey();
bool HasCss();
bool DiscInDrive();
static std::vector<OpticalDrive*>* ListOpticalDrives();

View File

@ -2,7 +2,28 @@
#include <iostream>
#include <string>
#ifdef _WIN32
#include <Windows.h>
#include <shlobj.h>
#endif
namespace Li {
std::string Utils::GetDocumentsFolder() {
std::string documentsFolder = "";
#ifdef _WIN32
WCHAR documents[MAX_PATH];
HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documents);
std::wstring wDocuments = std::wstring(documents);
documentsFolder = std::string(wDocuments.begin(), wDocuments.end());
#else
#error no way to find documents folder on this platform.
#endif
return documentsFolder;
}
bool Utils::CompareStringCaseInsensitive(std::string input, std::string compare) {
unsigned int sz = input.size();
if (compare.size() != sz)

View File

@ -3,6 +3,7 @@
namespace Li {
class Utils {
public:
static std::string GetDocumentsFolder();
static std::string HumanReadableByteStr(uint64_t bytes);
static bool CompareStringCaseInsensitive(std::string input, std::string compare);
};