The NaCL mount/unmount functions need to be in SDL_system.h and specific to NaCL
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21 /* Need this so Linux systems define fseek64o, ftell64o and off64_t */
22 #define _LARGEFILE64_SOURCE
23 #include "../SDL_internal.h"
25 #if defined(__WIN32__)
26 #include "../core/windows/SDL_windows.h"
30 /* This file provides a general interface for SDL to read and write
31 data sources. It can easily be extended to files, memory, etc.
34 #include "SDL_endian.h"
35 #include "SDL_rwops.h"
38 #include "cocoa/SDL_rwopsbundlesupport.h"
39 #endif /* __APPLE__ */
42 #include "../core/android/SDL_android.h"
43 #include "SDL_system.h"
47 #include "nacl_io/nacl_io.h"
52 /* Functions to read/write Win32 API file pointers */
54 #ifndef INVALID_SET_FILE_POINTER
55 #define INVALID_SET_FILE_POINTER 0xFFFFFFFF
58 #define READAHEAD_BUFFER_SIZE 1024
61 windows_file_open(SDL_RWops * context, const char *filename, const char *mode)
65 DWORD r_right, w_right;
66 DWORD must_exist, truncate;
70 return -1; /* failed (invalid call) */
72 context->hidden.windowsio.h = INVALID_HANDLE_VALUE; /* mark this as unusable */
73 context->hidden.windowsio.buffer.data = NULL;
74 context->hidden.windowsio.buffer.size = 0;
75 context->hidden.windowsio.buffer.left = 0;
77 /* "r" = reading, file must exist */
78 /* "w" = writing, truncate existing, file may not exist */
79 /* "r+"= reading or writing, file must exist */
80 /* "a" = writing, append file may not exist */
81 /* "a+"= append + read, file may not exist */
82 /* "w+" = read, write, truncate. file may not exist */
84 must_exist = (SDL_strchr(mode, 'r') != NULL) ? OPEN_EXISTING : 0;
85 truncate = (SDL_strchr(mode, 'w') != NULL) ? CREATE_ALWAYS : 0;
86 r_right = (SDL_strchr(mode, '+') != NULL
87 || must_exist) ? GENERIC_READ : 0;
88 a_mode = (SDL_strchr(mode, 'a') != NULL) ? OPEN_ALWAYS : 0;
89 w_right = (a_mode || SDL_strchr(mode, '+')
90 || truncate) ? GENERIC_WRITE : 0;
92 if (!r_right && !w_right) /* inconsistent mode */
93 return -1; /* failed (invalid call) */
95 context->hidden.windowsio.buffer.data =
96 (char *) SDL_malloc(READAHEAD_BUFFER_SIZE);
97 if (!context->hidden.windowsio.buffer.data) {
98 return SDL_OutOfMemory();
100 /* Do not open a dialog box if failure */
102 SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
105 LPTSTR tstr = WIN_UTF8ToString(filename);
106 h = CreateFile(tstr, (w_right | r_right),
107 (w_right) ? 0 : FILE_SHARE_READ, NULL,
108 (must_exist | truncate | a_mode),
109 FILE_ATTRIBUTE_NORMAL, NULL);
113 /* restore old behavior */
114 SetErrorMode(old_error_mode);
116 if (h == INVALID_HANDLE_VALUE) {
117 SDL_free(context->hidden.windowsio.buffer.data);
118 context->hidden.windowsio.buffer.data = NULL;
119 SDL_SetError("Couldn't open %s", filename);
120 return -2; /* failed (CreateFile) */
122 context->hidden.windowsio.h = h;
123 context->hidden.windowsio.append = a_mode ? SDL_TRUE : SDL_FALSE;
128 static Sint64 SDLCALL
129 windows_file_size(SDL_RWops * context)
133 if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) {
134 return SDL_SetError("windows_file_size: invalid context/file not opened");
137 if (!GetFileSizeEx(context->hidden.windowsio.h, &size)) {
138 return WIN_SetError("windows_file_size");
141 return size.QuadPart;
144 static Sint64 SDLCALL
145 windows_file_seek(SDL_RWops * context, Sint64 offset, int whence)
148 LARGE_INTEGER windowsoffset;
150 if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) {
151 return SDL_SetError("windows_file_seek: invalid context/file not opened");
154 /* FIXME: We may be able to satisfy the seek within buffered data */
155 if (whence == RW_SEEK_CUR && context->hidden.windowsio.buffer.left) {
156 offset -= (long)context->hidden.windowsio.buffer.left;
158 context->hidden.windowsio.buffer.left = 0;
162 windowswhence = FILE_BEGIN;
165 windowswhence = FILE_CURRENT;
168 windowswhence = FILE_END;
171 return SDL_SetError("windows_file_seek: Unknown value for 'whence'");
174 windowsoffset.QuadPart = offset;
175 if (!SetFilePointerEx(context->hidden.windowsio.h, windowsoffset, &windowsoffset, windowswhence)) {
176 return WIN_SetError("windows_file_seek");
178 return windowsoffset.QuadPart;
181 static size_t SDLCALL
182 windows_file_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
185 size_t total_read = 0;
189 total_need = size * maxnum;
191 if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE
195 if (context->hidden.windowsio.buffer.left > 0) {
196 void *data = (char *) context->hidden.windowsio.buffer.data +
197 context->hidden.windowsio.buffer.size -
198 context->hidden.windowsio.buffer.left;
200 SDL_min(total_need, context->hidden.windowsio.buffer.left);
201 SDL_memcpy(ptr, data, read_ahead);
202 context->hidden.windowsio.buffer.left -= read_ahead;
204 if (read_ahead == total_need) {
207 ptr = (char *) ptr + read_ahead;
208 total_need -= read_ahead;
209 total_read += read_ahead;
212 if (total_need < READAHEAD_BUFFER_SIZE) {
214 (context->hidden.windowsio.h, context->hidden.windowsio.buffer.data,
215 READAHEAD_BUFFER_SIZE, &byte_read, NULL)) {
216 SDL_Error(SDL_EFREAD);
219 read_ahead = SDL_min(total_need, (int) byte_read);
220 SDL_memcpy(ptr, context->hidden.windowsio.buffer.data, read_ahead);
221 context->hidden.windowsio.buffer.size = byte_read;
222 context->hidden.windowsio.buffer.left = byte_read - read_ahead;
223 total_read += read_ahead;
226 (context->hidden.windowsio.h, ptr, (DWORD)total_need, &byte_read, NULL)) {
227 SDL_Error(SDL_EFREAD);
230 total_read += byte_read;
232 return (total_read / size);
235 static size_t SDLCALL
236 windows_file_write(SDL_RWops * context, const void *ptr, size_t size,
244 total_bytes = size * num;
246 if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE
247 || total_bytes <= 0 || !size)
250 if (context->hidden.windowsio.buffer.left) {
251 SetFilePointer(context->hidden.windowsio.h,
252 -(LONG)context->hidden.windowsio.buffer.left, NULL,
254 context->hidden.windowsio.buffer.left = 0;
257 /* if in append mode, we must go to the EOF before write */
258 if (context->hidden.windowsio.append) {
259 if (SetFilePointer(context->hidden.windowsio.h, 0L, NULL, FILE_END) ==
260 INVALID_SET_FILE_POINTER) {
261 SDL_Error(SDL_EFWRITE);
267 (context->hidden.windowsio.h, ptr, (DWORD)total_bytes, &byte_written, NULL)) {
268 SDL_Error(SDL_EFWRITE);
272 nwritten = byte_written / size;
277 windows_file_close(SDL_RWops * context)
281 if (context->hidden.windowsio.h != INVALID_HANDLE_VALUE) {
282 CloseHandle(context->hidden.windowsio.h);
283 context->hidden.windowsio.h = INVALID_HANDLE_VALUE; /* to be sure */
285 SDL_free(context->hidden.windowsio.buffer.data);
286 context->hidden.windowsio.buffer.data = NULL;
291 #endif /* __WIN32__ */
295 /* Functions to read/write stdio file pointers */
297 static Sint64 SDLCALL
298 stdio_size(SDL_RWops * context)
302 pos = SDL_RWseek(context, 0, RW_SEEK_CUR);
306 size = SDL_RWseek(context, 0, RW_SEEK_END);
308 SDL_RWseek(context, pos, RW_SEEK_SET);
312 static Sint64 SDLCALL
313 stdio_seek(SDL_RWops * context, Sint64 offset, int whence)
316 if (fseeko64(context->hidden.stdio.fp, (off64_t)offset, whence) == 0) {
317 return ftello64(context->hidden.stdio.fp);
319 #elif defined(HAVE_FSEEKO)
320 if (fseeko(context->hidden.stdio.fp, (off_t)offset, whence) == 0) {
321 return ftello(context->hidden.stdio.fp);
323 #elif defined(HAVE__FSEEKI64)
324 if (_fseeki64(context->hidden.stdio.fp, offset, whence) == 0) {
325 return _ftelli64(context->hidden.stdio.fp);
328 if (fseek(context->hidden.stdio.fp, offset, whence) == 0) {
329 return ftell(context->hidden.stdio.fp);
332 return SDL_Error(SDL_EFSEEK);
335 static size_t SDLCALL
336 stdio_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
340 nread = fread(ptr, size, maxnum, context->hidden.stdio.fp);
341 if (nread == 0 && ferror(context->hidden.stdio.fp)) {
342 SDL_Error(SDL_EFREAD);
347 static size_t SDLCALL
348 stdio_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
352 nwrote = fwrite(ptr, size, num, context->hidden.stdio.fp);
353 if (nwrote == 0 && ferror(context->hidden.stdio.fp)) {
354 SDL_Error(SDL_EFWRITE);
360 stdio_close(SDL_RWops * context)
364 if (context->hidden.stdio.autoclose) {
365 /* WARNING: Check the return value here! */
366 if (fclose(context->hidden.stdio.fp) != 0) {
367 status = SDL_Error(SDL_EFWRITE);
374 #endif /* !HAVE_STDIO_H */
376 /* Functions to read/write memory pointers */
378 static Sint64 SDLCALL
379 mem_size(SDL_RWops * context)
381 return (Sint64)(context->hidden.mem.stop - context->hidden.mem.base);
384 static Sint64 SDLCALL
385 mem_seek(SDL_RWops * context, Sint64 offset, int whence)
391 newpos = context->hidden.mem.base + offset;
394 newpos = context->hidden.mem.here + offset;
397 newpos = context->hidden.mem.stop + offset;
400 return SDL_SetError("Unknown value for 'whence'");
402 if (newpos < context->hidden.mem.base) {
403 newpos = context->hidden.mem.base;
405 if (newpos > context->hidden.mem.stop) {
406 newpos = context->hidden.mem.stop;
408 context->hidden.mem.here = newpos;
409 return (Sint64)(context->hidden.mem.here - context->hidden.mem.base);
412 static size_t SDLCALL
413 mem_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
416 size_t mem_available;
418 total_bytes = (maxnum * size);
419 if ((maxnum <= 0) || (size <= 0)
420 || ((total_bytes / maxnum) != (size_t) size)) {
424 mem_available = (context->hidden.mem.stop - context->hidden.mem.here);
425 if (total_bytes > mem_available) {
426 total_bytes = mem_available;
429 SDL_memcpy(ptr, context->hidden.mem.here, total_bytes);
430 context->hidden.mem.here += total_bytes;
432 return (total_bytes / size);
435 static size_t SDLCALL
436 mem_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
438 if ((context->hidden.mem.here + (num * size)) > context->hidden.mem.stop) {
439 num = (context->hidden.mem.stop - context->hidden.mem.here) / size;
441 SDL_memcpy(context->hidden.mem.here, ptr, num * size);
442 context->hidden.mem.here += num * size;
446 static size_t SDLCALL
447 mem_writeconst(SDL_RWops * context, const void *ptr, size_t size, size_t num)
449 SDL_SetError("Can't write to read-only memory");
454 mem_close(SDL_RWops * context)
463 /* Functions to create SDL_RWops structures from various data sources */
466 SDL_RWFromFile(const char *file, const char *mode)
468 SDL_RWops *rwops = NULL;
469 if (!file || !*file || !mode || !*mode) {
470 SDL_SetError("SDL_RWFromFile(): No file or no mode specified");
473 #if defined(__ANDROID__)
475 /* Try to open the file on the filesystem first */
477 FILE *fp = fopen(file, mode);
479 return SDL_RWFromFP(fp, 1);
482 /* Try opening it from internal storage if it's a relative path */
486 path = SDL_stack_alloc(char, PATH_MAX);
488 SDL_snprintf(path, PATH_MAX, "%s/%s",
489 SDL_AndroidGetInternalStoragePath(), file);
490 fp = fopen(path, mode);
491 SDL_stack_free(path);
493 return SDL_RWFromFP(fp, 1);
497 #endif /* HAVE_STDIO_H */
499 /* Try to open the file from the asset system */
500 rwops = SDL_AllocRW();
502 return NULL; /* SDL_SetError already setup by SDL_AllocRW() */
503 if (Android_JNI_FileOpen(rwops, file, mode) < 0) {
507 rwops->size = Android_JNI_FileSize;
508 rwops->seek = Android_JNI_FileSeek;
509 rwops->read = Android_JNI_FileRead;
510 rwops->write = Android_JNI_FileWrite;
511 rwops->close = Android_JNI_FileClose;
512 rwops->type = SDL_RWOPS_JNIFILE;
514 #elif defined(__WIN32__)
515 rwops = SDL_AllocRW();
517 return NULL; /* SDL_SetError already setup by SDL_AllocRW() */
518 if (windows_file_open(rwops, file, mode) < 0) {
522 rwops->size = windows_file_size;
523 rwops->seek = windows_file_seek;
524 rwops->read = windows_file_read;
525 rwops->write = windows_file_write;
526 rwops->close = windows_file_close;
527 rwops->type = SDL_RWOPS_WINFILE;
532 FILE *fp = SDL_OpenFPFromBundleOrFallback(file, mode);
535 fopen_s(&fp, file, mode);
537 FILE *fp = fopen(file, mode);
540 SDL_SetError("Couldn't open %s", file);
542 rwops = SDL_RWFromFP(fp, 1);
546 SDL_SetError("SDL not compiled with stdio support");
547 #endif /* !HAVE_STDIO_H */
554 SDL_RWFromFP(FILE * fp, SDL_bool autoclose)
556 SDL_RWops *rwops = NULL;
558 rwops = SDL_AllocRW();
560 rwops->size = stdio_size;
561 rwops->seek = stdio_seek;
562 rwops->read = stdio_read;
563 rwops->write = stdio_write;
564 rwops->close = stdio_close;
565 rwops->hidden.stdio.fp = fp;
566 rwops->hidden.stdio.autoclose = autoclose;
567 rwops->type = SDL_RWOPS_STDFILE;
573 SDL_RWFromFP(void * fp, SDL_bool autoclose)
575 SDL_SetError("SDL not compiled with stdio support");
578 #endif /* HAVE_STDIO_H */
581 SDL_RWFromMem(void *mem, int size)
583 SDL_RWops *rwops = NULL;
585 SDL_InvalidParamError("mem");
589 SDL_InvalidParamError("size");
593 rwops = SDL_AllocRW();
595 rwops->size = mem_size;
596 rwops->seek = mem_seek;
597 rwops->read = mem_read;
598 rwops->write = mem_write;
599 rwops->close = mem_close;
600 rwops->hidden.mem.base = (Uint8 *) mem;
601 rwops->hidden.mem.here = rwops->hidden.mem.base;
602 rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
603 rwops->type = SDL_RWOPS_MEMORY;
609 SDL_RWFromConstMem(const void *mem, int size)
611 SDL_RWops *rwops = NULL;
613 SDL_InvalidParamError("mem");
617 SDL_InvalidParamError("size");
621 rwops = SDL_AllocRW();
623 rwops->size = mem_size;
624 rwops->seek = mem_seek;
625 rwops->read = mem_read;
626 rwops->write = mem_writeconst;
627 rwops->close = mem_close;
628 rwops->hidden.mem.base = (Uint8 *) mem;
629 rwops->hidden.mem.here = rwops->hidden.mem.base;
630 rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
631 rwops->type = SDL_RWOPS_MEMORY_RO;
641 area = (SDL_RWops *) SDL_malloc(sizeof *area);
645 area->type = SDL_RWOPS_UNKNOWN;
651 SDL_FreeRW(SDL_RWops * area)
656 /* Functions for dynamically reading and writing endian-specific values */
659 SDL_ReadU8(SDL_RWops * src)
663 SDL_RWread(src, &value, sizeof (value), 1);
668 SDL_ReadLE16(SDL_RWops * src)
672 SDL_RWread(src, &value, sizeof (value), 1);
673 return SDL_SwapLE16(value);
677 SDL_ReadBE16(SDL_RWops * src)
681 SDL_RWread(src, &value, sizeof (value), 1);
682 return SDL_SwapBE16(value);
686 SDL_ReadLE32(SDL_RWops * src)
690 SDL_RWread(src, &value, sizeof (value), 1);
691 return SDL_SwapLE32(value);
695 SDL_ReadBE32(SDL_RWops * src)
699 SDL_RWread(src, &value, sizeof (value), 1);
700 return SDL_SwapBE32(value);
704 SDL_ReadLE64(SDL_RWops * src)
708 SDL_RWread(src, &value, sizeof (value), 1);
709 return SDL_SwapLE64(value);
713 SDL_ReadBE64(SDL_RWops * src)
717 SDL_RWread(src, &value, sizeof (value), 1);
718 return SDL_SwapBE64(value);
722 SDL_WriteU8(SDL_RWops * dst, Uint8 value)
724 return SDL_RWwrite(dst, &value, sizeof (value), 1);
728 SDL_WriteLE16(SDL_RWops * dst, Uint16 value)
730 const Uint16 swapped = SDL_SwapLE16(value);
731 return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
735 SDL_WriteBE16(SDL_RWops * dst, Uint16 value)
737 const Uint16 swapped = SDL_SwapBE16(value);
738 return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
742 SDL_WriteLE32(SDL_RWops * dst, Uint32 value)
744 const Uint32 swapped = SDL_SwapLE32(value);
745 return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
749 SDL_WriteBE32(SDL_RWops * dst, Uint32 value)
751 const Uint32 swapped = SDL_SwapBE32(value);
752 return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
756 SDL_WriteLE64(SDL_RWops * dst, Uint64 value)
758 const Uint64 swapped = SDL_SwapLE64(value);
759 return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
763 SDL_WriteBE64(SDL_RWops * dst, Uint64 value)
765 const Uint64 swapped = SDL_SwapBE64(value);
766 return SDL_RWwrite(dst, &swapped, sizeof (swapped), 1);
769 /* vi: set ts=4 sw=4 expandtab: */