Fix bug 1560 - SDL_RWFromConstMem write operation returns -1 but should return 0.
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2013 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_config.h"
25 /* This file provides a general interface for SDL to read and write
26 data sources. It can easily be extended to files, memory, etc.
29 #include "SDL_endian.h"
30 #include "SDL_rwops.h"
33 #include "cocoa/SDL_rwopsbundlesupport.h"
34 #endif /* __APPLE__ */
37 #include "../core/android/SDL_android.h"
41 /* include libfat headers for fatInitDefault(). */
47 /* Functions to read/write Win32 API file pointers */
49 #include "../core/windows/SDL_windows.h"
51 #ifndef INVALID_SET_FILE_POINTER
52 #define INVALID_SET_FILE_POINTER 0xFFFFFFFF
55 #define READAHEAD_BUFFER_SIZE 1024
58 windows_file_open(SDL_RWops * context, const char *filename, const char *mode)
62 DWORD r_right, w_right;
63 DWORD must_exist, truncate;
67 return -1; /* failed (invalid call) */
69 context->hidden.windowsio.h = INVALID_HANDLE_VALUE; /* mark this as unusable */
70 context->hidden.windowsio.buffer.data = NULL;
71 context->hidden.windowsio.buffer.size = 0;
72 context->hidden.windowsio.buffer.left = 0;
74 /* "r" = reading, file must exist */
75 /* "w" = writing, truncate existing, file may not exist */
76 /* "r+"= reading or writing, file must exist */
77 /* "a" = writing, append file may not exist */
78 /* "a+"= append + read, file may not exist */
79 /* "w+" = read, write, truncate. file may not exist */
81 must_exist = (SDL_strchr(mode, 'r') != NULL) ? OPEN_EXISTING : 0;
82 truncate = (SDL_strchr(mode, 'w') != NULL) ? CREATE_ALWAYS : 0;
83 r_right = (SDL_strchr(mode, '+') != NULL
84 || must_exist) ? GENERIC_READ : 0;
85 a_mode = (SDL_strchr(mode, 'a') != NULL) ? OPEN_ALWAYS : 0;
86 w_right = (a_mode || SDL_strchr(mode, '+')
87 || truncate) ? GENERIC_WRITE : 0;
89 if (!r_right && !w_right) /* inconsistent mode */
90 return -1; /* failed (invalid call) */
92 context->hidden.windowsio.buffer.data =
93 (char *) SDL_malloc(READAHEAD_BUFFER_SIZE);
94 if (!context->hidden.windowsio.buffer.data) {
98 /* Do not open a dialog box if failure */
100 SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
103 LPTSTR tstr = WIN_UTF8ToString(filename);
104 h = CreateFile(tstr, (w_right | r_right),
105 (w_right) ? 0 : FILE_SHARE_READ, NULL,
106 (must_exist | truncate | a_mode),
107 FILE_ATTRIBUTE_NORMAL, NULL);
111 /* restore old behavior */
112 SetErrorMode(old_error_mode);
114 if (h == INVALID_HANDLE_VALUE) {
115 SDL_free(context->hidden.windowsio.buffer.data);
116 context->hidden.windowsio.buffer.data = NULL;
117 SDL_SetError("Couldn't open %s", filename);
118 return -2; /* failed (CreateFile) */
120 context->hidden.windowsio.h = h;
121 context->hidden.windowsio.append = a_mode ? SDL_TRUE : SDL_FALSE;
126 static Sint64 SDLCALL
127 windows_file_size(SDL_RWops * context)
131 if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) {
132 SDL_SetError("windows_file_size: invalid context/file not opened");
136 if (!GetFileSizeEx(context->hidden.windowsio.h, &size)) {
137 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 SDL_SetError("windows_file_seek: invalid context/file not opened");
155 /* FIXME: We may be able to satisfy the seek within buffered data */
156 if (whence == RW_SEEK_CUR && context->hidden.windowsio.buffer.left) {
157 offset -= (long)context->hidden.windowsio.buffer.left;
159 context->hidden.windowsio.buffer.left = 0;
163 windowswhence = FILE_BEGIN;
166 windowswhence = FILE_CURRENT;
169 windowswhence = FILE_END;
172 SDL_SetError("windows_file_seek: Unknown value for 'whence'");
176 windowsoffset.QuadPart = offset;
177 if (!SetFilePointerEx(context->hidden.windowsio.h, windowsoffset, &windowsoffset, windowswhence)) {
178 WIN_SetError("windows_file_seek");
181 return windowsoffset.QuadPart;
184 static size_t SDLCALL
185 windows_file_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
188 size_t total_read = 0;
192 total_need = size * maxnum;
194 if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE
198 if (context->hidden.windowsio.buffer.left > 0) {
199 void *data = (char *) context->hidden.windowsio.buffer.data +
200 context->hidden.windowsio.buffer.size -
201 context->hidden.windowsio.buffer.left;
203 SDL_min(total_need, context->hidden.windowsio.buffer.left);
204 SDL_memcpy(ptr, data, read_ahead);
205 context->hidden.windowsio.buffer.left -= read_ahead;
207 if (read_ahead == total_need) {
210 ptr = (char *) ptr + read_ahead;
211 total_need -= read_ahead;
212 total_read += read_ahead;
215 if (total_need < READAHEAD_BUFFER_SIZE) {
217 (context->hidden.windowsio.h, context->hidden.windowsio.buffer.data,
218 READAHEAD_BUFFER_SIZE, &byte_read, NULL)) {
219 SDL_Error(SDL_EFREAD);
222 read_ahead = SDL_min(total_need, (int) byte_read);
223 SDL_memcpy(ptr, context->hidden.windowsio.buffer.data, read_ahead);
224 context->hidden.windowsio.buffer.size = byte_read;
225 context->hidden.windowsio.buffer.left = byte_read - read_ahead;
226 total_read += read_ahead;
229 (context->hidden.windowsio.h, ptr, (DWORD)total_need, &byte_read, NULL)) {
230 SDL_Error(SDL_EFREAD);
233 total_read += byte_read;
235 return (total_read / size);
238 static size_t SDLCALL
239 windows_file_write(SDL_RWops * context, const void *ptr, size_t size,
247 total_bytes = size * num;
249 if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE
250 || total_bytes <= 0 || !size)
253 if (context->hidden.windowsio.buffer.left) {
254 SetFilePointer(context->hidden.windowsio.h,
255 -(LONG)context->hidden.windowsio.buffer.left, NULL,
257 context->hidden.windowsio.buffer.left = 0;
260 /* if in append mode, we must go to the EOF before write */
261 if (context->hidden.windowsio.append) {
262 if (SetFilePointer(context->hidden.windowsio.h, 0L, NULL, FILE_END) ==
263 INVALID_SET_FILE_POINTER) {
264 SDL_Error(SDL_EFWRITE);
270 (context->hidden.windowsio.h, ptr, (DWORD)total_bytes, &byte_written, NULL)) {
271 SDL_Error(SDL_EFWRITE);
275 nwritten = byte_written / size;
280 windows_file_close(SDL_RWops * context)
284 if (context->hidden.windowsio.h != INVALID_HANDLE_VALUE) {
285 CloseHandle(context->hidden.windowsio.h);
286 context->hidden.windowsio.h = INVALID_HANDLE_VALUE; /* to be sure */
288 if (context->hidden.windowsio.buffer.data) {
289 SDL_free(context->hidden.windowsio.buffer.data);
290 context->hidden.windowsio.buffer.data = NULL;
296 #endif /* __WIN32__ */
300 /* Functions to read/write stdio file pointers */
302 static Sint64 SDLCALL
303 stdio_size(SDL_RWops * context)
307 pos = SDL_RWseek(context, 0, RW_SEEK_CUR);
311 size = SDL_RWseek(context, 0, RW_SEEK_END);
313 SDL_RWseek(context, pos, RW_SEEK_SET);
317 static Sint64 SDLCALL
318 stdio_seek(SDL_RWops * context, Sint64 offset, int whence)
321 if (fseeko64(context->hidden.stdio.fp, (off64_t)offset, whence) == 0) {
322 return ftello64(context->hidden.stdio.fp);
324 #elif defined(HAVE_FSEEKO)
325 if (fseeko(context->hidden.stdio.fp, (off_t)offset, whence) == 0) {
326 return ftello(context->hidden.stdio.fp);
329 if (fseek(context->hidden.stdio.fp, offset, whence) == 0) {
330 return (ftell(context->hidden.stdio.fp));
333 SDL_Error(SDL_EFSEEK);
337 static size_t SDLCALL
338 stdio_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
342 nread = fread(ptr, size, maxnum, context->hidden.stdio.fp);
343 if (nread == 0 && ferror(context->hidden.stdio.fp)) {
344 SDL_Error(SDL_EFREAD);
349 static size_t SDLCALL
350 stdio_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
354 nwrote = fwrite(ptr, size, num, context->hidden.stdio.fp);
355 if (nwrote == 0 && ferror(context->hidden.stdio.fp)) {
356 SDL_Error(SDL_EFWRITE);
362 stdio_close(SDL_RWops * context)
366 if (context->hidden.stdio.autoclose) {
367 /* WARNING: Check the return value here! */
368 if (fclose(context->hidden.stdio.fp) != 0) {
369 SDL_Error(SDL_EFWRITE);
377 #endif /* !HAVE_STDIO_H */
379 /* Functions to read/write memory pointers */
381 static Sint64 SDLCALL
382 mem_size(SDL_RWops * context)
384 return (Sint64)(context->hidden.mem.stop - context->hidden.mem.base);
387 static Sint64 SDLCALL
388 mem_seek(SDL_RWops * context, Sint64 offset, int whence)
394 newpos = context->hidden.mem.base + offset;
397 newpos = context->hidden.mem.here + offset;
400 newpos = context->hidden.mem.stop + offset;
403 SDL_SetError("Unknown value for 'whence'");
406 if (newpos < context->hidden.mem.base) {
407 newpos = context->hidden.mem.base;
409 if (newpos > context->hidden.mem.stop) {
410 newpos = context->hidden.mem.stop;
412 context->hidden.mem.here = newpos;
413 return (Sint64)(context->hidden.mem.here - context->hidden.mem.base);
416 static size_t SDLCALL
417 mem_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
420 size_t mem_available;
422 total_bytes = (maxnum * size);
423 if ((maxnum <= 0) || (size <= 0)
424 || ((total_bytes / maxnum) != (size_t) size)) {
428 mem_available = (context->hidden.mem.stop - context->hidden.mem.here);
429 if (total_bytes > mem_available) {
430 total_bytes = mem_available;
433 SDL_memcpy(ptr, context->hidden.mem.here, total_bytes);
434 context->hidden.mem.here += total_bytes;
436 return (total_bytes / size);
439 static size_t SDLCALL
440 mem_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
442 if ((context->hidden.mem.here + (num * size)) > context->hidden.mem.stop) {
443 num = (context->hidden.mem.stop - context->hidden.mem.here) / size;
445 SDL_memcpy(context->hidden.mem.here, ptr, num * size);
446 context->hidden.mem.here += num * size;
450 static size_t SDLCALL
451 mem_writeconst(SDL_RWops * context, const void *ptr, size_t size, size_t num)
453 SDL_SetError("Can't write to read-only memory");
458 mem_close(SDL_RWops * context)
467 /* Functions to create SDL_RWops structures from various data sources */
470 SDL_RWFromFile(const char *file, const char *mode)
472 SDL_RWops *rwops = NULL;
473 if (!file || !*file || !mode || !*mode) {
474 SDL_SetError("SDL_RWFromFile(): No file or no mode specified");
479 /* Try to open the file on the filesystem first */
481 FILE *fp = fopen(file, mode);
483 return SDL_RWFromFP(fp, 1);
486 /* Try opening it from internal storage if it's a relative path */
490 path = SDL_stack_alloc(char, PATH_MAX);
492 SDL_snprintf(path, PATH_MAX, "%s/%s",
493 SDL_AndroidGetInternalStoragePath(), file);
494 fp = fopen(path, mode);
495 SDL_stack_free(path);
497 return SDL_RWFromFP(fp, 1);
501 #endif /* HAVE_STDIO_H */
503 /* Try to open the file from the asset system */
504 rwops = SDL_AllocRW();
506 return NULL; /* SDL_SetError already setup by SDL_AllocRW() */
507 if (Android_JNI_FileOpen(rwops, file, mode) < 0) {
511 rwops->size = Android_JNI_FileSize;
512 rwops->seek = Android_JNI_FileSeek;
513 rwops->read = Android_JNI_FileRead;
514 rwops->write = Android_JNI_FileWrite;
515 rwops->close = Android_JNI_FileClose;
517 #elif defined(__WIN32__)
518 rwops = SDL_AllocRW();
520 return NULL; /* SDL_SetError already setup by SDL_AllocRW() */
521 if (windows_file_open(rwops, file, mode) < 0) {
525 rwops->size = windows_file_size;
526 rwops->seek = windows_file_seek;
527 rwops->read = windows_file_read;
528 rwops->write = windows_file_write;
529 rwops->close = windows_file_close;
534 FILE *fp = SDL_OpenFPFromBundleOrFallback(file, mode);
536 FILE *fp = fopen(file, mode);
539 SDL_SetError("Couldn't open %s", file);
541 rwops = SDL_RWFromFP(fp, 1);
545 SDL_SetError("SDL not compiled with stdio support");
546 #endif /* !HAVE_STDIO_H */
553 SDL_RWFromFP(FILE * fp, SDL_bool autoclose)
555 SDL_RWops *rwops = NULL;
559 /* set it up so we can use stdio file function */
561 printf("called fatInitDefault()");
564 rwops = SDL_AllocRW();
566 rwops->size = stdio_size;
567 rwops->seek = stdio_seek;
568 rwops->read = stdio_read;
569 rwops->write = stdio_write;
570 rwops->close = stdio_close;
571 rwops->hidden.stdio.fp = fp;
572 rwops->hidden.stdio.autoclose = autoclose;
578 SDL_RWFromFP(void * fp, SDL_bool autoclose)
580 SDL_SetError("SDL not compiled with stdio support");
583 #endif /* HAVE_STDIO_H */
586 SDL_RWFromMem(void *mem, int size)
590 rwops = SDL_AllocRW();
592 rwops->size = mem_size;
593 rwops->seek = mem_seek;
594 rwops->read = mem_read;
595 rwops->write = mem_write;
596 rwops->close = mem_close;
597 rwops->hidden.mem.base = (Uint8 *) mem;
598 rwops->hidden.mem.here = rwops->hidden.mem.base;
599 rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
605 SDL_RWFromConstMem(const void *mem, int size)
609 rwops = SDL_AllocRW();
611 rwops->size = mem_size;
612 rwops->seek = mem_seek;
613 rwops->read = mem_read;
614 rwops->write = mem_writeconst;
615 rwops->close = mem_close;
616 rwops->hidden.mem.base = (Uint8 *) mem;
617 rwops->hidden.mem.here = rwops->hidden.mem.base;
618 rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
628 area = (SDL_RWops *) SDL_malloc(sizeof *area);
636 SDL_FreeRW(SDL_RWops * area)
641 /* Functions for dynamically reading and writing endian-specific values */
644 SDL_ReadU8(SDL_RWops * src)
648 SDL_RWread(src, &value, (sizeof value), 1);
653 SDL_ReadLE16(SDL_RWops * src)
657 SDL_RWread(src, &value, (sizeof value), 1);
658 return (SDL_SwapLE16(value));
662 SDL_ReadBE16(SDL_RWops * src)
666 SDL_RWread(src, &value, (sizeof value), 1);
667 return (SDL_SwapBE16(value));
671 SDL_ReadLE32(SDL_RWops * src)
675 SDL_RWread(src, &value, (sizeof value), 1);
676 return (SDL_SwapLE32(value));
680 SDL_ReadBE32(SDL_RWops * src)
684 SDL_RWread(src, &value, (sizeof value), 1);
685 return (SDL_SwapBE32(value));
689 SDL_ReadLE64(SDL_RWops * src)
693 SDL_RWread(src, &value, (sizeof value), 1);
694 return (SDL_SwapLE64(value));
698 SDL_ReadBE64(SDL_RWops * src)
702 SDL_RWread(src, &value, (sizeof value), 1);
703 return (SDL_SwapBE64(value));
707 SDL_WriteU8(SDL_RWops * dst, Uint8 value)
709 return (SDL_RWwrite(dst, &value, (sizeof value), 1));
713 SDL_WriteLE16(SDL_RWops * dst, Uint16 value)
715 value = SDL_SwapLE16(value);
716 return (SDL_RWwrite(dst, &value, (sizeof value), 1));
720 SDL_WriteBE16(SDL_RWops * dst, Uint16 value)
722 value = SDL_SwapBE16(value);
723 return (SDL_RWwrite(dst, &value, (sizeof value), 1));
727 SDL_WriteLE32(SDL_RWops * dst, Uint32 value)
729 value = SDL_SwapLE32(value);
730 return (SDL_RWwrite(dst, &value, (sizeof value), 1));
734 SDL_WriteBE32(SDL_RWops * dst, Uint32 value)
736 value = SDL_SwapBE32(value);
737 return (SDL_RWwrite(dst, &value, (sizeof value), 1));
741 SDL_WriteLE64(SDL_RWops * dst, Uint64 value)
743 value = SDL_SwapLE64(value);
744 return (SDL_RWwrite(dst, &value, (sizeof value), 1));
748 SDL_WriteBE64(SDL_RWops * dst, Uint64 value)
750 value = SDL_SwapBE64(value);
751 return (SDL_RWwrite(dst, &value, (sizeof value), 1));
754 /* vi: set ts=4 sw=4 expandtab: */