#include #include #include #include #include #include #include #include #include #include "devilution.h" #include "stubs.h" namespace dvl { struct memfile { std::string path; std::vector buf; std::size_t pos = 0; }; static std::set 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(filestream), std::istreambuf_iterator()); } } 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(hFile); UNIMPLEMENTED_UNLESS(!lpOverlapped); size_t len = std::min(file->buf.size() - file->pos, nNumberOfBytesToRead); std::copy(file->buf.begin() + file->pos, file->buf.begin() + file->pos + len, static_cast(lpBuffer)); file->pos += len; *lpNumberOfBytesRead = len; return true; } DWORD GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh) { memfile* file = static_cast(hFile); return file->buf.size(); } WINBOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { memfile* file = static_cast(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(lpBuffer), static_cast(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(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(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(hObject); if (files.find(file) == files.end()) return true; std::unique_ptr 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