CDVD: Add support for CHD format

This commit is contained in:
SleepyMan 2020-12-25 07:25:55 -03:00 committed by refractionpcsx2
parent 3dc5162079
commit 0599e675a0
13 changed files with 335 additions and 6 deletions

3
.gitmodules vendored
View File

@ -10,3 +10,6 @@
[submodule "3rdparty/yaml-cpp/yaml-cpp"]
path = 3rdparty/yaml-cpp/yaml-cpp
url = https://github.com/jbeder/yaml-cpp.git
[submodule "3rdparty/libchdr/libchdr"]
path = 3rdparty/libchdr/libchdr
url = http://github.com/rtissera/libchdr.git

1
3rdparty/libchdr/libchdr vendored Submodule

@ -0,0 +1 @@
Subproject commit 97706b2bf84b78bbf68b231d6870cc05e9e1fe7e

99
3rdparty/libchdr/libchdr.vcxproj vendored Normal file
View File

@ -0,0 +1,99 @@
<?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="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Devel|Win32">
<Configuration>Devel</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Devel|x64">
<Configuration>Devel</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<Import Project="$(SolutionDir)common\vsprops\WinSDK.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization Condition="$(Configuration.Contains(Release))">true</WholeProgramOptimization>
<UseDebugLibraries Condition="$(Configuration.Contains(Debug))">true</UseDebugLibraries>
<UseDebugLibraries Condition="!$(Configuration.Contains(Debug))">false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="PropertySheets">
<Import Project="..\DefaultProjectRootDir.props" />
<Import Project="..\3rdparty.props" />
<Import Condition="$(Configuration.Contains(Debug))" Project="..\..\common\vsprops\CodeGen_Debug.props" />
<Import Condition="$(Configuration.Contains(Devel))" Project="..\..\common\vsprops\CodeGen_Devel.props" />
<Import Condition="$(Configuration.Contains(Release))" Project="..\..\common\vsprops\CodeGen_Release.props" />
<Import Condition="!$(Configuration.Contains(Release))" Project="..\..\common\vsprops\IncrementalLinking.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<PublicIncludeDirectories>
</PublicIncludeDirectories>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_7ZIP_ST</PreprocessorDefinitions>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
<AdditionalIncludeDirectories>$(ProjectDir)/libchdr/include/;$(ProjectDir)/libchdr/src/;$(ProjectDir)/libchdr/deps/lzma-19.00/include;$(ProjectDir)/libchdr/deps/zlib-1.2.11;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">MaxSpeed</Optimization>
<FavorSizeOrSpeed Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Speed</FavorSizeOrSpeed>
<OmitFramePointers Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</OmitFramePointers>
<WholeProgramOptimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</WholeProgramOptimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Default</BasicRuntimeChecks>
<MinimalRebuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</MinimalRebuild>
<MinimalRebuild Condition="'$(Configuration)|$(Platform)'=='Devel|Win32'">false</MinimalRebuild>
<MinimalRebuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</MinimalRebuild>
<MinimalRebuild Condition="'$(Configuration)|$(Platform)'=='Devel|x64'">false</MinimalRebuild>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="libchdr\deps\lzma-19.00\src\Alloc.c" />
<ClCompile Include="libchdr\deps\lzma-19.00\src\Bra86.c" />
<ClCompile Include="libchdr\deps\lzma-19.00\src\BraIA64.c" />
<ClCompile Include="libchdr\deps\lzma-19.00\src\CpuArch.c" />
<ClCompile Include="libchdr\deps\lzma-19.00\src\Delta.c" />
<ClCompile Include="libchdr\deps\lzma-19.00\src\LzFind.c" />
<ClCompile Include="libchdr\deps\lzma-19.00\src\Lzma86Dec.c" />
<ClCompile Include="libchdr\deps\lzma-19.00\src\LzmaDec.c" />
<ClCompile Include="libchdr\deps\lzma-19.00\src\LzmaEnc.c" />
<ClCompile Include="libchdr\deps\lzma-19.00\src\Sort.c" />
<ClCompile Include="libchdr\src\libchdr_bitstream.c">
<DeploymentContent>false</DeploymentContent>
</ClCompile>
<ClCompile Include="libchdr\src\libchdr_cdrom.c" />
<ClCompile Include="libchdr\src\libchdr_chd.c" />
<ClCompile Include="libchdr\src\libchdr_flac.c" />
<ClCompile Include="libchdr\src\libchdr_huffman.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>

View File

@ -67,6 +67,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsamplerate", "3rdparty\l
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml", "3rdparty\yaml-cpp\yaml.vcxproj", "{48329442-E41B-4A1F-8364-36EEE1B71343}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libchdr", "3rdparty\libchdr\libchdr.vcxproj", "{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@ -527,6 +529,7 @@ Global
{449AD25E-424A-4714-BABC-68706CDCC33B} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{47AFDBEF-F15F-4BC0-B436-5BE443C3F80F} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{48329442-E41B-4A1F-8364-36EEE1B71343} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{A0D2B3AD-1F72-4EE3-8B5C-F2C358DA35F0} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0BC474EA-3628-45D3-9DBC-E22D0B7E0F77}

View File

@ -288,3 +288,6 @@ if(NOT USE_SYSTEM_YAML)
message(FATAL_ERROR "No bundled yaml-cpp was found")
endif()
endif()
add_subdirectory(3rdparty/libchdr/libchdr EXCLUDE_FROM_ALL)
include_directories(3rdparty/libchdr/libchdr/include)

View File

@ -111,7 +111,7 @@ set(UtilitiesFinalSources
set(UtilitiesFinalLibs
${LIBC_LIBRARIES} # Gold (new linux linker) does not get automatically dependency of dependency
${wxWidgets_LIBRARIES}
yaml-cpp
yaml-cpp chdr-static
)
add_pcsx2_lib(${Output} "${UtilitiesFinalSources}" "${UtilitiesFinalLibs}" "${UtilitiesFinalFlags}")

View File

@ -0,0 +1,173 @@
#include "PrecompiledHeader.h"
#include "ChdFileReader.h"
#include "CDVD/CompressedFileReaderUtils.h"
#include <wx/dir.h>
bool ChdFileReader::CanHandle(const wxString &fileName)
{
if (!wxFileName::FileExists(fileName) || !fileName.Lower().EndsWith(L".chd")) {
return false;
}
return true;
}
bool ChdFileReader::Open(const wxString &fileName)
{
m_filename = fileName;
chd_file *child = NULL;
chd_file *parent = NULL;
chd_header *header = new chd_header;
chd_header *parent_header = new chd_header;
wxString chds[8];
chds[0] = fileName;
int chd_depth = 0;
chd_error error;
do {
// Console.Error(L"chd_open checking: %s", static_cast<const char*>(chds[chd_depth]));
error = chd_open(static_cast<const char*>(chds[chd_depth]), CHD_OPEN_READ, NULL, &child);
if (error == CHDERR_REQUIRES_PARENT) {
if (chd_read_header(static_cast<const char*>(chds[chd_depth]), header) != CHDERR_NONE) {
Console.Error(L"chd_open chd_read_header error: %s: %s", chd_error_string(error), static_cast<const char*>(chds[chd_depth]));
delete header;
delete parent_header;
return false;
}
bool found_parent = false;
wxFileName wxfilename(chds[chd_depth]);
wxString dir_path = wxfilename.GetPath();
wxDir dir(dir_path);
if (dir.IsOpened()) {
wxString parent_fileName;
bool cont = dir.GetFirst(&parent_fileName, wxString("*.", wxfilename.GetExt()), wxDIR_FILES | wxDIR_HIDDEN);
while ( cont ) {
parent_fileName = wxFileName(dir_path, parent_fileName).GetFullPath();
if (chd_read_header(static_cast<const char*>(parent_fileName), parent_header) == CHDERR_NONE &&
memcmp(parent_header->sha1, header->parentsha1, sizeof(parent_header->sha1)) == 0) {
found_parent = true;
chds[++chd_depth] = wxString(parent_fileName);
break;
}
cont = dir.GetNext(&parent_fileName);
}
}
if (!found_parent) {
Console.Error(L"chd_open no parent for: %s", static_cast<const char*>(chds[chd_depth]));
break;
}
}
} while(error == CHDERR_REQUIRES_PARENT);
delete parent_header;
if (error != CHDERR_NONE) {
Console.Error(L"chd_open return error: %s", chd_error_string(error));
delete header;
return false;
}
// Console.Error(L"chd_opened parent: %d %s", chd_depth, static_cast<const char*>(chds[chd_depth]));
for (int d = chd_depth-1; d >= 0; d--) {
// parent = child;
// child = (chd_file**)malloc(sizeof(chd_file*));
parent = child;
child = NULL;
// Console.Error(L"chd_open opening chd: %d %s", d, static_cast<const char*>(chds[d]));
error = chd_open(static_cast<const char*>(chds[d]), CHD_OPEN_READ, parent, &child);
if (error != CHDERR_NONE) {
Console.Error(L"chd_open return error: %s", chd_error_string(error));
delete header;
return false;
}
}
ChdFile = child;
if (chd_read_header(static_cast<const char*>(chds[0]), header) != CHDERR_NONE) {
Console.Error(L"chd_open chd_read_header error: %s: %s", chd_error_string(error), static_cast<const char*>(chds[0]));
delete header;
return false;
}
// const chd_header *header = chd_get_header(ChdFile);
sector_size = header->unitbytes;
sector_count = header->unitcount;
sectors_per_hunk = header->hunkbytes / sector_size;
hunk_buffer = new u8[header->hunkbytes];
current_hunk = -1;
delete header;
return true;
}
int ChdFileReader::ReadSync(void *pBuffer, uint sector, uint count)
{
u8 *dst = (u8 *) pBuffer;
u32 hunk = sector / sectors_per_hunk;
u32 sector_in_hunk = sector % sectors_per_hunk;
chd_error error;
for (uint i = 0; i < count; i++) {
if (current_hunk != hunk) {
error = chd_read(ChdFile, hunk, hunk_buffer);
if (error != CHDERR_NONE) {
Console.Error(L"chd_read return error: %s", chd_error_string(error));
// return i * m_blocksize;
}
current_hunk = hunk;
}
memcpy(dst + i * m_blocksize, hunk_buffer + sector_in_hunk * sector_size, m_blocksize);
sector_in_hunk++;
if (sector_in_hunk >= sectors_per_hunk) {
hunk++;
sector_in_hunk = 0;
}
}
return m_blocksize * count;
}
void ChdFileReader::BeginRead(void *pBuffer, uint sector, uint count)
{
// TODO: Check if libchdr can read asynchronously
async_read = ReadSync(pBuffer, sector, count);
}
int ChdFileReader::FinishRead()
{
return async_read;
}
void ChdFileReader::Close()
{
if (hunk_buffer != NULL) {
//free(hunk_buffer);
delete[] hunk_buffer;
hunk_buffer = NULL;
}
if (ChdFile != NULL) {
chd_close(ChdFile);
ChdFile = NULL;
}
}
uint ChdFileReader::GetBlockSize() const
{
return m_blocksize;
}
void ChdFileReader::SetBlockSize(uint blocksize)
{
m_blocksize = blocksize;
}
u32 ChdFileReader::GetBlockCount() const
{
return sector_count;
}
ChdFileReader::ChdFileReader(void)
{
ChdFile = NULL;
hunk_buffer = NULL;
};

View File

@ -0,0 +1,34 @@
#pragma once
#include "AsyncFileReader.h"
#include "libchdr/chd.h"
class ChdFileReader : public AsyncFileReader
{
DeclareNoncopyableObject(ChdFileReader);
public:
virtual ~ChdFileReader(void) { Close(); };
static bool CanHandle(const wxString &fileName);
bool Open(const wxString &fileName) override;
int ReadSync(void *pBuffer, uint sector, uint count) override;
void BeginRead(void *pBuffer, uint sector, uint count) override;
int FinishRead(void) override;
void CancelRead(void) override {};
void Close(void) override;
void SetBlockSize(uint blocksize);
uint GetBlockSize() const;
uint GetBlockCount(void) const override;
ChdFileReader(void);
private:
chd_file *ChdFile;
u8 *hunk_buffer;
u32 sector_size;
u32 sector_count;
u32 sectors_per_hunk;
u32 current_hunk;
u32 async_read;
};

View File

@ -16,12 +16,16 @@
#include "PrecompiledHeader.h"
#include "AsyncFileReader.h"
#include "CompressedFileReader.h"
#include "ChdFileReader.h"
#include "CsoFileReader.h"
#include "GzippedFileReader.h"
// CompressedFileReader factory.
AsyncFileReader* CompressedFileReader::GetNewReader(const wxString& fileName)
{
if (ChdFileReader::CanHandle(fileName)) {
return new ChdFileReader();
}
if (GzippedFileReader::CanHandle(fileName))
{
return new GzippedFileReader();

View File

@ -208,6 +208,7 @@ set(pcsx2CDVDSources
CDVD/OutputIsoFile.cpp
CDVD/ChunksCache.cpp
CDVD/CompressedFileReader.cpp
CDVD/ChdFileReader.cpp
CDVD/CsoFileReader.cpp
CDVD/GzippedFileReader.cpp
CDVD/IsoFS/IsoFile.cpp
@ -226,6 +227,7 @@ set(pcsx2CDVDHeaders
CDVD/ChunksCache.h
CDVD/CompressedFileReader.h
CDVD/CompressedFileReaderUtils.h
CDVD/ChdFileReader.h
CDVD/CsoFileReader.h
CDVD/GzippedFileReader.h
CDVD/IsoFileFormats.h

View File

@ -374,8 +374,8 @@ bool MainEmuFrame::_DoSelectIsoBrowser(wxString& result)
wxArrayString isoFilterTypes;
isoFilterTypes.Add(pxsFmt(_("All Supported (%s)"), WX_STR((isoSupportedLabel + L" .dump" + L" .gz" + L" .cso"))));
isoFilterTypes.Add(isoSupportedList + L";*.dump" + L";*.gz" + L";*.cso");
isoFilterTypes.Add(pxsFmt(_("All Supported (%s)"), WX_STR((isoSupportedLabel + L" .dump" + L" .gz" + L" .cso" + L" .chd"))));
isoFilterTypes.Add(isoSupportedList + L";*.dump" + L";*.gz" + L";*.cso" + L";*.chd");
isoFilterTypes.Add(pxsFmt(_("Disc Images (%s)"), WX_STR(isoSupportedLabel)));
isoFilterTypes.Add(isoSupportedList);
@ -383,8 +383,8 @@ bool MainEmuFrame::_DoSelectIsoBrowser(wxString& result)
isoFilterTypes.Add(pxsFmt(_("Blockdumps (%s)"), L".dump"));
isoFilterTypes.Add(L"*.dump");
isoFilterTypes.Add(pxsFmt(_("Compressed (%s)"), L".gz .cso"));
isoFilterTypes.Add(L"*.gz;*.cso");
isoFilterTypes.Add(pxsFmt(_("Compressed (%s)"), L".gz .cso .chd"));
isoFilterTypes.Add(L"*.gz;*.cso;*.chd");
isoFilterTypes.Add(_("All Files (*.*)"));
isoFilterTypes.Add(L"*.*");

View File

@ -248,6 +248,7 @@
<ClCompile Include="..\..\CDVD\BlockdumpFileReader.cpp" />
<ClCompile Include="..\..\CDVD\CDVDdiscReader.cpp" />
<ClCompile Include="..\..\CDVD\CDVDdiscThread.cpp" />
<ClCompile Include="..\..\CDVD\ChdFileReader.cpp" />
<ClCompile Include="..\..\CDVD\ChunksCache.cpp" />
<ClCompile Include="..\..\CDVD\CompressedFileReader.cpp" />
<ClCompile Include="..\..\CDVD\CsoFileReader.cpp" />
@ -949,6 +950,9 @@
<ProjectReference Include="..\..\..\3rdparty\yaml-cpp\yaml.vcxproj">
<Project>{48329442-e41b-4a1f-8364-36eee1b71343}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\3rdparty\libchdr\libchdr.vcxproj">
<Project>{a0d2b3ad-1f72-4ee3-8b5c-f2c358da35f0}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\3rdparty\zlib\zlib.vcxproj">
<Project>{2f6c0388-20cb-4242-9f6c-a6ebb6a83f47}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>

View File

@ -1312,6 +1312,9 @@
<ClCompile Include="..\..\gui\Dialogs\GSDumpDialog.cpp">
<Filter>AppHost\Dialogs</Filter>
</ClCompile>
<ClCompile Include="..\..\CDVD\ChdFileReader.cpp">
<Filter>System\ISO</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\Patch.h">