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