fix(gx): SFile can read from an MPQ-archived file or a plain file

This commit is contained in:
phaneron 2024-02-17 21:31:52 -05:00
parent e20f185f75
commit 70642dec21
2 changed files with 90 additions and 24 deletions

View file

@ -4,6 +4,7 @@
#include <StormLib.h> #include <StormLib.h>
#include <storm/Memory.hpp> #include <storm/Memory.hpp>
#include <storm/String.hpp> #include <storm/String.hpp>
#include <bc/file/File.hpp>
#include "util/Filesystem.hpp" #include "util/Filesystem.hpp"
static char s_basepath[STORM_MAX_PATH] = {0}; static char s_basepath[STORM_MAX_PATH] = {0};
@ -11,15 +12,46 @@ static char s_datapath[STORM_MAX_PATH] = {0};
// TODO Proper implementation // TODO Proper implementation
int32_t SFile::Close(SFile* file) { int32_t SFile::Close(SFile* file) {
switch (file->m_type) {
case SFILE_PLAIN:
Blizzard::File::Close(reinterpret_cast<Blizzard::File::StreamRecord*>(file->m_handle));
break;
case SFILE_PAQ:
SFileCloseFile(file->m_handle); SFileCloseFile(file->m_handle);
break;
default:
STORM_ASSERT(0);
}
delete file; delete file;
return 1; return 1;
} }
// TODO Proper implementation // TODO Proper implementation
uint32_t SFile::GetFileSize(SFile* file, uint32_t* filesizeHigh) { uint32_t SFile::GetFileSize(SFile* file, uint32_t* filesizeHigh) {
DWORD high = 0; uint32_t high = 0;
DWORD low = SFileGetFileSize(file->m_handle, &high); uint32_t low = 0;
switch (file->m_type) {
case SFILE_PAQ:
{
// Get size from stormlib
DWORD dwHigh = 0;
DWORD dwLow = SFileGetFileSize(file->m_handle, &dwHigh);
low = static_cast<uint32_t>(dwLow);
high = static_cast<uint32_t>(dwHigh);
break;
}
case SFILE_PLAIN:
{
uint64_t size = Blizzard::File::GetFileInfo(reinterpret_cast<Blizzard::File::StreamRecord*>(file->m_handle))->size;
low = size & 0xFFFFFFFF;
high = size >> 32;
break;
}
default:
STORM_ASSERT(0);
}
if (filesizeHigh) { if (filesizeHigh) {
*filesizeHigh = high; *filesizeHigh = high;
@ -96,24 +128,44 @@ int32_t SFile::OpenEx(SArchive* archive, const char* filename, uint32_t flags, S
} }
SStrCopy(path, filename, STORM_MAX_PATH); SStrCopy(path, filename, STORM_MAX_PATH);
OsFileToNativeSlashes(path);
SFILE_TYPE filetype = SFILE_PLAIN;
void* filehandle;
HANDLE handle; HANDLE handle;
if (!SFileOpenFileEx(nullptr, path, SFILE_OPEN_LOCAL_FILE, &handle)) {
OsFileToBackSlashes(path); uint32_t openflags = BC_FILE_OPEN_MUST_EXIST | BC_FILE_OPEN_SHARE_READ | BC_FILE_OPEN_READ;
if (!SFileOpenFileEx(g_mpqHandle, path, SFILE_OPEN_FROM_MPQ, &handle)) { Blizzard::File::StreamRecord* stream;
// Attempt to open plain file first
if (Blizzard::File::Open(path, openflags, stream)) {
// plain file was opened
filehandle = reinterpret_cast<void*>(stream);
// Attempt to open MPQ archived file
} else if (SFileOpenFileEx(g_mpqHandle, path, SFILE_OPEN_FROM_MPQ, &handle)) {
filetype = SFILE_PAQ;
filehandle = static_cast<void*>(handle);
} else {
// could not open either plain or MPQ archived file
return 0; return 0;
} }
}
*file = new SFile; *file = new SFile;
(*file)->m_handle = handle; (*file)->m_handle = filehandle;
(*file)->m_type = filetype;
return 1; return 1;
} }
// TODO Proper implementation // TODO Proper implementation
int32_t SFile::Read(SFile* file, void* buffer, size_t bytestoread, size_t* bytesread, SOVERLAPPED* overlapped, TASYNCPARAMBLOCK* asyncparam) { int32_t SFile::Read(SFile* file, void* buffer, size_t bytestoread, size_t* bytesread, SOVERLAPPED* overlapped, TASYNCPARAMBLOCK* asyncparam) {
switch (file->m_type) {
case SFILE_PLAIN:
{
Blizzard::File::Read(file->m_stream, buffer, bytestoread, bytesread);
return 1;
}
case SFILE_PAQ:
{
DWORD read = 0; DWORD read = 0;
if (SFileReadFile(file->m_handle, buffer, static_cast<DWORD>(bytestoread), &read, nullptr)) { if (SFileReadFile(file->m_handle, buffer, static_cast<DWORD>(bytestoread), &read, nullptr)) {
if (bytesread) { if (bytesread) {
@ -127,6 +179,12 @@ int32_t SFile::Read(SFile* file, void* buffer, size_t bytestoread, size_t* bytes
return 0; return 0;
} }
} }
default:
STORM_ASSERT(0)
}
return 0;
}
int32_t SFile::Unload(void* ptr) { int32_t SFile::Unload(void* ptr) {
SMemFree(ptr, __FILE__, __LINE__, 0); SMemFree(ptr, __FILE__, __LINE__, 0);

View file

@ -13,6 +13,13 @@ class StreamRecord;
}; };
}; };
enum SFILE_TYPE {
SFILE_PLAIN = 0x0,
SFILE_COMPRESSED = 0x1,
SFILE_PAQ = 0x2,
SFILE_OLD_SFILE = 0x3,
SFILE_ZIP_FILE = 0x4
};
class SFile { class SFile {
public: public:
@ -31,6 +38,7 @@ class SFile {
static int32_t GetDataPath(char* path, size_t capacity); static int32_t GetDataPath(char* path, size_t capacity);
// Member variables // Member variables
SFILE_TYPE m_type;
void* m_handle; void* m_handle;
}; };