src/file/SDL_rwops.c
author David Ludwig <dludwig@pobox.com>
Wed, 17 Oct 2012 21:43:20 -0400
changeset 8316 88f011703f39
parent 6430 48d519500f7e
child 8317 4eec049a8b7c
permissions -rw-r--r--
Got a bare-bones version of SDL compiling for Windows RT. Dummy drivers are used in some places. Very little Windows-specific code (from the Win32 version of SDL) is used.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 /* This file provides a general interface for SDL to read and write
    24    data sources.  It can easily be extended to files, memory, etc.
    25 */
    26 
    27 #include "SDL_endian.h"
    28 #include "SDL_rwops.h"
    29 
    30 #ifdef __APPLE__
    31 #include "cocoa/SDL_rwopsbundlesupport.h"
    32 #endif /* __APPLE__ */
    33 
    34 #ifdef ANDROID
    35 #include "../core/android/SDL_android.h"
    36 #endif
    37 
    38 #ifdef __NDS__
    39 /* include libfat headers for fatInitDefault(). */
    40 #include <fat.h>
    41 #endif /* __NDS__ */
    42 
    43 #ifdef __WIN32__
    44 
    45 /* Functions to read/write Win32 API file pointers */
    46 
    47 #include "../core/windows/SDL_windows.h"
    48 
    49 #ifndef INVALID_SET_FILE_POINTER
    50 #define INVALID_SET_FILE_POINTER 0xFFFFFFFF
    51 #endif
    52 
    53 #define READAHEAD_BUFFER_SIZE	1024
    54 
    55 static int SDLCALL
    56 windows_file_open(SDL_RWops * context, const char *filename, const char *mode)
    57 {
    58     UINT old_error_mode;
    59     HANDLE h;
    60     DWORD r_right, w_right;
    61     DWORD must_exist, truncate;
    62     int a_mode;
    63 
    64     if (!context)
    65         return -1;              /* failed (invalid call) */
    66 
    67     context->hidden.windowsio.h = INVALID_HANDLE_VALUE;   /* mark this as unusable */
    68     context->hidden.windowsio.buffer.data = NULL;
    69     context->hidden.windowsio.buffer.size = 0;
    70     context->hidden.windowsio.buffer.left = 0;
    71 
    72     /* "r" = reading, file must exist */
    73     /* "w" = writing, truncate existing, file may not exist */
    74     /* "r+"= reading or writing, file must exist            */
    75     /* "a" = writing, append file may not exist             */
    76     /* "a+"= append + read, file may not exist              */
    77     /* "w+" = read, write, truncate. file may not exist    */
    78 
    79     must_exist = (SDL_strchr(mode, 'r') != NULL) ? OPEN_EXISTING : 0;
    80     truncate = (SDL_strchr(mode, 'w') != NULL) ? CREATE_ALWAYS : 0;
    81     r_right = (SDL_strchr(mode, '+') != NULL
    82                || must_exist) ? GENERIC_READ : 0;
    83     a_mode = (SDL_strchr(mode, 'a') != NULL) ? OPEN_ALWAYS : 0;
    84     w_right = (a_mode || SDL_strchr(mode, '+')
    85                || truncate) ? GENERIC_WRITE : 0;
    86 
    87     if (!r_right && !w_right)   /* inconsistent mode */
    88         return -1;              /* failed (invalid call) */
    89 
    90     context->hidden.windowsio.buffer.data =
    91         (char *) SDL_malloc(READAHEAD_BUFFER_SIZE);
    92     if (!context->hidden.windowsio.buffer.data) {
    93         SDL_OutOfMemory();
    94         return -1;
    95     }
    96     /* Do not open a dialog box if failure */
    97     old_error_mode =
    98         SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
    99 
   100     {
   101         LPTSTR tstr = WIN_UTF8ToString(filename);
   102         h = CreateFile(tstr, (w_right | r_right),
   103                        (w_right) ? 0 : FILE_SHARE_READ, NULL,
   104                        (must_exist | truncate | a_mode),
   105                        FILE_ATTRIBUTE_NORMAL, NULL);
   106         SDL_free(tstr);
   107     }
   108 
   109     /* restore old behavior */
   110     SetErrorMode(old_error_mode);
   111 
   112     if (h == INVALID_HANDLE_VALUE) {
   113         SDL_free(context->hidden.windowsio.buffer.data);
   114         context->hidden.windowsio.buffer.data = NULL;
   115         SDL_SetError("Couldn't open %s", filename);
   116         return -2;              /* failed (CreateFile) */
   117     }
   118     context->hidden.windowsio.h = h;
   119     context->hidden.windowsio.append = a_mode ? SDL_TRUE : SDL_FALSE;
   120 
   121     return 0;                   /* ok */
   122 }
   123 
   124 static long SDLCALL
   125 windows_file_seek(SDL_RWops * context, long offset, int whence)
   126 {
   127     DWORD windowswhence;
   128     long file_pos;
   129 
   130     if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) {
   131         SDL_SetError("windows_file_seek: invalid context/file not opened");
   132         return -1;
   133     }
   134 
   135     /* FIXME: We may be able to satisfy the seek within buffered data */
   136     if (whence == RW_SEEK_CUR && context->hidden.windowsio.buffer.left) {
   137         offset -= (long)context->hidden.windowsio.buffer.left;
   138     }
   139     context->hidden.windowsio.buffer.left = 0;
   140 
   141     switch (whence) {
   142     case RW_SEEK_SET:
   143         windowswhence = FILE_BEGIN;
   144         break;
   145     case RW_SEEK_CUR:
   146         windowswhence = FILE_CURRENT;
   147         break;
   148     case RW_SEEK_END:
   149         windowswhence = FILE_END;
   150         break;
   151     default:
   152         SDL_SetError("windows_file_seek: Unknown value for 'whence'");
   153         return -1;
   154     }
   155 
   156     file_pos =
   157         SetFilePointer(context->hidden.windowsio.h, offset, NULL, windowswhence);
   158 
   159     if (file_pos != INVALID_SET_FILE_POINTER)
   160         return file_pos;        /* success */
   161 
   162     SDL_Error(SDL_EFSEEK);
   163     return -1;                  /* error */
   164 }
   165 
   166 static size_t SDLCALL
   167 windows_file_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
   168 {
   169     size_t total_need;
   170     size_t total_read = 0;
   171     size_t read_ahead;
   172     DWORD byte_read;
   173 
   174     total_need = size * maxnum;
   175 
   176     if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE
   177         || !total_need)
   178         return 0;
   179 
   180     if (context->hidden.windowsio.buffer.left > 0) {
   181         void *data = (char *) context->hidden.windowsio.buffer.data +
   182             context->hidden.windowsio.buffer.size -
   183             context->hidden.windowsio.buffer.left;
   184         read_ahead =
   185             SDL_min(total_need, context->hidden.windowsio.buffer.left);
   186         SDL_memcpy(ptr, data, read_ahead);
   187         context->hidden.windowsio.buffer.left -= read_ahead;
   188 
   189         if (read_ahead == total_need) {
   190             return maxnum;
   191         }
   192         ptr = (char *) ptr + read_ahead;
   193         total_need -= read_ahead;
   194         total_read += read_ahead;
   195     }
   196 
   197     if (total_need < READAHEAD_BUFFER_SIZE) {
   198         if (!ReadFile
   199             (context->hidden.windowsio.h, context->hidden.windowsio.buffer.data,
   200              READAHEAD_BUFFER_SIZE, &byte_read, NULL)) {
   201             SDL_Error(SDL_EFREAD);
   202             return 0;
   203         }
   204         read_ahead = SDL_min(total_need, (int) byte_read);
   205         SDL_memcpy(ptr, context->hidden.windowsio.buffer.data, read_ahead);
   206         context->hidden.windowsio.buffer.size = byte_read;
   207         context->hidden.windowsio.buffer.left = byte_read - read_ahead;
   208         total_read += read_ahead;
   209     } else {
   210         if (!ReadFile
   211             (context->hidden.windowsio.h, ptr, (DWORD)total_need, &byte_read, NULL)) {
   212             SDL_Error(SDL_EFREAD);
   213             return 0;
   214         }
   215         total_read += byte_read;
   216     }
   217     return (total_read / size);
   218 }
   219 
   220 static size_t SDLCALL
   221 windows_file_write(SDL_RWops * context, const void *ptr, size_t size,
   222                  size_t num)
   223 {
   224 
   225     size_t total_bytes;
   226     DWORD byte_written;
   227     size_t nwritten;
   228 
   229     total_bytes = size * num;
   230 
   231     if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE
   232         || total_bytes <= 0 || !size)
   233         return 0;
   234 
   235     if (context->hidden.windowsio.buffer.left) {
   236         SetFilePointer(context->hidden.windowsio.h,
   237                        -(LONG)context->hidden.windowsio.buffer.left, NULL,
   238                        FILE_CURRENT);
   239         context->hidden.windowsio.buffer.left = 0;
   240     }
   241 
   242     /* if in append mode, we must go to the EOF before write */
   243     if (context->hidden.windowsio.append) {
   244         if (SetFilePointer(context->hidden.windowsio.h, 0L, NULL, FILE_END) ==
   245             INVALID_SET_FILE_POINTER) {
   246             SDL_Error(SDL_EFWRITE);
   247             return 0;
   248         }
   249     }
   250 
   251     if (!WriteFile
   252         (context->hidden.windowsio.h, ptr, (DWORD)total_bytes, &byte_written, NULL)) {
   253         SDL_Error(SDL_EFWRITE);
   254         return 0;
   255     }
   256 
   257     nwritten = byte_written / size;
   258     return nwritten;
   259 }
   260 
   261 static int SDLCALL
   262 windows_file_close(SDL_RWops * context)
   263 {
   264 
   265     if (context) {
   266         if (context->hidden.windowsio.h != INVALID_HANDLE_VALUE) {
   267             CloseHandle(context->hidden.windowsio.h);
   268             context->hidden.windowsio.h = INVALID_HANDLE_VALUE;   /* to be sure */
   269         }
   270         if (context->hidden.windowsio.buffer.data) {
   271             SDL_free(context->hidden.windowsio.buffer.data);
   272             context->hidden.windowsio.buffer.data = NULL;
   273         }
   274         SDL_FreeRW(context);
   275     }
   276     return (0);
   277 }
   278 #endif /* __WIN32__ */
   279 
   280 #ifdef HAVE_STDIO_H
   281 
   282 /* Functions to read/write stdio file pointers */
   283 
   284 static long SDLCALL
   285 stdio_seek(SDL_RWops * context, long offset, int whence)
   286 {
   287     if (fseek(context->hidden.stdio.fp, offset, whence) == 0) {
   288         return (ftell(context->hidden.stdio.fp));
   289     } else {
   290         SDL_Error(SDL_EFSEEK);
   291         return (-1);
   292     }
   293 }
   294 
   295 static size_t SDLCALL
   296 stdio_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
   297 {
   298     size_t nread;
   299 
   300     nread = fread(ptr, size, maxnum, context->hidden.stdio.fp);
   301     if (nread == 0 && ferror(context->hidden.stdio.fp)) {
   302         SDL_Error(SDL_EFREAD);
   303     }
   304     return (nread);
   305 }
   306 
   307 static size_t SDLCALL
   308 stdio_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
   309 {
   310     size_t nwrote;
   311 
   312     nwrote = fwrite(ptr, size, num, context->hidden.stdio.fp);
   313     if (nwrote == 0 && ferror(context->hidden.stdio.fp)) {
   314         SDL_Error(SDL_EFWRITE);
   315     }
   316     return (nwrote);
   317 }
   318 
   319 static int SDLCALL
   320 stdio_close(SDL_RWops * context)
   321 {
   322     int status = 0;
   323     if (context) {
   324         if (context->hidden.stdio.autoclose) {
   325             /* WARNING:  Check the return value here! */
   326             if (fclose(context->hidden.stdio.fp) != 0) {
   327                 SDL_Error(SDL_EFWRITE);
   328                 status = -1;
   329             }
   330         }
   331         SDL_FreeRW(context);
   332     }
   333     return status;
   334 }
   335 #endif /* !HAVE_STDIO_H */
   336 
   337 /* Functions to read/write memory pointers */
   338 
   339 static long SDLCALL
   340 mem_seek(SDL_RWops * context, long offset, int whence)
   341 {
   342     Uint8 *newpos;
   343 
   344     switch (whence) {
   345     case RW_SEEK_SET:
   346         newpos = context->hidden.mem.base + offset;
   347         break;
   348     case RW_SEEK_CUR:
   349         newpos = context->hidden.mem.here + offset;
   350         break;
   351     case RW_SEEK_END:
   352         newpos = context->hidden.mem.stop + offset;
   353         break;
   354     default:
   355         SDL_SetError("Unknown value for 'whence'");
   356         return (-1);
   357     }
   358     if (newpos < context->hidden.mem.base) {
   359         newpos = context->hidden.mem.base;
   360     }
   361     if (newpos > context->hidden.mem.stop) {
   362         newpos = context->hidden.mem.stop;
   363     }
   364     context->hidden.mem.here = newpos;
   365     return (long)(context->hidden.mem.here - context->hidden.mem.base);
   366 }
   367 
   368 static size_t SDLCALL
   369 mem_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
   370 {
   371     size_t total_bytes;
   372     size_t mem_available;
   373 
   374     total_bytes = (maxnum * size);
   375     if ((maxnum <= 0) || (size <= 0)
   376         || ((total_bytes / maxnum) != (size_t) size)) {
   377         return 0;
   378     }
   379 
   380     mem_available = (context->hidden.mem.stop - context->hidden.mem.here);
   381     if (total_bytes > mem_available) {
   382         total_bytes = mem_available;
   383     }
   384 
   385     SDL_memcpy(ptr, context->hidden.mem.here, total_bytes);
   386     context->hidden.mem.here += total_bytes;
   387 
   388     return (total_bytes / size);
   389 }
   390 
   391 static size_t SDLCALL
   392 mem_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
   393 {
   394     if ((context->hidden.mem.here + (num * size)) > context->hidden.mem.stop) {
   395         num = (context->hidden.mem.stop - context->hidden.mem.here) / size;
   396     }
   397     SDL_memcpy(context->hidden.mem.here, ptr, num * size);
   398     context->hidden.mem.here += num * size;
   399     return (num);
   400 }
   401 
   402 static size_t SDLCALL
   403 mem_writeconst(SDL_RWops * context, const void *ptr, size_t size, size_t num)
   404 {
   405     SDL_SetError("Can't write to read-only memory");
   406     return (-1);
   407 }
   408 
   409 static int SDLCALL
   410 mem_close(SDL_RWops * context)
   411 {
   412     if (context) {
   413         SDL_FreeRW(context);
   414     }
   415     return (0);
   416 }
   417 
   418 
   419 /* Functions to create SDL_RWops structures from various data sources */
   420 
   421 SDL_RWops *
   422 SDL_RWFromFile(const char *file, const char *mode)
   423 {
   424     SDL_RWops *rwops = NULL;
   425     if (!file || !*file || !mode || !*mode) {
   426         SDL_SetError("SDL_RWFromFile(): No file or no mode specified");
   427         return NULL;
   428     }
   429 #if defined(ANDROID)
   430     rwops = SDL_AllocRW();
   431     if (!rwops)
   432         return NULL;            /* SDL_SetError already setup by SDL_AllocRW() */
   433     if (Android_JNI_FileOpen(rwops, file, mode) < 0) {
   434         SDL_FreeRW(rwops);
   435         return NULL;
   436     }
   437     rwops->seek = Android_JNI_FileSeek;
   438     rwops->read = Android_JNI_FileRead;
   439     rwops->write = Android_JNI_FileWrite;
   440     rwops->close = Android_JNI_FileClose;
   441 
   442 #elif defined(__WIN32__)
   443     rwops = SDL_AllocRW();
   444     if (!rwops)
   445         return NULL;            /* SDL_SetError already setup by SDL_AllocRW() */
   446     if (windows_file_open(rwops, file, mode) < 0) {
   447         SDL_FreeRW(rwops);
   448         return NULL;
   449     }
   450     rwops->seek = windows_file_seek;
   451     rwops->read = windows_file_read;
   452     rwops->write = windows_file_write;
   453     rwops->close = windows_file_close;
   454 
   455 #elif HAVE_STDIO_H
   456     {
   457     	#ifdef __APPLE__
   458     	FILE *fp = SDL_OpenFPFromBundleOrFallback(file, mode);
   459         #elif __WINRT__
   460         FILE *fp = NULL;
   461         fopen_s(&fp, file, mode);
   462         #else
   463     	FILE *fp = fopen(file, mode);
   464     	#endif
   465     	if (fp == NULL) {
   466             SDL_SetError("Couldn't open %s", file);
   467         } else {
   468             rwops = SDL_RWFromFP(fp, SDL_TRUE);
   469         }
   470     }
   471 #else
   472     SDL_SetError("SDL not compiled with stdio support");
   473 #endif /* !HAVE_STDIO_H */
   474 
   475     return (rwops);
   476 }
   477 
   478 #ifdef HAVE_STDIO_H
   479 SDL_RWops *
   480 SDL_RWFromFP(FILE * fp, SDL_bool autoclose)
   481 {
   482     SDL_RWops *rwops = NULL;
   483 
   484 #if 0
   485 /*#ifdef __NDS__*/
   486     /* set it up so we can use stdio file function */
   487     fatInitDefault();
   488     printf("called fatInitDefault()");
   489 #endif /* __NDS__ */
   490 
   491     rwops = SDL_AllocRW();
   492     if (rwops != NULL) {
   493         rwops->seek = stdio_seek;
   494         rwops->read = stdio_read;
   495         rwops->write = stdio_write;
   496         rwops->close = stdio_close;
   497         rwops->hidden.stdio.fp = fp;
   498         rwops->hidden.stdio.autoclose = autoclose;
   499     }
   500     return (rwops);
   501 }
   502 #else
   503 SDL_RWops *
   504 SDL_RWFromFP(void * fp, SDL_bool autoclose)
   505 {
   506     SDL_SetError("SDL not compiled with stdio support");
   507     return NULL;
   508 }
   509 #endif /* HAVE_STDIO_H */
   510 
   511 SDL_RWops *
   512 SDL_RWFromMem(void *mem, int size)
   513 {
   514     SDL_RWops *rwops;
   515 
   516     rwops = SDL_AllocRW();
   517     if (rwops != NULL) {
   518         rwops->seek = mem_seek;
   519         rwops->read = mem_read;
   520         rwops->write = mem_write;
   521         rwops->close = mem_close;
   522         rwops->hidden.mem.base = (Uint8 *) mem;
   523         rwops->hidden.mem.here = rwops->hidden.mem.base;
   524         rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
   525     }
   526     return (rwops);
   527 }
   528 
   529 SDL_RWops *
   530 SDL_RWFromConstMem(const void *mem, int size)
   531 {
   532     SDL_RWops *rwops;
   533 
   534     rwops = SDL_AllocRW();
   535     if (rwops != NULL) {
   536         rwops->seek = mem_seek;
   537         rwops->read = mem_read;
   538         rwops->write = mem_writeconst;
   539         rwops->close = mem_close;
   540         rwops->hidden.mem.base = (Uint8 *) mem;
   541         rwops->hidden.mem.here = rwops->hidden.mem.base;
   542         rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
   543     }
   544     return (rwops);
   545 }
   546 
   547 SDL_RWops *
   548 SDL_AllocRW(void)
   549 {
   550     SDL_RWops *area;
   551 
   552     area = (SDL_RWops *) SDL_malloc(sizeof *area);
   553     if (area == NULL) {
   554         SDL_OutOfMemory();
   555     }
   556     return (area);
   557 }
   558 
   559 void
   560 SDL_FreeRW(SDL_RWops * area)
   561 {
   562     SDL_free(area);
   563 }
   564 
   565 /* Functions for dynamically reading and writing endian-specific values */
   566 
   567 Uint16
   568 SDL_ReadLE16(SDL_RWops * src)
   569 {
   570     Uint16 value;
   571 
   572     SDL_RWread(src, &value, (sizeof value), 1);
   573     return (SDL_SwapLE16(value));
   574 }
   575 
   576 Uint16
   577 SDL_ReadBE16(SDL_RWops * src)
   578 {
   579     Uint16 value;
   580 
   581     SDL_RWread(src, &value, (sizeof value), 1);
   582     return (SDL_SwapBE16(value));
   583 }
   584 
   585 Uint32
   586 SDL_ReadLE32(SDL_RWops * src)
   587 {
   588     Uint32 value;
   589 
   590     SDL_RWread(src, &value, (sizeof value), 1);
   591     return (SDL_SwapLE32(value));
   592 }
   593 
   594 Uint32
   595 SDL_ReadBE32(SDL_RWops * src)
   596 {
   597     Uint32 value;
   598 
   599     SDL_RWread(src, &value, (sizeof value), 1);
   600     return (SDL_SwapBE32(value));
   601 }
   602 
   603 Uint64
   604 SDL_ReadLE64(SDL_RWops * src)
   605 {
   606     Uint64 value;
   607 
   608     SDL_RWread(src, &value, (sizeof value), 1);
   609     return (SDL_SwapLE64(value));
   610 }
   611 
   612 Uint64
   613 SDL_ReadBE64(SDL_RWops * src)
   614 {
   615     Uint64 value;
   616 
   617     SDL_RWread(src, &value, (sizeof value), 1);
   618     return (SDL_SwapBE64(value));
   619 }
   620 
   621 size_t
   622 SDL_WriteLE16(SDL_RWops * dst, Uint16 value)
   623 {
   624     value = SDL_SwapLE16(value);
   625     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   626 }
   627 
   628 size_t
   629 SDL_WriteBE16(SDL_RWops * dst, Uint16 value)
   630 {
   631     value = SDL_SwapBE16(value);
   632     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   633 }
   634 
   635 size_t
   636 SDL_WriteLE32(SDL_RWops * dst, Uint32 value)
   637 {
   638     value = SDL_SwapLE32(value);
   639     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   640 }
   641 
   642 size_t
   643 SDL_WriteBE32(SDL_RWops * dst, Uint32 value)
   644 {
   645     value = SDL_SwapBE32(value);
   646     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   647 }
   648 
   649 size_t
   650 SDL_WriteLE64(SDL_RWops * dst, Uint64 value)
   651 {
   652     value = SDL_SwapLE64(value);
   653     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   654 }
   655 
   656 size_t
   657 SDL_WriteBE64(SDL_RWops * dst, Uint64 value)
   658 {
   659     value = SDL_SwapBE64(value);
   660     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   661 }
   662 
   663 /* vi: set ts=4 sw=4 expandtab: */