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