@@ -70,6 +70,9 @@ typedef struct IOStreamWindowsData
7070 void * data ;
7171 size_t size ;
7272 size_t left ;
73+ void * write_data ;
74+ size_t write_pos ;
75+ bool writable ;
7376 bool append ;
7477 bool autoclose ;
7578} IOStreamWindowsData ;
@@ -80,7 +83,8 @@ typedef struct IOStreamWindowsData
8083#define INVALID_SET_FILE_POINTER 0xFFFFFFFF
8184#endif
8285
83- #define READAHEAD_BUFFER_SIZE 1024
86+ #define READAHEAD_BUFFER_SIZE 1024
87+ #define WRITEBEHIND_BUFFER_SIZE 1024
8488
8589static HANDLE SDLCALL windows_file_open (const char * filename , const char * mode )
8690{
@@ -150,6 +154,41 @@ static HANDLE SDLCALL windows_file_open(const char *filename, const char *mode)
150154 return h ;
151155}
152156
157+ static bool windows_flush_write_buffer (IOStreamWindowsData * iodata ,
158+ SDL_IOStatus * status )
159+ {
160+ if (iodata -> write_pos == 0 ) {
161+ return true; // Nothing to flush
162+ }
163+
164+ // In append mode, seek to EOF before writing
165+ if (iodata -> append ) {
166+ LARGE_INTEGER windowsoffset ;
167+ windowsoffset .QuadPart = 0 ;
168+ if (!SetFilePointerEx (iodata -> h , windowsoffset ,
169+ & windowsoffset , FILE_END )) {
170+ if (status ) {
171+ * status = SDL_IO_STATUS_ERROR ;
172+ }
173+ WIN_SetError ("Error seeking in datastream" );
174+ return false;
175+ }
176+ }
177+
178+ DWORD bytes ;
179+ if (!WriteFile (iodata -> h , iodata -> write_data ,
180+ (DWORD )iodata -> write_pos , & bytes , NULL )) {
181+ if (status ) {
182+ * status = SDL_IO_STATUS_ERROR ;
183+ }
184+ WIN_SetError ("Error writing to datastream" );
185+ return false;
186+ }
187+
188+ iodata -> write_pos = 0 ;
189+ return true;
190+ }
191+
153192static Sint64 SDLCALL windows_file_size (void * userdata )
154193{
155194 IOStreamWindowsData * iodata = (IOStreamWindowsData * ) userdata ;
@@ -168,6 +207,10 @@ static Sint64 SDLCALL windows_file_seek(void *userdata, Sint64 offset, SDL_IOWhe
168207 DWORD windowswhence ;
169208 LARGE_INTEGER windowsoffset ;
170209
210+ if (!windows_flush_write_buffer (iodata , NULL )) {
211+ return -1 ;
212+ }
213+
171214 // FIXME: We may be able to satisfy the seek within buffered data
172215 if ((whence == SDL_IO_SEEK_CUR ) && (iodata -> left )) {
173216 offset -= iodata -> left ;
@@ -204,6 +247,10 @@ static size_t SDLCALL windows_file_read(void *userdata, void *ptr, size_t size,
204247 size_t read_ahead ;
205248 DWORD bytes ;
206249
250+ if (!windows_flush_write_buffer (iodata , status )) {
251+ return 0 ;
252+ }
253+
207254 if (iodata -> left > 0 ) {
208255 void * data = (char * )iodata -> data +
209256 iodata -> size -
@@ -270,42 +317,87 @@ static size_t SDLCALL windows_file_read(void *userdata, void *ptr, size_t size,
270317
271318static size_t SDLCALL windows_file_write (void * userdata , const void * ptr , size_t size , SDL_IOStatus * status )
272319{
273- IOStreamWindowsData * iodata = (IOStreamWindowsData * ) userdata ;
274- DWORD bytes ;
320+ IOStreamWindowsData * iodata = (IOStreamWindowsData * )userdata ;
321+ const Uint8 * src = (const Uint8 * )ptr ;
322+ size_t remaining = size ;
323+ size_t total_written = 0 ;
275324
325+ if (!iodata -> writable ) {
326+ * status = SDL_IO_STATUS_READONLY ;
327+ return 0 ;
328+ }
329+
330+ // Invalidate read-ahead buffer if it has data
276331 if (iodata -> left ) {
277- if (!SetFilePointer (iodata -> h , - (LONG )iodata -> left , NULL , FILE_CURRENT )) {
332+ if (!SetFilePointer (iodata -> h , - (LONG )iodata -> left ,
333+ NULL , FILE_CURRENT )) {
278334 * status = SDL_IO_STATUS_ERROR ;
279335 WIN_SetError ("Error seeking in datastream" );
280336 return 0 ;
281337 }
282338 iodata -> left = 0 ;
283339 }
284340
285- // if in append mode, we must go to the EOF before write
286- if (iodata -> append ) {
287- LARGE_INTEGER windowsoffset ;
288- windowsoffset .QuadPart = 0 ;
289- if (!SetFilePointerEx (iodata -> h , windowsoffset , & windowsoffset , FILE_END )) {
341+ // For large writes, flush buffer and write directly
342+ if (size >= WRITEBEHIND_BUFFER_SIZE ) {
343+ if (!windows_flush_write_buffer (iodata , status )) {
344+ return 0 ;
345+ }
346+
347+ // In append mode, seek to EOF before direct write
348+ if (iodata -> append ) {
349+ LARGE_INTEGER windowsoffset ;
350+ windowsoffset .QuadPart = 0 ;
351+ if (!SetFilePointerEx (iodata -> h , windowsoffset ,
352+ & windowsoffset , FILE_END )) {
353+ * status = SDL_IO_STATUS_ERROR ;
354+ WIN_SetError ("Error seeking in datastream" );
355+ return 0 ;
356+ }
357+ }
358+
359+ DWORD bytes ;
360+ if (!WriteFile (iodata -> h , ptr , (DWORD )size , & bytes , NULL )) {
290361 * status = SDL_IO_STATUS_ERROR ;
291- WIN_SetError ("Error seeking in datastream" );
362+ WIN_SetError ("Error writing to datastream" );
292363 return 0 ;
364+ } else if (bytes == 0 && size > 0 ) {
365+ * status = SDL_IO_STATUS_NOT_READY ;
293366 }
367+ return bytes ;
294368 }
295369
296- if (!WriteFile (iodata -> h , ptr , (DWORD )size , & bytes , NULL )) {
297- * status = SDL_IO_STATUS_ERROR ;
298- WIN_SetError ("Error writing to datastream" );
299- return 0 ;
300- } else if (bytes == 0 && size > 0 ) {
301- * status = SDL_IO_STATUS_NOT_READY ;
370+ // Buffer small writes
371+ while (remaining > 0 ) {
372+ size_t space = WRITEBEHIND_BUFFER_SIZE - iodata -> write_pos ;
373+ size_t to_buffer = SDL_min (remaining , space );
374+
375+ SDL_memcpy ((char * )iodata -> write_data + iodata -> write_pos ,
376+ src , to_buffer );
377+ iodata -> write_pos += to_buffer ;
378+ src += to_buffer ;
379+ remaining -= to_buffer ;
380+ total_written += to_buffer ;
381+
382+ if (iodata -> write_pos == WRITEBEHIND_BUFFER_SIZE ) {
383+ if (!windows_flush_write_buffer (iodata , status )) {
384+ return total_written ;
385+ }
386+ }
302387 }
303- return bytes ;
388+
389+ return total_written ;
304390}
305391
306392static bool SDLCALL windows_file_flush (void * userdata , SDL_IOStatus * status )
307393{
308- IOStreamWindowsData * iodata = (IOStreamWindowsData * ) userdata ;
394+ IOStreamWindowsData * iodata = (IOStreamWindowsData * )userdata ;
395+
396+ if (!windows_flush_write_buffer (iodata , status )) {
397+ return false;
398+ }
399+
400+ // Sync to disk
309401 if (!FlushFileBuffers (iodata -> h )) {
310402 return WIN_SetError ("Error flushing datastream" );
311403 }
@@ -314,16 +406,23 @@ static bool SDLCALL windows_file_flush(void *userdata, SDL_IOStatus *status)
314406
315407static bool SDLCALL windows_file_close (void * userdata )
316408{
317- IOStreamWindowsData * iodata = (IOStreamWindowsData * ) userdata ;
409+ IOStreamWindowsData * iodata = (IOStreamWindowsData * )userdata ;
410+ bool result = true;
411+
412+ if (!windows_flush_write_buffer (iodata , NULL )) {
413+ result = false;
414+ }
415+
318416 if (iodata -> h != INVALID_HANDLE_VALUE ) {
319417 if (iodata -> autoclose ) {
320418 CloseHandle (iodata -> h );
321419 }
322- iodata -> h = INVALID_HANDLE_VALUE ; // to be sure
420+ iodata -> h = INVALID_HANDLE_VALUE ;
323421 }
324422 SDL_free (iodata -> data );
423+ SDL_free (iodata -> write_data );
325424 SDL_free (iodata );
326- return true ;
425+ return result ;
327426}
328427
329428SDL_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)
348447 iface .close = windows_file_close ;
349448
350449 iodata -> h = handle ;
450+ iodata -> writable = (SDL_strchr (mode , 'w' ) != NULL ) ||
451+ (SDL_strchr (mode , 'a' ) != NULL ) ||
452+ (SDL_strchr (mode , '+' ) != NULL );
351453 iodata -> append = (SDL_strchr (mode , 'a' ) != NULL );
352454 iodata -> autoclose = autoclose ;
353455
@@ -357,6 +459,13 @@ SDL_IOStream *SDL_IOFromHandle(HANDLE handle, const char *mode, bool autoclose)
357459 return NULL ;
358460 }
359461
462+ iodata -> write_data = (char * )SDL_malloc (WRITEBEHIND_BUFFER_SIZE );
463+ if (!iodata -> write_data ) {
464+ iface .close (iodata );
465+ return NULL ;
466+ }
467+ iodata -> write_pos = 0 ;
468+
360469 SDL_IOStream * iostr = SDL_OpenIO (& iface , iodata );
361470 if (!iostr ) {
362471 iface .close (iodata );
0 commit comments