mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-06-01 23:07:45 +08:00
committed by
GitHub
parent
dd52dd8995
commit
7c9ae67706
+115
-6
@@ -70,6 +70,9 @@ typedef struct IOStreamWindowsData
|
|||||||
void *data;
|
void *data;
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t left;
|
size_t left;
|
||||||
|
void *write_data;
|
||||||
|
size_t write_pos;
|
||||||
|
bool writable;
|
||||||
bool append;
|
bool append;
|
||||||
bool autoclose;
|
bool autoclose;
|
||||||
} IOStreamWindowsData;
|
} IOStreamWindowsData;
|
||||||
@@ -81,6 +84,7 @@ typedef struct IOStreamWindowsData
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define READAHEAD_BUFFER_SIZE 1024
|
#define READAHEAD_BUFFER_SIZE 1024
|
||||||
|
#define WRITEBEHIND_BUFFER_SIZE 1024
|
||||||
|
|
||||||
static HANDLE SDLCALL windows_file_open(const char *filename, const char *mode)
|
static HANDLE SDLCALL windows_file_open(const char *filename, const char *mode)
|
||||||
{
|
{
|
||||||
@@ -150,6 +154,41 @@ static HANDLE SDLCALL windows_file_open(const char *filename, const char *mode)
|
|||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool windows_flush_write_buffer(IOStreamWindowsData *iodata,
|
||||||
|
SDL_IOStatus *status)
|
||||||
|
{
|
||||||
|
if (iodata->write_pos == 0) {
|
||||||
|
return true; // Nothing to flush
|
||||||
|
}
|
||||||
|
|
||||||
|
// In append mode, seek to EOF before writing
|
||||||
|
if (iodata->append) {
|
||||||
|
LARGE_INTEGER windowsoffset;
|
||||||
|
windowsoffset.QuadPart = 0;
|
||||||
|
if (!SetFilePointerEx(iodata->h, windowsoffset,
|
||||||
|
&windowsoffset, FILE_END)) {
|
||||||
|
if (status) {
|
||||||
|
*status = SDL_IO_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
WIN_SetError("Error seeking in datastream");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD bytes;
|
||||||
|
if (!WriteFile(iodata->h, iodata->write_data,
|
||||||
|
(DWORD)iodata->write_pos, &bytes, NULL)) {
|
||||||
|
if (status) {
|
||||||
|
*status = SDL_IO_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
WIN_SetError("Error writing to datastream");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
iodata->write_pos = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static Sint64 SDLCALL windows_file_size(void *userdata)
|
static Sint64 SDLCALL windows_file_size(void *userdata)
|
||||||
{
|
{
|
||||||
IOStreamWindowsData *iodata = (IOStreamWindowsData *) userdata;
|
IOStreamWindowsData *iodata = (IOStreamWindowsData *) userdata;
|
||||||
@@ -168,6 +207,10 @@ static Sint64 SDLCALL windows_file_seek(void *userdata, Sint64 offset, SDL_IOWhe
|
|||||||
DWORD windowswhence;
|
DWORD windowswhence;
|
||||||
LARGE_INTEGER windowsoffset;
|
LARGE_INTEGER windowsoffset;
|
||||||
|
|
||||||
|
if (!windows_flush_write_buffer(iodata, NULL)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: We may be able to satisfy the seek within buffered data
|
// FIXME: We may be able to satisfy the seek within buffered data
|
||||||
if ((whence == SDL_IO_SEEK_CUR) && (iodata->left)) {
|
if ((whence == SDL_IO_SEEK_CUR) && (iodata->left)) {
|
||||||
offset -= iodata->left;
|
offset -= iodata->left;
|
||||||
@@ -204,6 +247,10 @@ static size_t SDLCALL windows_file_read(void *userdata, void *ptr, size_t size,
|
|||||||
size_t read_ahead;
|
size_t read_ahead;
|
||||||
DWORD bytes;
|
DWORD bytes;
|
||||||
|
|
||||||
|
if (!windows_flush_write_buffer(iodata, status)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (iodata->left > 0) {
|
if (iodata->left > 0) {
|
||||||
void *data = (char *)iodata->data +
|
void *data = (char *)iodata->data +
|
||||||
iodata->size -
|
iodata->size -
|
||||||
@@ -271,10 +318,19 @@ static size_t SDLCALL windows_file_read(void *userdata, void *ptr, size_t size,
|
|||||||
static size_t SDLCALL windows_file_write(void *userdata, const void *ptr, size_t size, SDL_IOStatus *status)
|
static size_t SDLCALL windows_file_write(void *userdata, const void *ptr, size_t size, SDL_IOStatus *status)
|
||||||
{
|
{
|
||||||
IOStreamWindowsData *iodata = (IOStreamWindowsData *)userdata;
|
IOStreamWindowsData *iodata = (IOStreamWindowsData *)userdata;
|
||||||
DWORD bytes;
|
const Uint8 *src = (const Uint8 *)ptr;
|
||||||
|
size_t remaining = size;
|
||||||
|
size_t total_written = 0;
|
||||||
|
|
||||||
|
if (!iodata->writable) {
|
||||||
|
*status = SDL_IO_STATUS_READONLY;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalidate read-ahead buffer if it has data
|
||||||
if (iodata->left) {
|
if (iodata->left) {
|
||||||
if (!SetFilePointer(iodata->h, -(LONG)iodata->left, NULL, FILE_CURRENT)) {
|
if (!SetFilePointer(iodata->h, -(LONG)iodata->left,
|
||||||
|
NULL, FILE_CURRENT)) {
|
||||||
*status = SDL_IO_STATUS_ERROR;
|
*status = SDL_IO_STATUS_ERROR;
|
||||||
WIN_SetError("Error seeking in datastream");
|
WIN_SetError("Error seeking in datastream");
|
||||||
return 0;
|
return 0;
|
||||||
@@ -282,17 +338,25 @@ static size_t SDLCALL windows_file_write(void *userdata, const void *ptr, size_t
|
|||||||
iodata->left = 0;
|
iodata->left = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if in append mode, we must go to the EOF before write
|
// For large writes, flush buffer and write directly
|
||||||
|
if (size >= WRITEBEHIND_BUFFER_SIZE) {
|
||||||
|
if (!windows_flush_write_buffer(iodata, status)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In append mode, seek to EOF before direct write
|
||||||
if (iodata->append) {
|
if (iodata->append) {
|
||||||
LARGE_INTEGER windowsoffset;
|
LARGE_INTEGER windowsoffset;
|
||||||
windowsoffset.QuadPart = 0;
|
windowsoffset.QuadPart = 0;
|
||||||
if (!SetFilePointerEx(iodata->h, windowsoffset, &windowsoffset, FILE_END)) {
|
if (!SetFilePointerEx(iodata->h, windowsoffset,
|
||||||
|
&windowsoffset, FILE_END)) {
|
||||||
*status = SDL_IO_STATUS_ERROR;
|
*status = SDL_IO_STATUS_ERROR;
|
||||||
WIN_SetError("Error seeking in datastream");
|
WIN_SetError("Error seeking in datastream");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DWORD bytes;
|
||||||
if (!WriteFile(iodata->h, ptr, (DWORD)size, &bytes, NULL)) {
|
if (!WriteFile(iodata->h, ptr, (DWORD)size, &bytes, NULL)) {
|
||||||
*status = SDL_IO_STATUS_ERROR;
|
*status = SDL_IO_STATUS_ERROR;
|
||||||
WIN_SetError("Error writing to datastream");
|
WIN_SetError("Error writing to datastream");
|
||||||
@@ -303,9 +367,37 @@ static size_t SDLCALL windows_file_write(void *userdata, const void *ptr, size_t
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Buffer small writes
|
||||||
|
while (remaining > 0) {
|
||||||
|
size_t space = WRITEBEHIND_BUFFER_SIZE - iodata->write_pos;
|
||||||
|
size_t to_buffer = SDL_min(remaining, space);
|
||||||
|
|
||||||
|
SDL_memcpy((char *)iodata->write_data + iodata->write_pos,
|
||||||
|
src, to_buffer);
|
||||||
|
iodata->write_pos += to_buffer;
|
||||||
|
src += to_buffer;
|
||||||
|
remaining -= to_buffer;
|
||||||
|
total_written += to_buffer;
|
||||||
|
|
||||||
|
if (iodata->write_pos == WRITEBEHIND_BUFFER_SIZE) {
|
||||||
|
if (!windows_flush_write_buffer(iodata, status)) {
|
||||||
|
return total_written;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return total_written;
|
||||||
|
}
|
||||||
|
|
||||||
static bool SDLCALL windows_file_flush(void *userdata, SDL_IOStatus *status)
|
static bool SDLCALL windows_file_flush(void *userdata, SDL_IOStatus *status)
|
||||||
{
|
{
|
||||||
IOStreamWindowsData *iodata = (IOStreamWindowsData *)userdata;
|
IOStreamWindowsData *iodata = (IOStreamWindowsData *)userdata;
|
||||||
|
|
||||||
|
if (!windows_flush_write_buffer(iodata, status)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync to disk
|
||||||
if (!FlushFileBuffers(iodata->h)) {
|
if (!FlushFileBuffers(iodata->h)) {
|
||||||
return WIN_SetError("Error flushing datastream");
|
return WIN_SetError("Error flushing datastream");
|
||||||
}
|
}
|
||||||
@@ -315,15 +407,22 @@ static bool SDLCALL windows_file_flush(void *userdata, SDL_IOStatus *status)
|
|||||||
static bool SDLCALL windows_file_close(void *userdata)
|
static bool SDLCALL windows_file_close(void *userdata)
|
||||||
{
|
{
|
||||||
IOStreamWindowsData *iodata = (IOStreamWindowsData *)userdata;
|
IOStreamWindowsData *iodata = (IOStreamWindowsData *)userdata;
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
if (!windows_flush_write_buffer(iodata, NULL)) {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (iodata->h != INVALID_HANDLE_VALUE) {
|
if (iodata->h != INVALID_HANDLE_VALUE) {
|
||||||
if (iodata->autoclose) {
|
if (iodata->autoclose) {
|
||||||
CloseHandle(iodata->h);
|
CloseHandle(iodata->h);
|
||||||
}
|
}
|
||||||
iodata->h = INVALID_HANDLE_VALUE; // to be sure
|
iodata->h = INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
SDL_free(iodata->data);
|
SDL_free(iodata->data);
|
||||||
|
SDL_free(iodata->write_data);
|
||||||
SDL_free(iodata);
|
SDL_free(iodata);
|
||||||
return true;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_IOStream *SDL_IOFromHandle(HANDLE handle, const char *mode, bool autoclose)
|
SDL_IOStream *SDL_IOFromHandle(HANDLE handle, const char *mode, bool autoclose)
|
||||||
@@ -348,6 +447,9 @@ SDL_IOStream *SDL_IOFromHandle(HANDLE handle, const char *mode, bool autoclose)
|
|||||||
iface.close = windows_file_close;
|
iface.close = windows_file_close;
|
||||||
|
|
||||||
iodata->h = handle;
|
iodata->h = handle;
|
||||||
|
iodata->writable = (SDL_strchr(mode, 'w') != NULL) ||
|
||||||
|
(SDL_strchr(mode, 'a') != NULL) ||
|
||||||
|
(SDL_strchr(mode, '+') != NULL);
|
||||||
iodata->append = (SDL_strchr(mode, 'a') != NULL);
|
iodata->append = (SDL_strchr(mode, 'a') != NULL);
|
||||||
iodata->autoclose = autoclose;
|
iodata->autoclose = autoclose;
|
||||||
|
|
||||||
@@ -357,6 +459,13 @@ SDL_IOStream *SDL_IOFromHandle(HANDLE handle, const char *mode, bool autoclose)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iodata->write_data = (char *)SDL_malloc(WRITEBEHIND_BUFFER_SIZE);
|
||||||
|
if (!iodata->write_data) {
|
||||||
|
iface.close(iodata);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
iodata->write_pos = 0;
|
||||||
|
|
||||||
SDL_IOStream *iostr = SDL_OpenIO(&iface, iodata);
|
SDL_IOStream *iostr = SDL_OpenIO(&iface, iodata);
|
||||||
if (!iostr) {
|
if (!iostr) {
|
||||||
iface.close(iodata);
|
iface.close(iodata);
|
||||||
|
|||||||
Reference in New Issue
Block a user