RetroArch/libretro-common/file/nbio/nbio_windowsmmap.c

225 lines
6.5 KiB
C
Raw Normal View History

2018-04-16 08:57:17 +02:00
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (nbio_windowsmmap.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
2017-11-26 22:53:42 +01:00
#include <file/nbio.h>
#if defined(_WIN32) && !defined(_XBOX)
2017-11-24 22:42:21 +01:00
#include <stdio.h>
#include <stdlib.h>
#include <encodings/utf.h>
2017-11-24 22:42:21 +01:00
2017-11-25 17:38:37 +01:00
#include <windows.h>
/* Assume W-functions do not work below Win2K and Xbox platforms */
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
#ifndef LEGACY_WIN32
#define LEGACY_WIN32
#endif
#endif
2017-11-25 17:38:37 +01:00
#ifndef FILE_SHARE_ALL
#define FILE_SHARE_ALL (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE)
#endif
struct nbio_mmap_win32_t
2017-11-24 22:42:21 +01:00
{
2017-11-25 17:38:37 +01:00
HANDLE file;
bool is_write;
2017-11-24 22:42:21 +01:00
size_t len;
2017-11-25 17:38:37 +01:00
void* ptr;
2017-11-24 22:42:21 +01:00
};
static void *nbio_mmap_win32_open(const char * filename, unsigned mode)
2017-11-24 22:42:21 +01:00
{
2017-11-25 17:38:37 +01:00
static const DWORD dispositions[] = { OPEN_EXISTING, CREATE_ALWAYS, OPEN_ALWAYS, OPEN_EXISTING, CREATE_ALWAYS };
HANDLE mem;
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
2017-11-25 17:38:37 +01:00
LARGE_INTEGER len;
#else
SIZE_T len;
#endif
struct nbio_mmap_win32_t* handle = NULL;
void* ptr = NULL;
bool is_write = (mode == NBIO_WRITE || mode == NBIO_UPDATE || mode == BIO_WRITE);
DWORD access = (is_write ? GENERIC_READ|GENERIC_WRITE : GENERIC_READ);
#if !defined(_WIN32) || defined(LEGACY_WIN32)
HANDLE file = CreateFile(filename, access, FILE_SHARE_ALL, NULL, dispositions[mode], FILE_ATTRIBUTE_NORMAL, NULL);
#else
wchar_t *filename_wide = utf8_to_utf16_string_alloc(filename);
HANDLE file = CreateFileW(filename_wide, access, FILE_SHARE_ALL, NULL, dispositions[mode], FILE_ATTRIBUTE_NORMAL, NULL);
if (filename_wide)
free(filename_wide);
#endif
2017-11-25 17:38:37 +01:00
if (file == INVALID_HANDLE_VALUE)
return NULL;
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
/* GetFileSizeEx is new for Windows 2000 */
2017-11-25 17:38:37 +01:00
GetFileSizeEx(file, &len);
mem = CreateFileMapping(file, NULL, is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL);
ptr = MapViewOfFile(mem, is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len.QuadPart);
#else
GetFileSize(file, &len);
mem = CreateFileMapping(file, NULL, is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL);
ptr = MapViewOfFile(mem, is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len);
#endif
2017-11-25 17:38:37 +01:00
CloseHandle(mem);
2017-11-26 22:53:42 +01:00
handle = (struct nbio_mmap_win32_t*)malloc(sizeof(struct nbio_mmap_win32_t));
2017-11-25 17:38:37 +01:00
handle->file = file;
handle->is_write = is_write;
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
2017-11-25 17:38:37 +01:00
handle->len = len.QuadPart;
#else
handle->len = len;
#endif
2017-11-25 17:38:37 +01:00
handle->ptr = ptr;
2017-11-25 02:10:04 +01:00
2017-11-24 22:42:21 +01:00
return handle;
}
static void nbio_mmap_win32_begin_read(void *data)
2017-11-24 22:42:21 +01:00
{
2017-11-25 17:38:37 +01:00
/* not needed */
2017-11-24 22:42:21 +01:00
}
static void nbio_mmap_win32_begin_write(void *data)
2017-11-24 22:42:21 +01:00
{
2017-11-25 17:38:37 +01:00
/* not needed */
2017-11-24 22:42:21 +01:00
}
static bool nbio_mmap_win32_iterate(void *data)
2017-11-24 22:42:21 +01:00
{
2017-11-25 17:38:37 +01:00
/* not needed */
return true;
2017-11-24 22:42:21 +01:00
}
static void nbio_mmap_win32_resize(void *data, size_t len)
2017-11-24 22:42:21 +01:00
{
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
2017-11-25 17:38:37 +01:00
LARGE_INTEGER len_li;
#else
SIZE_T len_li;
#endif
2017-11-25 17:38:37 +01:00
HANDLE mem;
struct nbio_mmap_win32_t* handle = (struct nbio_mmap_win32_t*)data;
2017-11-25 17:38:37 +01:00
if (!handle)
return;
if (len < handle->len)
2017-11-24 22:42:21 +01:00
{
/* this works perfectly fine if this check is removed,
2017-11-25 17:38:37 +01:00
* but it won't work on other nbio implementations */
/* therefore, it's blocked so nobody accidentally
2017-11-25 17:38:37 +01:00
* relies on it. */
puts("ERROR - attempted file shrink operation, not implemented");
2017-11-24 22:42:21 +01:00
abort();
}
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
/* SetFilePointerEx is new for Windows 2000 */
2017-11-25 17:38:37 +01:00
len_li.QuadPart = len;
SetFilePointerEx(handle->file, len_li, NULL, FILE_BEGIN);
#else
len_li = len;
SetFilePointer(handle->file, len_li, NULL, FILE_BEGIN);
#endif
2017-11-25 17:38:37 +01:00
if (!SetEndOfFile(handle->file))
{
puts("ERROR - couldn't resize file (SetEndOfFile)");
abort(); /* this one returns void and I can't find any other way for it to report failure */
}
handle->len = len;
UnmapViewOfFile(handle->ptr);
mem = CreateFileMapping(handle->file, NULL, handle->is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL);
handle->ptr = MapViewOfFile(mem, handle->is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len);
CloseHandle(mem);
if (!handle->ptr)
{
puts("ERROR - couldn't resize file (MapViewOfFile)");
abort();
}
2017-11-24 22:42:21 +01:00
}
static void *nbio_mmap_win32_get_ptr(void *data, size_t* len)
2017-11-24 22:42:21 +01:00
{
struct nbio_mmap_win32_t* handle = (struct nbio_mmap_win32_t*)data;
2017-11-25 02:10:04 +01:00
if (!handle)
return NULL;
if (len)
*len = handle->len;
2017-11-25 17:38:37 +01:00
return handle->ptr;
2017-11-24 22:42:21 +01:00
}
static void nbio_mmap_win32_cancel(void *data)
2017-11-24 22:42:21 +01:00
{
2017-11-25 17:38:37 +01:00
/* not needed */
2017-11-24 22:42:21 +01:00
}
static void nbio_mmap_win32_free(void *data)
2017-11-24 22:42:21 +01:00
{
struct nbio_mmap_win32_t* handle = (struct nbio_mmap_win32_t*)data;
2017-11-25 02:10:04 +01:00
if (!handle)
return;
2017-11-25 17:38:37 +01:00
CloseHandle(handle->file);
UnmapViewOfFile(handle->ptr);
2017-11-24 22:42:21 +01:00
free(handle);
}
nbio_intf_t nbio_mmap_win32 = {
nbio_mmap_win32_open,
nbio_mmap_win32_begin_read,
nbio_mmap_win32_begin_write,
nbio_mmap_win32_iterate,
nbio_mmap_win32_resize,
nbio_mmap_win32_get_ptr,
nbio_mmap_win32_cancel,
nbio_mmap_win32_free,
"nbio_mmap_win32",
};
2017-11-26 22:53:42 +01:00
#else
nbio_intf_t nbio_mmap_win32 = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"nbio_mmap_win32",
};
#endif