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