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