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