Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for CHD format #13810

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,8 @@ setup_target_project(Common Common)

target_link_libraries(Common Ext::Snappy)

include_directories(ext/libchdr)

if(USING_GLES2 OR (USING_EGL AND NOT USING_FBDEV))
find_package(X11)
endif()
Expand Down Expand Up @@ -1824,6 +1826,7 @@ if(WIN32)
endif()

target_link_libraries(${CoreLibName} Common native kirk cityhash sfmt19937 xbrz xxhash ${GlslangLibs}
chdr
${CoreExtraLibs} ${OPENGL_LIBRARIES} ${X11_LIBRARIES} ${CMAKE_DL_LIBS})

if(FFmpeg_FOUND)
Expand Down
151 changes: 147 additions & 4 deletions Core/FileSystems/BlockDevices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@

extern "C"
{
#include <dirent.h>
#include <chd.h>
#include "zlib.h"
#include "ext/libkirk/amctrl.h"
#include "ext/libkirk/kirk_engine.h"
Expand All @@ -40,12 +42,14 @@ BlockDevice *constructBlockDevice(FileLoader *fileLoader) {
// Check for CISO
if (!fileLoader->Exists())
return nullptr;
char buffer[4]{};
size_t size = fileLoader->ReadAt(0, 1, 4, buffer);
if (size == 4 && !memcmp(buffer, "CISO", 4))
char buffer[8]{};
size_t size = fileLoader->ReadAt(0, 1, 8, buffer);
if (size >= 4 && !memcmp(buffer, "CISO", 4))
return new CISOFileBlockDevice(fileLoader);
else if (size == 4 && !memcmp(buffer, "\x00PBP", 4))
else if (size >= 4 && !memcmp(buffer, "\x00PBP", 4))
return new NPDRMDemoBlockDevice(fileLoader);
else if (size >= 8 && !memcmp(buffer, "MComprHD", 8))
return new CHDFileBlockDevice(fileLoader);
else
return new FileBlockDevice(fileLoader);
}
Expand Down Expand Up @@ -377,6 +381,145 @@ bool CISOFileBlockDevice::ReadBlocks(u32 minBlock, int count, u8 *outPtr) {
return true;
}

/*
* CHD file
*/
static const UINT8 nullsha1[CHD_SHA1_BYTES] = { 0 };

CHDFileBlockDevice::CHDFileBlockDevice(FileLoader *fileLoader)
: chd(), header()
{
// Default, in case of failure
numBlocks = 0;

chd_header childHeader;

int depth = 0;
std::string paths[8];
paths[0] = fileLoader->Path();

chd_error err = chd_read_header(paths[0].c_str(), &childHeader);
if (err != CHDERR_NONE) {
ERROR_LOG(LOADER, "Error loading CHD header for '%s': %s", fileLoader->Path().c_str(), chd_error_string(err));
NotifyReadError();
return;
}

if (memcmp(nullsha1, childHeader.parentsha1, sizeof(childHeader.sha1)) != 0) {
chd_header parentHeader;

// Look for parent CHD in current directory
std::string chdDir;
#ifdef _WIN32
const size_t sepIndex = fileLoader->Path().rfind("\\");
#else
const size_t sepIndex = fileLoader->Path().rfind("/");
#endif
if (sepIndex != std::string::npos) {
chdDir = fileLoader->Path().substr(0, sepIndex);
} else {
chdDir = ".";
}
DIR *dir;
struct dirent *entry;
std::string filepath;

do {
parentHeader.length = 0;
dir = opendir(chdDir.c_str());
while ((entry = readdir(dir)) != NULL) {
#ifdef _WIN32
filepath = chdDir + "\\" + entry->d_name;
#else
filepath = chdDir + "/" + entry->d_name;
#endif
if (chd_read_header(filepath.c_str(), &parentHeader) == CHDERR_NONE &&
memcmp(parentHeader.sha1, childHeader.parentsha1, sizeof(parentHeader.sha1)) == 0) {
// ERROR_LOG(LOADER, "Checking '%s'", filepath.c_str());
paths[++depth] = filepath;
break;
}
}
// Check if parentHeader was opened
if (parentHeader.length == 0) {
ERROR_LOG(LOADER, "Error loading CHD '%s': parents not found", fileLoader->Path().c_str());
NotifyReadError();
return;
}
memcpy(childHeader.parentsha1, parentHeader.parentsha1, sizeof(childHeader.parentsha1));
} while (memcmp(nullsha1, childHeader.parentsha1, sizeof(childHeader.sha1)) != 0);
}

chd_file *parent = NULL;
chd_file *child = NULL;
err = chd_open(paths[depth].c_str(), CHD_OPEN_READ, NULL, &child);
if (err != CHDERR_NONE) {
ERROR_LOG(LOADER, "Error loading CHD '%s': %s", paths[depth].c_str(), chd_error_string(err));
NotifyReadError();
return;
}
for (int d = depth-1; d >= 0; d--) {
parent = child;
child = NULL;
err = chd_open(paths[d].c_str(), CHD_OPEN_READ, parent, &child);
if (err != CHDERR_NONE) {
ERROR_LOG(LOADER, "Error loading CHD '%s': %s", paths[d].c_str(), chd_error_string(err));
NotifyReadError();
return;
}
}
chd = child;

header = chd_get_header(chd);
readBuffer = new u8[header->hunkbytes];
currentHunk = -1;
blocksPerHunk = header->hunkbytes / header->unitbytes;
numBlocks = header->unitcount;
}

CHDFileBlockDevice::~CHDFileBlockDevice()
{
if (numBlocks > 0) {
chd_close(chd);
delete [] readBuffer;
}
}

bool CHDFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr, bool uncached)
{
if ((u32)blockNumber >= numBlocks) {
memset(outPtr, 0, GetBlockSize());
return false;
}
u32 hunk = blockNumber / blocksPerHunk;
u32 blockInHunk = blockNumber % blocksPerHunk;

if (currentHunk != hunk) {
chd_error err = chd_read(chd, hunk, readBuffer);
if (err != CHDERR_NONE) {
ERROR_LOG(LOADER, "CHD read failed: %d %d %s", blockNumber, hunk, chd_error_string(err));
NotifyReadError();
}
}
memcpy(outPtr, readBuffer + blockInHunk * header->unitbytes, GetBlockSize());

return true;
}

bool CHDFileBlockDevice::ReadBlocks(u32 minBlock, int count, u8 *outPtr) {
if (minBlock >= numBlocks) {
memset(outPtr, 0, GetBlockSize() * count);
return false;
}

for (int i = 0; i < count; i++) {
if (!ReadBlock(minBlock+i, outPtr+i*GetBlockSize())) {
return false;
}
}
return true;
}

NPDRMDemoBlockDevice::NPDRMDemoBlockDevice(FileLoader *fileLoader)
: fileLoader_(fileLoader)
{
Expand Down
19 changes: 19 additions & 0 deletions Core/FileSystems/BlockDevices.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
// with CISO images.

#include <mutex>
#include <chd.h>

#include "Common/CommonTypes.h"
#include "Core/ELF/PBPReader.h"
Expand Down Expand Up @@ -77,6 +78,24 @@ class CISOFileBlockDevice : public BlockDevice {
int ver_;
};

class CHDFileBlockDevice : public BlockDevice {
public:
CHDFileBlockDevice(FileLoader *fileLoader);
~CHDFileBlockDevice();
bool ReadBlock(int blockNumber, u8 *outPtr, bool uncached = false) override;
bool ReadBlocks(u32 minBlock, int count, u8 *outPtr) override;
u32 GetNumBlocks() override { return numBlocks; }
bool IsDisc() override { return true; }

private:
chd_file *chd;
const chd_header *header;
u8 *readBuffer;
u32 currentHunk;
u32 blocksPerHunk;
u32 numBlocks;
};


class FileBlockDevice : public BlockDevice {
public:
Expand Down
4 changes: 4 additions & 0 deletions Core/Loaders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader) {
// maybe it also just happened to have that size,
}
return IdentifiedFileType::PSP_ISO;
} else if (!strcasecmp(extension.c_str(), ".chd")) {
return IdentifiedFileType::PSP_ISO;
} else if (!strcasecmp(extension.c_str(), ".cso")) {
return IdentifiedFileType::PSP_ISO;
} else if (!strcasecmp(extension.c_str(), ".ppst")) {
Expand Down Expand Up @@ -181,6 +183,8 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader) {
else if (!strcasecmp(extension.c_str(),".pbp")) {
ERROR_LOG(LOADER, "A PBP with the wrong magic number?");
return IdentifiedFileType::PSP_PBP;
} else if (!strcasecmp(extension.c_str(),".chd")) {
return IdentifiedFileType::ARCHIVE_CHD;
} else if (!strcasecmp(extension.c_str(),".bin")) {
return IdentifiedFileType::UNKNOWN_BIN;
} else if (!strcasecmp(extension.c_str(),".zip")) {
Expand Down
1 change: 1 addition & 0 deletions Core/Loaders.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ enum class IdentifiedFileType {
ARCHIVE_RAR,
ARCHIVE_ZIP,
ARCHIVE_7Z,
ARCHIVE_CHD,
PSP_PS1_PBP,
ISO_MODE2,

Expand Down
2 changes: 1 addition & 1 deletion UI/MainScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,7 @@ void GameBrowser::Refresh() {
}
} else if (!listingPending_) {
std::vector<FileInfo> fileInfo;
path_.GetListing(fileInfo, "iso:cso:pbp:elf:prx:ppdmp:");
path_.GetListing(fileInfo, "iso:cso:pbp:elf:prx:ppdmp:chd:");
for (size_t i = 0; i < fileInfo.size(); i++) {
bool isGame = !fileInfo[i].isDirectory;
bool isSaveData = false;
Expand Down
53 changes: 53 additions & 0 deletions android/jni/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,58 @@ EXT_FILES := \
$(SRC)/ext/xbrz/xbrz.cpp \
$(SRC)/ext/xxhash.c \

FLAC_FILES := \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/bitmath.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/bitreader.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/cpu.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/crc.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/fixed.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/fixed_intrin_sse2.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/fixed_intrin_ssse3.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/float.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/format.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/lpc.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/lpc_intrin_avx2.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/lpc_intrin_sse2.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/lpc_intrin_sse41.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/lpc_intrin_sse.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/lpc_intrin_vsx.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/md5.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/memory.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/metadata_iterators.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/metadata_object.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/stream_decoder.c \
$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/window.c \

LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SRC)/ext/libchdr/deps/flac-1.3.3/src/libFLAC/include $(LOCAL_C_INCLUDES)

LZMA_FILES := \
$(SRC)/ext/libchdr/deps/lzma-16.04/C/Alloc.c \
$(SRC)/ext/libchdr/deps/lzma-16.04/C/Bra86.c \
$(SRC)/ext/libchdr/deps/lzma-16.04/C/Bra.c \
$(SRC)/ext/libchdr/deps/lzma-16.04/C/BraIA64.c \
$(SRC)/ext/libchdr/deps/lzma-16.04/C/CpuArch.c \
$(SRC)/ext/libchdr/deps/lzma-16.04/C/Delta.c \
$(SRC)/ext/libchdr/deps/lzma-16.04/C/LzFind.c \
$(SRC)/ext/libchdr/deps/lzma-16.04/C/Lzma2Dec.c \
$(SRC)/ext/libchdr/deps/lzma-16.04/C/Lzma2Enc.c \
$(SRC)/ext/libchdr/deps/lzma-16.04/C/Lzma86Dec.c \
$(SRC)/ext/libchdr/deps/lzma-16.04/C/Lzma86Enc.c \
$(SRC)/ext/libchdr/deps/lzma-16.04/C/LzmaDec.c \
$(SRC)/ext/libchdr/deps/lzma-16.04/C/LzmaEnc.c \
$(SRC)/ext/libchdr/deps/lzma-16.04/C/LzmaLib.c \
$(SRC)/ext/libchdr/deps/lzma-16.04/C/Sort.c \

LOCAL_CFLAGS += -D'PACKAGE_VERSION="1.3.3"' -DFLAC__HAS_OGG=0 -DFLAC__NO_DLL -DHAVE_LROUND -DHAVE_STDINT_H -DHAVE_STDLIB_H -D_7ZIP_ST

LIBCHDR_FILES := \
$(FLAC_FILES) \
$(LZMA_FILES) \
$(SRC)/ext/libchdr/src/bitstream.c \
$(SRC)/ext/libchdr/src/cdrom.c \
$(SRC)/ext/libchdr/src/chd.c \
$(SRC)/ext/libchdr/src/flac.c \
$(SRC)/ext/libchdr/src/huffman.c

EXEC_AND_LIB_FILES := \
$(ARCH_FILES) \
Expand All @@ -197,6 +249,7 @@ EXEC_AND_LIB_FILES := \
$(SPIRV_CROSS_FILES) \
$(EXT_FILES) \
$(NATIVE_FILES) \
$(LIBCHDR_FILES) \
TestRunner.cpp \
$(SRC)/Core/MIPS/MIPS.cpp.arm \
$(SRC)/Core/MIPS/MIPSAnalyst.cpp \
Expand Down
4 changes: 4 additions & 0 deletions android/jni/Locals.mk
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/../../ext/glslang \
$(LOCAL_PATH)/../../ext/miniupnp \
$(LOCAL_PATH)/../../ext/miniupnp-build \
$(LOCAL_PATH)/../../ext/libchdr/src \
$(LOCAL_PATH)/../../ext/libchdr/deps/flac-1.3.3/include \
$(LOCAL_PATH)/../../ext/libchdr/deps/lzma-16.04/C \
$(LOCAL_PATH)/../../ext/libchdr/deps/crypto \
$(LOCAL_PATH)/$(NATIVE)/base \
$(LOCAL_PATH)/../../ext/libpng17 \
$(LOCAL_PATH)/../../ext/libzip \
Expand Down
Loading