src/file/SDL_rwops.c
author Ryan C. Gordon <icculus@icculus.org>
Tue, 15 Aug 2017 16:30:26 -0400
changeset 11304 03d0ffb1f3dd
parent 11236 8c3cba28b1fd
child 11416 7e7d8a125d6a
permissions -rw-r--r--
rwops: Fixed 64-bit file i/o on QNX.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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 
    22 /* We won't get fseeko64 on QNX if _LARGEFILE64_SOURCE is defined, but the
    23    configure script knows the C runtime has it and enables it. */
    24 #ifndef __QNXNTO__
    25 /* Need this so Linux systems define fseek64o, ftell64o and off64_t */
    26 #define _LARGEFILE64_SOURCE
    27 #endif
    28 
    29 #include "../SDL_internal.h"
    30 
    31 #if defined(__WIN32__)
    32 #include "../core/windows/SDL_windows.h"
    33 #endif
    34 
    35 
    36 /* This file provides a general interface for SDL to read and write
    37    data sources.  It can easily be extended to files, memory, etc.
    38 */
    39 
    40 #include "SDL_endian.h"
    41 #include "SDL_rwops.h"
    42 
    43 #ifdef __APPLE__
    44 #include "cocoa/SDL_rwopsbundlesupport.h"
    45 #endif /* __APPLE__ */
    46 
    47 #ifdef __ANDROID__
    48 #include "../core/android/SDL_android.h"
    49 #include "SDL_system.h"
    50 #endif
    51 
    52 #if __NACL__
    53 #include "nacl_io/nacl_io.h"
    54 #endif
    55 
    56 #ifdef __WIN32__
    57 
    58 /* Functions to read/write Win32 API file pointers */
    59 
    60 #ifndef INVALID_SET_FILE_POINTER
    61 #define INVALID_SET_FILE_POINTER 0xFFFFFFFF
    62 #endif
    63 
    64 #define READAHEAD_BUFFER_SIZE   1024
    65 
    66 static int SDLCALL
    67 windows_file_open(SDL_RWops * context, const char *filename, const char *mode)
    68 {
    69     UINT old_error_mode;
    70     HANDLE h;
    71     DWORD r_right, w_right;
    72     DWORD must_exist, truncate;
    73     int a_mode;
    74 
    75     if (!context)
    76         return -1;              /* failed (invalid call) */
    77 
    78     context->hidden.windowsio.h = INVALID_HANDLE_VALUE;   /* mark this as unusable */
    79     context->hidden.windowsio.buffer.data = NULL;
    80     context->hidden.windowsio.buffer.size = 0;
    81     context->hidden.windowsio.buffer.left = 0;
    82 
    83     /* "r" = reading, file must exist */
    84     /* "w" = writing, truncate existing, file may not exist */
    85     /* "r+"= reading or writing, file must exist            */
    86     /* "a" = writing, append file may not exist             */
    87     /* "a+"= append + read, file may not exist              */
    88     /* "w+" = read, write, truncate. file may not exist    */
    89 
    90     must_exist = (SDL_strchr(mode, 'r') != NULL) ? OPEN_EXISTING : 0;
    91     truncate = (SDL_strchr(mode, 'w') != NULL) ? CREATE_ALWAYS : 0;
    92     r_right = (SDL_strchr(mode, '+') != NULL
    93                || must_exist) ? GENERIC_READ : 0;
    94     a_mode = (SDL_strchr(mode, 'a') != NULL) ? OPEN_ALWAYS : 0;
    95     w_right = (a_mode || SDL_strchr(mode, '+')
    96                || truncate) ? GENERIC_WRITE : 0;
    97 
    98     if (!r_right && !w_right)   /* inconsistent mode */
    99         return -1;              /* failed (invalid call) */
   100 
   101     context->hidden.windowsio.buffer.data =
   102         (char *) SDL_malloc(READAHEAD_BUFFER_SIZE);
   103     if (!context->hidden.windowsio.buffer.data) {
   104         return SDL_OutOfMemory();
   105     }
   106     /* Do not open a dialog box if failure */
   107     old_error_mode =
   108         SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
   109 
   110     {
   111         LPTSTR tstr = WIN_UTF8ToString(filename);
   112         h = CreateFile(tstr, (w_right | r_right),
   113                        (w_right) ? 0 : FILE_SHARE_READ, NULL,
   114                        (must_exist | truncate | a_mode),
   115                        FILE_ATTRIBUTE_NORMAL, NULL);
   116         SDL_free(tstr);
   117     }
   118 
   119     /* restore old behavior */
   120     SetErrorMode(old_error_mode);
   121 
   122     if (h == INVALID_HANDLE_VALUE) {
   123         SDL_free(context->hidden.windowsio.buffer.data);
   124         context->hidden.windowsio.buffer.data = NULL;
   125         SDL_SetError("Couldn't open %s", filename);
   126         return -2;              /* failed (CreateFile) */
   127     }
   128     context->hidden.windowsio.h = h;
   129     context->hidden.windowsio.append = a_mode ? SDL_TRUE : SDL_FALSE;
   130 
   131     return 0;                   /* ok */
   132 }
   133 
   134 static Sint64 SDLCALL
   135 windows_file_size(SDL_RWops * context)
   136 {
   137     LARGE_INTEGER size;
   138 
   139     if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) {
   140         return SDL_SetError("windows_file_size: invalid context/file not opened");
   141     }
   142 
   143     if (!GetFileSizeEx(context->hidden.windowsio.h, &size)) {
   144         return WIN_SetError("windows_file_size");
   145     }
   146 
   147     return size.QuadPart;
   148 }
   149 
   150 static Sint64 SDLCALL
   151 windows_file_seek(SDL_RWops * context, Sint64 offset, int whence)
   152 {
   153     DWORD windowswhence;
   154     LARGE_INTEGER windowsoffset;
   155 
   156     if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) {
   157         return SDL_SetError("windows_file_seek: invalid context/file not opened");
   158     }
   159 
   160     /* FIXME: We may be able to satisfy the seek within buffered data */
   161     if (whence == RW_SEEK_CUR && context->hidden.windowsio.buffer.left) {
   162         offset -= (long)context->hidden.windowsio.buffer.left;
   163     }
   164     context->hidden.windowsio.buffer.left = 0;
   165 
   166     switch (whence) {
   167     case RW_SEEK_SET:
   168         windowswhence = FILE_BEGIN;
   169         break;
   170     case RW_SEEK_CUR:
   171         windowswhence = FILE_CURRENT;
   172         break;
   173     case RW_SEEK_END:
   174         windowswhence = FILE_END;
   175         break;
   176     default:
   177         return SDL_SetError("windows_file_seek: Unknown value for 'whence'");
   178     }
   179 
   180     windowsoffset.QuadPart = offset;
   181     if (!SetFilePointerEx(context->hidden.windowsio.h, windowsoffset, &windowsoffset, windowswhence)) {
   182         return WIN_SetError("windows_file_seek");
   183     }
   184     return windowsoffset.QuadPart;
   185 }
   186 
   187 static size_t SDLCALL
   188 windows_file_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
   189 {
   190     size_t total_need;
   191     size_t total_read = 0;
   192     size_t read_ahead;
   193     DWORD byte_read;
   194 
   195     total_need = size * maxnum;
   196 
   197     if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE
   198         || !total_need)
   199         return 0;
   200 
   201     if (context->hidden.windowsio.buffer.left > 0) {
   202         void *data = (char *) context->hidden.windowsio.buffer.data +
   203             context->hidden.windowsio.buffer.size -
   204             context->hidden.windowsio.buffer.left;
   205         read_ahead =
   206             SDL_min(total_need, context->hidden.windowsio.buffer.left);
   207         SDL_memcpy(ptr, data, read_ahead);
   208         context->hidden.windowsio.buffer.left -= read_ahead;
   209 
   210         if (read_ahead == total_need) {
   211             return maxnum;
   212         }
   213         ptr = (char *) ptr + read_ahead;
   214         total_need -= read_ahead;
   215         total_read += read_ahead;
   216     }
   217 
   218     if (total_need < READAHEAD_BUFFER_SIZE) {
   219         if (!ReadFile
   220             (context->hidden.windowsio.h, context->hidden.windowsio.buffer.data,
   221              READAHEAD_BUFFER_SIZE, &byte_read, NULL)) {
   222             SDL_Error(SDL_EFREAD);
   223             return 0;
   224         }
   225         read_ahead = SDL_min(total_need, (int) byte_read);
   226         SDL_memcpy(ptr, context->hidden.windowsio.buffer.data, read_ahead);
   227         context->hidden.windowsio.buffer.size = byte_read;
   228         context->hidden.windowsio.buffer.left = byte_read - read_ahead;
   229         total_read += read_ahead;
   230     } else {
   231         if (!ReadFile
   232             (context->hidden.windowsio.h, ptr, (DWORD)total_need, &byte_read, NULL)) {
   233             SDL_Error(SDL_EFREAD);
   234             return 0;
   235         }
   236         total_read += byte_read;
   237     }
   238     return (total_read / size);
   239 }
   240 
   241 static size_t SDLCALL
   242 windows_file_write(SDL_RWops * context, const void *ptr, size_t size,
   243                  size_t num)
   244 {
   245 
   246     size_t total_bytes;
   247     DWORD byte_written;
   248     size_t nwritten;
   249 
   250     total_bytes = size * num;
   251 
   252     if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE
   253         || total_bytes <= 0 || !size)
   254         return 0;
   255 
   256     if (context->hidden.windowsio.buffer.left) {
   257         SetFilePointer(context->hidden.windowsio.h,
   258                        -(LONG)context->hidden.windowsio.buffer.left, NULL,
   259                        FILE_CURRENT);
   260         context->hidden.windowsio.buffer.left = 0;
   261     }
   262 
   263     /* if in append mode, we must go to the EOF before write */
   264     if (context->hidden.windowsio.append) {
   265         if (SetFilePointer(context->hidden.windowsio.h, 0L, NULL, FILE_END) ==
   266             INVALID_SET_FILE_POINTER) {
   267             SDL_Error(SDL_EFWRITE);
   268             return 0;
   269         }
   270     }
   271 
   272     if (!WriteFile
   273         (context->hidden.windowsio.h, ptr, (DWORD)total_bytes, &byte_written, NULL)) {
   274         SDL_Error(SDL_EFWRITE);
   275         return 0;
   276     }
   277 
   278     nwritten = byte_written / size;
   279     return nwritten;
   280 }
   281 
   282 static int SDLCALL
   283 windows_file_close(SDL_RWops * context)
   284 {
   285 
   286     if (context) {
   287         if (context->hidden.windowsio.h != INVALID_HANDLE_VALUE) {
   288             CloseHandle(context->hidden.windowsio.h);
   289             context->hidden.windowsio.h = INVALID_HANDLE_VALUE;   /* to be sure */
   290         }
   291         SDL_free(context->hidden.windowsio.buffer.data);
   292         context->hidden.windowsio.buffer.data = NULL;
   293         SDL_FreeRW(context);
   294     }
   295     return 0;
   296 }
   297 #endif /* __WIN32__ */
   298 
   299 #ifdef HAVE_STDIO_H
   300 
   301 #ifdef HAVE_FOPEN64
   302 #define fopen   fopen64
   303 #endif
   304 #ifdef HAVE_FSEEKO64
   305 #define fseek_off_t off64_t
   306 #define fseek   fseeko64
   307 #define ftell   ftello64
   308 #elif defined(HAVE_FSEEKO)
   309 #define fseek_off_t off_t
   310 #define fseek   fseeko
   311 #define ftell   ftello
   312 #elif defined(HAVE__FSEEKI64)
   313 #define fseek_off_t __int64
   314 #define fseek   _fseeki64
   315 #define ftell   _ftelli64
   316 #else
   317 #define fseek_off_t long
   318 #endif
   319 
   320 /* Functions to read/write stdio file pointers */
   321 
   322 static Sint64 SDLCALL
   323 stdio_size(SDL_RWops * context)
   324 {
   325     Sint64 pos, size;
   326 
   327     pos = SDL_RWseek(context, 0, RW_SEEK_CUR);
   328     if (pos < 0) {
   329         return -1;
   330     }
   331     size = SDL_RWseek(context, 0, RW_SEEK_END);
   332 
   333     SDL_RWseek(context, pos, RW_SEEK_SET);
   334     return size;
   335 }
   336 
   337 static Sint64 SDLCALL
   338 stdio_seek(SDL_RWops * context, Sint64 offset, int whence)
   339 {
   340     if (fseek(context->hidden.stdio.fp, (fseek_off_t)offset, whence) == 0) {
   341         return ftell(context->hidden.stdio.fp);
   342     }
   343     return SDL_Error(SDL_EFSEEK);
   344 }
   345 
   346 static size_t SDLCALL
   347 stdio_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
   348 {
   349     size_t nread;
   350 
   351     nread = fread(ptr, size, maxnum, context->hidden.stdio.fp);
   352     if (nread == 0 && ferror(context->hidden.stdio.fp)) {
   353         SDL_Error(SDL_EFREAD);
   354     }
   355     return nread;
   356 }
   357 
   358 static size_t SDLCALL
   359 stdio_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
   360 {
   361     size_t nwrote;
   362 
   363     nwrote = fwrite(ptr, size, num, context->hidden.stdio.fp);
   364     if (nwrote == 0 && ferror(context->hidden.stdio.fp)) {
   365         SDL_Error(SDL_EFWRITE);
   366     }
   367     return nwrote;
   368 }
   369 
   370 static int SDLCALL
   371 stdio_close(SDL_RWops * context)
   372 {
   373     int status = 0;
   374     if (context) {
   375         if (context->hidden.stdio.autoclose) {
   376             /* WARNING:  Check the return value here! */
   377             if (fclose(context->hidden.stdio.fp) != 0) {
   378                 status = SDL_Error(SDL_EFWRITE);
   379             }
   380         }
   381         SDL_FreeRW(context);
   382     }
   383     return status;
   384 }
   385 #endif /* !HAVE_STDIO_H */
   386 
   387 /* Functions to read/write memory pointers */
   388 
   389 static Sint64 SDLCALL
   390 mem_size(SDL_RWops * context)
   391 {
   392     return (Sint64)(context->hidden.mem.stop - context->hidden.mem.base);
   393 }
   394 
   395 static Sint64 SDLCALL
   396 mem_seek(SDL_RWops * context, Sint64 offset, int whence)
   397 {
   398     Uint8 *newpos;
   399 
   400     switch (whence) {
   401     case RW_SEEK_SET:
   402         newpos = context->hidden.mem.base + offset;
   403         break;
   404     case RW_SEEK_CUR:
   405         newpos = context->hidden.mem.here + offset;
   406         break;
   407     case RW_SEEK_END:
   408         newpos = context->hidden.mem.stop + offset;
   409         break;
   410     default:
   411         return SDL_SetError("Unknown value for 'whence'");
   412     }
   413     if (newpos < context->hidden.mem.base) {
   414         newpos = context->hidden.mem.base;
   415     }
   416     if (newpos > context->hidden.mem.stop) {
   417         newpos = context->hidden.mem.stop;
   418     }
   419     context->hidden.mem.here = newpos;
   420     return (Sint64)(context->hidden.mem.here - context->hidden.mem.base);
   421 }
   422 
   423 static size_t SDLCALL
   424 mem_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
   425 {
   426     size_t total_bytes;
   427     size_t mem_available;
   428 
   429     total_bytes = (maxnum * size);
   430     if ((maxnum <= 0) || (size <= 0)
   431         || ((total_bytes / maxnum) != (size_t) size)) {
   432         return 0;
   433     }
   434 
   435     mem_available = (context->hidden.mem.stop - context->hidden.mem.here);
   436     if (total_bytes > mem_available) {
   437         total_bytes = mem_available;
   438     }
   439 
   440     SDL_memcpy(ptr, context->hidden.mem.here, total_bytes);
   441     context->hidden.mem.here += total_bytes;
   442 
   443     return (total_bytes / size);
   444 }
   445 
   446 static size_t SDLCALL
   447 mem_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
   448 {
   449     if ((context->hidden.mem.here + (num * size)) > context->hidden.mem.stop) {
   450         num = (context->hidden.mem.stop - context->hidden.mem.here) / size;
   451     }
   452     SDL_memcpy(context->hidden.mem.here, ptr, num * size);
   453     context->hidden.mem.here += num * size;
   454     return num;
   455 }
   456 
   457 static size_t SDLCALL
   458 mem_writeconst(SDL_RWops * context, const void *ptr, size_t size, size_t num)
   459 {
   460     SDL_SetError("Can't write to read-only memory");
   461     return 0;
   462 }
   463 
   464 static int SDLCALL
   465 mem_close(SDL_RWops * context)
   466 {
   467     if (context) {
   468         SDL_FreeRW(context);
   469     }
   470     return 0;
   471 }
   472 
   473 
   474 /* Functions to create SDL_RWops structures from various data sources */
   475 
   476 SDL_RWops *
   477 SDL_RWFromFile(const char *file, const char *mode)
   478 {
   479     SDL_RWops *rwops = NULL;
   480     if (!file || !*file || !mode || !*mode) {
   481         SDL_SetError("SDL_RWFromFile(): No file or no mode specified");
   482         return NULL;
   483     }
   484 #if defined(__ANDROID__)
   485 #ifdef HAVE_STDIO_H
   486     /* Try to open the file on the filesystem first */
   487     if (*file == '/') {
   488         FILE *fp = fopen(file, mode);
   489         if (fp) {
   490             return SDL_RWFromFP(fp, 1);
   491         }
   492     } else {
   493         /* Try opening it from internal storage if it's a relative path */
   494         char *path;
   495         FILE *fp;
   496 
   497         path = SDL_stack_alloc(char, PATH_MAX);
   498         if (path) {
   499             SDL_snprintf(path, PATH_MAX, "%s/%s",
   500                          SDL_AndroidGetInternalStoragePath(), file);
   501             fp = fopen(path, mode);
   502             SDL_stack_free(path);
   503             if (fp) {
   504                 return SDL_RWFromFP(fp, 1);
   505             }
   506         }
   507     }
   508 #endif /* HAVE_STDIO_H */
   509 
   510     /* Try to open the file from the asset system */
   511     rwops = SDL_AllocRW();
   512     if (!rwops)
   513         return NULL;            /* SDL_SetError already setup by SDL_AllocRW() */
   514     if (Android_JNI_FileOpen(rwops, file, mode) < 0) {
   515         SDL_FreeRW(rwops);
   516         return NULL;
   517     }
   518     rwops->size = Android_JNI_FileSize;
   519     rwops->seek = Android_JNI_FileSeek;
   520     rwops->read = Android_JNI_FileRead;
   521     rwops->write = Android_JNI_FileWrite;
   522     rwops->close = Android_JNI_FileClose;
   523     rwops->type = SDL_RWOPS_JNIFILE;
   524 
   525 #elif defined(__WIN32__)
   526     rwops = SDL_AllocRW();
   527     if (!rwops)
   528         return NULL;            /* SDL_SetError already setup by SDL_AllocRW() */
   529     if (windows_file_open(rwops, file, mode) < 0) {
   530         SDL_FreeRW(rwops);
   531         return NULL;
   532     }
   533     rwops->size = windows_file_size;
   534     rwops->seek = windows_file_seek;
   535     rwops->read = windows_file_read;
   536     rwops->write = windows_file_write;
   537     rwops->close = windows_file_close;
   538     rwops->type = SDL_RWOPS_WINFILE;
   539 
   540 #elif HAVE_STDIO_H
   541     {
   542         #ifdef __APPLE__
   543         FILE *fp = SDL_OpenFPFromBundleOrFallback(file, mode);
   544         #elif __WINRT__
   545         FILE *fp = NULL;
   546         fopen_s(&fp, file, mode);
   547         #else
   548         FILE *fp = fopen(file, mode);
   549         #endif
   550         if (fp == NULL) {
   551             SDL_SetError("Couldn't open %s", file);
   552         } else {
   553             rwops = SDL_RWFromFP(fp, 1);
   554         }
   555     }
   556 #else
   557     SDL_SetError("SDL not compiled with stdio support");
   558 #endif /* !HAVE_STDIO_H */
   559 
   560     return rwops;
   561 }
   562 
   563 #ifdef HAVE_STDIO_H
   564 SDL_RWops *
   565 SDL_RWFromFP(FILE * fp, SDL_bool autoclose)
   566 {
   567     SDL_RWops *rwops = NULL;
   568 
   569     rwops = SDL_AllocRW();
   570     if (rwops != NULL) {
   571         rwops->size = stdio_size;
   572         rwops->seek = stdio_seek;
   573         rwops->read = stdio_read;
   574         rwops->write = stdio_write;
   575         rwops->close = stdio_close;
   576         rwops->hidden.stdio.fp = fp;
   577         rwops->hidden.stdio.autoclose = autoclose;
   578         rwops->type = SDL_RWOPS_STDFILE;
   579     }
   580     return rwops;
   581 }
   582 #else
   583 SDL_RWops *
   584 SDL_RWFromFP(void * fp, SDL_bool autoclose)
   585 {
   586     SDL_SetError("SDL not compiled with stdio support");
   587     return NULL;
   588 }
   589 #endif /* HAVE_STDIO_H */
   590 
   591 SDL_RWops *
   592 SDL_RWFromMem(void *mem, int size)
   593 {
   594     SDL_RWops *rwops = NULL;
   595     if (!mem) {
   596       SDL_InvalidParamError("mem");
   597       return rwops;
   598     }
   599     if (!size) {
   600       SDL_InvalidParamError("size");
   601       return rwops;
   602     }
   603 
   604     rwops = SDL_AllocRW();
   605     if (rwops != NULL) {
   606         rwops->size = mem_size;
   607         rwops->seek = mem_seek;
   608         rwops->read = mem_read;
   609         rwops->write = mem_write;
   610         rwops->close = mem_close;
   611         rwops->hidden.mem.base = (Uint8 *) mem;
   612         rwops->hidden.mem.here = rwops->hidden.mem.base;
   613         rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
   614         rwops->type = SDL_RWOPS_MEMORY;
   615     }
   616     return rwops;
   617 }
   618 
   619 SDL_RWops *
   620 SDL_RWFromConstMem(const void *mem, int size)
   621 {
   622     SDL_RWops *rwops = NULL;
   623     if (!mem) {
   624       SDL_InvalidParamError("mem");
   625       return rwops;
   626     }
   627     if (!size) {
   628       SDL_InvalidParamError("size");
   629       return rwops;
   630     }
   631 
   632     rwops = SDL_AllocRW();
   633     if (rwops != NULL) {
   634         rwops->size = mem_size;
   635         rwops->seek = mem_seek;
   636         rwops->read = mem_read;
   637         rwops->write = mem_writeconst;
   638         rwops->close = mem_close;
   639         rwops->hidden.mem.base = (Uint8 *) mem;
   640         rwops->hidden.mem.here = rwops->hidden.mem.base;
   641         rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
   642         rwops->type = SDL_RWOPS_MEMORY_RO;
   643     }
   644     return rwops;
   645 }
   646 
   647 SDL_RWops *
   648 SDL_AllocRW(void)
   649 {
   650     SDL_RWops *area;
   651 
   652     area = (SDL_RWops *) SDL_malloc(sizeof *area);
   653     if (area == NULL) {
   654         SDL_OutOfMemory();
   655     } else {
   656         area->type = SDL_RWOPS_UNKNOWN;
   657     }
   658     return area;
   659 }
   660 
   661 void
   662 SDL_FreeRW(SDL_RWops * area)
   663 {
   664     SDL_free(area);
   665 }
   666 
   667 /* Load all the data from an SDL data stream */
   668 void *
   669 SDL_LoadFile_RW(SDL_RWops * src, size_t *datasize, int freesrc)
   670 {
   671     const int FILE_CHUNK_SIZE = 1024;
   672     Sint64 size;
   673     size_t size_read, size_total;
   674     void *data = NULL, *newdata;
   675 
   676     if (!src) {
   677         SDL_InvalidParamError("src");
   678         return NULL;
   679     }
   680 
   681     size = SDL_RWsize(src);
   682     if (size < 0) {
   683         size = FILE_CHUNK_SIZE;
   684     }
   685     data = SDL_malloc((size_t)(size + 1));
   686 
   687     size_total = 0;
   688     for (;;) {
   689         if ((size_total + FILE_CHUNK_SIZE) > size) {
   690             size = (size_total + FILE_CHUNK_SIZE);
   691             newdata = SDL_realloc(data, (size_t)(size + 1));
   692             if (!newdata) {
   693                 SDL_free(data);
   694                 data = NULL;
   695                 SDL_OutOfMemory();
   696                 goto done;
   697             }
   698             data = newdata;
   699         }
   700 
   701         size_read = SDL_RWread(src, (char *)data+size_total, 1, (size_t)(size-size_total));
   702         if (size_read == 0) {
   703             break;
   704         }
   705         size_total += size_read;
   706     }
   707 
   708     if (datasize) {
   709         *datasize = size_total;
   710     }
   711     ((char *)data)[size_total] = '\0';
   712 
   713 done:
   714     if (freesrc && src) {
   715         SDL_RWclose(src);
   716     }
   717     return data;
   718 }
   719 
   720 /* Functions for dynamically reading and writing endian-specific values */
   721 
   722 Uint8
   723 SDL_ReadU8(SDL_RWops * src)
   724 {
   725     Uint8 value = 0;
   726 
   727     SDL_RWread(src, &value, sizeof (value), 1);
   728     return value;
   729 }
   730 
   731 Uint16
   732 SDL_ReadLE16(SDL_RWops * src)
   733 {
   734     Uint16 value = 0;
   735 
   736     SDL_RWread(src, &value, sizeof (value), 1);
   737     return SDL_SwapLE16(value);
   738 }
   739 
   740 Uint16
   741 SDL_ReadBE16(SDL_RWops * src)
   742 {
   743     Uint16 value = 0;
   744 
   745     SDL_RWread(src, &value, sizeof (value), 1);
   746     return SDL_SwapBE16(value);
   747 }
   748 
   749 Uint32
   750 SDL_ReadLE32(SDL_RWops * src)
   751 {
   752     Uint32 value = 0;
   753 
   754     SDL_RWread(src, &value, sizeof (value), 1);
   755     return SDL_SwapLE32(value);
   756 }
   757 
   758 Uint32
   759 SDL_ReadBE32(SDL_RWops * src)
   760 {
   761     Uint32 value = 0;
   762 
   763     SDL_RWread(src, &value, sizeof (value), 1);
   764     return SDL_SwapBE32(value);
   765 }
   766 
   767 Uint64
   768 SDL_ReadLE64(SDL_RWops * src)
   769 {
   770     Uint64 value = 0;
   771 
   772     SDL_RWread(src, &value, sizeof (value), 1);
   773     return SDL_SwapLE64(value);
   774 }
   775 
   776 Uint64
   777 SDL_ReadBE64(SDL_RWops * src)
   778 {
   779     Uint64 value = 0;
   780 
   781     SDL_RWread(src, &value, sizeof (value), 1);
   782     return SDL_SwapBE64(value);
   783 }
   784 
   785 size_t
   786 SDL_WriteU8(SDL_RWops * dst, Uint8 value)
   787 {
   788     return SDL_RWwrite(dst, &value, sizeof (value), 1);
   789 }
   790 
   791 size_t
   792 SDL_WriteLE16(SDL_RWops * dst, Uint16 value)
   793 {
   794     const Uint16 swapped = SDL_SwapLE16(value);
   795     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   796 }
   797 
   798 size_t
   799 SDL_WriteBE16(SDL_RWops * dst, Uint16 value)
   800 {
   801     const Uint16 swapped = SDL_SwapBE16(value);
   802     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   803 }
   804 
   805 size_t
   806 SDL_WriteLE32(SDL_RWops * dst, Uint32 value)
   807 {
   808     const Uint32 swapped = SDL_SwapLE32(value);
   809     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   810 }
   811 
   812 size_t
   813 SDL_WriteBE32(SDL_RWops * dst, Uint32 value)
   814 {
   815     const Uint32 swapped = SDL_SwapBE32(value);
   816     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   817 }
   818 
   819 size_t
   820 SDL_WriteLE64(SDL_RWops * dst, Uint64 value)
   821 {
   822     const Uint64 swapped = SDL_SwapLE64(value);
   823     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   824 }
   825 
   826 size_t
   827 SDL_WriteBE64(SDL_RWops * dst, Uint64 value)
   828 {
   829     const Uint64 swapped = SDL_SwapBE64(value);
   830     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   831 }
   832 
   833 /* vi: set ts=4 sw=4 expandtab: */