You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
3.2 KiB
135 lines
3.2 KiB
#include "storm/storm_sdl_rw.h" |
|
|
|
#include <algorithm> |
|
#include <cstdint> |
|
#include <cstring> |
|
|
|
#include "engine.h" |
|
#include "storm/storm.h" |
|
#include "utils/log.hpp" |
|
#include "utils/paths.h" |
|
|
|
namespace devilution { |
|
|
|
namespace { |
|
|
|
static HANDLE SFileRwGetHandle(struct SDL_RWops *context) |
|
{ |
|
return (HANDLE)context->hidden.unknown.data1; |
|
} |
|
|
|
static void SFileRwSetHandle(struct SDL_RWops *context, HANDLE handle) |
|
{ |
|
context->hidden.unknown.data1 = handle; |
|
} |
|
|
|
#ifndef USE_SDL1 |
|
static Sint64 SFileRwSize(struct SDL_RWops *context) |
|
{ |
|
return SFileGetFileSize(SFileRwGetHandle(context)); |
|
} |
|
#endif |
|
|
|
#ifndef USE_SDL1 |
|
static Sint64 SFileRwSeek(struct SDL_RWops *context, Sint64 offset, int whence) |
|
#else |
|
static int SFileRwSeek(struct SDL_RWops *context, int offset, int whence) |
|
#endif |
|
{ |
|
DWORD swhence; |
|
switch (whence) { |
|
case RW_SEEK_SET: |
|
swhence = DVL_FILE_BEGIN; |
|
break; |
|
case RW_SEEK_CUR: |
|
swhence = DVL_FILE_CURRENT; |
|
break; |
|
case RW_SEEK_END: |
|
swhence = DVL_FILE_END; |
|
break; |
|
default: |
|
return -1; |
|
} |
|
const std::uint64_t pos = SFileSetFilePointer(SFileRwGetHandle(context), offset, swhence); |
|
if (pos == static_cast<std::uint64_t>(-1)) { |
|
Log("SFileRwSeek error: {}", SErrGetLastError()); |
|
} |
|
return pos; |
|
} |
|
|
|
#ifndef USE_SDL1 |
|
static size_t SFileRwRead(struct SDL_RWops *context, void *ptr, size_t size, size_t maxnum) |
|
#else |
|
static int SFileRwRead(struct SDL_RWops *context, void *ptr, int size, int maxnum) |
|
#endif |
|
{ |
|
size_t numRead = 0; |
|
if (!SFileReadFileThreadSafe(SFileRwGetHandle(context), ptr, maxnum * size, &numRead)) { |
|
const auto errCode = SErrGetLastError(); |
|
if (errCode != STORM_ERROR_HANDLE_EOF) { |
|
Log("SFileRwRead error: {} {} ERROR CODE {}", size, maxnum, errCode); |
|
} |
|
} |
|
return numRead / size; |
|
} |
|
|
|
static int SFileRwClose(struct SDL_RWops *context) |
|
{ |
|
SFileCloseFileThreadSafe(SFileRwGetHandle(context)); |
|
delete context; |
|
return 0; |
|
} |
|
|
|
SDL_RWops *SFileRw_FromStormHandle(HANDLE handle) |
|
{ |
|
auto *result = new SDL_RWops(); |
|
std::memset(result, 0, sizeof(*result)); |
|
|
|
#ifndef USE_SDL1 |
|
result->size = &SFileRwSize; |
|
result->type = SDL_RWOPS_UNKNOWN; |
|
#else |
|
result->type = 0; |
|
#endif |
|
|
|
result->seek = &SFileRwSeek; |
|
result->read = &SFileRwRead; |
|
result->write = nullptr; |
|
result->close = &SFileRwClose; |
|
SFileRwSetHandle(result, handle); |
|
return result; |
|
} |
|
|
|
} // namespace |
|
|
|
SDL_RWops *SFileOpenRw(const char *filename) |
|
{ |
|
HANDLE handle; |
|
if (SFileOpenFile(filename, &handle)) |
|
return SFileRw_FromStormHandle(handle); |
|
|
|
std::string relativePath = filename; |
|
#ifndef _WIN32 |
|
std::replace(relativePath.begin(), relativePath.end(), '\\', '/'); |
|
#endif |
|
|
|
SDL_RWops *rwops; |
|
if (relativePath[0] == '/') { |
|
return SDL_RWFromFile(relativePath.c_str(), "rb"); |
|
} |
|
|
|
const std::string path = paths::AssetsPath() + relativePath; |
|
if ((rwops = SDL_RWFromFile(path.c_str(), "rb")) != nullptr) |
|
return rwops; |
|
|
|
#ifdef __ANDROID__ |
|
// On Android, fall back to the APK's assets. |
|
// This is handled by SDL when we pass a relative path. |
|
if (!paths::AssetsPath().empty() && (rwops = SDL_RWFromFile(relativePath.c_str(), "rb"))) |
|
return rwops; |
|
#endif |
|
|
|
return nullptr; |
|
} |
|
|
|
} // namespace devilution
|
|
|