diff --git a/DumpDVD/Dvd/DvdRipper.cpp b/DumpDVD/Dvd/DvdRipper.cpp index ebc0ad1..fc6dfa5 100644 --- a/DumpDVD/Dvd/DvdRipper.cpp +++ b/DumpDVD/Dvd/DvdRipper.cpp @@ -1,4 +1,5 @@ #include "DvdRipper.hpp" +#include #include #include @@ -15,16 +16,10 @@ namespace Li::Dvd { uint32_t DvdRipper::FileSoFar() { - if (this->inFile) - return this->fileReadSoFar; - else - return this->nonFileReadSoFar; + return this->fileReadSoFar; } uint32_t DvdRipper::FileLen() { - if (this->inFile) - return this->fileRemain; - else - return this->nonFileRemain; + return this->fileRemain; } float DvdRipper::PercentDone() { @@ -33,13 +28,18 @@ namespace Li::Dvd { uint32_t DvdRipper::SectorsReadSoFar() { return this->sectorsReadSoFar; } - uint32_t DvdRipper::FileReadSoFar() { - return this->fileReadSoFar; - } std::string DvdRipper::OutputPath() { return this->outputPath; } + std::byte* DvdRipper::GetDiscKey() { + return this->discKey; + } + + std::byte* DvdRipper::GetTitleKey() { + return this->titleKey; + } + bool DvdRipper::Done() { return this->done; } @@ -49,102 +49,96 @@ namespace Li::Dvd { std::string DvdRipper::ErrorMessage() { return this->errorMsg; } - int DvdRipper::read1SectorATimeSkippingBadSectors(int toRead) { - memset(this->tmpBuffer, 0x00, this->sectorsAtOnce * DVDCSS_BLOCK_SIZE); + int DvdRipper::read1SectorATimeSkippingBadSectors(int toRead) { int nmRd = 0; for (int i = 0; i < toRead; i++) { for (int retry = 0; retry < 10; retry++) { - int dataRd = dvdcss_read(driveIoCtl->GetDvdCssHandle(), this->tmpBuffer + (i * DVDCSS_BLOCK_SIZE), 1, DVDCSS_READ_DECRYPT); + memset(this->tmpBuffer, 0x00, DVDCSS_BLOCK_SIZE); + int dataRd = dvdcss_read(driveIoCtl->GetDvdCssHandle(), this->tmpBuffer, 1, DVDCSS_READ_DECRYPT); if (dataRd < 0) { + dvdcss_seek(driveIoCtl->GetDvdCssHandle(), this->sectorsReadSoFar, DVDCSS_SEEK_KEY); + + if (retry+1 >= 10) + dvdcss_seek(driveIoCtl->GetDvdCssHandle(), this->sectorsReadSoFar + 1, DVDCSS_SEEK_KEY); + continue; // retry } + else { + this->iso->write((const char*)this->tmpBuffer, DVDCSS_BLOCK_SIZE * dataRd); + break; + } } nmRd += 1; + this->sectorsReadSoFar += 1; + this->fileReadSoFar += 1; + + if (this->sectorsReadSoFar > this->drive->Sectors()) // check if we've read the last sector ... + break; } return nmRd; } - void DvdRipper::readNonFileSectors() { - dvdcss_title(this->driveIoCtl->GetDvdCssHandle(), this->sectorsReadSoFar); - - this->nonFileRemain = Li::Dvd::TitleKey::GetDistanceToNextFile(this->sectorsReadSoFar); - if (this->nonFileRemain == (uint32_t)-1) { - this->nonFileRemain = (this->drive->Sectors() - this->sectorsReadSoFar); - } - if ((this->sectorsReadSoFar + this->nonFileRemain) > this->drive->Sectors()) { - this->nonFileRemain = (this->drive->Sectors() - this->sectorsReadSoFar); - } - this->nonFileReadSoFar = 0; + void DvdRipper::readSectors() { do { int toRead = this->sectorsAtOnce; - if ((this->nonFileReadSoFar + toRead) > this->nonFileRemain) { - toRead = this->nonFileRemain - this->nonFileReadSoFar; + if ((this->fileReadSoFar + toRead) > this->fileRemain) { + toRead = (this->fileRemain - this->fileReadSoFar); } + int numRead = dvdcss_read(driveIoCtl->GetDvdCssHandle(), this->tmpBuffer, toRead, DVDCSS_READ_DECRYPT); if (dvdcss_was_error(driveIoCtl->GetDvdCssHandle())) { this->errorMsg = std::string(dvdcss_error(driveIoCtl->GetDvdCssHandle())); } if (numRead < 0) { - dvdcss_seek(driveIoCtl->GetDvdCssHandle(), this->sectorsAtOnce, DVDCSS_SEEK_MPEG); - numRead = read1SectorATimeSkippingBadSectors(toRead); + dvdcss_seek(driveIoCtl->GetDvdCssHandle(), this->sectorsReadSoFar, DVDCSS_SEEK_KEY); + read1SectorATimeSkippingBadSectors(toRead); } - - this->iso->write((const char*)this->tmpBuffer, DVDCSS_BLOCK_SIZE * numRead); - - this->sectorsReadSoFar += numRead; - this->nonFileReadSoFar += numRead; - - } while (this->nonFileReadSoFar < this->nonFileRemain && this->keepRunning); + else { + this->iso->write((const char*)this->tmpBuffer, DVDCSS_BLOCK_SIZE * numRead); + this->sectorsReadSoFar += numRead; + this->fileReadSoFar += numRead; + } + } while ( (this->fileReadSoFar < this->fileRemain) && + (this->sectorsReadSoFar < this->drive->Sectors()) && + this->keepRunning); this->inFile = Li::Dvd::TitleKey::IsSectorInFile(this->sectorsReadSoFar); this->fileReadSoFar = 0; - this->nonFileReadSoFar = 0; + this->fileRemain = 0; } - void DvdRipper::readFileSectors() { + void DvdRipper::readNonFileSectors() { dvdcss_title(this->driveIoCtl->GetDvdCssHandle(), this->sectorsReadSoFar); + this->fileRemain = Li::Dvd::TitleKey::GetDistanceToNextFile(this->sectorsReadSoFar); - sectorInfo* sectorInf = Li::Dvd::TitleKey::GetSectorInfo(this->sectorsReadSoFar); - this->fileRemain = (sectorInf->endSector - sectorInf->startSector); - if ((this->sectorsReadSoFar + this->fileRemain) > this->drive->Sectors()) { this->fileRemain = (this->drive->Sectors() - this->sectorsReadSoFar); } this->fileReadSoFar = 0; - do { - int toRead = this->sectorsAtOnce; - if ((this->fileReadSoFar + toRead) > this->fileRemain) { - toRead = this->fileRemain - this->fileReadSoFar; - } - int numRead = dvdcss_read(driveIoCtl->GetDvdCssHandle(), this->tmpBuffer, toRead, DVDCSS_READ_DECRYPT); - - if (dvdcss_was_error(driveIoCtl->GetDvdCssHandle())) { - this->errorMsg = std::string(dvdcss_error(driveIoCtl->GetDvdCssHandle())); - } - if (numRead <= 0) { - numRead = read1SectorATimeSkippingBadSectors(toRead); - } + this->readSectors(); + } - iso->write((const char*)this->tmpBuffer, DVDCSS_BLOCK_SIZE * numRead); + void DvdRipper::readFileSectors() { + dvdcss_title(this->driveIoCtl->GetDvdCssHandle(), this->sectorsReadSoFar); + this->titleKey = (std::byte*)dvdcss_get_cur_titlekey(this->driveIoCtl->GetDvdCssHandle()); + sectorInfo* sectorInf = Li::Dvd::TitleKey::GetSectorInfo(this->sectorsReadSoFar); + this->fileRemain = (sectorInf->endSector - sectorInf->startSector); - this->sectorsReadSoFar += numRead; - this->fileReadSoFar += numRead; + if ((this->sectorsReadSoFar + this->fileRemain) > this->drive->Sectors()) { + this->fileRemain = (this->drive->Sectors() - this->sectorsReadSoFar); + } - } while ((this->fileReadSoFar < this->fileRemain) && this->keepRunning); - - this->inFile = Li::Dvd::TitleKey::IsSectorInFile(this->sectorsReadSoFar); this->fileReadSoFar = 0; - this->nonFileReadSoFar = 0; + + this->readSectors(); } void DvdRipper::ripThread() { - - this->sectorsReadSoFar = 0; Li::Dvd::TitleKey::GetTitleKeys(driveIoCtl->GetDvdCssHandle()); @@ -153,9 +147,9 @@ namespace Li::Dvd { do { if (this->inFile) - this->readFileSectors(); + this->readFileSectors(); // read & decrypt all files (including those associated w the filesystem) else - this->readNonFileSectors(); + this->readNonFileSectors(); // read the data not associated with any file on the filesystem. } while (this->sectorsReadSoFar < this->drive->Sectors() && this->keepRunning); @@ -172,9 +166,6 @@ namespace Li::Dvd { this->fileReadSoFar = 0; this->fileRemain = 0; - this->nonFileReadSoFar = 0; - this->nonFileRemain = 0; - this->inFile = false; this->done = false; this->error = false; @@ -182,7 +173,8 @@ namespace Li::Dvd { this->keepRunning = false; this->ripinThread = nullptr; - this->tmpBuffer = new uint8_t[DVDCSS_BLOCK_SIZE * this->sectorsAtOnce]; + this->tmpBuffer = new std::byte[DVDCSS_BLOCK_SIZE * this->sectorsAtOnce]; + } DvdRipper::~DvdRipper() { @@ -204,6 +196,11 @@ namespace Li::Dvd { 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->iso = new std::ofstream(this->outputPath, std::ios::binary); this->keepRunning = true; diff --git a/DumpDVD/Dvd/DvdRipper.hpp b/DumpDVD/Dvd/DvdRipper.hpp index 32b23ec..88f5378 100644 --- a/DumpDVD/Dvd/DvdRipper.hpp +++ b/DumpDVD/Dvd/DvdRipper.hpp @@ -20,10 +20,6 @@ namespace Li::Dvd { uint32_t fileReadSoFar; uint32_t fileRemain; - uint32_t nonFileReadSoFar; - uint32_t nonFileRemain; - - uint32_t sectorsAtOnce; uint32_t sectorsReadSoFar; @@ -33,26 +29,33 @@ namespace Li::Dvd { bool keepRunning; std::ofstream* iso; - uint8_t* tmpBuffer; - + std::byte* tmpBuffer; + + std::byte* titleKey; + std::byte* discKey; + Li::Scsi::IoCtl* driveIoCtl; Li::Scsi::OpticalDrive* drive; void ripThread(); void readNonFileSectors(); void readFileSectors(); + + void readSectors(); int read1SectorATimeSkippingBadSectors(int toRead); public: DvdRipper(Li::Scsi::OpticalDrive* opticalDrive, std::string outputISO, uint32_t sectorsAtOnce); ~DvdRipper(); uint32_t SectorsReadSoFar(); - uint32_t FileReadSoFar(); float PercentDone(); std::string OutputPath(); uint32_t FileSoFar(); uint32_t FileLen(); + std::byte* GetTitleKey(); + std::byte* GetDiscKey(); + bool Done(); bool Error(); std::string ErrorMessage(); diff --git a/DumpDVD/Dvd/TitleKey.cpp b/DumpDVD/Dvd/TitleKey.cpp index 77c4721..b6860c2 100644 --- a/DumpDVD/Dvd/TitleKey.cpp +++ b/DumpDVD/Dvd/TitleKey.cpp @@ -29,12 +29,12 @@ namespace Li::Dvd { uint32_t TitleKey::GetDistanceToNextFile(uint32_t currentSector) { - uint32_t lowestDistance = -1; + uint32_t lowestDistance = 0xFFFFFFFF; for (sectorInfo* inf : sectorsList) { if (currentSector >= inf->startSector && currentSector < inf->endSector) return 0; - uint32_t distance = inf->startSector - currentSector; + int32_t distance = (inf->startSector - currentSector); if (distance < 0) continue; if (distance < lowestDistance) { @@ -69,18 +69,34 @@ 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); } - else if (TitleKey::GetSectorInfo(*(uint32_t*)dent->size.le) == nullptr) { + else if (TitleKey::GetSectorInfo(cSector) == nullptr) { sectorInfo* file = new sectorInfo(); + file->startSector = cSector; - file->startSector = *(uint32_t*)dent->sector.le; - file->endSector = file->startSector + (*(uint32_t*)dent->size.le / DVDCSS_BLOCK_SIZE); + dvdcss_title(drv, file->startSector); + char* titleKey = dvdcss_get_cur_titlekey(drv); - sectorsList.push_back(file); + // check title is encrypted ... + if (memcmp(titleKey, "\0\0\0\0\0", 5)) { + // Round to sector boundary + uint32_t sz = (*(uint32_t*)dent->size.le); + if((sz % DVDCSS_BLOCK_SIZE) != 0) + sz += (DVDCSS_BLOCK_SIZE - (sz % DVDCSS_BLOCK_SIZE)); + file->endSector = (file->startSector + (sz / DVDCSS_BLOCK_SIZE)); + + sectorsList.push_back(file); + } + else { + delete file; + } } } diff --git a/DumpDVD/Gui/DumpDVD.cpp b/DumpDVD/Gui/DumpDVD.cpp index a6e264b..fd7154c 100644 --- a/DumpDVD/Gui/DumpDVD.cpp +++ b/DumpDVD/Gui/DumpDVD.cpp @@ -147,12 +147,24 @@ 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->FileReadSoFar(), this->dvdRipper->FileLen()); + 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)"); + + 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]); + + ImGui::SeparatorText("Output"); ImGui::Text("Output file: \"%s\"", this->outputFile); diff --git a/lib/libdvdcss.lib b/lib/libdvdcss.lib index 0af46a1..53a5d1e 100644 Binary files a/lib/libdvdcss.lib and b/lib/libdvdcss.lib differ diff --git a/libdvdcss/src/dvdcss/dvdcss.h b/libdvdcss/src/dvdcss/dvdcss.h index a38b1ad..7cb3604 100644 --- a/libdvdcss/src/dvdcss/dvdcss.h +++ b/libdvdcss/src/dvdcss/dvdcss.h @@ -106,6 +106,8 @@ LIBDVDCSS_EXPORT const char *dvdcss_error ( const dvdcss_t ); LIBDVDCSS_EXPORT int dvdcss_is_scrambled ( dvdcss_t ); +LIBDVDCSS_EXPORT char* dvdcss_get_cur_disckey(dvdcss_t dvdcss); +LIBDVDCSS_EXPORT char* dvdcss_get_cur_titlekey(dvdcss_t dvdcss); LIBDVDCSS_EXPORT int dvdcss_title(dvdcss_t dvdcss, int i_block); LIBDVDCSS_EXPORT int dvdcss_get_raw_fd(dvdcss_t); LIBDVDCSS_EXPORT int dvdcss_was_error(dvdcss_t); diff --git a/libdvdcss/src/libdvdcss.c b/libdvdcss/src/libdvdcss.c index 063d7dc..627fcc6 100644 --- a/libdvdcss/src/libdvdcss.c +++ b/libdvdcss/src/libdvdcss.c @@ -486,7 +486,16 @@ static void init_cache( dvdcss_t dvdcss ) /* If the cache is enabled, create a DVD-specific subdirectory. */ create_cache_subdir( dvdcss ); } -int dvdcss_was_error_common(dvdcss_t drive) { + +LIBDVDCSS_EXPORT char* dvdcss_get_cur_disckey(dvdcss_t dvdcss) { + return dvdcss->css.p_disc_key; +} +LIBDVDCSS_EXPORT char* dvdcss_get_cur_titlekey(dvdcss_t dvdcss) { + return dvdcss->css.p_title_key; +} + +LIBDVDCSS_EXPORT int dvdcss_was_error(dvdcss_t drive) +{ if (drive->b_errors) { drive->b_errors = FALSE; @@ -495,18 +504,9 @@ int dvdcss_was_error_common(dvdcss_t drive) { return FALSE; } -int dvdcss_get_fd_common(dvdcss_t drive) { - return drive->i_fd; -} - -LIBDVDCSS_EXPORT int dvdcss_was_error(dvdcss_t drive) -{ - return dvdcss_was_error_common(drive); -} - LIBDVDCSS_EXPORT int dvdcss_get_raw_fd(dvdcss_t drive) { - return dvdcss_get_fd_common(drive); + return drive->i_fd; } /**