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