Cogs.Core
FileHandle.Windows.cpp
1#include "FileHandle.h"
2
3#include "Unicode.h"
4
5#include "../StringViewFormat.h"
6
7#include "../Logging/Logger.h"
8
9namespace {
10 const Cogs::Logging::Log logger = Cogs::Logging::getLogger("FileHandle");
11}
12
13Cogs::FileHandle::~FileHandle() {
14 close();
15}
16
17Cogs::FileHandle::Ptr Cogs::FileHandle::open(std::string_view path, OpenMode openMode, AccessMode accessMode) {
18 Ptr handle = std::make_shared<FileHandle>();
19
20 constexpr DWORD dwOpenMode[] = {
21 CREATE_NEW,
22 CREATE_ALWAYS,
23 OPEN_EXISTING,
24 OPEN_ALWAYS,
25 TRUNCATE_EXISTING,
26 };
27
28 constexpr DWORD dwAccessMode[] = {
29 GENERIC_READ,
30 GENERIC_WRITE
31 };
32
33 constexpr DWORD dwShareMode[] = {
34 FILE_SHARE_READ,
35 0
36 };
37
38 handle->fileHandle = CreateFileW(Cogs::widen(path).c_str(), dwAccessMode[(int)accessMode], dwShareMode[(int)accessMode], nullptr, dwOpenMode[(int)openMode], FILE_ATTRIBUTE_NORMAL, nullptr);
39
40 if (handle->fileHandle == INVALID_HANDLE_VALUE) {
41 LPSTR messageBuffer = nullptr;
42
43 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
44 nullptr,
45 GetLastError(),
46 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
47 reinterpret_cast<LPSTR>(&messageBuffer),
48 0,
49 nullptr);
50
51 LOG_ERROR(logger, "Cogs::FileHandle::open(): Failed to open %.*s. Error: %s.", StringViewFormat(path), messageBuffer);
52
53 LocalFree(messageBuffer);
54 return Ptr();
55 }
56 return handle;
57}
58
59void Cogs::FileHandle::close() {
60 if (mappedMemory) {
61 ::UnmapViewOfFile(mappedMemory);
62 mappedMemory = nullptr;
63 }
64
65 if (mapHandle) {
66 ::CloseHandle(mapHandle);
67 mapHandle = nullptr;
68 }
69
70 if (fileHandle) {
71 ::CloseHandle(fileHandle);
72 fileHandle = INVALID_HANDLE_VALUE;
73 }
74}
75
76bool Cogs::FileHandle::isOpen() const {
77 return fileHandle != INVALID_HANDLE_VALUE;
78}
79
80size_t Cogs::FileHandle::getSize() const {
81 if (fileHandle != INVALID_HANDLE_VALUE) {
82 DWORD highSize;
83 DWORD lowSize = ::GetFileSize(fileHandle, &highSize);
84
85 return (static_cast<size_t>(highSize) << 32) + lowSize;
86 }
87 return 0;
88}
89
90bool Cogs::FileHandle::write(const void* buffer, size_t size, size_t& bytesWritten)
91{
92 const uint8_t* src = static_cast<const uint8_t*>(buffer);
93 DWORD justWritten;
94
95 bytesWritten = 0;
96
97 for (constexpr size_t limit = std::numeric_limits<DWORD>::max(); size > limit; ) {
98 if (WriteFile(fileHandle, src, static_cast<DWORD>(limit), &justWritten, nullptr)) {
99 src += justWritten;
100 size -= justWritten;
101 bytesWritten += justWritten;
102 }
103 else {
104 LOG_ERROR(logger, "write(): Failed to write FileHandle %p. Error: %d.", fileHandle, GetLastError());
105 return false;
106 }
107 }
108 if (size) {
109 if (WriteFile(fileHandle, src, static_cast<DWORD>(size), &justWritten, nullptr)) {
110 bytesWritten += justWritten;
111 }
112 else {
113 LOG_ERROR(logger, "write(): Failed to write FileHandle %p. Error: %d.", fileHandle, GetLastError());
114 return false;
115 }
116 }
117 return true;
118}
119
120bool Cogs::FileHandle::read(void* buffer, size_t size, size_t& bytesRead)
121{
122 uint8_t* dest = reinterpret_cast<uint8_t*>(buffer);
123 DWORD justRead;
124
125 bytesRead = 0;
126
127 for (size_t limit = std::numeric_limits<DWORD>::max(); size > limit; ) {
128 if (ReadFile(fileHandle, dest, static_cast<DWORD>(limit), &justRead, nullptr)) {
129 dest += justRead;
130 size -= justRead;
131 bytesRead += justRead;
132 }
133 else {
134 LOG_ERROR(logger, "read(): Failed to read FileHandle %p. Error: %d.", fileHandle, GetLastError());
135 return false;
136 }
137 }
138 if (size) {
139 if (ReadFile(fileHandle, dest, static_cast<DWORD>(size), &justRead, nullptr)) {
140 bytesRead += justRead;
141 }
142 else {
143 LOG_ERROR(logger, "read(): Failed to read FileHandle %p. Error: %d.", fileHandle, GetLastError());
144 return false;
145 }
146 }
147 return true;
148}
149
150void* Cogs::FileHandle::map(ProtectionMode /*protectionMode*/, size_t offset, size_t size) {
151 if (fileHandle == INVALID_HANDLE_VALUE) {
152 LOG_ERROR(logger, "Cannot map invalid file handle.");
153 return nullptr;
154 }
155
156 if (mapHandle) {
157 LOG_ERROR(logger, "File handle cannot be mapped multiple times.");
158 return nullptr;
159 }
160
161 DWORD maximumSize = (DWORD)(offset + size);
162 DWORD maxHigh = (DWORD)((offset + size) >> 32);
163
164 mapHandle = ::CreateFileMapping(fileHandle, nullptr, PAGE_READONLY, maxHigh, maximumSize, nullptr);
165
166 if (!mapHandle) {
167 LOG_ERROR(logger, "map(): CreateFileMapping failed. Last error: %d", GetLastError());
168 return nullptr;
169 }
170
171 mappedMemory = ::MapViewOfFile(mapHandle, FILE_MAP_READ, 0, static_cast<DWORD>(offset), size);
172
173 if (!mappedMemory) {
174 LOG_ERROR(logger, "map(): MapViewOfFile failed. Last error: %d", GetLastError());
175 return nullptr;
176 }
177
178 return mappedMemory;
179}
180
181void Cogs::FileHandle::unmap() {
182 if (!mappedMemory) {
183 LOG_WARNING(logger, "Cannot unmap file without mapped memory address (file mapping may have failed).");
184 return;
185 }
186
187 ::UnmapViewOfFile(mappedMemory);
188 mappedMemory = nullptr;
189
190 ::CloseHandle(mapHandle);
191 mapHandle = nullptr;
192}
Log implementation class.
Definition: LogManager.h:139
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180