diff --git a/.gitignore b/.gitignore
index 7c1d329..73a369b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,10 @@ libdvdcss/msvc/Debug/*
libdvdcss/msvc/Release/*
libdvdcss/msvc/.vs/*
+Lib9660/Release/*
+Lib9660/Debug/*
+
+
ImGui/Release/*
ImGui/Debug/*
diff --git a/DumpDVD.sln b/DumpDVD.sln
index 0eaebce..62d0753 100644
--- a/DumpDVD.sln
+++ b/DumpDVD.sln
@@ -4,29 +4,58 @@ Microsoft Visual Studio Solution File, Format Version 12.00
VisualStudioVersion = 17.4.33205.214
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DumpDVD", "DumpDVD\DumpDVD.vcxproj", "{A9A5F041-541F-47EA-B583-DE84B59D9B62}"
+ ProjectSection(ProjectDependencies) = postProject
+ {50F2BF62-8520-4B37-97DD-578EA282EC04} = {50F2BF62-8520-4B37-97DD-578EA282EC04}
+ {7F404DED-08FF-4092-97EF-0F63C5788DD2} = {7F404DED-08FF-4092-97EF-0F63C5788DD2}
+ {B2BCCCDA-BDB0-4FBE-84A3-EA1E8429F732} = {B2BCCCDA-BDB0-4FBE-84A3-EA1E8429F732}
+ EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libdvdcss", "libdvdcss\msvc\libdvdcss.vcxproj", "{50F2BF62-8520-4B37-97DD-578EA282EC04}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImGui", "ImGui\ImGui.vcxproj", "{B2BCCCDA-BDB0-4FBE-84A3-EA1E8429F732}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Lib9660", "Lib9660\Lib9660.vcxproj", "{7F404DED-08FF-4092-97EF-0F63C5788DD2}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A9A5F041-541F-47EA-B583-DE84B59D9B62}.Debug|x64.ActiveCfg = Debug|x64
+ {A9A5F041-541F-47EA-B583-DE84B59D9B62}.Debug|x64.Build.0 = Debug|x64
{A9A5F041-541F-47EA-B583-DE84B59D9B62}.Debug|x86.ActiveCfg = Debug|Win32
{A9A5F041-541F-47EA-B583-DE84B59D9B62}.Debug|x86.Build.0 = Debug|Win32
+ {A9A5F041-541F-47EA-B583-DE84B59D9B62}.Release|x64.ActiveCfg = Release|x64
+ {A9A5F041-541F-47EA-B583-DE84B59D9B62}.Release|x64.Build.0 = Release|x64
{A9A5F041-541F-47EA-B583-DE84B59D9B62}.Release|x86.ActiveCfg = Release|Win32
{A9A5F041-541F-47EA-B583-DE84B59D9B62}.Release|x86.Build.0 = Release|Win32
+ {50F2BF62-8520-4B37-97DD-578EA282EC04}.Debug|x64.ActiveCfg = Debug|x64
+ {50F2BF62-8520-4B37-97DD-578EA282EC04}.Debug|x64.Build.0 = Debug|x64
{50F2BF62-8520-4B37-97DD-578EA282EC04}.Debug|x86.ActiveCfg = Release|Win32
{50F2BF62-8520-4B37-97DD-578EA282EC04}.Debug|x86.Build.0 = Release|Win32
+ {50F2BF62-8520-4B37-97DD-578EA282EC04}.Release|x64.ActiveCfg = Release|x64
+ {50F2BF62-8520-4B37-97DD-578EA282EC04}.Release|x64.Build.0 = Release|x64
{50F2BF62-8520-4B37-97DD-578EA282EC04}.Release|x86.ActiveCfg = Release|Win32
{50F2BF62-8520-4B37-97DD-578EA282EC04}.Release|x86.Build.0 = Release|Win32
+ {B2BCCCDA-BDB0-4FBE-84A3-EA1E8429F732}.Debug|x64.ActiveCfg = Debug|x64
+ {B2BCCCDA-BDB0-4FBE-84A3-EA1E8429F732}.Debug|x64.Build.0 = Debug|x64
{B2BCCCDA-BDB0-4FBE-84A3-EA1E8429F732}.Debug|x86.ActiveCfg = Release|Win32
{B2BCCCDA-BDB0-4FBE-84A3-EA1E8429F732}.Debug|x86.Build.0 = Release|Win32
+ {B2BCCCDA-BDB0-4FBE-84A3-EA1E8429F732}.Release|x64.ActiveCfg = Release|x64
+ {B2BCCCDA-BDB0-4FBE-84A3-EA1E8429F732}.Release|x64.Build.0 = Release|x64
{B2BCCCDA-BDB0-4FBE-84A3-EA1E8429F732}.Release|x86.ActiveCfg = Release|Win32
{B2BCCCDA-BDB0-4FBE-84A3-EA1E8429F732}.Release|x86.Build.0 = Release|Win32
+ {7F404DED-08FF-4092-97EF-0F63C5788DD2}.Debug|x64.ActiveCfg = Debug|x64
+ {7F404DED-08FF-4092-97EF-0F63C5788DD2}.Debug|x64.Build.0 = Debug|x64
+ {7F404DED-08FF-4092-97EF-0F63C5788DD2}.Debug|x86.ActiveCfg = Release|Win32
+ {7F404DED-08FF-4092-97EF-0F63C5788DD2}.Debug|x86.Build.0 = Release|Win32
+ {7F404DED-08FF-4092-97EF-0F63C5788DD2}.Release|x64.ActiveCfg = Release|x64
+ {7F404DED-08FF-4092-97EF-0F63C5788DD2}.Release|x64.Build.0 = Release|x64
+ {7F404DED-08FF-4092-97EF-0F63C5788DD2}.Release|x86.ActiveCfg = Release|Win32
+ {7F404DED-08FF-4092-97EF-0F63C5788DD2}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/DumpDVD/DumpDVD.vcxproj b/DumpDVD/DumpDVD.vcxproj
index ec08c29..414bc86 100644
--- a/DumpDVD/DumpDVD.vcxproj
+++ b/DumpDVD/DumpDVD.vcxproj
@@ -19,6 +19,8 @@
+
+
@@ -29,6 +31,8 @@
+
+
@@ -96,7 +100,7 @@
true
_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
- $(SolutionDir)include\PFD;$(SolutionDir)include\SDL;$(SolutionDir)ImGui;$(SolutionDir)libdvdcss\src\dvdcss;%(AdditionalIncludeDirectories)
+ $(SolutionDir)include\PFD;$(SolutionDir)include\SDL;$(SolutionDir)Lib9660;$(SolutionDir)ImGui;$(SolutionDir)libdvdcss\src\dvdcss;%(AdditionalIncludeDirectories)
stdcpp20
stdc17
@@ -104,7 +108,7 @@
Windows
true
$(SolutionDir)\lib;%(AdditionalLibraryDirectories)
- d3d11.lib;winmm.lib;version.lib;Imm32.lib;Setupapi.lib;SDL2.lib;ImGui.lib;libdvdcss.lib;%(AdditionalDependencies)
+ d3d11.lib;winmm.lib;version.lib;Imm32.lib;Setupapi.lib;SDL2.lib;ImGui.lib;Lib9660.lib;libdvdcss.lib;%(AdditionalDependencies)
@@ -117,7 +121,7 @@
false
_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
- $(SolutionDir)include\PFD;$(SolutionDir)include\SDL;$(SolutionDir)ImGui;$(SolutionDir)libdvdcss\src\dvdcss;%(AdditionalIncludeDirectories)
+ $(SolutionDir)include\PFD;$(SolutionDir)include\SDL;$(SolutionDir)Lib9660;$(SolutionDir)ImGui;$(SolutionDir)libdvdcss\src\dvdcss;%(AdditionalIncludeDirectories)
MultiThreaded
stdcpp20
stdc17
@@ -128,7 +132,7 @@
true
false
$(SolutionDir)\lib;%(AdditionalLibraryDirectories)
- d3d11.lib;winmm.lib;version.lib;Imm32.lib;Setupapi.lib;SDL2.lib;ImGui.lib;libdvdcss.lib;%(AdditionalDependencies)
+ d3d11.lib;winmm.lib;version.lib;Imm32.lib;Setupapi.lib;SDL2.lib;ImGui.lib;Lib9660.lib;libdvdcss.lib;%(AdditionalDependencies)
diff --git a/DumpDVD/DumpDVD.vcxproj.filters b/DumpDVD/DumpDVD.vcxproj.filters
index 893fe00..f6aee24 100644
--- a/DumpDVD/DumpDVD.vcxproj.filters
+++ b/DumpDVD/DumpDVD.vcxproj.filters
@@ -39,6 +39,12 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
@@ -65,5 +71,11 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
\ No newline at end of file
diff --git a/DumpDVD/Dvd/DvdRipper.cpp b/DumpDVD/Dvd/DvdRipper.cpp
new file mode 100644
index 0000000..ebc0ad1
--- /dev/null
+++ b/DumpDVD/Dvd/DvdRipper.cpp
@@ -0,0 +1,233 @@
+#include "DvdRipper.hpp"
+
+#include
+#include
+#include
+#include
+#include
+
+#include "../Scsi/IoCtl.hpp"
+#include "../Scsi/OpticalDrive.hpp"
+#include "../Dvd/TitleKey.hpp"
+
+namespace Li::Dvd {
+
+
+
+ uint32_t DvdRipper::FileSoFar() {
+ if (this->inFile)
+ return this->fileReadSoFar;
+ else
+ return this->nonFileReadSoFar;
+ }
+ uint32_t DvdRipper::FileLen() {
+ if (this->inFile)
+ return this->fileRemain;
+ else
+ return this->nonFileRemain;
+ }
+
+ float DvdRipper::PercentDone() {
+ return (((float)this->sectorsReadSoFar / (float)this->drive->Sectors()));
+ }
+ uint32_t DvdRipper::SectorsReadSoFar() {
+ return this->sectorsReadSoFar;
+ }
+ uint32_t DvdRipper::FileReadSoFar() {
+ return this->fileReadSoFar;
+ }
+ std::string DvdRipper::OutputPath() {
+ return this->outputPath;
+ }
+
+ bool DvdRipper::Done() {
+ return this->done;
+ }
+ bool DvdRipper::Error() {
+ return this->error;
+ }
+ std::string DvdRipper::ErrorMessage() {
+ return this->errorMsg;
+ }
+ int DvdRipper::read1SectorATimeSkippingBadSectors(int toRead) {
+ memset(this->tmpBuffer, 0x00, this->sectorsAtOnce * DVDCSS_BLOCK_SIZE);
+ 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);
+ if (dataRd < 0) {
+ continue; // retry
+ }
+ }
+ nmRd += 1;
+ }
+
+ 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;
+
+ do {
+ int toRead = this->sectorsAtOnce;
+ if ((this->nonFileReadSoFar + toRead) > this->nonFileRemain) {
+ toRead = this->nonFileRemain - this->nonFileReadSoFar;
+ }
+ 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);
+ }
+
+ this->iso->write((const char*)this->tmpBuffer, DVDCSS_BLOCK_SIZE * numRead);
+
+ this->sectorsReadSoFar += numRead;
+ this->nonFileReadSoFar += numRead;
+
+ } while (this->nonFileReadSoFar < this->nonFileRemain && this->keepRunning);
+
+ this->inFile = Li::Dvd::TitleKey::IsSectorInFile(this->sectorsReadSoFar);
+ this->fileReadSoFar = 0;
+ this->nonFileReadSoFar = 0;
+ }
+
+ void DvdRipper::readFileSectors() {
+ dvdcss_title(this->driveIoCtl->GetDvdCssHandle(), 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);
+ }
+
+ iso->write((const char*)this->tmpBuffer, DVDCSS_BLOCK_SIZE * numRead);
+
+ this->sectorsReadSoFar += numRead;
+ this->fileReadSoFar += numRead;
+
+ } while ((this->fileReadSoFar < this->fileRemain) && this->keepRunning);
+
+ this->inFile = Li::Dvd::TitleKey::IsSectorInFile(this->sectorsReadSoFar);
+ this->fileReadSoFar = 0;
+ this->nonFileReadSoFar = 0;
+ }
+
+ 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);
+
+ do {
+ if (this->inFile)
+ this->readFileSectors();
+ else
+ this->readNonFileSectors();
+
+ } while (this->sectorsReadSoFar < this->drive->Sectors() && this->keepRunning);
+
+ this->done = true;
+ }
+
+ DvdRipper::DvdRipper(Li::Scsi::OpticalDrive* opticalDrive, std::string outputISO, uint32_t sectorsAtOnce) {
+ this->drive = opticalDrive;
+ this->outputPath = outputISO;
+ this->sectorsAtOnce = sectorsAtOnce;
+
+ this->sectorsReadSoFar = 0;
+
+ this->fileReadSoFar = 0;
+ this->fileRemain = 0;
+
+ this->nonFileReadSoFar = 0;
+ this->nonFileRemain = 0;
+
+ this->inFile = false;
+ this->done = false;
+ this->error = false;
+ this->errorMsg = "";
+ this->keepRunning = false;
+
+ this->ripinThread = nullptr;
+ this->tmpBuffer = new uint8_t[DVDCSS_BLOCK_SIZE * this->sectorsAtOnce];
+ }
+
+ DvdRipper::~DvdRipper() {
+ delete this->tmpBuffer;
+
+ if (this->ripinThread != nullptr) {
+ this->EndRip();
+ }
+ if (this->iso != nullptr) {
+ if (this->iso->is_open())
+ this->iso->close();
+ delete this->iso;
+ }
+ }
+
+ void DvdRipper::StartRip(uint32_t driveSpeed) {
+
+ this->driveIoCtl = new Li::Scsi::IoCtl(this->drive->DrivePath());
+ this->driveIoCtl->AllowReadingPastDisc();
+ this->driveIoCtl->SetDriveSpeed(driveSpeed, driveSpeed);
+ this->driveIoCtl->ExclusiveLockDrive();
+ this->iso = new std::ofstream(this->outputPath, std::ios::binary);
+ this->keepRunning = true;
+
+ this->ripinThread = new std::thread(&DvdRipper::ripThread, this);
+
+ }
+
+ void DvdRipper::EndRip() {
+ this->done = false;
+ this->error = false;
+ this->errorMsg = "";
+
+ this->sectorsReadSoFar = 0;
+ this->fileReadSoFar = 0;
+ this->keepRunning = false;
+ this->ripinThread->join();
+
+ delete this->driveIoCtl;
+ delete this->ripinThread;
+ this->ripinThread = nullptr;
+ iso->close();
+ delete iso;
+
+ this->iso = nullptr;
+ this->driveIoCtl->ExclusiveUnlockDrive();
+ }
+}
\ No newline at end of file
diff --git a/DumpDVD/Dvd/DvdRipper.hpp b/DumpDVD/Dvd/DvdRipper.hpp
new file mode 100644
index 0000000..32b23ec
--- /dev/null
+++ b/DumpDVD/Dvd/DvdRipper.hpp
@@ -0,0 +1,64 @@
+#ifndef _LI_DVDRIPPER
+#define _LI_DVDRIPPER 1
+#include
+#include
+#include
+#include
+#include
+
+#include "../Scsi/IoCtl.hpp"
+#include "../Scsi/OpticalDrive.hpp"
+
+namespace Li::Dvd {
+ class DvdRipper {
+ private:
+ bool error;
+ bool done;
+ std::string errorMsg;
+
+ bool inFile;
+ uint32_t fileReadSoFar;
+ uint32_t fileRemain;
+
+ uint32_t nonFileReadSoFar;
+ uint32_t nonFileRemain;
+
+
+ uint32_t sectorsAtOnce;
+ uint32_t sectorsReadSoFar;
+
+ std::string outputPath;
+ std::thread* ripinThread;
+
+ bool keepRunning;
+
+ std::ofstream* iso;
+ uint8_t* tmpBuffer;
+
+ Li::Scsi::IoCtl* driveIoCtl;
+ Li::Scsi::OpticalDrive* drive;
+ void ripThread();
+ void readNonFileSectors();
+ void readFileSectors();
+ 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();
+
+ bool Done();
+ bool Error();
+ std::string ErrorMessage();
+
+ void StartRip(uint32_t driveSpeed);
+ void EndRip();
+ };
+}
+#endif
\ No newline at end of file
diff --git a/DumpDVD/Dvd/TitleKey.cpp b/DumpDVD/Dvd/TitleKey.cpp
new file mode 100644
index 0000000..77c4721
--- /dev/null
+++ b/DumpDVD/Dvd/TitleKey.cpp
@@ -0,0 +1,112 @@
+#include "TitleKey.hpp"
+#include
+#include
+#include
+#include
+
+#include "../Utils.hpp"
+
+namespace Li::Dvd {
+
+
+ static std::vector sectorsList;
+ static dvdcss_t drv;
+
+ bool TitleKey::readSector(l9660_fs* fs, void* buf, uint32_t sector) {
+ dvdcss_seek(drv, sector, DVDCSS_SEEK_KEY);
+ dvdcss_read(drv, buf, 1, DVDCSS_READ_DECRYPT);
+
+ return !dvdcss_was_error(drv);
+ }
+
+ bool TitleKey::IsSectorInFile(uint32_t currentSector) {
+ for (sectorInfo* inf : sectorsList) {
+ if (currentSector >= inf->startSector && currentSector < inf->endSector)
+ return true;
+ }
+ return false;
+ }
+
+ uint32_t TitleKey::GetDistanceToNextFile(uint32_t currentSector) {
+
+ uint32_t lowestDistance = -1;
+ for (sectorInfo* inf : sectorsList) {
+ if (currentSector >= inf->startSector && currentSector < inf->endSector)
+ return 0;
+
+ uint32_t distance = inf->startSector - currentSector;
+ if (distance < 0) continue;
+
+ if (distance < lowestDistance) {
+ lowestDistance = distance;
+ }
+ }
+
+ return lowestDistance;
+
+ }
+
+ sectorInfo* TitleKey::GetSectorInfo(uint32_t currentSector) {
+
+ for (sectorInfo* inf : sectorsList) {
+ if (currentSector >= inf->startSector && currentSector < inf->endSector) {
+ return inf;
+ }
+ }
+
+ return nullptr;
+
+ }
+
+ void readDir(l9660_dir* dir) {
+ while (true) {
+ l9660_dirent* dent;
+ l9660_status status = l9660_readdir(dir, &dent);
+
+ if (dent == nullptr)
+ break;
+
+ if (dent->name_len < 2)
+ continue;
+
+ 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) {
+ sectorInfo* file = new sectorInfo();
+
+ file->startSector = *(uint32_t*)dent->sector.le;
+ file->endSector = file->startSector + (*(uint32_t*)dent->size.le / DVDCSS_BLOCK_SIZE);
+
+ sectorsList.push_back(file);
+ }
+
+ }
+ }
+
+ std::vector TitleKey::GetTitleKeys(dvdcss_t drive) {
+ drv = drive;
+ sectorsList = std::vector();
+
+ l9660_dir rootDir;
+ l9660_fs isoFs;
+ l9660_status status;
+
+ status = l9660_openfs(&isoFs, TitleKey::readSector);
+ status = l9660_fs_open_root(&rootDir, &isoFs);
+ readDir(&rootDir);
+
+ return sectorsList;
+ }
+
+ void TitleKey::FreeMemory() {
+ for (sectorInfo* inf : sectorsList) {
+ delete inf;
+ }
+
+ sectorsList.clear();
+
+ }
+}
\ No newline at end of file
diff --git a/DumpDVD/Dvd/TitleKey.hpp b/DumpDVD/Dvd/TitleKey.hpp
new file mode 100644
index 0000000..4788c78
--- /dev/null
+++ b/DumpDVD/Dvd/TitleKey.hpp
@@ -0,0 +1,25 @@
+#ifndef _LI_TITLEKEY
+#define _LI_TITLEKEY 1
+#include
+#include
+#include
+
+typedef struct sectorInfo {
+ uint32_t startSector;
+ uint32_t endSector;
+} sectorInfo;
+
+namespace Li::Dvd {
+ class TitleKey {
+ private:
+ static bool readSector(l9660_fs* fs, void* buf, uint32_t sector);
+ public:
+ static std::vector GetTitleKeys(dvdcss_t drive);
+ static uint32_t GetDistanceToNextFile(uint32_t currentSector);
+ static bool IsSectorInFile(uint32_t currentSector);
+ static sectorInfo* GetSectorInfo(uint32_t currentSector);
+ static void FreeMemory();
+ };
+}
+
+#endif
\ No newline at end of file
diff --git a/DumpDVD/Gui/DumpDVD.cpp b/DumpDVD/Gui/DumpDVD.cpp
index 2d9382a..a6e264b 100644
--- a/DumpDVD/Gui/DumpDVD.cpp
+++ b/DumpDVD/Gui/DumpDVD.cpp
@@ -1,3 +1,4 @@
+#include "DumpDVD.hpp"
#include
#include
@@ -8,18 +9,17 @@
#include
-#include
-#include
#include
#include
-#include
#include
-#include "DumpDVD.hpp"
+
#include "../Utils.hpp"
#include "../Scsi/IoCtl.hpp"
#include "../Scsi/OpticalDrive.hpp"
+#include "../Dvd/DvdRipper.hpp"
+#include "../Dvd/TitleKey.hpp"
namespace Li::Gui {
@@ -29,20 +29,14 @@ namespace Li::Gui {
this->keepPolling = true;
this->showDemoWindow = true;
this->imRippinIt = false;
- this->error = false;
- this->done = false;
-
this->selectedDrive = 0;
- this->windowFlags = ImGuiWindowFlags_NoCollapse;
this->selectedDriveSpeed = 0;
this->counter = 0;
this->drivesList = Li::Scsi::OpticalDrive::ListOpticalDrives();
this->pollDrives = new std::thread(&DumpDVD::pollDrivesThread, this);
- this->sectorsReadSoFar = 0;
this->sectorsAtOnce = 0x400;
-
this->lock = new std::mutex();
this->reset();
@@ -56,54 +50,6 @@ namespace Li::Gui {
freeOldDriveList();
}
- void DumpDVD::ripDiscThread() {
- std::ofstream* iso = new std::ofstream(std::string(this->outputFile), std::ios::binary);
- uint64_t totalSectors = this->GetCurrentSelectedDrive()->Sectors();
-
- std::vector* speeds = this->GetCurrentSelectedDrive()->SupportedSpeeds();
- uint32_t speed = 0xFFFF;
- if (this->selectedDriveSpeed < speeds->size()) {
- speed = speeds->at(this->selectedDriveSpeed);
- }
-
- Li::Scsi::IoCtl* drive = new Li::Scsi::IoCtl(this->GetCurrentSelectedDrive()->DrivePath());
-
- drive->AllowReadingPastDisc();
- drive->SetDriveSpeed(speed, speed);
- drive->ExclusiveLockDrive();
- this->sectorsReadSoFar = 0;
- dvdcss_seek(drive->GetDvdCssHandle(), 0, DVDCSS_SEEK_KEY);
-
- uint8_t* buffer = new uint8_t[DVDCSS_BLOCK_SIZE * this->sectorsAtOnce];
-
- do {
- int sectorsToRead = this->sectorsAtOnce;
- if ((this->sectorsReadSoFar + sectorsToRead) > totalSectors) {
- sectorsToRead = totalSectors - this->sectorsReadSoFar;
- }
-
- int numRead = dvdcss_read(drive->GetDvdCssHandle(), buffer, sectorsToRead, DVDCSS_READ_DECRYPT);
-
- if (numRead <= 0) {
- this->error = true;
- this->errorMsg = std::string(dvdcss_error(drive->GetDvdCssHandle()));
- break;
- }
-
- iso->write((const char*)buffer, DVDCSS_BLOCK_SIZE * numRead);
- this->sectorsReadSoFar += numRead;
-
- } while (this->sectorsReadSoFar < totalSectors && this->imRippinIt);
-
-
- drive->ExclusiveUnlockDrive();
- iso->close();
- this->done = true;
- delete buffer;
- delete drive;
- delete iso;
- }
-
void DumpDVD::pollDrivesThread() {
while (this->keepPolling) {
if ( (this->counter % (60 * 10)) == 0) {
@@ -167,18 +113,25 @@ namespace Li::Gui {
this->pollDrives->join();
delete this->pollDrives;
- this->pollDrives = new std::thread(&DumpDVD::ripDiscThread, this);
+ std::vector* speeds = this->GetCurrentSelectedDrive()->SupportedSpeeds();
+ uint32_t speed = 0xFFFF;
+ if (this->selectedDriveSpeed < speeds->size()) {
+ speed = speeds->at(this->selectedDriveSpeed);
+ }
+
+ this->dvdRipper = new Li::Dvd::DvdRipper(this->GetCurrentSelectedDrive(), std::string(this->outputFile), this->sectorsAtOnce);
+ this->dvdRipper->StartRip(speed);
+
this->imRippinIt = true;
}
}
void DumpDVD::endRipAndGoBackToMenu() {
- this->done = false;
+ this->dvdRipper->EndRip();
+ delete this->dvdRipper;
+
this->imRippinIt = false;
this->reset();
- this->sectorsReadSoFar = 0;
- this->counter = 0;
- this->pollDrives->join();
this->keepPolling = true;
this->drivesList = Li::Scsi::OpticalDrive::ListOpticalDrives();
@@ -189,28 +142,29 @@ namespace Li::Gui {
void DumpDVD::showRippingStatus() {
ImGui::SeparatorText("Status");
- float percentage = (((float)this->sectorsReadSoFar / (float)this->GetCurrentSelectedDrive()->Sectors()));
- ImGui::Text("Copying Disc ... ", (int)percentage);
+ ImGui::Text("Copying Disc ... ");
ImGui::SameLine();
- ImGui::ProgressBar(percentage);
+ ImGui::ProgressBar(this->dvdRipper->PercentDone());
- ImGui::Text("Sector %lli / %lli", this->sectorsReadSoFar, this->GetCurrentSelectedDrive()->Sectors());
-
- uint64_t szSoFar = this->sectorsReadSoFar * DVDCSS_BLOCK_SIZE;
- uint64_t szTotal = this->GetCurrentSelectedDrive()->Sectors() * DVDCSS_BLOCK_SIZE;
+ ImGui::Text("Sector %i / %i", this->dvdRipper->SectorsReadSoFar(), this->GetCurrentSelectedDrive()->Sectors());
+ ImGui::Text("File: %i / %i", this->dvdRipper->FileReadSoFar(), 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("Output");
ImGui::Text("Output file: \"%s\"", this->outputFile);
if (ImGui::Button("Cancel")) {
this->endRipAndGoBackToMenu();
std::filesystem::remove(std::string(this->outputFile));
+ return;
}
- if (this->done) {
- if (!this->error) {
- ImGui::Begin("Complete", &done, this->windowFlags);
+ if (this->dvdRipper->Done()) {
+ if (!this->dvdRipper->Error()) {
+ ImGui::Begin("Complete", &this->imRippinIt, ImGuiWindowFlags_NoCollapse);
ImGui::Text("ISO file was created successfully.");
if (ImGui::Button("OK")) {
this->endRipAndGoBackToMenu();
@@ -218,8 +172,8 @@ namespace Li::Gui {
ImGui::End();
}
else {
- ImGui::Begin("Error", &done, this->windowFlags);
- ImGui::Text("Error occured when creating an ISO\n\"%s\"", this->errorMsg.c_str());
+ ImGui::Begin("Error", &this->imRippinIt, ImGuiWindowFlags_NoCollapse);
+ ImGui::Text("Error occured when creating an ISO\n\"%s\"", this->dvdRipper->ErrorMessage().c_str());
if (ImGui::Button("OK")) {
this->endRipAndGoBackToMenu();
std::filesystem::remove(std::string(this->outputFile));
@@ -309,7 +263,7 @@ namespace Li::Gui {
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Appearing);
ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize, ImGuiCond_Appearing);
- ImGui::Begin("DVD Dumper", NULL, windowFlags);
+ ImGui::Begin("DVD Dumper", NULL, ImGuiWindowFlags_NoCollapse);
if (this->imRippinIt)
{
diff --git a/DumpDVD/Gui/DumpDVD.hpp b/DumpDVD/Gui/DumpDVD.hpp
index cc84fbe..9c21ffe 100644
--- a/DumpDVD/Gui/DumpDVD.hpp
+++ b/DumpDVD/Gui/DumpDVD.hpp
@@ -2,11 +2,12 @@
#define _LI_DUMP_DVD_H 1
#include
#include
+#include
#include
#include
-#include "../Scsi/IoCtl.hpp"
#include "../Scsi/OpticalDrive.hpp"
+#include "../Dvd/DvdRipper.hpp"
namespace Li::Gui {
@@ -18,22 +19,17 @@ namespace Li::Gui {
std::mutex* lock;
- bool error;
- bool done;
- std::string errorMsg;
- uint64_t sectorsReadSoFar;
int sectorsAtOnce;
-
bool discInserted;
int selectedDrive;
- ImGuiWindowFlags windowFlags;
int selectedDriveSpeed;
uint32_t counter;
char outputFile[0x8000];
-
std::vector* drivesList;
std::thread* pollDrives;
+
+ Li::Dvd::DvdRipper* dvdRipper;
void ripDiscThread();
void pollDrivesThread();
diff --git a/DumpDVD/Scsi/OpticalDrive.cpp b/DumpDVD/Scsi/OpticalDrive.cpp
index d18a63a..480ede1 100644
--- a/DumpDVD/Scsi/OpticalDrive.cpp
+++ b/DumpDVD/Scsi/OpticalDrive.cpp
@@ -60,7 +60,7 @@ namespace Li::Scsi {
return this->drivePath;
}
- uint64_t OpticalDrive::Sectors() {
+ uint32_t OpticalDrive::Sectors() {
return this->sectors;
}
diff --git a/DumpDVD/Scsi/OpticalDrive.hpp b/DumpDVD/Scsi/OpticalDrive.hpp
index e81983d..510aa43 100644
--- a/DumpDVD/Scsi/OpticalDrive.hpp
+++ b/DumpDVD/Scsi/OpticalDrive.hpp
@@ -10,7 +10,7 @@ namespace Li::Scsi {
bool discInDrive;
std::vector* supportedSpeeds;
- uint64_t sectors;
+ uint32_t sectors;
void getDriveInformation(std::string drv);
public:
@@ -20,7 +20,7 @@ namespace Li::Scsi {
std::vector* SupportedSpeeds();
std::string DrivePath();
std::string VolumeName();
- uint64_t Sectors();
+ uint32_t Sectors();
bool DiscInDrive();
static std::vector* ListOpticalDrives();
diff --git a/DumpDVD/Utils.cpp b/DumpDVD/Utils.cpp
index 9621b31..ff847de 100644
--- a/DumpDVD/Utils.cpp
+++ b/DumpDVD/Utils.cpp
@@ -3,6 +3,15 @@
#include
namespace Li {
+ bool Utils::CompareStringCaseInsensitive(std::string input, std::string compare) {
+ unsigned int sz = input.size();
+ if (compare.size() != sz)
+ return false;
+ for (unsigned int i = 0; i < sz; ++i)
+ if (tolower(input[i]) != tolower(compare[i]))
+ return false;
+ return true;
+ }
std::string Utils::HumanReadableByteStr(uint64_t bytes)
{
const char* suffix[5] = { "B", "KB", "MB", "GB", "TB" };
diff --git a/DumpDVD/Utils.hpp b/DumpDVD/Utils.hpp
index d899781..9bd6870 100644
--- a/DumpDVD/Utils.hpp
+++ b/DumpDVD/Utils.hpp
@@ -4,6 +4,7 @@ namespace Li {
class Utils {
public:
static std::string HumanReadableByteStr(uint64_t bytes);
+ static bool CompareStringCaseInsensitive(std::string input, std::string compare);
};
}
#endif
\ No newline at end of file
diff --git a/Lib9660/Jamfile b/Lib9660/Jamfile
new file mode 100644
index 0000000..68ae755
--- /dev/null
+++ b/Lib9660/Jamfile
@@ -0,0 +1,4 @@
+SubDir LIB9660_TOP ;
+SubDirCcFlags -std=c99 $(LIB9660_OPTS) ;
+
+Library lib9660 : lib9660.c ;
diff --git a/Lib9660/Lib9660.vcxproj b/Lib9660/Lib9660.vcxproj
new file mode 100644
index 0000000..a185e12
--- /dev/null
+++ b/Lib9660/Lib9660.vcxproj
@@ -0,0 +1,158 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+
+
+
+
+
+
+ 16.0
+ Win32Proj
+ {7f404ded-08ff-4092-97ef-0f63c5788dd2}
+ Lib9660
+ 10.0
+
+
+
+ StaticLibrary
+ true
+ v143
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ StaticLibrary
+ true
+ v143
+ Unicode
+
+
+ StaticLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)lib\
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+ pch.h
+ MultiThreadedDebug
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ NotUsing
+ pch.h
+ MultiThreaded
+
+
+
+
+ true
+ true
+ true
+
+
+ $(SolutionDir)lib\$(TargetName)$(TargetExt)
+
+
+
+
+ Level3
+ true
+ _DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+
+
+
+
+ true
+ true
+ true
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Lib9660/Lib9660.vcxproj.filters b/Lib9660/Lib9660.vcxproj.filters
new file mode 100644
index 0000000..6950d0c
--- /dev/null
+++ b/Lib9660/Lib9660.vcxproj.filters
@@ -0,0 +1,27 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/Lib9660/Lib9660.vcxproj.user b/Lib9660/Lib9660.vcxproj.user
new file mode 100644
index 0000000..966b4ff
--- /dev/null
+++ b/Lib9660/Lib9660.vcxproj.user
@@ -0,0 +1,6 @@
+
+
+
+ true
+
+
\ No newline at end of file
diff --git a/Lib9660/Makefile b/Lib9660/Makefile
new file mode 100644
index 0000000..06cde20
--- /dev/null
+++ b/Lib9660/Makefile
@@ -0,0 +1,28 @@
+.POSIX:
+.SUFFIXES:
+.SUFFIXES: .o .c
+.PHONY: all clean install
+
+PREFIX = /usr/local
+CFLAGS = -DL9660_HAVE_STDIO -g -DDEBUG
+
+OBJS := lib9660.o
+ALL := lib9660.a tb9660
+
+all: $(ALL)
+
+.c.o:
+ $(CC) -c -o $@ $< $(CFLAGS)
+
+lib9660.a: $(OBJS)
+ ar cru lib9660.a $(OBJS)
+
+tb9660: tb9660.c lib9660.a
+ $(CC) -g -o tb9660 tb9660.c lib9660.a $(CFLAGS)
+
+clean:
+ rm $(ALL) $(OBJS)
+
+install:
+ install -m644 lib9660.a $(DESTDIR)$(PREFIX)/lib
+ install -m644 lib9660.h $(DESTDIR)$(PREFIX)/include
diff --git a/Lib9660/README.md b/Lib9660/README.md
new file mode 100644
index 0000000..1a81b26
--- /dev/null
+++ b/Lib9660/README.md
@@ -0,0 +1,53 @@
+# lib9660 - a simple implementation of the ISO 9660 file system
+
+lib9660 is a simple implementation of the ISO 9660 file system, as used on CD.
+It does not perform any dynamic memory allocations or depend upon any
+complicated standard library routines (actually all it requires is memcmp and
+memcpy). It provides a reasonable facsimilie of the standard POSIX file
+descriptor I/O API.
+
+lib9660 is re-entrant; it is safe to use it from multiple threads, provided you
+do not access the same file from multiple threads (note that for these purposes
+the openat and opendirat functions count as accessing the passed parent file)
+
+## Usage notes
+l9660_dir is simply a wrapper for l9660_file. You may use them interchangably if
+necessary to save memory (note that this will require casting). The distinct
+types are provided purely for type checking.
+
+You can pass the same file/directory pointer for both child and parent
+parameters of l9660_open(dir)at. This can be useful in memory constrained
+environments.
+
+l9660_read will not perform a read from the underlying device as long as the
+request can be answered from its' internal buffer. Be prepared for short reads.
+
+lib9660_open(dir)at use lib9660_readdir internally. Remember to save and
+restore your seek position if that will be necessary.
+
+## Tuning parameters
+### L9660_SINGLEBUFFER
+By default, lib9660 maintains a buffer per open file. This means each file (and
+directory) consumes just over 2kB of RAM for the buffer and state information.
+
+If you are memory constrained, you can build with L9660_SINGLEBUFFER (make sure
+it is also defined in any files which include lib9660.h), which causes lib9660
+to instead use a single common buffer. lib9660 will now consume a constant
+2kB of RAM for this buffer, instead of 2kB per file.
+
+The cost of this is slightly reduced performance; if you alternate between
+reading multiple files, then each time you change file that file's buffer must
+be reloaded. Additionally, this makes lib9660 no longer thread safe.
+
+### L9660_HAVE_STDIO
+If your system has stdio.h and it defines SEEK_[SET,CUR,END], then lib9660 will
+use those definitions for l9660_seek. Otherwise, it will use its' own
+definitions of L9660_SEEK_[SET,CUR,END].
+
+### DEBUG
+If you build l9660.c with DEBUG defined, then this will enable some library
+debugging features. Most notably, if L9660_DEBUG is set in the environment,
+then all directory entries processed (by the open[dir]at functions) will be
+dumped to stdout.
+
+This requires a functioning printf and getenv. You probably don't need it
\ No newline at end of file
diff --git a/Lib9660/lib9660.c b/Lib9660/lib9660.c
new file mode 100644
index 0000000..1d4b7e3
--- /dev/null
+++ b/Lib9660/lib9660.c
@@ -0,0 +1,336 @@
+/* lib9660: a simple ISO9660 reader library especially suited to embedded
+ * systems
+ *
+ * Copyright © 2014, Owen Shepherd
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice appears in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "lib9660.h"
+#include
+
+#ifdef DEBUG
+#include
+#endif
+
+#ifdef L9660_HAVE_STDIO
+#include
+#else
+#define SEEK_END L9660_SEEK_END
+#define SEEK_SET L9660_SEEK_SET
+#define SEEK_CUR L9660_SEEK_CUR
+#endif
+
+#define DENT_EXISTS (1 << 0)
+#define DENT_ISDIR (1 << 1)
+#define DENT_ASSOCIATED (1 << 2)
+#define DENT_RECORD (1 << 3)
+#define DENT_PROTECTION (1 << 4)
+#define DENT_MULTIEXTENT (1 << 5)
+
+#define PVD(vdesc) ((l9660_vdesc_primary*)(vdesc))
+
+#ifdef L9660_BIG_ENDIAN
+#define READ16(v) (((v).be[1]) | ((v).be[0] << 8))
+#define READ32(v) (((v).be[3]) | ((v).be[2] << 8) | ((v).be[1]) << 16 | ((v).be[0] << 24))
+#else
+#define READ16(v) (((v).le[0]) | ((v).le[1] << 8))
+#define READ32(v) (((v).le[0]) | ((v).le[1] << 8) | ((v).le[2]) << 16 | ((v).le[3] << 24))
+#endif
+
+#ifndef L9660_SINGLEBUFFER
+#define HAVEBUFFER(f) (true)
+#define BUF(f) ((f)->buf)
+#else
+#define HAVEBUFFER(f) ((f) == last_file)
+#define BUF(f) (gbuf)
+static l9660_file *last_file;
+static char gbuf[2048];
+#endif
+
+static char *strchrnul(const char *s, int c)
+{
+ while (*s) {
+ if((*s++) == c)
+ break;
+ }
+ return (char *) s;
+}
+
+static inline uint16_t fsectoff(l9660_file *f)
+{
+ return f->position % 2048;
+}
+
+static inline uint32_t fsector(l9660_file *f)
+{
+ return f->position / 2048;
+}
+
+static inline uint32_t fnextsectpos(l9660_file *f)
+{
+ return (f->position + 2047) & ~2047;
+}
+
+l9660_status l9660_openfs(
+ l9660_fs *fs,
+ bool (*read_sector)(l9660_fs *fs, void *buf, uint32_t sector))
+{
+ fs->read_sector = read_sector;
+
+#ifndef L9660_SINGLEBUFFER
+ l9660_vdesc_primary *pvd = PVD(&fs->pvd);
+#else
+ last_file = NULL;
+ l9660_vdesc_primary *pvd = PVD(gbuf);
+#endif
+ uint32_t idx = 0x10;
+ for (;;) {
+ // Read next sector
+ if (!read_sector(fs, pvd, idx))
+ return L9660_EIO;
+
+ // Validate magic
+ if (memcmp(pvd->hdr.magic, "CD001", 5) != 0)
+ return L9660_EBADFS;
+
+ if (pvd->hdr.type == 1)
+ break; // Found PVD
+ else if(pvd->hdr.type == 255)
+ return L9660_EBADFS;
+ }
+
+#ifdef L9660_SINGLEBUFFER
+ memcpy(&fs->root_dir_ent, &pvd->root_dir_ent, pvd->root_dir_ent.length);
+#endif
+
+ return L9660_OK;
+}
+
+l9660_status l9660_fs_open_root(l9660_dir *dir, l9660_fs *fs)
+{
+ l9660_file *f = &dir->file;
+#ifndef L9660_SINGLEBUFFER
+ l9660_dirent *dirent = &PVD(&fs->pvd)->root_dir_ent;
+#else
+ l9660_dirent *dirent = &fs->root_dir_ent;
+#endif
+
+ f->fs = fs;
+ f->first_sector = READ32(dirent->sector);
+ f->length = READ32(dirent->size);
+ f->position = 0;
+
+ return L9660_OK;
+}
+
+static l9660_status buffer(l9660_file *f)
+{
+#ifdef L9660_SINGLEBUFFER
+ last_file = f;
+#endif
+ if (!f->fs->read_sector(f->fs, BUF(f), f->first_sector + f->position / 2048))
+ return L9660_EIO;
+ else
+ return L9660_OK;
+}
+
+static l9660_status prebuffer(l9660_file *f)
+{
+ if (!HAVEBUFFER(f) || (f->position % 2048) == 0)
+ return buffer(f);
+ else return L9660_OK;
+}
+
+#if defined(DEBUG)
+static void print_dirent(l9660_dirent *dent)
+{
+ if (!getenv("L9660_DEBUG"))
+ return;
+
+ printf("| ---- dirent\n");
+ printf("| length %d\n", dent->length);
+ printf("| xattr_length %d\n", dent->xattr_length);
+ printf("| sector %u\n", READ32(dent->sector));
+ printf("| size %u\n", READ32(dent->size));
+ printf("| name \"%.*s\"\n", dent->name_len, dent->name);
+ printf("| ---- end dirent\n");
+}
+#endif
+
+static l9660_status openat_raw(l9660_file *child, l9660_dir *parent, const char *name, bool isdir)
+{
+ l9660_status rv;
+ l9660_dirent *dent = NULL;
+ if ((rv = l9660_seekdir(parent, 0))) return rv;
+
+ do {
+ const char *seg = name;
+ name = strchrnul(name, '/');
+ size_t seglen = name - seg;
+
+ /* ISO9660 stores '.' as '\0' */
+ if (seglen == 1 && *seg == '.')
+ seg = "\0";
+
+ /* ISO9660 stores ".." as '\1' */
+ if (seglen == 2 && seg[0] == '.' && seg[1] == '.') {
+ seg = "\1";
+ seglen = 1;
+ }
+
+ for(;;) {
+ if ((rv = l9660_readdir(parent, &dent)))
+ return rv;
+
+ /* EOD */
+ if (!dent)
+ return L9660_ENOENT;
+
+#ifdef DEBUG
+ print_dirent(dent);
+#endif
+
+ /* wrong length */
+ if (seglen > dent->name_len)
+ continue;
+
+ /* check name */
+ if (memcmp(seg, dent->name, seglen) != 0)
+ continue;
+
+ /* check for a revision tag */
+ if (dent->name_len > seglen && dent->name[seglen] != ';')
+ continue;
+
+ /* all tests pass */
+ break;
+ }
+
+ child->fs = parent->file.fs;
+ child->first_sector = READ32(dent->sector) + dent->xattr_length;
+ child->length = READ32(dent->size);
+ child->position = 0;
+
+ if (*name && (dent->flags & DENT_ISDIR) != 0)
+ return L9660_ENOTDIR;
+
+ parent = (l9660_dir*) child;
+ } while(*name);
+
+ if (isdir) {
+ if ((dent->flags & DENT_ISDIR) == 0)
+ return L9660_ENOTDIR;
+ } else {
+ if ((dent->flags & DENT_ISDIR) != 0)
+ return L9660_ENOTFILE;
+ }
+
+ return L9660_OK;
+}
+
+l9660_status l9660_opendirat(l9660_dir *dir, l9660_dir *parent, const char *path)
+{
+ return openat_raw(&dir->file, parent, path, true);
+}
+
+static inline unsigned aligneven(unsigned v) {
+ return v + (v & 1);
+}
+
+l9660_status l9660_readdir(l9660_dir *dir, l9660_dirent **pdirent)
+{
+ l9660_status rv;
+ l9660_file *f = &dir->file;
+
+rebuffer:
+ if(f->position >= f->length) {
+ *pdirent = NULL;
+ return L9660_OK;
+ }
+
+ if ((rv = prebuffer(f)))
+ return rv;
+
+ char *off = BUF(f) + fsectoff(f);
+ if (*off == 0) {
+ // Padded end of sector
+ f->position = fnextsectpos(f);
+ goto rebuffer;
+ }
+
+ l9660_dirent *dirent = (l9660_dirent*) off;
+ f->position += aligneven(dirent->length);
+
+ *pdirent = dirent;
+ return L9660_OK;
+}
+
+l9660_status l9660_openat(l9660_file *child, l9660_dir *parent, const char * name)
+{
+ return openat_raw(child, parent, name, false);
+}
+
+/*! Seek the file to \p offset from \p whence */
+l9660_status l9660_seek(l9660_file *f, int whence, int32_t offset)
+{
+ l9660_status rv;
+ uint32_t cursect = fsector(f);
+
+ switch (whence) {
+ case SEEK_SET:
+ f->position = offset;
+ break;
+
+ case SEEK_CUR:
+ f->position = f->position + offset;
+ break;
+
+ case SEEK_END:
+ f->position = f->length - offset;
+ break;
+ }
+
+ if (fsector(f) != cursect && fsectoff(f) != 0) {
+ if ((rv = buffer(f)))
+ return rv;
+ }
+
+ return L9660_OK;
+}
+
+uint32_t l9660_tell(l9660_file *f)
+{
+ return f->position;
+}
+
+l9660_status l9660_read(l9660_file *f, void* buf, size_t size, size_t *read)
+{
+ l9660_status rv;
+
+ if ((rv = prebuffer(f)))
+ return rv;
+
+ uint16_t rem = 2048 - fsectoff(f);
+ if (rem > f->length - f->position)
+ rem = f->length - f->position;
+ if (rem < size)
+ size = rem;
+
+ memcpy(buf, BUF(f) + fsectoff(f), size);
+
+ *read = size;
+ f->position += size;
+
+ return L9660_OK;
+}
diff --git a/Lib9660/lib9660.h b/Lib9660/lib9660.h
new file mode 100644
index 0000000..6162a7b
--- /dev/null
+++ b/Lib9660/lib9660.h
@@ -0,0 +1,219 @@
+/* lib9660: a simple ISO9660 reader library especially suited to embedded
+ * systems
+ *
+ * Copyright © 2014, Owen Shepherd
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice appears in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef LIB9660_H
+#define LIB9660_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+#include
+
+#ifdef L9660_HAVE_STDIO
+#include
+#define L9660_SEEK_END SEEK_END
+#define L9660_SEEK_SET SEEK_SET
+#define L9660_SEEK_CUR SEEK_CUR
+#else
+#define L9660_SEEK_END -1
+#define L9660_SEEK_SET 0
+#define L9660_SEEK_CUR +1
+#endif
+
+#define DENT_EXISTS (1 << 0)
+#define DENT_ISDIR (1 << 1)
+#define DENT_ASSOCIATED (1 << 2)
+#define DENT_RECORD (1 << 3)
+#define DENT_PROTECTION (1 << 4)
+#define DENT_MULTIEXTENT (1 << 5)
+
+ /* Our error return format */
+ typedef enum {
+ /*! Success! */
+ L9660_OK = 0,
+ /*! read_sector callback returned false */
+ L9660_EIO,
+ /*! file system is bad */
+ L9660_EBADFS,
+ /*! specified name does not exist */
+ L9660_ENOENT,
+ /*! attempted to open a non-file (e.g. a directory) as a file */
+ L9660_ENOTFILE,
+ /*! attempted to open a non-directory (e.g. a file) as a directory
+ * may be returned by l9660_openat if e.g. you pass path "a/b" and
+ * "a" is a file
+ */
+ L9660_ENOTDIR,
+ } l9660_status;
+
+ /* ISO9660 uses big/little/dual endian integers */
+ typedef struct { uint8_t le[2]; } l9660_luint16;
+ typedef struct { uint8_t be[2]; } l9660_buint16;
+ typedef struct { uint8_t le[2], be[2]; } l9660_duint16;
+ typedef struct { uint8_t le[4]; } l9660_luint32;
+ typedef struct { uint8_t be[4]; } l9660_buint32;
+ typedef struct { uint8_t le[4], be[4]; } l9660_duint32;
+
+ /* Descriptor time format */
+ typedef struct {
+ char d[17];
+ } l9660_desctime;
+
+ /* File time format */
+ typedef struct {
+ char d[7];
+ } l9660_filetime;
+
+ /* Directory entry */
+ typedef struct {
+ uint8_t length;
+ uint8_t xattr_length;
+ l9660_duint32 sector;
+ l9660_duint32 size;
+ l9660_filetime time;
+ uint8_t flags;
+ uint8_t unit_size;
+ uint8_t gap_size;
+ l9660_duint16 vol_seq_number;
+ uint8_t name_len;
+ char name[/*name_len*/];
+ } l9660_dirent;
+
+ /* Volume descriptor header */
+ typedef struct {
+ uint8_t type;
+ char magic[5];
+ uint8_t version;
+ } l9660_vdesc_header;
+
+ /* Primary volume descriptor */
+ typedef struct {
+ l9660_vdesc_header hdr;
+ char pad0[1];
+ char system_id[32];
+ char volume_id[32];
+ char pad1[8];
+ l9660_duint32 volume_space_size;
+ char pad2[32];
+ l9660_duint16 volume_set_size;
+ l9660_duint16 volume_seq_number;
+ l9660_duint16 logical_block_size;
+ l9660_duint32 path_table_size;
+ l9660_luint32 path_table_le;
+ l9660_luint32 path_table_opt_le;
+ l9660_buint32 path_table_be;
+ l9660_buint32 path_table_opt_be;
+ union {
+ l9660_dirent root_dir_ent;
+ char pad3[34];
+ };
+ char volume_set_id[128];
+ char data_preparer_id[128];
+ char app_id[128];
+ char copyright_file[38];
+ char abstract_file[36];
+ char bibliography_file[37];
+ l9660_desctime volume_created,
+ volume_modified,
+ volume_expires,
+ volume_effective;
+ uint8_t file_structure_version;
+ char pad4[1];
+ char app_reserved[512];
+ char reserved[653];
+ } l9660_vdesc_primary;
+
+ /* A generic volume descriptor (i.e. 2048 bytes) */
+ typedef union {
+ l9660_vdesc_header hdr;
+ char _bits[2048];
+ } l9660_vdesc;
+
+ /* File system structure.
+ * Stick this inside your own structure and cast/offset as appropriate to store
+ * private data
+ */
+ typedef struct l9660_fs {
+#ifdef L9660_SINGLEBUFFER
+ union {
+ l9660_dirent root_dir_ent;
+ char root_dir_pad[34];
+ };
+#else
+ /* Sector buffer to hold the PVD */
+ l9660_vdesc pvd;
+#endif
+
+ /* read_sector func */
+ bool (*read_sector)(struct l9660_fs* fs, void* buf, uint32_t sector);
+ } l9660_fs;
+
+ typedef struct {
+#ifndef L9660_SINGLEBUFFER
+ /* single sector buffer */
+ char buf[2048];
+#endif
+ l9660_fs* fs;
+ uint32_t first_sector;
+ uint32_t position;
+ uint32_t length;
+ } l9660_file;
+
+ typedef struct {
+ /* directories are mostly just files with special accessors, but we like type safetey */
+ l9660_file file;
+ } l9660_dir;
+
+ /* Open a file system, initialising *fs. */
+ l9660_status l9660_openfs(
+ l9660_fs* fs,
+ bool (*read_sector)(l9660_fs* fs, void* buf, uint32_t sector));
+
+ /*void l9660_closefs(l9660_fs *fs); (nop) */
+
+ /*! Open the root directory */
+ l9660_status l9660_fs_open_root(l9660_dir* dir, l9660_fs* fs);
+
+ /*! Open the subdirectory given by \p path */
+ l9660_status l9660_opendirat(l9660_dir* dir, l9660_dir* parent, const char* path);
+ /*! Returns the next directory entry. If end-of-directory is reached, *dirent is
+ * set to NULL. */
+ l9660_status l9660_readdir(l9660_dir* dir, l9660_dirent** dirent);
+
+#define l9660_seekdir(dir, pos) (l9660_seek(&(dir)->file, L9660_SEEK_SET, (pos)))
+#define l9660_telldir(dir) (l9660_tell(&(dir)->file))
+
+ /*! Open the file given by \p path in \p parent */
+ l9660_status l9660_openat(l9660_file* file, l9660_dir* parent, const char* path);
+
+ /*! Read \p size bytes into \p buf. The number of bytes read will be returned in
+ * \p *read. May be less than \p size (but only 0 on EOF)
+ */
+ l9660_status l9660_read(l9660_file* file, void* buf, size_t size, size_t* read);
+ /*! Seek the file to \p offset from \p whence */
+ l9660_status l9660_seek(l9660_file* file, int whence, int32_t offset);
+ /*! Return the current position (suitable for passing to l9660_seek(file, SEEK_SET, ...)) */
+ uint32_t l9660_tell(l9660_file* file);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/ImGui.lib b/lib/ImGui.lib
index aa1d1fd..80485ec 100644
Binary files a/lib/ImGui.lib and b/lib/ImGui.lib differ
diff --git a/lib/Lib9660.lib b/lib/Lib9660.lib
new file mode 100644
index 0000000..c94c524
Binary files /dev/null and b/lib/Lib9660.lib differ
diff --git a/lib/libdvdcss.lib b/lib/libdvdcss.lib
index d61b7c0..0af46a1 100644
Binary files a/lib/libdvdcss.lib and b/lib/libdvdcss.lib differ
diff --git a/libdvdcss/msvc/libdvdcss.vcxproj b/libdvdcss/msvc/libdvdcss.vcxproj
index c6c0111..6fe6715 100644
--- a/libdvdcss/msvc/libdvdcss.vcxproj
+++ b/libdvdcss/msvc/libdvdcss.vcxproj
@@ -112,7 +112,7 @@
true
- $(SolutionDir)lib\
+ $(SolutionDir)lib\$(TargetName)$(TargetExt)
@@ -148,7 +148,7 @@
MultiThreadedDebug
Default
- false
+ true
Disabled
true
Level3
@@ -172,7 +172,7 @@
true
- $(SolutionDir)lib\
+ $(SolutionDir)lib\$(TargetName)$(TargetExt)
diff --git a/libdvdcss/src/dvdcss/dvdcss.h b/libdvdcss/src/dvdcss/dvdcss.h
index 2d86043..a38b1ad 100644
--- a/libdvdcss/src/dvdcss/dvdcss.h
+++ b/libdvdcss/src/dvdcss/dvdcss.h
@@ -106,7 +106,9 @@ LIBDVDCSS_EXPORT const char *dvdcss_error ( const dvdcss_t );
LIBDVDCSS_EXPORT int dvdcss_is_scrambled ( dvdcss_t );
+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);
#ifdef __cplusplus
}
#endif
diff --git a/libdvdcss/src/libdvdcss.c b/libdvdcss/src/libdvdcss.c
index 54e5d38..063d7dc 100644
--- a/libdvdcss/src/libdvdcss.c
+++ b/libdvdcss/src/libdvdcss.c
@@ -486,11 +486,24 @@ 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) {
+ if (drive->b_errors)
+ {
+ drive->b_errors = FALSE;
+ return TRUE;
+ }
+ 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);