Mercurial > foo_out_sdl
comparison foosdk/sdk/foobar2000/helpers/file_win32_wrapper.h @ 1:20d02a178406 default tip
*: check in everything else
yay
| author | Paper <paper@tflc.us> |
|---|---|
| date | Mon, 05 Jan 2026 02:15:46 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:e9bb126753e7 | 1:20d02a178406 |
|---|---|
| 1 #pragma once | |
| 2 | |
| 3 #include <libPPUI/win32_op.h> | |
| 4 #include <pfc/string-conv-lite.h> | |
| 5 | |
| 6 #ifdef _WIN32 | |
| 7 namespace file_win32_helpers { | |
| 8 t_filesize get_size(HANDLE p_handle); | |
| 9 void seek(HANDLE p_handle,t_sfilesize p_position,file::t_seek_mode p_mode); | |
| 10 void fillOverlapped(OVERLAPPED & ol, HANDLE myEvent, t_filesize s); | |
| 11 void writeOverlappedPass(HANDLE handle, HANDLE myEvent, t_filesize position, const void * in,DWORD inBytes, abort_callback & abort); | |
| 12 void writeOverlapped(HANDLE handle, HANDLE myEvent, t_filesize & position, const void * in, size_t inBytes, abort_callback & abort); | |
| 13 void writeStreamOverlapped(HANDLE handle, HANDLE myEvent, const void * in, size_t inBytes, abort_callback & abort); | |
| 14 DWORD readOverlappedPass(HANDLE handle, HANDLE myEvent, t_filesize position, void * out, DWORD outBytes, abort_callback & abort); | |
| 15 size_t readOverlapped(HANDLE handle, HANDLE myEvent, t_filesize & position, void * out, size_t outBytes, abort_callback & abort); | |
| 16 size_t readStreamOverlapped(HANDLE handle, HANDLE myEvent, void * out, size_t outBytes, abort_callback & abort); | |
| 17 HANDLE createFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile, abort_callback & abort); | |
| 18 size_t lowLevelIO(HANDLE hFile, const GUID & guid, size_t arg1, void * arg2, size_t arg2size, bool canWrite, abort_callback & abort); | |
| 19 bool querySeekPenalty(const char * fb2k_path, bool & out); | |
| 20 bool querySeekPenalty(const wchar_t * nativePath, bool & out); | |
| 21 | |
| 22 static uint64_t make_uint64(t_uint32 p_low, t_uint32 p_high) { | |
| 23 return ((t_uint64)p_low) + ((t_uint64)p_high << 32); | |
| 24 } | |
| 25 static uint64_t make_uint64(LARGE_INTEGER const& i) { | |
| 26 return reinterpret_cast<uint64_t const&>(i); | |
| 27 } | |
| 28 static uint64_t make_uint64(FILETIME const& ft) { | |
| 29 return reinterpret_cast<uint64_t const&>(ft); | |
| 30 // return make_uint64(ft.dwLowDateTime, ft.dwHighDateTime); | |
| 31 } | |
| 32 | |
| 33 template<typename t_info> | |
| 34 static t_filestats translate_stats(const t_info& p_info) { | |
| 35 t_filestats ret; | |
| 36 ret.m_size = make_uint64(p_info.nFileSizeLow, p_info.nFileSizeHigh); | |
| 37 ret.m_timestamp = make_uint64(p_info.ftLastWriteTime); | |
| 38 return ret; | |
| 39 } | |
| 40 | |
| 41 void attribs_from_win32(t_filestats2& out, DWORD in); | |
| 42 template<typename t_info> | |
| 43 static t_filestats2 translate_stats2(const t_info& p_info) { | |
| 44 t_filestats2 ret; | |
| 45 ret.m_size = make_uint64(p_info.nFileSizeLow, p_info.nFileSizeHigh); | |
| 46 ret.m_timestamp = make_uint64(p_info.ftLastWriteTime); | |
| 47 ret.m_timestampCreate = make_uint64(p_info.ftCreationTime); | |
| 48 attribs_from_win32(ret, p_info.dwFileAttributes); | |
| 49 return ret; | |
| 50 } | |
| 51 | |
| 52 t_filestats2 stats2_from_handle(HANDLE, const wchar_t * fallbackPath, uint32_t flags, abort_callback &a); | |
| 53 }; | |
| 54 | |
| 55 | |
| 56 template<bool p_seekable,bool p_writeable> | |
| 57 class file_win32_wrapper_t : public service_multi_inherit<file_v2, file_lowLevelIO> { | |
| 58 typedef file_win32_wrapper_t<p_seekable, p_writeable> self_t; | |
| 59 public: | |
| 60 file_win32_wrapper_t(HANDLE handle, pfc::wstringLite && path) : m_handle(handle), m_path(std::move(path)) {} | |
| 61 | |
| 62 static file::ptr g_CreateFile(const char * p_path,DWORD p_access,DWORD p_sharemode,LPSECURITY_ATTRIBUTES p_security_attributes,DWORD p_createmode,DWORD p_flags,HANDLE p_template) { | |
| 63 auto pathW = pfc::wideFromUTF8(p_path); | |
| 64 SetLastError(NO_ERROR); | |
| 65 HANDLE handle = CreateFile(pathW,p_access,p_sharemode,p_security_attributes,p_createmode,p_flags,p_template); | |
| 66 if (handle == INVALID_HANDLE_VALUE) { | |
| 67 const DWORD code = GetLastError(); | |
| 68 if (p_access & GENERIC_WRITE) win32_file_write_failure(code, p_path); | |
| 69 else exception_io_from_win32(code); | |
| 70 } | |
| 71 try { | |
| 72 return g_create_from_handle(handle, std::move(pathW)); | |
| 73 } catch(...) {CloseHandle(handle); throw;} | |
| 74 } | |
| 75 | |
| 76 static service_ptr_t<file> g_create_from_handle(HANDLE handle, pfc::wstringLite && path) { | |
| 77 return new service_impl_t<self_t>(handle, std::move(path)); | |
| 78 } | |
| 79 static service_ptr_t<file> g_create_from_handle(HANDLE handle) { | |
| 80 pfc::wstringLite blank; | |
| 81 g_create_from_handle(handle, std::move(blank)); | |
| 82 } | |
| 83 | |
| 84 | |
| 85 void reopen(abort_callback & p_abort) {seek(0,p_abort);} | |
| 86 | |
| 87 void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) { | |
| 88 if (!p_writeable) throw exception_io_denied(); | |
| 89 | |
| 90 PFC_STATIC_ASSERT(sizeof(t_size) >= sizeof(DWORD)); | |
| 91 | |
| 92 t_size bytes_written_total = 0; | |
| 93 | |
| 94 if (sizeof(t_size) == sizeof(DWORD)) { | |
| 95 p_abort.check_e(); | |
| 96 DWORD bytes_written = 0; | |
| 97 SetLastError(ERROR_SUCCESS); | |
| 98 if (!WriteFile(m_handle,p_buffer,(DWORD)p_bytes,&bytes_written,0)) exception_io_from_win32(GetLastError()); | |
| 99 if (bytes_written != p_bytes) throw exception_io("Write failure"); | |
| 100 bytes_written_total = bytes_written; | |
| 101 m_position += bytes_written; | |
| 102 } else { | |
| 103 while(bytes_written_total < p_bytes) { | |
| 104 p_abort.check_e(); | |
| 105 DWORD bytes_written = 0; | |
| 106 DWORD delta = (DWORD) pfc::min_t<t_size>(p_bytes - bytes_written_total, 0x80000000u); | |
| 107 SetLastError(ERROR_SUCCESS); | |
| 108 if (!WriteFile(m_handle,(const t_uint8*)p_buffer + bytes_written_total,delta,&bytes_written,0)) exception_io_from_win32(GetLastError()); | |
| 109 if (bytes_written != delta) throw exception_io("Write failure"); | |
| 110 bytes_written_total += bytes_written; | |
| 111 m_position += bytes_written; | |
| 112 } | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) { | |
| 117 PFC_STATIC_ASSERT(sizeof(t_size) >= sizeof(DWORD)); | |
| 118 | |
| 119 t_size bytes_read_total = 0; | |
| 120 if (sizeof(t_size) == sizeof(DWORD)) { | |
| 121 p_abort.check_e(); | |
| 122 DWORD bytes_read = 0; | |
| 123 SetLastError(ERROR_SUCCESS); | |
| 124 if (!ReadFile(m_handle,p_buffer,pfc::downcast_guarded<DWORD>(p_bytes),&bytes_read,0)) exception_io_from_win32(GetLastError()); | |
| 125 bytes_read_total = bytes_read; | |
| 126 m_position += bytes_read; | |
| 127 } else { | |
| 128 while(bytes_read_total < p_bytes) { | |
| 129 p_abort.check_e(); | |
| 130 DWORD bytes_read = 0; | |
| 131 DWORD delta = (DWORD) pfc::min_t<t_size>(p_bytes - bytes_read_total, 0x80000000u); | |
| 132 SetLastError(ERROR_SUCCESS); | |
| 133 if (!ReadFile(m_handle,(t_uint8*)p_buffer + bytes_read_total,delta,&bytes_read,0)) exception_io_from_win32(GetLastError()); | |
| 134 bytes_read_total += bytes_read; | |
| 135 m_position += bytes_read; | |
| 136 if (bytes_read != delta) break; | |
| 137 } | |
| 138 } | |
| 139 return bytes_read_total; | |
| 140 } | |
| 141 | |
| 142 | |
| 143 t_filesize get_size(abort_callback & p_abort) { | |
| 144 p_abort.check_e(); | |
| 145 return file_win32_helpers::get_size(m_handle); | |
| 146 } | |
| 147 | |
| 148 t_filesize get_position(abort_callback & p_abort) { | |
| 149 p_abort.check_e(); | |
| 150 return m_position; | |
| 151 } | |
| 152 | |
| 153 void resize(t_filesize p_size,abort_callback & p_abort) { | |
| 154 if (!p_writeable) throw exception_io_denied(); | |
| 155 p_abort.check_e(); | |
| 156 if (m_position != p_size) { | |
| 157 file_win32_helpers::seek(m_handle,p_size,file::seek_from_beginning); | |
| 158 } | |
| 159 SetLastError(ERROR_SUCCESS); | |
| 160 if (!SetEndOfFile(m_handle)) { | |
| 161 DWORD code = GetLastError(); | |
| 162 if (m_position != p_size) try {file_win32_helpers::seek(m_handle,m_position,file::seek_from_beginning);} catch(...) {} | |
| 163 exception_io_from_win32(code); | |
| 164 } | |
| 165 if (m_position > p_size) m_position = p_size; | |
| 166 if (m_position != p_size) file_win32_helpers::seek(m_handle,m_position,file::seek_from_beginning); | |
| 167 } | |
| 168 | |
| 169 | |
| 170 void seek(t_filesize p_position,abort_callback & p_abort) { | |
| 171 if (!p_seekable) throw exception_io_object_not_seekable(); | |
| 172 p_abort.check_e(); | |
| 173 if (p_position > file_win32_helpers::get_size(m_handle)) throw exception_io_seek_out_of_range(); | |
| 174 file_win32_helpers::seek(m_handle,p_position,file::seek_from_beginning); | |
| 175 m_position = p_position; | |
| 176 } | |
| 177 | |
| 178 bool can_seek() {return p_seekable;} | |
| 179 bool get_content_type(pfc::string_base & out) {return false;} | |
| 180 bool is_in_memory() {return false;} | |
| 181 void on_idle(abort_callback & p_abort) {p_abort.check_e();} | |
| 182 | |
| 183 t_filestats2 get_stats2(uint32_t f, abort_callback& a) { | |
| 184 a.check(); | |
| 185 if (p_writeable) FlushFileBuffers(m_handle); | |
| 186 return file_win32_helpers::stats2_from_handle(m_handle, m_path, f, a); | |
| 187 } | |
| 188 t_filetimestamp get_timestamp(abort_callback & p_abort) { | |
| 189 p_abort.check_e(); | |
| 190 if (p_writeable) FlushFileBuffers(m_handle); | |
| 191 SetLastError(ERROR_SUCCESS); | |
| 192 FILETIME temp; | |
| 193 if (!GetFileTime(m_handle,0,0,&temp)) exception_io_from_win32(GetLastError()); | |
| 194 return file_win32_helpers::make_uint64(temp); | |
| 195 } | |
| 196 | |
| 197 bool is_remote() {return false;} | |
| 198 ~file_win32_wrapper_t() {CloseHandle(m_handle);} | |
| 199 | |
| 200 size_t lowLevelIO(const GUID & guid, size_t arg1, void * arg2, size_t arg2size, abort_callback & abort) override { | |
| 201 return file_win32_helpers::lowLevelIO(m_handle, guid, arg1, arg2, arg2size, p_writeable, abort); | |
| 202 } | |
| 203 protected: | |
| 204 HANDLE m_handle; | |
| 205 t_filesize m_position = 0; | |
| 206 pfc::wstringLite m_path; | |
| 207 }; | |
| 208 | |
| 209 template<bool p_writeable> | |
| 210 class file_win32_wrapper_overlapped_t : public service_multi_inherit< file_v2, file_lowLevelIO > { | |
| 211 typedef file_win32_wrapper_overlapped_t<p_writeable> self_t; | |
| 212 public: | |
| 213 file_win32_wrapper_overlapped_t(HANDLE file, pfc::wstringLite && path) : m_handle(file), m_path(std::move(path)) { | |
| 214 WIN32_OP( (m_event = CreateEvent(NULL, TRUE, FALSE, NULL)) != NULL ); | |
| 215 } | |
| 216 ~file_win32_wrapper_overlapped_t() {CloseHandle(m_event); CloseHandle(m_handle);} | |
| 217 void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) { | |
| 218 if (!p_writeable) throw exception_io_denied(); | |
| 219 return file_win32_helpers::writeOverlapped(m_handle, m_event, m_position, p_buffer, p_bytes, p_abort); | |
| 220 } | |
| 221 t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) { | |
| 222 return file_win32_helpers::readOverlapped(m_handle, m_event, m_position, p_buffer, p_bytes, p_abort); | |
| 223 } | |
| 224 | |
| 225 void reopen(abort_callback & p_abort) {seek(0,p_abort);} | |
| 226 | |
| 227 | |
| 228 t_filesize get_size(abort_callback & p_abort) { | |
| 229 p_abort.check_e(); | |
| 230 return file_win32_helpers::get_size(m_handle); | |
| 231 } | |
| 232 | |
| 233 t_filesize get_position(abort_callback & p_abort) { | |
| 234 p_abort.check_e(); | |
| 235 return m_position; | |
| 236 } | |
| 237 | |
| 238 void resize(t_filesize p_size,abort_callback & p_abort) { | |
| 239 if (!p_writeable) throw exception_io_denied(); | |
| 240 p_abort.check_e(); | |
| 241 file_win32_helpers::seek(m_handle,p_size,file::seek_from_beginning); | |
| 242 SetLastError(ERROR_SUCCESS); | |
| 243 if (!SetEndOfFile(m_handle)) { | |
| 244 DWORD code = GetLastError(); | |
| 245 exception_io_from_win32(code); | |
| 246 } | |
| 247 if (m_position > p_size) m_position = p_size; | |
| 248 } | |
| 249 | |
| 250 | |
| 251 void seek(t_filesize p_position,abort_callback & p_abort) { | |
| 252 p_abort.check_e(); | |
| 253 if (p_position > file_win32_helpers::get_size(m_handle)) throw exception_io_seek_out_of_range(); | |
| 254 // file_win32_helpers::seek(m_handle,p_position,file::seek_from_beginning); | |
| 255 m_position = p_position; | |
| 256 } | |
| 257 | |
| 258 bool can_seek() {return true;} | |
| 259 bool get_content_type(pfc::string_base & out) {return false;} | |
| 260 bool is_in_memory() {return false;} | |
| 261 void on_idle(abort_callback & p_abort) {p_abort.check_e();} | |
| 262 | |
| 263 | |
| 264 t_filestats2 get_stats2(uint32_t f, abort_callback& a) { | |
| 265 a.check(); | |
| 266 if (p_writeable) FlushFileBuffers(m_handle); | |
| 267 return file_win32_helpers::stats2_from_handle(m_handle, m_path, f, a); | |
| 268 } | |
| 269 | |
| 270 t_filetimestamp get_timestamp(abort_callback & p_abort) { | |
| 271 p_abort.check_e(); | |
| 272 if (p_writeable) FlushFileBuffers(m_handle); | |
| 273 SetLastError(ERROR_SUCCESS); | |
| 274 FILETIME temp; | |
| 275 if (!GetFileTime(m_handle,0,0,&temp)) exception_io_from_win32(GetLastError()); | |
| 276 return file_win32_helpers::make_uint64(temp); | |
| 277 } | |
| 278 | |
| 279 bool is_remote() {return false;} | |
| 280 | |
| 281 | |
| 282 static file::ptr g_CreateFile(const char * p_path,DWORD p_access,DWORD p_sharemode,LPSECURITY_ATTRIBUTES p_security_attributes,DWORD p_createmode,DWORD p_flags,HANDLE p_template) { | |
| 283 auto pathW = pfc::wideFromUTF8(p_path); | |
| 284 p_flags |= FILE_FLAG_OVERLAPPED; | |
| 285 SetLastError(NO_ERROR); | |
| 286 HANDLE handle = CreateFile(pathW,p_access,p_sharemode,p_security_attributes,p_createmode,p_flags,p_template); | |
| 287 if (handle == INVALID_HANDLE_VALUE) { | |
| 288 const DWORD code = GetLastError(); | |
| 289 if (p_access & GENERIC_WRITE) win32_file_write_failure(code, p_path); | |
| 290 else exception_io_from_win32(code); | |
| 291 } | |
| 292 try { | |
| 293 return g_create_from_handle(handle, std::move(pathW)); | |
| 294 } catch(...) {CloseHandle(handle); throw;} | |
| 295 } | |
| 296 | |
| 297 static file::ptr g_create_from_handle(HANDLE p_handle, pfc::wstringLite && path) { | |
| 298 return new service_impl_t<self_t>(p_handle, std::move(path)); | |
| 299 } | |
| 300 static file::ptr g_create_from_handle(HANDLE p_handle) { | |
| 301 pfc::wstringLite blank; | |
| 302 return g_create_from_handle(p_handle, std::move(blank)); | |
| 303 } | |
| 304 | |
| 305 size_t lowLevelIO(const GUID & guid, size_t arg1, void * arg2, size_t arg2size, abort_callback & abort) override { | |
| 306 return file_win32_helpers::lowLevelIO(m_handle, guid, arg1, arg2, arg2size, p_writeable, abort); | |
| 307 } | |
| 308 | |
| 309 protected: | |
| 310 HANDLE m_event, m_handle; | |
| 311 t_filesize m_position = 0; | |
| 312 pfc::wstringLite m_path; | |
| 313 }; | |
| 314 | |
| 315 #endif // _WIN32 |
