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.
153 lines
4.6 KiB
153 lines
4.6 KiB
#include <cstdio> |
|
#include <set> |
|
#include <string> |
|
#include <iterator> |
|
#include <vector> |
|
#include <algorithm> |
|
#include <fstream> |
|
#include <memory> |
|
#include <stdexcept> |
|
|
|
#include "devilution.h" |
|
#include "stubs.h" |
|
|
|
namespace dvl { |
|
|
|
struct memfile { |
|
std::string path; |
|
std::vector<char> buf; |
|
std::size_t pos = 0; |
|
}; |
|
|
|
static std::set<memfile *> files; |
|
|
|
HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, |
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, |
|
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) |
|
{ |
|
char name[DVL_MAX_PATH]; |
|
TranslateFileName(name, sizeof(name), lpFileName); |
|
DUMMY_PRINT("file: %s (%s)", lpFileName, name); |
|
UNIMPLEMENTED_UNLESS(!(dwDesiredAccess & ~(DVL_GENERIC_READ | DVL_GENERIC_WRITE))); |
|
memfile *file = new memfile; |
|
file->path = name; |
|
if (dwCreationDisposition == DVL_OPEN_EXISTING) { |
|
// read contents of existing file into buffer |
|
std::ifstream filestream(file->path, std::ios::binary); |
|
if (!filestream.fail()) { |
|
file->buf.insert(file->buf.begin(), |
|
std::istreambuf_iterator<char>(filestream), |
|
std::istreambuf_iterator<char>()); |
|
} |
|
} else if (dwCreationDisposition == DVL_CREATE_ALWAYS) { |
|
// start with empty file |
|
} else { |
|
UNIMPLEMENTED(); |
|
} |
|
files.insert(file); |
|
return file; |
|
} |
|
|
|
WINBOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, |
|
LPOVERLAPPED lpOverlapped) |
|
{ |
|
memfile *file = static_cast<memfile *>(hFile); |
|
UNIMPLEMENTED_UNLESS(!lpOverlapped); |
|
size_t len = std::min<size_t>(file->buf.size() - file->pos, nNumberOfBytesToRead); |
|
std::copy(file->buf.begin() + file->pos, file->buf.begin() + file->pos + len, static_cast<char *>(lpBuffer)); |
|
file->pos += len; |
|
*lpNumberOfBytesRead = len; |
|
return true; |
|
} |
|
|
|
DWORD GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh) |
|
{ |
|
memfile *file = static_cast<memfile *>(hFile); |
|
return file->buf.size(); |
|
} |
|
|
|
WINBOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, |
|
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) |
|
{ |
|
memfile *file = static_cast<memfile *>(hFile); |
|
UNIMPLEMENTED_UNLESS(!lpOverlapped); |
|
if (!nNumberOfBytesToWrite) |
|
return true; |
|
if (file->buf.size() < file->pos + nNumberOfBytesToWrite) |
|
file->buf.resize(file->pos + nNumberOfBytesToWrite); |
|
std::copy(static_cast<const char *>(lpBuffer), |
|
static_cast<const char *>(lpBuffer) + nNumberOfBytesToWrite, |
|
file->buf.begin() + file->pos); |
|
file->pos += nNumberOfBytesToWrite; |
|
*lpNumberOfBytesWritten = nNumberOfBytesToWrite; |
|
return true; |
|
} |
|
|
|
DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) |
|
{ |
|
memfile *file = static_cast<memfile *>(hFile); |
|
UNIMPLEMENTED_UNLESS(!lpDistanceToMoveHigh); |
|
if (dwMoveMethod == DVL_FILE_BEGIN) { |
|
file->pos = lDistanceToMove; |
|
} else if (dwMoveMethod == DVL_FILE_CURRENT) { |
|
file->pos += lDistanceToMove; |
|
} else { |
|
UNIMPLEMENTED(); |
|
} |
|
if (file->buf.size() < file->pos + 1) |
|
file->buf.resize(file->pos + 1); |
|
return file->pos; |
|
} |
|
|
|
WINBOOL SetEndOfFile(HANDLE hFile) |
|
{ |
|
memfile *file = static_cast<memfile *>(hFile); |
|
file->buf.erase(file->buf.begin() + file->pos, file->buf.end()); |
|
return true; |
|
} |
|
|
|
DWORD GetFileAttributesA(LPCSTR lpFileName) |
|
{ |
|
char name[DVL_MAX_PATH]; |
|
TranslateFileName(name, sizeof(name), lpFileName); |
|
std::ifstream filestream(name, std::ios::binary); |
|
if (filestream.fail()) { |
|
SetLastError(DVL_ERROR_FILE_NOT_FOUND); |
|
return (DWORD)-1; |
|
} |
|
return 0x80; |
|
} |
|
|
|
WINBOOL SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes) |
|
{ |
|
return true; |
|
} |
|
|
|
WINBOOL CloseHandle(HANDLE hObject) |
|
{ |
|
memfile *file = static_cast<memfile *>(hObject); |
|
if (files.find(file) == files.end()) |
|
return CloseEvent(hObject); |
|
std::unique_ptr<memfile> ufile(file); // ensure that delete file is |
|
// called on returning |
|
files.erase(file); |
|
try { |
|
std::ofstream filestream(file->path + ".tmp", std::ios::binary | std::ios::trunc); |
|
if (filestream.fail()) |
|
throw std::runtime_error("ofstream"); |
|
filestream.write(file->buf.data(), file->buf.size()); |
|
if (filestream.fail()) |
|
throw std::runtime_error("ofstream::write"); |
|
filestream.close(); |
|
std::remove(file->path.c_str()); |
|
if (std::rename((file->path + ".tmp").c_str(), file->path.c_str())) |
|
throw std::runtime_error("rename"); |
|
return true; |
|
} catch (std::runtime_error &e) { |
|
// log |
|
DialogBoxParam(ghInst, DVL_MAKEINTRESOURCE(IDD_DIALOG7), ghMainWnd, (DLGPROC)FuncDlg, (LPARAM)file->path.c_str()); |
|
return false; |
|
} |
|
} |
|
|
|
} // namespace dvl
|
|
|