Merged read-ahead support for Win32 file I/O from SDL 1.2 revision 3183
authorSam Lantinga <slouken@libsdl.org>
Tue, 10 Jul 2007 05:01:22 +0000
changeset 2159 dd4753e47ed4
parent 2158 eff395617ed8
child 2160 00adbaed3910
Merged read-ahead support for Win32 file I/O from SDL 1.2 revision 3183
include/SDL_rwops.h
src/file/SDL_rwops.c
--- a/include/SDL_rwops.h	Tue Jul 10 04:45:50 2007 +0000
+++ b/include/SDL_rwops.h	Tue Jul 10 05:01:22 2007 +0000
@@ -76,6 +76,12 @@
         {
             int append;
             void *h;
+            struct
+            {
+                void *data;
+                int size;
+                int left;
+            } buffer;
         } win32io;
 #endif
 #ifdef HAVE_STDIO_H
--- a/src/file/SDL_rwops.c	Tue Jul 10 04:45:50 2007 +0000
+++ b/src/file/SDL_rwops.c	Tue Jul 10 05:01:22 2007 +0000
@@ -29,7 +29,7 @@
 #include "SDL_rwops.h"
 
 
-#if defined(__WIN32__)
+#ifdef __WIN32__
 
 /* Functions to read/write Win32 API file pointers */
 /* Will not use it on WinCE because stdio is buffered, it means
@@ -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)
 {
@@ -59,6 +61,15 @@
 
     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            */
@@ -128,6 +139,12 @@
         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;
@@ -155,23 +172,54 @@
 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_bytes = size * maxnum;
+    total_need = size * maxnum;
 
     if (!context || context->hidden.win32io.h == INVALID_HANDLE_VALUE
-        || total_bytes <= 0 || !size)
+        || total_need <= 0 || !size)
         return 0;
 
-    if (!ReadFile
-        (context->hidden.win32io.h, ptr, total_bytes, &byte_read, NULL)) {
-        SDL_Error(SDL_EFREAD);
-        return 0;
+    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;
     }
-    nread = byte_read / size;
-    return nread;
+
+    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, (int) 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)
@@ -186,10 +234,17 @@
         || 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) {
+        if (SetFilePointer(context->hidden.win32io.h, 0L, NULL, FILE_END) ==
+            INVALID_SET_FILE_POINTER) {
             SDL_Error(SDL_EFWRITE);
             return 0;
         }
@@ -213,6 +268,10 @@
             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);