src/file/SDL_rwops.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 08 Jun 2019 17:43:23 -0700
changeset 12799 302904fa669a
parent 12503 806492103856
child 12965 cac903c755a1
permissions -rw-r--r--
Fixed bug 4526 - replace SDL_RW* macros with functions for using in bindings

ace

I got this bug in SDL_ttf:
https://bugzilla.libsdl.org/show_bug.cgi?id=4524
Sylvain proposed solution:
SDL_RWseek(RWops, 0, RW_SEEK_SET);

And it works, but i can use it my project, because it written in C# with SDL2-CS wrapper and there not export for macroses:
#define SDL_RWsize(ctx) (ctx)->size(ctx)
#define SDL_RWseek(ctx, offset, whence) (ctx)->seek(ctx, offset, whence)
#define SDL_RWtell(ctx) (ctx)->seek(ctx, 0, RW_SEEK_CUR)
#define SDL_RWread(ctx, ptr, size, n) (ctx)->read(ctx, ptr, size, n)
#define SDL_RWwrite(ctx, ptr, size, n) (ctx)->write(ctx, ptr, size, n)
#define SDL_RWclose(ctx) (ctx)->close(ctx)

Therefore, I suggest replacing this macros with functions so that they can be exported and used in bindings
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 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 void *
   756 SDL_LoadFile(const char *file, size_t *datasize)
   757 {
   758    return SDL_LoadFile_RW(SDL_RWFromFile(file, "rb"), datasize, 1);
   759 }
   760 
   761 Sint64
   762 SDL_RWsize(SDL_RWops *context)
   763 {
   764     return context->size(context);
   765 }
   766 
   767 Sint64
   768 SDL_RWseek(SDL_RWops *context, Sint64 offset, int whence)
   769 {
   770     return context->seek(context, offset, whence);
   771 }
   772 
   773 Sint64
   774 SDL_RWtell(SDL_RWops *context)
   775 {
   776     return context->seek(context, 0, RW_SEEK_CUR);
   777 }
   778 
   779 size_t
   780 SDL_RWread(SDL_RWops *context, void *ptr, size_t size, size_t maxnum)
   781 {
   782     return context->read(context, ptr, size, maxnum);
   783 }
   784 
   785 size_t
   786 SDL_RWwrite(SDL_RWops *context, const void *ptr, size_t size, size_t num)
   787 {
   788     return context->write(context, ptr, size, num);
   789 }
   790 
   791 int
   792 SDL_RWclose(SDL_RWops *context)
   793 {
   794     return context->close(context);
   795 }
   796 
   797 /* Functions for dynamically reading and writing endian-specific values */
   798 
   799 Uint8
   800 SDL_ReadU8(SDL_RWops * src)
   801 {
   802     Uint8 value = 0;
   803 
   804     SDL_RWread(src, &value, sizeof (value), 1);
   805     return value;
   806 }
   807 
   808 Uint16
   809 SDL_ReadLE16(SDL_RWops * src)
   810 {
   811     Uint16 value = 0;
   812 
   813     SDL_RWread(src, &value, sizeof (value), 1);
   814     return SDL_SwapLE16(value);
   815 }
   816 
   817 Uint16
   818 SDL_ReadBE16(SDL_RWops * src)
   819 {
   820     Uint16 value = 0;
   821 
   822     SDL_RWread(src, &value, sizeof (value), 1);
   823     return SDL_SwapBE16(value);
   824 }
   825 
   826 Uint32
   827 SDL_ReadLE32(SDL_RWops * src)
   828 {
   829     Uint32 value = 0;
   830 
   831     SDL_RWread(src, &value, sizeof (value), 1);
   832     return SDL_SwapLE32(value);
   833 }
   834 
   835 Uint32
   836 SDL_ReadBE32(SDL_RWops * src)
   837 {
   838     Uint32 value = 0;
   839 
   840     SDL_RWread(src, &value, sizeof (value), 1);
   841     return SDL_SwapBE32(value);
   842 }
   843 
   844 Uint64
   845 SDL_ReadLE64(SDL_RWops * src)
   846 {
   847     Uint64 value = 0;
   848 
   849     SDL_RWread(src, &value, sizeof (value), 1);
   850     return SDL_SwapLE64(value);
   851 }
   852 
   853 Uint64
   854 SDL_ReadBE64(SDL_RWops * src)
   855 {
   856     Uint64 value = 0;
   857 
   858     SDL_RWread(src, &value, sizeof (value), 1);
   859     return SDL_SwapBE64(value);
   860 }
   861 
   862 size_t
   863 SDL_WriteU8(SDL_RWops * dst, Uint8 value)
   864 {
   865     return SDL_RWwrite(dst, &value, sizeof (value), 1);
   866 }
   867 
   868 size_t
   869 SDL_WriteLE16(SDL_RWops * dst, Uint16 value)
   870 {
   871     const Uint16 swapped = SDL_SwapLE16(value);
   872     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   873 }
   874 
   875 size_t
   876 SDL_WriteBE16(SDL_RWops * dst, Uint16 value)
   877 {
   878     const Uint16 swapped = SDL_SwapBE16(value);
   879     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   880 }
   881 
   882 size_t
   883 SDL_WriteLE32(SDL_RWops * dst, Uint32 value)
   884 {
   885     const Uint32 swapped = SDL_SwapLE32(value);
   886     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   887 }
   888 
   889 size_t
   890 SDL_WriteBE32(SDL_RWops * dst, Uint32 value)
   891 {
   892     const Uint32 swapped = SDL_SwapBE32(value);
   893     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   894 }
   895 
   896 size_t
   897 SDL_WriteLE64(SDL_RWops * dst, Uint64 value)
   898 {
   899     const Uint64 swapped = SDL_SwapLE64(value);
   900     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   901 }
   902 
   903 size_t
   904 SDL_WriteBE64(SDL_RWops * dst, Uint64 value)
   905 {
   906     const Uint64 swapped = SDL_SwapBE64(value);
   907     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   908 }
   909 
   910 /* vi: set ts=4 sw=4 expandtab: */