src/file/SDL_rwops.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 29 Jul 2011 16:51:25 -0400
changeset 5582 1281a3f1f0a6
parent 5535 96594ac5fd1a
child 6138 4c64952a58fb
permissions -rw-r--r--
Allow Android platforms to read from .apk files via the RWOPS interface.

Fixes Bugzilla #1261.

Thanks to Tim Angus for the patch!
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2011 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 #include "SDL_config.h"
    22 
    23 /* This file provides a general interface for SDL to read and write
    24    data sources.  It can easily be extended to files, memory, etc.
    25 */
    26 
    27 #include "SDL_endian.h"
    28 #include "SDL_rwops.h"
    29 
    30 #ifdef __APPLE__
    31 #include "cocoa/SDL_rwopsbundlesupport.h"
    32 #endif /* __APPLE__ */
    33 
    34 #ifdef ANDROID
    35 #include "../core/android/SDL_android.h"
    36 #endif
    37 
    38 #ifdef __NDS__
    39 /* include libfat headers for fatInitDefault(). */
    40 #include <fat.h>
    41 #endif /* __NDS__ */
    42 
    43 #ifdef __WIN32__
    44 
    45 /* Functions to read/write Win32 API file pointers */
    46 /* Will not use it on WinCE because stdio is buffered, it means
    47    faster, and all stdio functions anyway are embedded in coredll.dll - 
    48    the main wince dll*/
    49 
    50 #include "../core/windows/SDL_windows.h"
    51 
    52 #ifndef INVALID_SET_FILE_POINTER
    53 #define INVALID_SET_FILE_POINTER 0xFFFFFFFF
    54 #endif
    55 
    56 #define READAHEAD_BUFFER_SIZE	1024
    57 
    58 static int SDLCALL
    59 windows_file_open(SDL_RWops * context, const char *filename, const char *mode)
    60 {
    61 #ifndef _WIN32_WCE
    62     UINT old_error_mode;
    63 #endif
    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         SDL_OutOfMemory();
    99         return -1;
   100     }
   101 #ifdef _WIN32_WCE
   102     {
   103         LPTSTR tstr = WIN_UTF8ToString(filename);
   104         h = CreateFile(tstr, (w_right | r_right),
   105                        (w_right) ? 0 : FILE_SHARE_READ, NULL,
   106                        (must_exist | truncate | a_mode),
   107                        FILE_ATTRIBUTE_NORMAL, NULL);
   108         SDL_free(tstr);
   109     }
   110 #else
   111     /* Do not open a dialog box if failure */
   112     old_error_mode =
   113         SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
   114 
   115     {
   116         LPTSTR tstr = WIN_UTF8ToString(filename);
   117         h = CreateFile(tstr, (w_right | r_right),
   118                        (w_right) ? 0 : FILE_SHARE_READ, NULL,
   119                        (must_exist | truncate | a_mode),
   120                        FILE_ATTRIBUTE_NORMAL, NULL);
   121         SDL_free(tstr);
   122     }
   123 
   124     /* restore old behavior */
   125     SetErrorMode(old_error_mode);
   126 #endif /* _WIN32_WCE */
   127 
   128     if (h == INVALID_HANDLE_VALUE) {
   129         SDL_free(context->hidden.windowsio.buffer.data);
   130         context->hidden.windowsio.buffer.data = NULL;
   131         SDL_SetError("Couldn't open %s", filename);
   132         return -2;              /* failed (CreateFile) */
   133     }
   134     context->hidden.windowsio.h = h;
   135     context->hidden.windowsio.append = a_mode ? SDL_TRUE : SDL_FALSE;
   136 
   137     return 0;                   /* ok */
   138 }
   139 
   140 static long SDLCALL
   141 windows_file_seek(SDL_RWops * context, long offset, int whence)
   142 {
   143     DWORD windowswhence;
   144     long file_pos;
   145 
   146     if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) {
   147         SDL_SetError("windows_file_seek: invalid context/file not opened");
   148         return -1;
   149     }
   150 
   151     /* FIXME: We may be able to satisfy the seek within buffered data */
   152     if (whence == RW_SEEK_CUR && context->hidden.windowsio.buffer.left) {
   153         offset -= (long)context->hidden.windowsio.buffer.left;
   154     }
   155     context->hidden.windowsio.buffer.left = 0;
   156 
   157     switch (whence) {
   158     case RW_SEEK_SET:
   159         windowswhence = FILE_BEGIN;
   160         break;
   161     case RW_SEEK_CUR:
   162         windowswhence = FILE_CURRENT;
   163         break;
   164     case RW_SEEK_END:
   165         windowswhence = FILE_END;
   166         break;
   167     default:
   168         SDL_SetError("windows_file_seek: Unknown value for 'whence'");
   169         return -1;
   170     }
   171 
   172     file_pos =
   173         SetFilePointer(context->hidden.windowsio.h, offset, NULL, windowswhence);
   174 
   175     if (file_pos != INVALID_SET_FILE_POINTER)
   176         return file_pos;        /* success */
   177 
   178     SDL_Error(SDL_EFSEEK);
   179     return -1;                  /* error */
   180 }
   181 
   182 static size_t SDLCALL
   183 windows_file_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
   184 {
   185     size_t total_need;
   186     size_t total_read = 0;
   187     size_t read_ahead;
   188     DWORD byte_read;
   189 
   190     total_need = size * maxnum;
   191 
   192     if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE
   193         || !total_need)
   194         return 0;
   195 
   196     if (context->hidden.windowsio.buffer.left > 0) {
   197         void *data = (char *) context->hidden.windowsio.buffer.data +
   198             context->hidden.windowsio.buffer.size -
   199             context->hidden.windowsio.buffer.left;
   200         read_ahead =
   201             SDL_min(total_need, context->hidden.windowsio.buffer.left);
   202         SDL_memcpy(ptr, data, read_ahead);
   203         context->hidden.windowsio.buffer.left -= read_ahead;
   204 
   205         if (read_ahead == total_need) {
   206             return maxnum;
   207         }
   208         ptr = (char *) ptr + read_ahead;
   209         total_need -= read_ahead;
   210         total_read += read_ahead;
   211     }
   212 
   213     if (total_need < READAHEAD_BUFFER_SIZE) {
   214         if (!ReadFile
   215             (context->hidden.windowsio.h, context->hidden.windowsio.buffer.data,
   216              READAHEAD_BUFFER_SIZE, &byte_read, NULL)) {
   217             SDL_Error(SDL_EFREAD);
   218             return 0;
   219         }
   220         read_ahead = SDL_min(total_need, (int) byte_read);
   221         SDL_memcpy(ptr, context->hidden.windowsio.buffer.data, read_ahead);
   222         context->hidden.windowsio.buffer.size = byte_read;
   223         context->hidden.windowsio.buffer.left = byte_read - read_ahead;
   224         total_read += read_ahead;
   225     } else {
   226         if (!ReadFile
   227             (context->hidden.windowsio.h, ptr, (DWORD)total_need, &byte_read, NULL)) {
   228             SDL_Error(SDL_EFREAD);
   229             return 0;
   230         }
   231         total_read += byte_read;
   232     }
   233     return (total_read / size);
   234 }
   235 
   236 static size_t SDLCALL
   237 windows_file_write(SDL_RWops * context, const void *ptr, size_t size,
   238                  size_t num)
   239 {
   240 
   241     size_t total_bytes;
   242     DWORD byte_written;
   243     size_t nwritten;
   244 
   245     total_bytes = size * num;
   246 
   247     if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE
   248         || total_bytes <= 0 || !size)
   249         return 0;
   250 
   251     if (context->hidden.windowsio.buffer.left) {
   252         SetFilePointer(context->hidden.windowsio.h,
   253                        -(LONG)context->hidden.windowsio.buffer.left, NULL,
   254                        FILE_CURRENT);
   255         context->hidden.windowsio.buffer.left = 0;
   256     }
   257 
   258     /* if in append mode, we must go to the EOF before write */
   259     if (context->hidden.windowsio.append) {
   260         if (SetFilePointer(context->hidden.windowsio.h, 0L, NULL, FILE_END) ==
   261             INVALID_SET_FILE_POINTER) {
   262             SDL_Error(SDL_EFWRITE);
   263             return 0;
   264         }
   265     }
   266 
   267     if (!WriteFile
   268         (context->hidden.windowsio.h, ptr, (DWORD)total_bytes, &byte_written, NULL)) {
   269         SDL_Error(SDL_EFWRITE);
   270         return 0;
   271     }
   272 
   273     nwritten = byte_written / size;
   274     return nwritten;
   275 }
   276 
   277 static int SDLCALL
   278 windows_file_close(SDL_RWops * context)
   279 {
   280 
   281     if (context) {
   282         if (context->hidden.windowsio.h != INVALID_HANDLE_VALUE) {
   283             CloseHandle(context->hidden.windowsio.h);
   284             context->hidden.windowsio.h = INVALID_HANDLE_VALUE;   /* to be sure */
   285         }
   286         if (context->hidden.windowsio.buffer.data) {
   287             SDL_free(context->hidden.windowsio.buffer.data);
   288             context->hidden.windowsio.buffer.data = NULL;
   289         }
   290         SDL_FreeRW(context);
   291     }
   292     return (0);
   293 }
   294 #endif /* __WIN32__ */
   295 
   296 #ifdef HAVE_STDIO_H
   297 
   298 /* Functions to read/write stdio file pointers */
   299 
   300 static long SDLCALL
   301 stdio_seek(SDL_RWops * context, long offset, int whence)
   302 {
   303     if (fseek(context->hidden.stdio.fp, offset, whence) == 0) {
   304         return (ftell(context->hidden.stdio.fp));
   305     } else {
   306         SDL_Error(SDL_EFSEEK);
   307         return (-1);
   308     }
   309 }
   310 
   311 static size_t SDLCALL
   312 stdio_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
   313 {
   314     size_t nread;
   315 
   316     nread = fread(ptr, size, maxnum, context->hidden.stdio.fp);
   317     if (nread == 0 && ferror(context->hidden.stdio.fp)) {
   318         SDL_Error(SDL_EFREAD);
   319     }
   320     return (nread);
   321 }
   322 
   323 static size_t SDLCALL
   324 stdio_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
   325 {
   326     size_t nwrote;
   327 
   328     nwrote = fwrite(ptr, size, num, context->hidden.stdio.fp);
   329     if (nwrote == 0 && ferror(context->hidden.stdio.fp)) {
   330         SDL_Error(SDL_EFWRITE);
   331     }
   332     return (nwrote);
   333 }
   334 
   335 static int SDLCALL
   336 stdio_close(SDL_RWops * context)
   337 {
   338     int status = 0;
   339     if (context) {
   340         if (context->hidden.stdio.autoclose) {
   341             /* WARNING:  Check the return value here! */
   342             if (fclose(context->hidden.stdio.fp) != 0) {
   343                 SDL_Error(SDL_EFWRITE);
   344                 status = -1;
   345             }
   346         }
   347         SDL_FreeRW(context);
   348     }
   349     return status;
   350 }
   351 #endif /* !HAVE_STDIO_H */
   352 
   353 /* Functions to read/write memory pointers */
   354 
   355 static long SDLCALL
   356 mem_seek(SDL_RWops * context, long offset, int whence)
   357 {
   358     Uint8 *newpos;
   359 
   360     switch (whence) {
   361     case RW_SEEK_SET:
   362         newpos = context->hidden.mem.base + offset;
   363         break;
   364     case RW_SEEK_CUR:
   365         newpos = context->hidden.mem.here + offset;
   366         break;
   367     case RW_SEEK_END:
   368         newpos = context->hidden.mem.stop + offset;
   369         break;
   370     default:
   371         SDL_SetError("Unknown value for 'whence'");
   372         return (-1);
   373     }
   374     if (newpos < context->hidden.mem.base) {
   375         newpos = context->hidden.mem.base;
   376     }
   377     if (newpos > context->hidden.mem.stop) {
   378         newpos = context->hidden.mem.stop;
   379     }
   380     context->hidden.mem.here = newpos;
   381     return (long)(context->hidden.mem.here - context->hidden.mem.base);
   382 }
   383 
   384 static size_t SDLCALL
   385 mem_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
   386 {
   387     size_t total_bytes;
   388     size_t mem_available;
   389 
   390     total_bytes = (maxnum * size);
   391     if ((maxnum <= 0) || (size <= 0)
   392         || ((total_bytes / maxnum) != (size_t) size)) {
   393         return 0;
   394     }
   395 
   396     mem_available = (context->hidden.mem.stop - context->hidden.mem.here);
   397     if (total_bytes > mem_available) {
   398         total_bytes = mem_available;
   399     }
   400 
   401     SDL_memcpy(ptr, context->hidden.mem.here, total_bytes);
   402     context->hidden.mem.here += total_bytes;
   403 
   404     return (total_bytes / size);
   405 }
   406 
   407 static size_t SDLCALL
   408 mem_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
   409 {
   410     if ((context->hidden.mem.here + (num * size)) > context->hidden.mem.stop) {
   411         num = (context->hidden.mem.stop - context->hidden.mem.here) / size;
   412     }
   413     SDL_memcpy(context->hidden.mem.here, ptr, num * size);
   414     context->hidden.mem.here += num * size;
   415     return (num);
   416 }
   417 
   418 static size_t SDLCALL
   419 mem_writeconst(SDL_RWops * context, const void *ptr, size_t size, size_t num)
   420 {
   421     SDL_SetError("Can't write to read-only memory");
   422     return (-1);
   423 }
   424 
   425 static int SDLCALL
   426 mem_close(SDL_RWops * context)
   427 {
   428     if (context) {
   429         SDL_FreeRW(context);
   430     }
   431     return (0);
   432 }
   433 
   434 
   435 /* Functions to create SDL_RWops structures from various data sources */
   436 
   437 SDL_RWops *
   438 SDL_RWFromFile(const char *file, const char *mode)
   439 {
   440     SDL_RWops *rwops = NULL;
   441 #ifdef HAVE_STDIO_H
   442     FILE *fp = NULL;
   443 #endif
   444     if (!file || !*file || !mode || !*mode) {
   445         SDL_SetError("SDL_RWFromFile(): No file or no mode specified");
   446         return NULL;
   447     }
   448 #if defined(ANDROID)
   449     rwops = SDL_AllocRW();
   450     if (!rwops)
   451         return NULL;            /* SDL_SetError already setup by SDL_AllocRW() */
   452     if (Android_JNI_FileOpen(rwops, file, mode) < 0) {
   453         SDL_FreeRW(rwops);
   454         return NULL;
   455     }
   456     rwops->seek = Android_JNI_FileSeek;
   457     rwops->read = Android_JNI_FileRead;
   458     rwops->write = Android_JNI_FileWrite;
   459     rwops->close = Android_JNI_FileClose;
   460 
   461 #elif defined(__WIN32__)
   462     rwops = SDL_AllocRW();
   463     if (!rwops)
   464         return NULL;            /* SDL_SetError already setup by SDL_AllocRW() */
   465     if (windows_file_open(rwops, file, mode) < 0) {
   466         SDL_FreeRW(rwops);
   467         return NULL;
   468     }
   469     rwops->seek = windows_file_seek;
   470     rwops->read = windows_file_read;
   471     rwops->write = windows_file_write;
   472     rwops->close = windows_file_close;
   473 
   474 #elif HAVE_STDIO_H
   475 	#ifdef __APPLE__
   476 	fp = SDL_OpenFPFromBundleOrFallback(file, mode);
   477     #else
   478 	fp = fopen(file, mode);
   479 	#endif
   480 	if (fp == NULL) {
   481         SDL_SetError("Couldn't open %s", file);
   482     } else {
   483         rwops = SDL_RWFromFP(fp, 1);
   484     }
   485 #else
   486     SDL_SetError("SDL not compiled with stdio support");
   487 #endif /* !HAVE_STDIO_H */
   488 
   489     return (rwops);
   490 }
   491 
   492 #ifdef HAVE_STDIO_H
   493 SDL_RWops *
   494 SDL_RWFromFP(FILE * fp, SDL_bool autoclose)
   495 {
   496     SDL_RWops *rwops = NULL;
   497 
   498 #if 0
   499 /*#ifdef __NDS__*/
   500     /* set it up so we can use stdio file function */
   501     fatInitDefault();
   502     printf("called fatInitDefault()");
   503 #endif /* __NDS__ */
   504 
   505     rwops = SDL_AllocRW();
   506     if (rwops != NULL) {
   507         rwops->seek = stdio_seek;
   508         rwops->read = stdio_read;
   509         rwops->write = stdio_write;
   510         rwops->close = stdio_close;
   511         rwops->hidden.stdio.fp = fp;
   512         rwops->hidden.stdio.autoclose = autoclose;
   513     }
   514     return (rwops);
   515 }
   516 #else
   517 SDL_RWops *
   518 SDL_RWFromFP(void * fp, SDL_bool autoclose)
   519 {
   520     SDL_SetError("SDL not compiled with stdio support");
   521     return NULL;
   522 }
   523 #endif /* HAVE_STDIO_H */
   524 
   525 SDL_RWops *
   526 SDL_RWFromMem(void *mem, int size)
   527 {
   528     SDL_RWops *rwops;
   529 
   530     rwops = SDL_AllocRW();
   531     if (rwops != NULL) {
   532         rwops->seek = mem_seek;
   533         rwops->read = mem_read;
   534         rwops->write = mem_write;
   535         rwops->close = mem_close;
   536         rwops->hidden.mem.base = (Uint8 *) mem;
   537         rwops->hidden.mem.here = rwops->hidden.mem.base;
   538         rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
   539     }
   540     return (rwops);
   541 }
   542 
   543 SDL_RWops *
   544 SDL_RWFromConstMem(const void *mem, int size)
   545 {
   546     SDL_RWops *rwops;
   547 
   548     rwops = SDL_AllocRW();
   549     if (rwops != NULL) {
   550         rwops->seek = mem_seek;
   551         rwops->read = mem_read;
   552         rwops->write = mem_writeconst;
   553         rwops->close = mem_close;
   554         rwops->hidden.mem.base = (Uint8 *) mem;
   555         rwops->hidden.mem.here = rwops->hidden.mem.base;
   556         rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
   557     }
   558     return (rwops);
   559 }
   560 
   561 SDL_RWops *
   562 SDL_AllocRW(void)
   563 {
   564     SDL_RWops *area;
   565 
   566     area = (SDL_RWops *) SDL_malloc(sizeof *area);
   567     if (area == NULL) {
   568         SDL_OutOfMemory();
   569     }
   570     return (area);
   571 }
   572 
   573 void
   574 SDL_FreeRW(SDL_RWops * area)
   575 {
   576     SDL_free(area);
   577 }
   578 
   579 /* Functions for dynamically reading and writing endian-specific values */
   580 
   581 Uint16
   582 SDL_ReadLE16(SDL_RWops * src)
   583 {
   584     Uint16 value;
   585 
   586     SDL_RWread(src, &value, (sizeof value), 1);
   587     return (SDL_SwapLE16(value));
   588 }
   589 
   590 Uint16
   591 SDL_ReadBE16(SDL_RWops * src)
   592 {
   593     Uint16 value;
   594 
   595     SDL_RWread(src, &value, (sizeof value), 1);
   596     return (SDL_SwapBE16(value));
   597 }
   598 
   599 Uint32
   600 SDL_ReadLE32(SDL_RWops * src)
   601 {
   602     Uint32 value;
   603 
   604     SDL_RWread(src, &value, (sizeof value), 1);
   605     return (SDL_SwapLE32(value));
   606 }
   607 
   608 Uint32
   609 SDL_ReadBE32(SDL_RWops * src)
   610 {
   611     Uint32 value;
   612 
   613     SDL_RWread(src, &value, (sizeof value), 1);
   614     return (SDL_SwapBE32(value));
   615 }
   616 
   617 Uint64
   618 SDL_ReadLE64(SDL_RWops * src)
   619 {
   620     Uint64 value;
   621 
   622     SDL_RWread(src, &value, (sizeof value), 1);
   623     return (SDL_SwapLE64(value));
   624 }
   625 
   626 Uint64
   627 SDL_ReadBE64(SDL_RWops * src)
   628 {
   629     Uint64 value;
   630 
   631     SDL_RWread(src, &value, (sizeof value), 1);
   632     return (SDL_SwapBE64(value));
   633 }
   634 
   635 size_t
   636 SDL_WriteLE16(SDL_RWops * dst, Uint16 value)
   637 {
   638     value = SDL_SwapLE16(value);
   639     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   640 }
   641 
   642 size_t
   643 SDL_WriteBE16(SDL_RWops * dst, Uint16 value)
   644 {
   645     value = SDL_SwapBE16(value);
   646     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   647 }
   648 
   649 size_t
   650 SDL_WriteLE32(SDL_RWops * dst, Uint32 value)
   651 {
   652     value = SDL_SwapLE32(value);
   653     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   654 }
   655 
   656 size_t
   657 SDL_WriteBE32(SDL_RWops * dst, Uint32 value)
   658 {
   659     value = SDL_SwapBE32(value);
   660     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   661 }
   662 
   663 size_t
   664 SDL_WriteLE64(SDL_RWops * dst, Uint64 value)
   665 {
   666     value = SDL_SwapLE64(value);
   667     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   668 }
   669 
   670 size_t
   671 SDL_WriteBE64(SDL_RWops * dst, Uint64 value)
   672 {
   673     value = SDL_SwapBE64(value);
   674     return (SDL_RWwrite(dst, &value, (sizeof value), 1));
   675 }
   676 
   677 /* vi: set ts=4 sw=4 expandtab: */