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