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