From 4b89904edbc5c4da53dc7be3f6dfbbebf5def2de Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 10 Jul 2007 04:01:46 +0000 Subject: [PATCH] Added read-ahead support for Win32 file IO --HG-- branch : SDL-1.2 extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/branches/SDL-1.2%402450 --- include/SDL_rwops.h | 11 ++++-- src/file/SDL_rwops.c | 82 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 76 insertions(+), 17 deletions(-) diff --git a/include/SDL_rwops.h b/include/SDL_rwops.h index d7e01d8fd..8c177017f 100644 --- a/include/SDL_rwops.h +++ b/include/SDL_rwops.h @@ -62,10 +62,15 @@ typedef struct SDL_RWops { Uint32 type; union { -#ifdef __WIN32__ +#if defined(__WIN32__) && !defined(__SYMBIAN32__) struct { - int append; - void* h; + int append; + void *h; + struct { + void *data; + int size; + int left; + } buffer; } win32io; #endif #ifdef HAVE_STDIO_H diff --git a/src/file/SDL_rwops.c b/src/file/SDL_rwops.c index c47f43862..6d0bf136e 100644 --- a/src/file/SDL_rwops.c +++ b/src/file/SDL_rwops.c @@ -43,6 +43,8 @@ #define INVALID_SET_FILE_POINTER 0xFFFFFFFF #endif +#define READAHEAD_BUFFER_SIZE 1024 + static int SDLCALL win32_file_open(SDL_RWops *context, const char *filename, const char *mode) { #ifndef _WIN32_WCE @@ -58,6 +60,14 @@ static int SDLCALL win32_file_open(SDL_RWops *context, const char *filename, con context->hidden.win32io.h = INVALID_HANDLE_VALUE; /* mark this as unusable */ + context->hidden.win32io.buffer.data = (char *)SDL_malloc(READAHEAD_BUFFER_SIZE); + if (!context->hidden.win32io.buffer.data) { + SDL_OutOfMemory(); + return -1; + } + context->hidden.win32io.buffer.size = 0; + context->hidden.win32io.buffer.left = 0; + /* "r" = reading, file must exist */ /* "w" = writing, truncate existing, file may not exist */ /* "r+"= reading or writing, file must exist */ @@ -117,7 +127,13 @@ static int SDLCALL win32_file_seek(SDL_RWops *context, int offset, int whence) SDL_SetError("win32_file_seek: invalid context/file not opened"); return -1; } - + + /* FIXME: We may be able to satisfy the seek within buffered data */ + if (whence == RW_SEEK_CUR && context->hidden.win32io.buffer.left) { + offset -= context->hidden.win32io.buffer.left; + } + context->hidden.win32io.buffer.left = 0; + switch (whence) { case RW_SEEK_SET: win32whence = FILE_BEGIN; break; @@ -129,7 +145,7 @@ static int SDLCALL win32_file_seek(SDL_RWops *context, int offset, int whence) SDL_SetError("win32_file_seek: Unknown value for 'whence'"); return -1; } - + file_pos = SetFilePointer(context->hidden.win32io.h,offset,NULL,win32whence); if ( file_pos != INVALID_SET_FILE_POINTER ) @@ -140,21 +156,50 @@ static int SDLCALL win32_file_seek(SDL_RWops *context, int offset, int whence) } static int SDLCALL win32_file_read(SDL_RWops *context, void *ptr, int size, int maxnum) { + int total_need; + int total_read = 0; + int read_ahead; + DWORD byte_read; - int total_bytes; - DWORD byte_read,nread; + total_need = size*maxnum; - total_bytes = size*maxnum; - - if (!context || context->hidden.win32io.h == INVALID_HANDLE_VALUE || total_bytes<=0 || !size) + if (!context || context->hidden.win32io.h == INVALID_HANDLE_VALUE || total_need<=0 || !size) return 0; - - if (!ReadFile(context->hidden.win32io.h,ptr,total_bytes,&byte_read,NULL)) { - SDL_Error(SDL_EFREAD); - return 0; - } - nread = byte_read/size; - return nread; + + if (context->hidden.win32io.buffer.left > 0) { + void *data = (char *)context->hidden.win32io.buffer.data + + context->hidden.win32io.buffer.size - + context->hidden.win32io.buffer.left; + read_ahead = SDL_min(total_need, context->hidden.win32io.buffer.left); + SDL_memcpy(ptr, data, read_ahead); + context->hidden.win32io.buffer.left -= read_ahead; + + if (read_ahead == total_need) { + return maxnum; + } + ptr = (char *)ptr + read_ahead; + total_need -= read_ahead; + total_read += read_ahead; + } + + if (total_need < READAHEAD_BUFFER_SIZE) { + if (!ReadFile(context->hidden.win32io.h,context->hidden.win32io.buffer.data,READAHEAD_BUFFER_SIZE,&byte_read,NULL)) { + SDL_Error(SDL_EFREAD); + return 0; + } + read_ahead = SDL_min(total_need, byte_read); + SDL_memcpy(ptr, context->hidden.win32io.buffer.data, read_ahead); + context->hidden.win32io.buffer.size = byte_read; + context->hidden.win32io.buffer.left = byte_read-read_ahead; + total_read += read_ahead; + } else { + if (!ReadFile(context->hidden.win32io.h,ptr,total_need,&byte_read,NULL)) { + SDL_Error(SDL_EFREAD); + return 0; + } + total_read += byte_read; + } + return (total_read/size); } static int SDLCALL win32_file_write(SDL_RWops *context, const void *ptr, int size, int num) { @@ -167,6 +212,11 @@ static int SDLCALL win32_file_write(SDL_RWops *context, const void *ptr, int siz if (!context || context->hidden.win32io.h==INVALID_HANDLE_VALUE || total_bytes<=0 || !size) return 0; + if (context->hidden.win32io.buffer.left) { + SetFilePointer(context->hidden.win32io.h,-context->hidden.win32io.buffer.left,NULL,FILE_CURRENT); + context->hidden.win32io.buffer.left = 0; + } + /* if in append mode, we must go to the EOF before write */ if (context->hidden.win32io.append) { if ( SetFilePointer(context->hidden.win32io.h,0L,NULL,FILE_END) == INVALID_SET_FILE_POINTER ) { @@ -191,6 +241,10 @@ static int SDLCALL win32_file_close(SDL_RWops *context) CloseHandle(context->hidden.win32io.h); context->hidden.win32io.h = INVALID_HANDLE_VALUE; /* to be sure */ } + if (context->hidden.win32io.buffer.data) { + SDL_free(context->hidden.win32io.buffer.data); + context->hidden.win32io.buffer.data = NULL; + } SDL_FreeRW(context); } return(0);