src/file/SDL_rwops.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 03 Jan 2018 10:03:25 -0800
changeset 11811 5d94cb6b24d3
parent 11480 e7a79b236dc0
child 12349 a67dedb293c8
permissions -rw-r--r--
Updated copyright for 2018
     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         path = SDL_stack_alloc(char, PATH_MAX);
   532         if (path) {
   533             SDL_snprintf(path, PATH_MAX, "%s/%s",
   534                          SDL_AndroidGetInternalStoragePath(), file);
   535             fp = fopen(path, mode);
   536             SDL_stack_free(path);
   537             if (fp) {
   538                 return SDL_RWFromFP(fp, 1);
   539             }
   540         }
   541     }
   542 #endif /* HAVE_STDIO_H */
   543 
   544     /* Try to open the file from the asset system */
   545     rwops = SDL_AllocRW();
   546     if (!rwops)
   547         return NULL;            /* SDL_SetError already setup by SDL_AllocRW() */
   548     if (Android_JNI_FileOpen(rwops, file, mode) < 0) {
   549         SDL_FreeRW(rwops);
   550         return NULL;
   551     }
   552     rwops->size = Android_JNI_FileSize;
   553     rwops->seek = Android_JNI_FileSeek;
   554     rwops->read = Android_JNI_FileRead;
   555     rwops->write = Android_JNI_FileWrite;
   556     rwops->close = Android_JNI_FileClose;
   557     rwops->type = SDL_RWOPS_JNIFILE;
   558 
   559 #elif defined(__WIN32__)
   560     rwops = SDL_AllocRW();
   561     if (!rwops)
   562         return NULL;            /* SDL_SetError already setup by SDL_AllocRW() */
   563     if (windows_file_open(rwops, file, mode) < 0) {
   564         SDL_FreeRW(rwops);
   565         return NULL;
   566     }
   567     rwops->size = windows_file_size;
   568     rwops->seek = windows_file_seek;
   569     rwops->read = windows_file_read;
   570     rwops->write = windows_file_write;
   571     rwops->close = windows_file_close;
   572     rwops->type = SDL_RWOPS_WINFILE;
   573 
   574 #elif HAVE_STDIO_H
   575     {
   576         #ifdef __APPLE__
   577         FILE *fp = SDL_OpenFPFromBundleOrFallback(file, mode);
   578         #elif __WINRT__
   579         FILE *fp = NULL;
   580         fopen_s(&fp, file, mode);
   581         #else
   582         FILE *fp = fopen(file, mode);
   583         #endif
   584         if (fp == NULL) {
   585             SDL_SetError("Couldn't open %s", file);
   586         } else {
   587             rwops = SDL_RWFromFP(fp, 1);
   588         }
   589     }
   590 #else
   591     SDL_SetError("SDL not compiled with stdio support");
   592 #endif /* !HAVE_STDIO_H */
   593 
   594     return rwops;
   595 }
   596 
   597 #ifdef HAVE_STDIO_H
   598 SDL_RWops *
   599 SDL_RWFromFP(FILE * fp, SDL_bool autoclose)
   600 {
   601     SDL_RWops *rwops = NULL;
   602 
   603     rwops = SDL_AllocRW();
   604     if (rwops != NULL) {
   605         rwops->size = stdio_size;
   606         rwops->seek = stdio_seek;
   607         rwops->read = stdio_read;
   608         rwops->write = stdio_write;
   609         rwops->close = stdio_close;
   610         rwops->hidden.stdio.fp = fp;
   611         rwops->hidden.stdio.autoclose = autoclose;
   612         rwops->type = SDL_RWOPS_STDFILE;
   613     }
   614     return rwops;
   615 }
   616 #else
   617 SDL_RWops *
   618 SDL_RWFromFP(void * fp, SDL_bool autoclose)
   619 {
   620     SDL_SetError("SDL not compiled with stdio support");
   621     return NULL;
   622 }
   623 #endif /* HAVE_STDIO_H */
   624 
   625 SDL_RWops *
   626 SDL_RWFromMem(void *mem, int size)
   627 {
   628     SDL_RWops *rwops = NULL;
   629     if (!mem) {
   630       SDL_InvalidParamError("mem");
   631       return rwops;
   632     }
   633     if (!size) {
   634       SDL_InvalidParamError("size");
   635       return rwops;
   636     }
   637 
   638     rwops = SDL_AllocRW();
   639     if (rwops != NULL) {
   640         rwops->size = mem_size;
   641         rwops->seek = mem_seek;
   642         rwops->read = mem_read;
   643         rwops->write = mem_write;
   644         rwops->close = mem_close;
   645         rwops->hidden.mem.base = (Uint8 *) mem;
   646         rwops->hidden.mem.here = rwops->hidden.mem.base;
   647         rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
   648         rwops->type = SDL_RWOPS_MEMORY;
   649     }
   650     return rwops;
   651 }
   652 
   653 SDL_RWops *
   654 SDL_RWFromConstMem(const void *mem, int size)
   655 {
   656     SDL_RWops *rwops = NULL;
   657     if (!mem) {
   658       SDL_InvalidParamError("mem");
   659       return rwops;
   660     }
   661     if (!size) {
   662       SDL_InvalidParamError("size");
   663       return rwops;
   664     }
   665 
   666     rwops = SDL_AllocRW();
   667     if (rwops != NULL) {
   668         rwops->size = mem_size;
   669         rwops->seek = mem_seek;
   670         rwops->read = mem_read;
   671         rwops->write = mem_writeconst;
   672         rwops->close = mem_close;
   673         rwops->hidden.mem.base = (Uint8 *) mem;
   674         rwops->hidden.mem.here = rwops->hidden.mem.base;
   675         rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
   676         rwops->type = SDL_RWOPS_MEMORY_RO;
   677     }
   678     return rwops;
   679 }
   680 
   681 SDL_RWops *
   682 SDL_AllocRW(void)
   683 {
   684     SDL_RWops *area;
   685 
   686     area = (SDL_RWops *) SDL_malloc(sizeof *area);
   687     if (area == NULL) {
   688         SDL_OutOfMemory();
   689     } else {
   690         area->type = SDL_RWOPS_UNKNOWN;
   691     }
   692     return area;
   693 }
   694 
   695 void
   696 SDL_FreeRW(SDL_RWops * area)
   697 {
   698     SDL_free(area);
   699 }
   700 
   701 /* Load all the data from an SDL data stream */
   702 void *
   703 SDL_LoadFile_RW(SDL_RWops * src, size_t *datasize, int freesrc)
   704 {
   705     const int FILE_CHUNK_SIZE = 1024;
   706     Sint64 size;
   707     size_t size_read, size_total;
   708     void *data = NULL, *newdata;
   709 
   710     if (!src) {
   711         SDL_InvalidParamError("src");
   712         return NULL;
   713     }
   714 
   715     size = SDL_RWsize(src);
   716     if (size < 0) {
   717         size = FILE_CHUNK_SIZE;
   718     }
   719     data = SDL_malloc((size_t)(size + 1));
   720 
   721     size_total = 0;
   722     for (;;) {
   723         if ((((Sint64)size_total) + FILE_CHUNK_SIZE) > size) {
   724             size = (size_total + FILE_CHUNK_SIZE);
   725             newdata = SDL_realloc(data, (size_t)(size + 1));
   726             if (!newdata) {
   727                 SDL_free(data);
   728                 data = NULL;
   729                 SDL_OutOfMemory();
   730                 goto done;
   731             }
   732             data = newdata;
   733         }
   734 
   735         size_read = SDL_RWread(src, (char *)data+size_total, 1, (size_t)(size-size_total));
   736         if (size_read == 0) {
   737             break;
   738         }
   739         size_total += size_read;
   740     }
   741 
   742     if (datasize) {
   743         *datasize = size_total;
   744     }
   745     ((char *)data)[size_total] = '\0';
   746 
   747 done:
   748     if (freesrc && src) {
   749         SDL_RWclose(src);
   750     }
   751     return data;
   752 }
   753 
   754 /* Functions for dynamically reading and writing endian-specific values */
   755 
   756 Uint8
   757 SDL_ReadU8(SDL_RWops * src)
   758 {
   759     Uint8 value = 0;
   760 
   761     SDL_RWread(src, &value, sizeof (value), 1);
   762     return value;
   763 }
   764 
   765 Uint16
   766 SDL_ReadLE16(SDL_RWops * src)
   767 {
   768     Uint16 value = 0;
   769 
   770     SDL_RWread(src, &value, sizeof (value), 1);
   771     return SDL_SwapLE16(value);
   772 }
   773 
   774 Uint16
   775 SDL_ReadBE16(SDL_RWops * src)
   776 {
   777     Uint16 value = 0;
   778 
   779     SDL_RWread(src, &value, sizeof (value), 1);
   780     return SDL_SwapBE16(value);
   781 }
   782 
   783 Uint32
   784 SDL_ReadLE32(SDL_RWops * src)
   785 {
   786     Uint32 value = 0;
   787 
   788     SDL_RWread(src, &value, sizeof (value), 1);
   789     return SDL_SwapLE32(value);
   790 }
   791 
   792 Uint32
   793 SDL_ReadBE32(SDL_RWops * src)
   794 {
   795     Uint32 value = 0;
   796 
   797     SDL_RWread(src, &value, sizeof (value), 1);
   798     return SDL_SwapBE32(value);
   799 }
   800 
   801 Uint64
   802 SDL_ReadLE64(SDL_RWops * src)
   803 {
   804     Uint64 value = 0;
   805 
   806     SDL_RWread(src, &value, sizeof (value), 1);
   807     return SDL_SwapLE64(value);
   808 }
   809 
   810 Uint64
   811 SDL_ReadBE64(SDL_RWops * src)
   812 {
   813     Uint64 value = 0;
   814 
   815     SDL_RWread(src, &value, sizeof (value), 1);
   816     return SDL_SwapBE64(value);
   817 }
   818 
   819 size_t
   820 SDL_WriteU8(SDL_RWops * dst, Uint8 value)
   821 {
   822     return SDL_RWwrite(dst, &value, sizeof (value), 1);
   823 }
   824 
   825 size_t
   826 SDL_WriteLE16(SDL_RWops * dst, Uint16 value)
   827 {
   828     const Uint16 swapped = SDL_SwapLE16(value);
   829     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   830 }
   831 
   832 size_t
   833 SDL_WriteBE16(SDL_RWops * dst, Uint16 value)
   834 {
   835     const Uint16 swapped = SDL_SwapBE16(value);
   836     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   837 }
   838 
   839 size_t
   840 SDL_WriteLE32(SDL_RWops * dst, Uint32 value)
   841 {
   842     const Uint32 swapped = SDL_SwapLE32(value);
   843     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   844 }
   845 
   846 size_t
   847 SDL_WriteBE32(SDL_RWops * dst, Uint32 value)
   848 {
   849     const Uint32 swapped = SDL_SwapBE32(value);
   850     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   851 }
   852 
   853 size_t
   854 SDL_WriteLE64(SDL_RWops * dst, Uint64 value)
   855 {
   856     const Uint64 swapped = SDL_SwapLE64(value);
   857     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   858 }
   859 
   860 size_t
   861 SDL_WriteBE64(SDL_RWops * dst, Uint64 value)
   862 {
   863     const Uint64 swapped = SDL_SwapBE64(value);
   864     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   865 }
   866 
   867 /* vi: set ts=4 sw=4 expandtab: */