Fix decryption

This commit is contained in:
Li 2023-03-17 08:26:43 +13:00
parent 7eeee60df5
commit 103bb58da3
28 changed files with 1383 additions and 94 deletions

4
.gitignore vendored
View File

@ -6,6 +6,10 @@ libdvdcss/msvc/Debug/*
libdvdcss/msvc/Release/*
libdvdcss/msvc/.vs/*
Lib9660/Release/*
Lib9660/Debug/*
ImGui/Release/*
ImGui/Debug/*

View File

@ -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

View File

@ -19,6 +19,8 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Dvd\DvdRipper.cpp" />
<ClCompile Include="Dvd\TitleKey.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="Gui\D3D.cpp" />
<ClCompile Include="Gui\DumpDVD.cpp" />
@ -29,6 +31,8 @@
<ClCompile Include="Utils.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Dvd\DvdRipper.hpp" />
<ClInclude Include="Dvd\TitleKey.hpp" />
<ClInclude Include="Gui\D3D.hpp" />
<ClInclude Include="Gui\DumpDVD.hpp" />
<ClInclude Include="Gui\MainWindow.hpp" />
@ -96,7 +100,7 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(SolutionDir)include\PFD;$(SolutionDir)include\SDL;$(SolutionDir)ImGui;$(SolutionDir)libdvdcss\src\dvdcss;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)include\PFD;$(SolutionDir)include\SDL;$(SolutionDir)Lib9660;$(SolutionDir)ImGui;$(SolutionDir)libdvdcss\src\dvdcss;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp20</LanguageStandard>
<LanguageStandard_C>stdc17</LanguageStandard_C>
</ClCompile>
@ -104,7 +108,7 @@
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(SolutionDir)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>d3d11.lib;winmm.lib;version.lib;Imm32.lib;Setupapi.lib;SDL2.lib;ImGui.lib;libdvdcss.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>d3d11.lib;winmm.lib;version.lib;Imm32.lib;Setupapi.lib;SDL2.lib;ImGui.lib;Lib9660.lib;libdvdcss.lib;%(AdditionalDependencies)</AdditionalDependencies>
<EntryPointSymbol>
</EntryPointSymbol>
</Link>
@ -117,7 +121,7 @@
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(SolutionDir)include\PFD;$(SolutionDir)include\SDL;$(SolutionDir)ImGui;$(SolutionDir)libdvdcss\src\dvdcss;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)include\PFD;$(SolutionDir)include\SDL;$(SolutionDir)Lib9660;$(SolutionDir)ImGui;$(SolutionDir)libdvdcss\src\dvdcss;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<LanguageStandard>stdcpp20</LanguageStandard>
<LanguageStandard_C>stdc17</LanguageStandard_C>
@ -128,7 +132,7 @@
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(SolutionDir)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>d3d11.lib;winmm.lib;version.lib;Imm32.lib;Setupapi.lib;SDL2.lib;ImGui.lib;libdvdcss.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>d3d11.lib;winmm.lib;version.lib;Imm32.lib;Setupapi.lib;SDL2.lib;ImGui.lib;Lib9660.lib;libdvdcss.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

View File

@ -39,6 +39,12 @@
<ClCompile Include="Utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Dvd\TitleKey.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Dvd\DvdRipper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Scsi\IoCtl.hpp">
@ -65,5 +71,11 @@
<ClInclude Include="Utils.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Dvd\TitleKey.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Dvd\DvdRipper.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

233
DumpDVD/Dvd/DvdRipper.cpp Normal file
View File

@ -0,0 +1,233 @@
#include "DvdRipper.hpp"
#include <iostream>
#include <fstream>
#include <thread>
#include <sstream>
#include <filesystem>
#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();
}
}

64
DumpDVD/Dvd/DvdRipper.hpp Normal file
View File

@ -0,0 +1,64 @@
#ifndef _LI_DVDRIPPER
#define _LI_DVDRIPPER 1
#include <iostream>
#include <dvdcss.h>
#include <thread>
#include <string>
#include <fstream>
#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

112
DumpDVD/Dvd/TitleKey.cpp Normal file
View File

@ -0,0 +1,112 @@
#include "TitleKey.hpp"
#include <lib9660.h>
#include <iostream>
#include <vector>
#include <filesystem>
#include "../Utils.hpp"
namespace Li::Dvd {
static std::vector<sectorInfo*> 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<sectorInfo*> TitleKey::GetTitleKeys(dvdcss_t drive) {
drv = drive;
sectorsList = std::vector<sectorInfo*>();
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();
}
}

25
DumpDVD/Dvd/TitleKey.hpp Normal file
View File

@ -0,0 +1,25 @@
#ifndef _LI_TITLEKEY
#define _LI_TITLEKEY 1
#include <dvdcss.h>
#include <lib9660.h>
#include <vector>
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<sectorInfo*> 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

View File

@ -1,3 +1,4 @@
#include "DumpDVD.hpp"
#include <imgui.h>
#include <SDL.h>
@ -8,18 +9,17 @@
#include <portable-file-dialogs.h>
#include <iostream>
#include <fstream>
#include <mutex>
#include <thread>
#include <sstream>
#include <filesystem>
#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<uint32_t>* 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<uint32_t>* 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)
{

View File

@ -2,11 +2,12 @@
#define _LI_DUMP_DVD_H 1
#include <iostream>
#include <string>
#include <vector>
#include <thread>
#include <mutex>
#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<Li::Scsi::OpticalDrive*>* drivesList;
std::thread* pollDrives;
Li::Dvd::DvdRipper* dvdRipper;
void ripDiscThread();
void pollDrivesThread();

View File

@ -60,7 +60,7 @@ namespace Li::Scsi {
return this->drivePath;
}
uint64_t OpticalDrive::Sectors() {
uint32_t OpticalDrive::Sectors() {
return this->sectors;
}

View File

@ -10,7 +10,7 @@ namespace Li::Scsi {
bool discInDrive;
std::vector<uint32_t>* supportedSpeeds;
uint64_t sectors;
uint32_t sectors;
void getDriveInformation(std::string drv);
public:
@ -20,7 +20,7 @@ namespace Li::Scsi {
std::vector<uint32_t>* SupportedSpeeds();
std::string DrivePath();
std::string VolumeName();
uint64_t Sectors();
uint32_t Sectors();
bool DiscInDrive();
static std::vector<OpticalDrive*>* ListOpticalDrives();

View File

@ -3,6 +3,15 @@
#include <string>
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" };

View File

@ -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

4
Lib9660/Jamfile Normal file
View File

@ -0,0 +1,4 @@
SubDir LIB9660_TOP ;
SubDirCcFlags -std=c99 $(LIB9660_OPTS) ;
Library lib9660 : lib9660.c ;

158
Lib9660/Lib9660.vcxproj Normal file
View File

@ -0,0 +1,158 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="lib9660.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="lib9660.c" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{7f404ded-08ff-4092-97ef-0f63c5788dd2}</ProjectGuid>
<RootNamespace>Lib9660</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)lib\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>
</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>
</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<OutputFile>$(SolutionDir)lib\$(TargetName)$(TargetExt)</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>
</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>
</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="lib9660.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="lib9660.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ShowAllFiles>true</ShowAllFiles>
</PropertyGroup>
</Project>

28
Lib9660/Makefile Normal file
View File

@ -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

53
Lib9660/README.md Normal file
View File

@ -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

336
Lib9660/lib9660.c Normal file
View File

@ -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 <string.h>
#ifdef DEBUG
#include <stdlib.h>
#endif
#ifdef L9660_HAVE_STDIO
#include <stdio.h>
#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;
}

219
Lib9660/lib9660.h Normal file
View File

@ -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 <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#ifdef L9660_HAVE_STDIO
#include <stdio.h>
#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

Binary file not shown.

BIN
lib/Lib9660.lib Normal file

Binary file not shown.

Binary file not shown.

View File

@ -112,7 +112,7 @@
</Bscmake>
<Lib>
<SuppressStartupBanner>true</SuppressStartupBanner>
<OutputFile>$(SolutionDir)lib\</OutputFile>
<OutputFile>$(SolutionDir)lib\$(TargetName)$(TargetExt)</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -148,7 +148,7 @@
<ClCompile>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<InlineFunctionExpansion>Default</InlineFunctionExpansion>
<FunctionLevelLinking>false</FunctionLevelLinking>
<FunctionLevelLinking>true</FunctionLevelLinking>
<Optimization>Disabled</Optimization>
<SuppressStartupBanner>true</SuppressStartupBanner>
<WarningLevel>Level3</WarningLevel>
@ -172,7 +172,7 @@
</Bscmake>
<Lib>
<SuppressStartupBanner>true</SuppressStartupBanner>
<OutputFile>$(SolutionDir)lib\</OutputFile>
<OutputFile>$(SolutionDir)lib\$(TargetName)$(TargetExt)</OutputFile>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

View File

@ -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

View File

@ -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);