Merge branch 'skmp/fix-case-streamheaderpack' into 'main'

streamheaderpack: bring in fcaseopen for case insensitive paths

See merge request skmp/dca3-game!51
This commit is contained in:
Stefanos Kornilios Mitsis Poiitidis 2025-03-11 19:20:13 +00:00
commit 8eaa1c73ea

View file

@ -4,6 +4,9 @@
#include <string>
#include <cstring>
#include <dirent.h>
#include <unistd.h>
struct WavHeader {
// RIFF Header
char riff[4]; // RIFF Header Magic header
@ -29,6 +32,140 @@ struct WavHeader {
#define DCStreamedNameTable DCStreamedNameTable_miami
#include "../miami/audio/sampman_dc_streams.h"
#undef DCStreamedNameTable
// Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen)
// Returned string should freed manually (if exists)
char* casepath(char const* path, bool checkPathFirst = true)
{
//TODO: Implement this
bool access_ok = false; //access(path, F_OK) != -1
// printf("TODO: FIXME %s\n", __func__);
if (checkPathFirst && access_ok ) {
// File path is correct
return nullptr;
}
size_t l = strlen(path);
if (l > 2 && path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
// remove ./ from the start of the path
path += 2;
}
char* p = (char*)alloca(l + 1);
char* out = (char*)malloc(l + 3); // for extra ./
strcpy(p, path);
size_t rl = 0;
DIR* d;
char* c;
#if defined(__SWITCH__) || defined(PSP2)
if( (c = strstr(p, ":/")) != NULL) // scheme used by some environments, eg. switch, vita
{
size_t deviceNameOffset = c - p + 3;
char* deviceNamePath = (char*)alloca(deviceNameOffset + 1);
strlcpy(deviceNamePath, p, deviceNameOffset);
deviceNamePath[deviceNameOffset] = 0;
d = opendir(deviceNamePath);
p = c + 1;
}
else
#endif
if (p[0] == '/' || p[0] == '\\')
{
d = opendir("/");
}
else
{
d = opendir(".");
out[0] = '.';
out[1] = 0;
rl = 1;
}
bool cantProceed = false; // just convert slashes in what's left in string, don't correct case of letters(because we can't)
bool mayBeTrailingSlash = false;
while (c = strsep(&p, "/\\"))
{
// May be trailing slash(allow), slash at the start(avoid), or multiple slashes(avoid)
if (*c == '\0')
{
mayBeTrailingSlash = true;
continue;
} else {
mayBeTrailingSlash = false;
}
out[rl] = '/';
rl += 1;
out[rl] = 0;
if (cantProceed)
{
strcpy(out + rl, c);
rl += strlen(c);
continue;
}
struct dirent* e;
while (e = readdir(d))
{
if (strcasecmp(c, e->d_name) == 0)
{
strcpy(out + rl, e->d_name);
int reportedLen = (int)strlen(e->d_name);
rl += reportedLen;
assert(reportedLen == strlen(c) && "casepath: This is not good at all");
closedir(d);
d = opendir(out);
// Either it wasn't a folder, or permission error, I/O error etc.
if (!d) {
cantProceed = true;
}
break;
}
}
if (!e)
{
printf("casepath couldn't find dir/file \"%s\", full path was %s\n", c, path);
// No match, add original name and continue converting further slashes.
strcpy(out + rl, c);
rl += strlen(c);
cantProceed = true;
}
}
if (d) closedir(d);
if (mayBeTrailingSlash) {
out[rl] = '/'; rl += 1;
out[rl] = '\0';
}
if (rl > l + 2) {
printf("\n\ncasepath: Corrected path length is longer then original+2:\n\tOriginal: %s (%zu chars)\n\tCorrected: %s (%zu chars)\n\n", path, l, out, rl);
}
return out;
}
FILE* fcaseopen(char const* filename, char const* mode)
{
FILE* result;
char* real = casepath(filename);
if (!real)
result = fopen(filename, mode);
else {
result = fopen(real, mode);
free(real);
}
return result;
}
int main(int argc, const char** argv) {
size_t table_len = 0;
@ -50,7 +187,7 @@ int main(int argc, const char** argv) {
return 1;
}
FILE* fout=fopen(argv[3], "wb");
FILE* fout=fcaseopen(argv[3], "wb");
if (!fout) {
std::cerr << "Failed to open " << argv[3] << " for writing" << std::endl;
return 1;
@ -59,7 +196,7 @@ int main(int argc, const char** argv) {
for (int i = 0; i < table_len; i++) {
std::string filename = std::string(argv[2]) + "/" + table[i];
FILE* f = fopen(filename.c_str(), "rb");
FILE* f = fcaseopen(filename.c_str(), "rb");
if (!f) {
std::cerr << "Failed to open " << filename << std::endl;
fclose(fout);