src/file/SDL_rwops.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 08 Dec 2019 11:36:40 -0800
changeset 13321 37350f1e7902
parent 13200 057a3fe53d5a
permissions -rw-r--r--
Fixed bug 4883 - Add approximation for display DPI on iOS

Aaron Barany

There appears to be no way to directly access the display DPI on iOS, so as an approximation the DPI for the iPhone 1 is used as a base value and is multiplied by the screen's scale. This should at least give a ballpark number for the various screen scales. (based on https://stackoverflow.com/questions/25756087/detecting-iphone-6-6-screen-sizes-in-point-values it appears that both 2x and 3x are used)

I have updated the patch to use a table of current devices and use a computation as a fallback. I have also updated the fallback computation to be more accurate.
     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     int stdiowhence;
   365 
   366     switch (whence) {
   367     case RW_SEEK_SET:
   368         stdiowhence = SEEK_SET;
   369         break;
   370     case RW_SEEK_CUR:
   371         stdiowhence = SEEK_CUR;
   372         break;
   373     case RW_SEEK_END:
   374         stdiowhence = SEEK_END;
   375         break;
   376     default:
   377         return SDL_SetError("Unknown value for 'whence'");
   378     }
   379 
   380 #if defined(FSEEK_OFF_MIN) && defined(FSEEK_OFF_MAX)
   381     if (offset < (Sint64)(FSEEK_OFF_MIN) || offset > (Sint64)(FSEEK_OFF_MAX)) {
   382         return SDL_SetError("Seek offset out of range");
   383     }
   384 #endif
   385 
   386     if (fseek(context->hidden.stdio.fp, (fseek_off_t)offset, stdiowhence) == 0) {
   387         Sint64 pos = ftell(context->hidden.stdio.fp);
   388         if (pos < 0) {
   389             return SDL_SetError("Couldn't get stream offset");
   390         }
   391         return pos;
   392     }
   393     return SDL_Error(SDL_EFSEEK);
   394 }
   395 
   396 static size_t SDLCALL
   397 stdio_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
   398 {
   399     size_t nread;
   400 
   401     nread = fread(ptr, size, maxnum, context->hidden.stdio.fp);
   402     if (nread == 0 && ferror(context->hidden.stdio.fp)) {
   403         SDL_Error(SDL_EFREAD);
   404     }
   405     return nread;
   406 }
   407 
   408 static size_t SDLCALL
   409 stdio_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
   410 {
   411     size_t nwrote;
   412 
   413     nwrote = fwrite(ptr, size, num, context->hidden.stdio.fp);
   414     if (nwrote == 0 && ferror(context->hidden.stdio.fp)) {
   415         SDL_Error(SDL_EFWRITE);
   416     }
   417     return nwrote;
   418 }
   419 
   420 static int SDLCALL
   421 stdio_close(SDL_RWops * context)
   422 {
   423     int status = 0;
   424     if (context) {
   425         if (context->hidden.stdio.autoclose) {
   426             /* WARNING:  Check the return value here! */
   427             if (fclose(context->hidden.stdio.fp) != 0) {
   428                 status = SDL_Error(SDL_EFWRITE);
   429             }
   430         }
   431         SDL_FreeRW(context);
   432     }
   433     return status;
   434 }
   435 #endif /* !HAVE_STDIO_H */
   436 
   437 /* Functions to read/write memory pointers */
   438 
   439 static Sint64 SDLCALL
   440 mem_size(SDL_RWops * context)
   441 {
   442     return (Sint64)(context->hidden.mem.stop - context->hidden.mem.base);
   443 }
   444 
   445 static Sint64 SDLCALL
   446 mem_seek(SDL_RWops * context, Sint64 offset, int whence)
   447 {
   448     Uint8 *newpos;
   449 
   450     switch (whence) {
   451     case RW_SEEK_SET:
   452         newpos = context->hidden.mem.base + offset;
   453         break;
   454     case RW_SEEK_CUR:
   455         newpos = context->hidden.mem.here + offset;
   456         break;
   457     case RW_SEEK_END:
   458         newpos = context->hidden.mem.stop + offset;
   459         break;
   460     default:
   461         return SDL_SetError("Unknown value for 'whence'");
   462     }
   463     if (newpos < context->hidden.mem.base) {
   464         newpos = context->hidden.mem.base;
   465     }
   466     if (newpos > context->hidden.mem.stop) {
   467         newpos = context->hidden.mem.stop;
   468     }
   469     context->hidden.mem.here = newpos;
   470     return (Sint64)(context->hidden.mem.here - context->hidden.mem.base);
   471 }
   472 
   473 static size_t SDLCALL
   474 mem_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
   475 {
   476     size_t total_bytes;
   477     size_t mem_available;
   478 
   479     total_bytes = (maxnum * size);
   480     if ((maxnum <= 0) || (size <= 0)
   481         || ((total_bytes / maxnum) != size)) {
   482         return 0;
   483     }
   484 
   485     mem_available = (context->hidden.mem.stop - context->hidden.mem.here);
   486     if (total_bytes > mem_available) {
   487         total_bytes = mem_available;
   488     }
   489 
   490     SDL_memcpy(ptr, context->hidden.mem.here, total_bytes);
   491     context->hidden.mem.here += total_bytes;
   492 
   493     return (total_bytes / size);
   494 }
   495 
   496 static size_t SDLCALL
   497 mem_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
   498 {
   499     if ((context->hidden.mem.here + (num * size)) > context->hidden.mem.stop) {
   500         num = (context->hidden.mem.stop - context->hidden.mem.here) / size;
   501     }
   502     SDL_memcpy(context->hidden.mem.here, ptr, num * size);
   503     context->hidden.mem.here += num * size;
   504     return num;
   505 }
   506 
   507 static size_t SDLCALL
   508 mem_writeconst(SDL_RWops * context, const void *ptr, size_t size, size_t num)
   509 {
   510     SDL_SetError("Can't write to read-only memory");
   511     return 0;
   512 }
   513 
   514 static int SDLCALL
   515 mem_close(SDL_RWops * context)
   516 {
   517     if (context) {
   518         SDL_FreeRW(context);
   519     }
   520     return 0;
   521 }
   522 
   523 
   524 /* Functions to create SDL_RWops structures from various data sources */
   525 
   526 SDL_RWops *
   527 SDL_RWFromFile(const char *file, const char *mode)
   528 {
   529     SDL_RWops *rwops = NULL;
   530     if (!file || !*file || !mode || !*mode) {
   531         SDL_SetError("SDL_RWFromFile(): No file or no mode specified");
   532         return NULL;
   533     }
   534 #if defined(__ANDROID__)
   535 #ifdef HAVE_STDIO_H
   536     /* Try to open the file on the filesystem first */
   537     if (*file == '/') {
   538         FILE *fp = fopen(file, mode);
   539         if (fp) {
   540             return SDL_RWFromFP(fp, 1);
   541         }
   542     } else {
   543         /* Try opening it from internal storage if it's a relative path */
   544         char *path;
   545         FILE *fp;
   546 
   547         /* !!! FIXME: why not just "char path[PATH_MAX];" ? */
   548         path = SDL_stack_alloc(char, PATH_MAX);
   549         if (path) {
   550             SDL_snprintf(path, PATH_MAX, "%s/%s",
   551                          SDL_AndroidGetInternalStoragePath(), file);
   552             fp = fopen(path, mode);
   553             SDL_stack_free(path);
   554             if (fp) {
   555                 return SDL_RWFromFP(fp, 1);
   556             }
   557         }
   558     }
   559 #endif /* HAVE_STDIO_H */
   560 
   561     /* Try to open the file from the asset system */
   562     rwops = SDL_AllocRW();
   563     if (!rwops)
   564         return NULL;            /* SDL_SetError already setup by SDL_AllocRW() */
   565     if (Android_JNI_FileOpen(rwops, file, mode) < 0) {
   566         SDL_FreeRW(rwops);
   567         return NULL;
   568     }
   569     rwops->size = Android_JNI_FileSize;
   570     rwops->seek = Android_JNI_FileSeek;
   571     rwops->read = Android_JNI_FileRead;
   572     rwops->write = Android_JNI_FileWrite;
   573     rwops->close = Android_JNI_FileClose;
   574     rwops->type = SDL_RWOPS_JNIFILE;
   575 
   576 #elif defined(__WIN32__)
   577     rwops = SDL_AllocRW();
   578     if (!rwops)
   579         return NULL;            /* SDL_SetError already setup by SDL_AllocRW() */
   580     if (windows_file_open(rwops, file, mode) < 0) {
   581         SDL_FreeRW(rwops);
   582         return NULL;
   583     }
   584     rwops->size = windows_file_size;
   585     rwops->seek = windows_file_seek;
   586     rwops->read = windows_file_read;
   587     rwops->write = windows_file_write;
   588     rwops->close = windows_file_close;
   589     rwops->type = SDL_RWOPS_WINFILE;
   590 
   591 #elif HAVE_STDIO_H
   592     {
   593         #ifdef __APPLE__
   594         FILE *fp = SDL_OpenFPFromBundleOrFallback(file, mode);
   595         #elif __WINRT__
   596         FILE *fp = NULL;
   597         fopen_s(&fp, file, mode);
   598         #else
   599         FILE *fp = fopen(file, mode);
   600         #endif
   601         if (fp == NULL) {
   602             SDL_SetError("Couldn't open %s", file);
   603         } else {
   604             rwops = SDL_RWFromFP(fp, SDL_TRUE);
   605         }
   606     }
   607 #else
   608     SDL_SetError("SDL not compiled with stdio support");
   609 #endif /* !HAVE_STDIO_H */
   610 
   611     return rwops;
   612 }
   613 
   614 #ifdef HAVE_STDIO_H
   615 SDL_RWops *
   616 SDL_RWFromFP(FILE * fp, SDL_bool autoclose)
   617 {
   618     SDL_RWops *rwops = NULL;
   619 
   620     rwops = SDL_AllocRW();
   621     if (rwops != NULL) {
   622         rwops->size = stdio_size;
   623         rwops->seek = stdio_seek;
   624         rwops->read = stdio_read;
   625         rwops->write = stdio_write;
   626         rwops->close = stdio_close;
   627         rwops->hidden.stdio.fp = fp;
   628         rwops->hidden.stdio.autoclose = autoclose;
   629         rwops->type = SDL_RWOPS_STDFILE;
   630     }
   631     return rwops;
   632 }
   633 #else
   634 SDL_RWops *
   635 SDL_RWFromFP(void * fp, SDL_bool autoclose)
   636 {
   637     SDL_SetError("SDL not compiled with stdio support");
   638     return NULL;
   639 }
   640 #endif /* HAVE_STDIO_H */
   641 
   642 SDL_RWops *
   643 SDL_RWFromMem(void *mem, int size)
   644 {
   645     SDL_RWops *rwops = NULL;
   646     if (!mem) {
   647       SDL_InvalidParamError("mem");
   648       return rwops;
   649     }
   650     if (!size) {
   651       SDL_InvalidParamError("size");
   652       return rwops;
   653     }
   654 
   655     rwops = SDL_AllocRW();
   656     if (rwops != NULL) {
   657         rwops->size = mem_size;
   658         rwops->seek = mem_seek;
   659         rwops->read = mem_read;
   660         rwops->write = mem_write;
   661         rwops->close = mem_close;
   662         rwops->hidden.mem.base = (Uint8 *) mem;
   663         rwops->hidden.mem.here = rwops->hidden.mem.base;
   664         rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
   665         rwops->type = SDL_RWOPS_MEMORY;
   666     }
   667     return rwops;
   668 }
   669 
   670 SDL_RWops *
   671 SDL_RWFromConstMem(const void *mem, int size)
   672 {
   673     SDL_RWops *rwops = NULL;
   674     if (!mem) {
   675       SDL_InvalidParamError("mem");
   676       return rwops;
   677     }
   678     if (!size) {
   679       SDL_InvalidParamError("size");
   680       return rwops;
   681     }
   682 
   683     rwops = SDL_AllocRW();
   684     if (rwops != NULL) {
   685         rwops->size = mem_size;
   686         rwops->seek = mem_seek;
   687         rwops->read = mem_read;
   688         rwops->write = mem_writeconst;
   689         rwops->close = mem_close;
   690         rwops->hidden.mem.base = (Uint8 *) mem;
   691         rwops->hidden.mem.here = rwops->hidden.mem.base;
   692         rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
   693         rwops->type = SDL_RWOPS_MEMORY_RO;
   694     }
   695     return rwops;
   696 }
   697 
   698 SDL_RWops *
   699 SDL_AllocRW(void)
   700 {
   701     SDL_RWops *area;
   702 
   703     area = (SDL_RWops *) SDL_malloc(sizeof *area);
   704     if (area == NULL) {
   705         SDL_OutOfMemory();
   706     } else {
   707         area->type = SDL_RWOPS_UNKNOWN;
   708     }
   709     return area;
   710 }
   711 
   712 void
   713 SDL_FreeRW(SDL_RWops * area)
   714 {
   715     SDL_free(area);
   716 }
   717 
   718 /* Load all the data from an SDL data stream */
   719 void *
   720 SDL_LoadFile_RW(SDL_RWops * src, size_t *datasize, int freesrc)
   721 {
   722     const int FILE_CHUNK_SIZE = 1024;
   723     Sint64 size;
   724     size_t size_read, size_total;
   725     void *data = NULL, *newdata;
   726 
   727     if (!src) {
   728         SDL_InvalidParamError("src");
   729         return NULL;
   730     }
   731 
   732     size = SDL_RWsize(src);
   733     if (size < 0) {
   734         size = FILE_CHUNK_SIZE;
   735     }
   736     data = SDL_malloc((size_t)(size + 1));
   737 
   738     size_total = 0;
   739     for (;;) {
   740         if ((((Sint64)size_total) + FILE_CHUNK_SIZE) > size) {
   741             size = (size_total + FILE_CHUNK_SIZE);
   742             newdata = SDL_realloc(data, (size_t)(size + 1));
   743             if (!newdata) {
   744                 SDL_free(data);
   745                 data = NULL;
   746                 SDL_OutOfMemory();
   747                 goto done;
   748             }
   749             data = newdata;
   750         }
   751 
   752         size_read = SDL_RWread(src, (char *)data+size_total, 1, (size_t)(size-size_total));
   753         if (size_read == 0) {
   754             break;
   755         }
   756         size_total += size_read;
   757     }
   758 
   759     if (datasize) {
   760         *datasize = size_total;
   761     }
   762     ((char *)data)[size_total] = '\0';
   763 
   764 done:
   765     if (freesrc && src) {
   766         SDL_RWclose(src);
   767     }
   768     return data;
   769 }
   770 
   771 void *
   772 SDL_LoadFile(const char *file, size_t *datasize)
   773 {
   774    return SDL_LoadFile_RW(SDL_RWFromFile(file, "rb"), datasize, 1);
   775 }
   776 
   777 Sint64
   778 SDL_RWsize(SDL_RWops *context)
   779 {
   780     return context->size(context);
   781 }
   782 
   783 Sint64
   784 SDL_RWseek(SDL_RWops *context, Sint64 offset, int whence)
   785 {
   786     return context->seek(context, offset, whence);
   787 }
   788 
   789 Sint64
   790 SDL_RWtell(SDL_RWops *context)
   791 {
   792     return context->seek(context, 0, RW_SEEK_CUR);
   793 }
   794 
   795 size_t
   796 SDL_RWread(SDL_RWops *context, void *ptr, size_t size, size_t maxnum)
   797 {
   798     return context->read(context, ptr, size, maxnum);
   799 }
   800 
   801 size_t
   802 SDL_RWwrite(SDL_RWops *context, const void *ptr, size_t size, size_t num)
   803 {
   804     return context->write(context, ptr, size, num);
   805 }
   806 
   807 int
   808 SDL_RWclose(SDL_RWops *context)
   809 {
   810     return context->close(context);
   811 }
   812 
   813 /* Functions for dynamically reading and writing endian-specific values */
   814 
   815 Uint8
   816 SDL_ReadU8(SDL_RWops * src)
   817 {
   818     Uint8 value = 0;
   819 
   820     SDL_RWread(src, &value, sizeof (value), 1);
   821     return value;
   822 }
   823 
   824 Uint16
   825 SDL_ReadLE16(SDL_RWops * src)
   826 {
   827     Uint16 value = 0;
   828 
   829     SDL_RWread(src, &value, sizeof (value), 1);
   830     return SDL_SwapLE16(value);
   831 }
   832 
   833 Uint16
   834 SDL_ReadBE16(SDL_RWops * src)
   835 {
   836     Uint16 value = 0;
   837 
   838     SDL_RWread(src, &value, sizeof (value), 1);
   839     return SDL_SwapBE16(value);
   840 }
   841 
   842 Uint32
   843 SDL_ReadLE32(SDL_RWops * src)
   844 {
   845     Uint32 value = 0;
   846 
   847     SDL_RWread(src, &value, sizeof (value), 1);
   848     return SDL_SwapLE32(value);
   849 }
   850 
   851 Uint32
   852 SDL_ReadBE32(SDL_RWops * src)
   853 {
   854     Uint32 value = 0;
   855 
   856     SDL_RWread(src, &value, sizeof (value), 1);
   857     return SDL_SwapBE32(value);
   858 }
   859 
   860 Uint64
   861 SDL_ReadLE64(SDL_RWops * src)
   862 {
   863     Uint64 value = 0;
   864 
   865     SDL_RWread(src, &value, sizeof (value), 1);
   866     return SDL_SwapLE64(value);
   867 }
   868 
   869 Uint64
   870 SDL_ReadBE64(SDL_RWops * src)
   871 {
   872     Uint64 value = 0;
   873 
   874     SDL_RWread(src, &value, sizeof (value), 1);
   875     return SDL_SwapBE64(value);
   876 }
   877 
   878 size_t
   879 SDL_WriteU8(SDL_RWops * dst, Uint8 value)
   880 {
   881     return SDL_RWwrite(dst, &value, sizeof (value), 1);
   882 }
   883 
   884 size_t
   885 SDL_WriteLE16(SDL_RWops * dst, Uint16 value)
   886 {
   887     const Uint16 swapped = SDL_SwapLE16(value);
   888     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   889 }
   890 
   891 size_t
   892 SDL_WriteBE16(SDL_RWops * dst, Uint16 value)
   893 {
   894     const Uint16 swapped = SDL_SwapBE16(value);
   895     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   896 }
   897 
   898 size_t
   899 SDL_WriteLE32(SDL_RWops * dst, Uint32 value)
   900 {
   901     const Uint32 swapped = SDL_SwapLE32(value);
   902     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   903 }
   904 
   905 size_t
   906 SDL_WriteBE32(SDL_RWops * dst, Uint32 value)
   907 {
   908     const Uint32 swapped = SDL_SwapBE32(value);
   909     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   910 }
   911 
   912 size_t
   913 SDL_WriteLE64(SDL_RWops * dst, Uint64 value)
   914 {
   915     const Uint64 swapped = SDL_SwapLE64(value);
   916     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   917 }
   918 
   919 size_t
   920 SDL_WriteBE64(SDL_RWops * dst, Uint64 value)
   921 {
   922     const Uint64 swapped = SDL_SwapBE64(value);
   923     return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
   924 }
   925 
   926 /* vi: set ts=4 sw=4 expandtab: */