src/file/SDL_rwops.c
author Eric Wing <ewing . public |-at-| gmail . com>
Sat, 08 May 2010 00:54:22 -0700
changeset 4447 947201caa46e
parent 3697 f7b03b6838cb
child 4454 be387681d876
permissions -rw-r--r--
Added automated test to Xcode project plus needed changes to SDL_RWFromFile to be OS X bundle aware.

The Mac OS X project has a new target called testsdl which builds the automated test. I looked at using Xcode's native unit test support, but the impedance mismatch between the existing automated test structure and Apple's was more than I could handle.

As such, the testsdl application is a full blown proper OS X application, which means it is a self-contained .app bundle. This immediately revealed some problems from the automated test. The largest problem was the assumption about the current working directory and where to find resources. (I suspect Windows may have a similar problem depending on circumstance.) To open resources, the test was looking in directories relative to the SDL source directory, but this will not work well with self-contained .app bundles and Xcode which can place its built applications almost anywhere. And for real-world situations, this is pretty useless anyway.

So I modified SDL_RWFromFile to do special things on OS X. First, it will look for a file in the .app bundle. If not found, it will fallback and just call fopen as it used to do.

I also had to modify the automated test itself because it had a contrieved test which called fopen directly to do read from an existing FILE pointer. In addition, there was a write test. Since a .app bundle is likely going to be read-only, I added a special case for OS X to write to NSTemporaryDirectory.

I expect these changes should work for both Mac and iPhone OS (which includes iPad).

I will update the iPhone Xcode project next.

Finally, FYI, the X11 automated test seems to be failing. Below is my output.


Pending breakpoint 4 - "-[NSException raise]" resolved
Platform : All tests successful (2)
SDL_RWops : All tests successful (5)
Rect : All tests successful (1)
SDL_Surface : All tests successful (6)
Rendering with cocoa driver : All tests successful (3)
Assert Failed!
Blit output not the same.
Test Case 'Renderer x11'
Test Suite 'Rendering with x11 driver'
Last SDL error ''
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSGetSurfaceBounds
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorFailure: Set a breakpoint @ CGErrorBreakpoint() to catch errors as they are logged.
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSGetWindowBounds
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSGetSurfaceBounds
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSGetWindowBounds
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSGetSurfaceBounds
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSGetWindowBounds
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSGetSurfaceBounds
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSGetWindowBounds
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSGetSurfaceBounds
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSGetWindowBounds
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSGetSurfaceBounds
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSGetWindowBounds
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSGetSurfaceBounds
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Sat May 8 00:30:34 iMacAL.local testsdl[71586] <Error>: kCGErrorIllegalArgument: CGSBindSurface: Invalid window 0xa150
Rendering with x11 driver : Failed 1 out of 4 testcases!
Rendering with dummy driver : All tests successful (3)
SDL_Audio : All tests successful (1)
Tests run with SDL 1.3.0 revision 1095906
System is running Mac OS X and is little endian
slouken@0
     1
/*
slouken@0
     2
    SDL - Simple DirectMedia Layer
slouken@3697
     3
    Copyright (C) 1997-2010 Sam Lantinga
slouken@0
     4
slouken@0
     5
    This library is free software; you can redistribute it and/or
slouken@1312
     6
    modify it under the terms of the GNU Lesser General Public
slouken@0
     7
    License as published by the Free Software Foundation; either
slouken@1312
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@0
     9
slouken@0
    10
    This library is distributed in the hope that it will be useful,
slouken@0
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@0
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1312
    13
    Lesser General Public License for more details.
slouken@0
    14
slouken@1312
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1312
    16
    License along with this library; if not, write to the Free Software
slouken@1312
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@0
    18
slouken@0
    19
    Sam Lantinga
slouken@252
    20
    slouken@libsdl.org
slouken@0
    21
*/
slouken@1402
    22
#include "SDL_config.h"
slouken@0
    23
slouken@0
    24
/* This file provides a general interface for SDL to read and write
slouken@0
    25
   data sources.  It can easily be extended to files, memory, etc.
slouken@0
    26
*/
slouken@0
    27
slouken@1354
    28
#include "SDL_endian.h"
slouken@0
    29
#include "SDL_rwops.h"
slouken@1330
    30
ewing@4447
    31
#ifdef __APPLE__
ewing@4447
    32
#include "SDL_rwopsbundlesupport.h"
ewing@4447
    33
#endif /* __APPLE__ */
ewing@4447
    34
slouken@2735
    35
#ifdef __NDS__
slouken@2735
    36
/* include libfat headers for fatInitDefault(). */
slouken@2735
    37
#include <fat.h>
slouken@2735
    38
#endif /* __NDS__ */
slouken@1354
    39
slouken@2159
    40
#ifdef __WIN32__
slouken@0
    41
slouken@1447
    42
/* Functions to read/write Win32 API file pointers */
slouken@1465
    43
/* Will not use it on WinCE because stdio is buffered, it means
slouken@1465
    44
   faster, and all stdio functions anyway are embedded in coredll.dll - 
slouken@1465
    45
   the main wince dll*/
slouken@0
    46
slouken@1446
    47
#define WINDOWS_LEAN_AND_MEAN
slouken@1446
    48
#include <windows.h>
slouken@1446
    49
slouken@1465
    50
#ifndef INVALID_SET_FILE_POINTER
slouken@1465
    51
#define INVALID_SET_FILE_POINTER 0xFFFFFFFF
slouken@1465
    52
#endif
slouken@1465
    53
slouken@2159
    54
#define READAHEAD_BUFFER_SIZE	1024
slouken@2159
    55
slouken@1895
    56
static int SDLCALL
slouken@1895
    57
win32_file_open(SDL_RWops * context, const char *filename, const char *mode)
slouken@1465
    58
{
slouken@1465
    59
#ifndef _WIN32_WCE
slouken@1895
    60
    UINT old_error_mode;
slouken@1465
    61
#endif
slouken@1895
    62
    HANDLE h;
slouken@1895
    63
    DWORD r_right, w_right;
slouken@1895
    64
    DWORD must_exist, truncate;
slouken@1895
    65
    int a_mode;
slouken@1446
    66
slouken@1895
    67
    if (!context)
slouken@2164
    68
        return -1;              /* failed (invalid call) */
slouken@2159
    69
slouken@2173
    70
    context->hidden.win32io.h = INVALID_HANDLE_VALUE;   /* mark this as unusable */
icculus@2165
    71
    context->hidden.win32io.buffer.data = NULL;
icculus@2165
    72
    context->hidden.win32io.buffer.size = 0;
icculus@2165
    73
    context->hidden.win32io.buffer.left = 0;
icculus@2165
    74
slouken@1895
    75
    /* "r" = reading, file must exist */
slouken@1895
    76
    /* "w" = writing, truncate existing, file may not exist */
slouken@1895
    77
    /* "r+"= reading or writing, file must exist            */
slouken@1895
    78
    /* "a" = writing, append file may not exist             */
slouken@1895
    79
    /* "a+"= append + read, file may not exist              */
slouken@1895
    80
    /* "w+" = read, write, truncate. file may not exist    */
slouken@1895
    81
slouken@1895
    82
    must_exist = (SDL_strchr(mode, 'r') != NULL) ? OPEN_EXISTING : 0;
slouken@1895
    83
    truncate = (SDL_strchr(mode, 'w') != NULL) ? CREATE_ALWAYS : 0;
slouken@1895
    84
    r_right = (SDL_strchr(mode, '+') != NULL
slouken@1895
    85
               || must_exist) ? GENERIC_READ : 0;
slouken@1895
    86
    a_mode = (SDL_strchr(mode, 'a') != NULL) ? OPEN_ALWAYS : 0;
slouken@1895
    87
    w_right = (a_mode || SDL_strchr(mode, '+')
slouken@1895
    88
               || truncate) ? GENERIC_WRITE : 0;
slouken@1895
    89
slouken@1895
    90
    if (!r_right && !w_right)   /* inconsistent mode */
slouken@1895
    91
        return -1;              /* failed (invalid call) */
slouken@1465
    92
slouken@2173
    93
    context->hidden.win32io.buffer.data =
slouken@2173
    94
        (char *) SDL_malloc(READAHEAD_BUFFER_SIZE);
icculus@2165
    95
    if (!context->hidden.win32io.buffer.data) {
icculus@2165
    96
        SDL_OutOfMemory();
icculus@2165
    97
        return -1;
icculus@2165
    98
    }
slouken@1465
    99
#ifdef _WIN32_WCE
slouken@1895
   100
    {
slouken@1895
   101
        size_t size = SDL_strlen(filename) + 1;
slouken@1895
   102
        wchar_t *filenameW = SDL_stack_alloc(wchar_t, size);
slouken@1465
   103
slouken@1895
   104
        if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, size) ==
slouken@1895
   105
            0) {
icculus@2165
   106
            SDL_stack_free(filenameW);
icculus@2165
   107
            SDL_free(context->hidden.win32io.buffer.data);
icculus@2165
   108
            context->hidden.win32io.buffer.data = NULL;
slouken@1895
   109
            SDL_SetError("Unable to convert filename to Unicode");
slouken@1895
   110
            return -1;
slouken@1895
   111
        }
slouken@1895
   112
        h = CreateFile(filenameW, (w_right | r_right),
slouken@1895
   113
                       (w_right) ? 0 : FILE_SHARE_READ, NULL,
slouken@1895
   114
                       (must_exist | truncate | a_mode),
slouken@1895
   115
                       FILE_ATTRIBUTE_NORMAL, NULL);
slouken@1895
   116
        SDL_stack_free(filenameW);
slouken@1895
   117
    }
slouken@1465
   118
#else
slouken@1895
   119
    /* Do not open a dialog box if failure */
slouken@1895
   120
    old_error_mode =
slouken@1895
   121
        SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
slouken@1465
   122
slouken@1895
   123
    h = CreateFile(filename, (w_right | r_right),
slouken@1895
   124
                   (w_right) ? 0 : FILE_SHARE_READ, NULL,
slouken@1895
   125
                   (must_exist | truncate | a_mode), FILE_ATTRIBUTE_NORMAL,
slouken@1895
   126
                   NULL);
slouken@1465
   127
slouken@1895
   128
    /* restore old behaviour */
slouken@1895
   129
    SetErrorMode(old_error_mode);
slouken@1465
   130
#endif /* _WIN32_WCE */
slouken@1446
   131
slouken@1895
   132
    if (h == INVALID_HANDLE_VALUE) {
icculus@2165
   133
        SDL_free(context->hidden.win32io.buffer.data);
icculus@2165
   134
        context->hidden.win32io.buffer.data = NULL;
slouken@1895
   135
        SDL_SetError("Couldn't open %s", filename);
slouken@1895
   136
        return -2;              /* failed (CreateFile) */
slouken@1895
   137
    }
slouken@1895
   138
    context->hidden.win32io.h = h;
slouken@2161
   139
    context->hidden.win32io.append = a_mode ? SDL_TRUE : SDL_FALSE;
slouken@1895
   140
slouken@1895
   141
    return 0;                   /* ok */
slouken@1446
   142
}
slouken@2735
   143
slouken@2160
   144
static long SDLCALL
slouken@2160
   145
win32_file_seek(SDL_RWops * context, long offset, int whence)
slouken@1465
   146
{
slouken@1895
   147
    DWORD win32whence;
slouken@2160
   148
    long file_pos;
slouken@1446
   149
slouken@1895
   150
    if (!context || context->hidden.win32io.h == INVALID_HANDLE_VALUE) {
slouken@1895
   151
        SDL_SetError("win32_file_seek: invalid context/file not opened");
slouken@1895
   152
        return -1;
slouken@1895
   153
    }
slouken@1895
   154
slouken@2159
   155
    /* FIXME: We may be able to satisfy the seek within buffered data */
slouken@2159
   156
    if (whence == RW_SEEK_CUR && context->hidden.win32io.buffer.left) {
slouken@3253
   157
        offset -= (long)context->hidden.win32io.buffer.left;
slouken@2159
   158
    }
slouken@2159
   159
    context->hidden.win32io.buffer.left = 0;
slouken@2159
   160
slouken@1895
   161
    switch (whence) {
slouken@1895
   162
    case RW_SEEK_SET:
slouken@1895
   163
        win32whence = FILE_BEGIN;
slouken@1895
   164
        break;
slouken@1895
   165
    case RW_SEEK_CUR:
slouken@1895
   166
        win32whence = FILE_CURRENT;
slouken@1895
   167
        break;
slouken@1895
   168
    case RW_SEEK_END:
slouken@1895
   169
        win32whence = FILE_END;
slouken@1895
   170
        break;
slouken@1895
   171
    default:
slouken@1895
   172
        SDL_SetError("win32_file_seek: Unknown value for 'whence'");
slouken@1895
   173
        return -1;
slouken@1895
   174
    }
slouken@1895
   175
slouken@1895
   176
    file_pos =
slouken@1895
   177
        SetFilePointer(context->hidden.win32io.h, offset, NULL, win32whence);
slouken@1895
   178
slouken@1895
   179
    if (file_pos != INVALID_SET_FILE_POINTER)
slouken@1895
   180
        return file_pos;        /* success */
slouken@1895
   181
slouken@1895
   182
    SDL_Error(SDL_EFSEEK);
slouken@1895
   183
    return -1;                  /* error */
slouken@1446
   184
}
slouken@2735
   185
slouken@2160
   186
static size_t SDLCALL
slouken@2160
   187
win32_file_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
slouken@1465
   188
{
slouken@2160
   189
    size_t total_need;
slouken@2160
   190
    size_t total_read = 0;
slouken@2160
   191
    size_t read_ahead;
slouken@2159
   192
    DWORD byte_read;
slouken@1895
   193
slouken@2159
   194
    total_need = size * maxnum;
slouken@1895
   195
slouken@1895
   196
    if (!context || context->hidden.win32io.h == INVALID_HANDLE_VALUE
slouken@2160
   197
        || !total_need)
slouken@1895
   198
        return 0;
slouken@1895
   199
slouken@2159
   200
    if (context->hidden.win32io.buffer.left > 0) {
slouken@2159
   201
        void *data = (char *) context->hidden.win32io.buffer.data +
slouken@2159
   202
            context->hidden.win32io.buffer.size -
slouken@2159
   203
            context->hidden.win32io.buffer.left;
bob@2185
   204
        read_ahead =
slouken@3253
   205
            SDL_min(total_need, context->hidden.win32io.buffer.left);
slouken@2159
   206
        SDL_memcpy(ptr, data, read_ahead);
slouken@2159
   207
        context->hidden.win32io.buffer.left -= read_ahead;
slouken@2159
   208
slouken@2159
   209
        if (read_ahead == total_need) {
slouken@2159
   210
            return maxnum;
slouken@2159
   211
        }
slouken@2159
   212
        ptr = (char *) ptr + read_ahead;
slouken@2159
   213
        total_need -= read_ahead;
slouken@2159
   214
        total_read += read_ahead;
slouken@1895
   215
    }
slouken@2159
   216
slouken@2159
   217
    if (total_need < READAHEAD_BUFFER_SIZE) {
slouken@2159
   218
        if (!ReadFile
slouken@2159
   219
            (context->hidden.win32io.h, context->hidden.win32io.buffer.data,
slouken@2159
   220
             READAHEAD_BUFFER_SIZE, &byte_read, NULL)) {
slouken@2159
   221
            SDL_Error(SDL_EFREAD);
slouken@2159
   222
            return 0;
slouken@2159
   223
        }
slouken@2159
   224
        read_ahead = SDL_min(total_need, (int) byte_read);
slouken@2159
   225
        SDL_memcpy(ptr, context->hidden.win32io.buffer.data, read_ahead);
slouken@2159
   226
        context->hidden.win32io.buffer.size = byte_read;
slouken@2159
   227
        context->hidden.win32io.buffer.left = byte_read - read_ahead;
slouken@2159
   228
        total_read += read_ahead;
slouken@2159
   229
    } else {
slouken@2159
   230
        if (!ReadFile
slouken@3253
   231
            (context->hidden.win32io.h, ptr, (DWORD)total_need, &byte_read, NULL)) {
slouken@2159
   232
            SDL_Error(SDL_EFREAD);
slouken@2159
   233
            return 0;
slouken@2159
   234
        }
slouken@2159
   235
        total_read += byte_read;
slouken@2159
   236
    }
slouken@2159
   237
    return (total_read / size);
slouken@1446
   238
}
slouken@2735
   239
slouken@2160
   240
static size_t SDLCALL
slouken@2160
   241
win32_file_write(SDL_RWops * context, const void *ptr, size_t size,
slouken@2160
   242
                 size_t num)
slouken@1465
   243
{
slouken@1446
   244
slouken@2160
   245
    size_t total_bytes;
slouken@3253
   246
    DWORD byte_written;
slouken@3253
   247
    size_t nwritten;
slouken@1446
   248
slouken@1895
   249
    total_bytes = size * num;
slouken@1895
   250
slouken@1895
   251
    if (!context || context->hidden.win32io.h == INVALID_HANDLE_VALUE
slouken@1895
   252
        || total_bytes <= 0 || !size)
slouken@1895
   253
        return 0;
slouken@1895
   254
slouken@2159
   255
    if (context->hidden.win32io.buffer.left) {
slouken@2159
   256
        SetFilePointer(context->hidden.win32io.h,
slouken@3253
   257
                       -(LONG)context->hidden.win32io.buffer.left, NULL,
slouken@2159
   258
                       FILE_CURRENT);
slouken@2159
   259
        context->hidden.win32io.buffer.left = 0;
slouken@2159
   260
    }
slouken@2159
   261
slouken@1895
   262
    /* if in append mode, we must go to the EOF before write */
slouken@1895
   263
    if (context->hidden.win32io.append) {
slouken@2159
   264
        if (SetFilePointer(context->hidden.win32io.h, 0L, NULL, FILE_END) ==
slouken@2159
   265
            INVALID_SET_FILE_POINTER) {
slouken@1895
   266
            SDL_Error(SDL_EFWRITE);
slouken@1895
   267
            return 0;
slouken@1895
   268
        }
slouken@1895
   269
    }
slouken@1895
   270
slouken@1895
   271
    if (!WriteFile
slouken@3253
   272
        (context->hidden.win32io.h, ptr, (DWORD)total_bytes, &byte_written, NULL)) {
slouken@1895
   273
        SDL_Error(SDL_EFWRITE);
slouken@1895
   274
        return 0;
slouken@1895
   275
    }
slouken@1895
   276
slouken@1895
   277
    nwritten = byte_written / size;
slouken@1895
   278
    return nwritten;
slouken@1446
   279
}
slouken@2735
   280
slouken@1895
   281
static int SDLCALL
slouken@1895
   282
win32_file_close(SDL_RWops * context)
slouken@1465
   283
{
slouken@1895
   284
slouken@1895
   285
    if (context) {
slouken@1895
   286
        if (context->hidden.win32io.h != INVALID_HANDLE_VALUE) {
slouken@1895
   287
            CloseHandle(context->hidden.win32io.h);
slouken@1895
   288
            context->hidden.win32io.h = INVALID_HANDLE_VALUE;   /* to be sure */
slouken@1895
   289
        }
slouken@2159
   290
        if (context->hidden.win32io.buffer.data) {
slouken@2159
   291
            SDL_free(context->hidden.win32io.buffer.data);
slouken@2159
   292
            context->hidden.win32io.buffer.data = NULL;
slouken@2159
   293
        }
slouken@1895
   294
        SDL_FreeRW(context);
slouken@1895
   295
    }
slouken@1895
   296
    return (0);
slouken@1446
   297
}
slouken@1447
   298
#endif /* __WIN32__ */
slouken@1446
   299
slouken@1447
   300
#ifdef HAVE_STDIO_H
slouken@1446
   301
slouken@1447
   302
/* Functions to read/write stdio file pointers */
slouken@1446
   303
slouken@2160
   304
static long SDLCALL
slouken@2160
   305
stdio_seek(SDL_RWops * context, long offset, int whence)
slouken@1447
   306
{
slouken@1895
   307
    if (fseek(context->hidden.stdio.fp, offset, whence) == 0) {
slouken@1895
   308
        return (ftell(context->hidden.stdio.fp));
slouken@1895
   309
    } else {
slouken@1895
   310
        SDL_Error(SDL_EFSEEK);
slouken@1895
   311
        return (-1);
slouken@1895
   312
    }
slouken@1447
   313
}
slouken@2735
   314
slouken@2160
   315
static size_t SDLCALL
slouken@2160
   316
stdio_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
slouken@1447
   317
{
slouken@1895
   318
    size_t nread;
slouken@1447
   319
slouken@1895
   320
    nread = fread(ptr, size, maxnum, context->hidden.stdio.fp);
slouken@1895
   321
    if (nread == 0 && ferror(context->hidden.stdio.fp)) {
slouken@1895
   322
        SDL_Error(SDL_EFREAD);
slouken@1895
   323
    }
slouken@1895
   324
    return (nread);
slouken@1447
   325
}
slouken@2735
   326
slouken@2160
   327
static size_t SDLCALL
slouken@2160
   328
stdio_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
slouken@1447
   329
{
slouken@1895
   330
    size_t nwrote;
slouken@1447
   331
slouken@1895
   332
    nwrote = fwrite(ptr, size, num, context->hidden.stdio.fp);
slouken@1895
   333
    if (nwrote == 0 && ferror(context->hidden.stdio.fp)) {
slouken@1895
   334
        SDL_Error(SDL_EFWRITE);
slouken@1895
   335
    }
slouken@1895
   336
    return (nwrote);
slouken@1447
   337
}
slouken@2735
   338
slouken@1895
   339
static int SDLCALL
slouken@1895
   340
stdio_close(SDL_RWops * context)
slouken@1447
   341
{
slouken@2160
   342
    int status = 0;
slouken@1895
   343
    if (context) {
slouken@1895
   344
        if (context->hidden.stdio.autoclose) {
slouken@1895
   345
            /* WARNING:  Check the return value here! */
slouken@2160
   346
            if (fclose(context->hidden.stdio.fp) != 0) {
slouken@2160
   347
                SDL_Error(SDL_EFWRITE);
slouken@2160
   348
                status = -1;
slouken@2160
   349
            }
slouken@1895
   350
        }
slouken@1895
   351
        SDL_FreeRW(context);
slouken@1895
   352
    }
slouken@2160
   353
    return status;
slouken@1447
   354
}
slouken@1446
   355
#endif /* !HAVE_STDIO_H */
slouken@1330
   356
slouken@0
   357
/* Functions to read/write memory pointers */
slouken@0
   358
slouken@2160
   359
static long SDLCALL
slouken@2160
   360
mem_seek(SDL_RWops * context, long offset, int whence)
slouken@0
   361
{
slouken@1895
   362
    Uint8 *newpos;
slouken@0
   363
slouken@1895
   364
    switch (whence) {
slouken@1895
   365
    case RW_SEEK_SET:
slouken@1895
   366
        newpos = context->hidden.mem.base + offset;
slouken@1895
   367
        break;
slouken@1895
   368
    case RW_SEEK_CUR:
slouken@1895
   369
        newpos = context->hidden.mem.here + offset;
slouken@1895
   370
        break;
slouken@1895
   371
    case RW_SEEK_END:
slouken@1895
   372
        newpos = context->hidden.mem.stop + offset;
slouken@1895
   373
        break;
slouken@1895
   374
    default:
slouken@1895
   375
        SDL_SetError("Unknown value for 'whence'");
slouken@1895
   376
        return (-1);
slouken@1895
   377
    }
slouken@1895
   378
    if (newpos < context->hidden.mem.base) {
slouken@1895
   379
        newpos = context->hidden.mem.base;
slouken@1895
   380
    }
slouken@1895
   381
    if (newpos > context->hidden.mem.stop) {
slouken@1895
   382
        newpos = context->hidden.mem.stop;
slouken@1895
   383
    }
slouken@1895
   384
    context->hidden.mem.here = newpos;
slouken@3253
   385
    return (long)(context->hidden.mem.here - context->hidden.mem.base);
slouken@0
   386
}
slouken@2735
   387
slouken@2160
   388
static size_t SDLCALL
slouken@2160
   389
mem_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
slouken@0
   390
{
slouken@1895
   391
    size_t total_bytes;
slouken@1895
   392
    size_t mem_available;
slouken@0
   393
slouken@1895
   394
    total_bytes = (maxnum * size);
slouken@1895
   395
    if ((maxnum <= 0) || (size <= 0)
slouken@1895
   396
        || ((total_bytes / maxnum) != (size_t) size)) {
slouken@1895
   397
        return 0;
slouken@1895
   398
    }
icculus@1078
   399
slouken@1895
   400
    mem_available = (context->hidden.mem.stop - context->hidden.mem.here);
slouken@1895
   401
    if (total_bytes > mem_available) {
slouken@1895
   402
        total_bytes = mem_available;
slouken@1895
   403
    }
icculus@1078
   404
slouken@1895
   405
    SDL_memcpy(ptr, context->hidden.mem.here, total_bytes);
slouken@1895
   406
    context->hidden.mem.here += total_bytes;
icculus@1078
   407
slouken@1895
   408
    return (total_bytes / size);
slouken@0
   409
}
slouken@2735
   410
slouken@2160
   411
static size_t SDLCALL
slouken@2160
   412
mem_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
slouken@0
   413
{
slouken@1895
   414
    if ((context->hidden.mem.here + (num * size)) > context->hidden.mem.stop) {
slouken@1895
   415
        num = (context->hidden.mem.stop - context->hidden.mem.here) / size;
slouken@1895
   416
    }
slouken@1895
   417
    SDL_memcpy(context->hidden.mem.here, ptr, num * size);
slouken@1895
   418
    context->hidden.mem.here += num * size;
slouken@1895
   419
    return (num);
slouken@0
   420
}
slouken@2735
   421
slouken@2160
   422
static size_t SDLCALL
slouken@2160
   423
mem_writeconst(SDL_RWops * context, const void *ptr, size_t size, size_t num)
slouken@764
   424
{
slouken@1895
   425
    SDL_SetError("Can't write to read-only memory");
slouken@1895
   426
    return (-1);
slouken@764
   427
}
slouken@2735
   428
slouken@1895
   429
static int SDLCALL
slouken@1895
   430
mem_close(SDL_RWops * context)
slouken@0
   431
{
slouken@1895
   432
    if (context) {
slouken@1895
   433
        SDL_FreeRW(context);
slouken@1895
   434
    }
slouken@1895
   435
    return (0);
slouken@0
   436
}
slouken@0
   437
slouken@1447
   438
slouken@0
   439
/* Functions to create SDL_RWops structures from various data sources */
slouken@0
   440
slouken@1895
   441
SDL_RWops *
slouken@1895
   442
SDL_RWFromFile(const char *file, const char *mode)
slouken@0
   443
{
slouken@1895
   444
    SDL_RWops *rwops = NULL;
slouken@1465
   445
#ifdef HAVE_STDIO_H
slouken@1895
   446
    FILE *fp = NULL;
slouken@1465
   447
#endif
slouken@1895
   448
    if (!file || !*file || !mode || !*mode) {
slouken@1895
   449
        SDL_SetError("SDL_RWFromFile(): No file or no mode specified");
slouken@1895
   450
        return NULL;
slouken@1895
   451
    }
slouken@1465
   452
#if defined(__WIN32__)
slouken@1895
   453
    rwops = SDL_AllocRW();
slouken@1895
   454
    if (!rwops)
slouken@1895
   455
        return NULL;            /* SDL_SetError already setup by SDL_AllocRW() */
slouken@2164
   456
    if (win32_file_open(rwops, file, mode) < 0) {
slouken@1895
   457
        SDL_FreeRW(rwops);
slouken@1895
   458
        return NULL;
slouken@1895
   459
    }
slouken@1895
   460
    rwops->seek = win32_file_seek;
slouken@1895
   461
    rwops->read = win32_file_read;
slouken@1895
   462
    rwops->write = win32_file_write;
slouken@1895
   463
    rwops->close = win32_file_close;
slouken@1447
   464
slouken@1447
   465
#elif HAVE_STDIO_H
ewing@4447
   466
	#ifdef __APPLE__
ewing@4447
   467
	fp = SDL_OpenFPFromBundleOrFallback(file, mode);
ewing@4447
   468
    #else
ewing@4447
   469
	fp = fopen(file, mode);
ewing@4447
   470
	#endif
ewing@4447
   471
	if (fp == NULL) {
slouken@1895
   472
        SDL_SetError("Couldn't open %s", file);
slouken@1895
   473
    } else {
slouken@1895
   474
        rwops = SDL_RWFromFP(fp, 1);
slouken@1895
   475
    }
slouken@0
   476
#else
slouken@1895
   477
    SDL_SetError("SDL not compiled with stdio support");
slouken@1446
   478
#endif /* !HAVE_STDIO_H */
slouken@1447
   479
slouken@1895
   480
    return (rwops);
slouken@0
   481
}
slouken@0
   482
slouken@1330
   483
#ifdef HAVE_STDIO_H
slouken@1895
   484
SDL_RWops *
slouken@2161
   485
SDL_RWFromFP(FILE * fp, SDL_bool autoclose)
slouken@0
   486
{
slouken@1895
   487
    SDL_RWops *rwops = NULL;
slouken@0
   488
slouken@2735
   489
#if 0
slouken@2735
   490
/*#ifdef __NDS__*/
slouken@2735
   491
    /* set it up so we can use stdio file function */
slouken@2735
   492
    fatInitDefault();
slouken@2735
   493
    printf("called fatInitDefault()");
slouken@2735
   494
#endif /* __NDS__ */
slouken@2735
   495
slouken@1895
   496
    rwops = SDL_AllocRW();
slouken@1895
   497
    if (rwops != NULL) {
slouken@1895
   498
        rwops->seek = stdio_seek;
slouken@1895
   499
        rwops->read = stdio_read;
slouken@1895
   500
        rwops->write = stdio_write;
slouken@1895
   501
        rwops->close = stdio_close;
slouken@1895
   502
        rwops->hidden.stdio.fp = fp;
slouken@1895
   503
        rwops->hidden.stdio.autoclose = autoclose;
slouken@1895
   504
    }
slouken@1895
   505
    return (rwops);
slouken@0
   506
}
slouken@3564
   507
#else
slouken@3564
   508
SDL_RWops *
slouken@3564
   509
SDL_RWFromFP(void * fp, SDL_bool autoclose)
slouken@3564
   510
{
slouken@3564
   511
    SDL_SetError("SDL not compiled with stdio support");
slouken@3564
   512
    return NULL;
slouken@3564
   513
}
slouken@1330
   514
#endif /* HAVE_STDIO_H */
slouken@0
   515
slouken@1895
   516
SDL_RWops *
slouken@1895
   517
SDL_RWFromMem(void *mem, int size)
slouken@0
   518
{
slouken@1895
   519
    SDL_RWops *rwops;
slouken@0
   520
slouken@1895
   521
    rwops = SDL_AllocRW();
slouken@1895
   522
    if (rwops != NULL) {
slouken@1895
   523
        rwops->seek = mem_seek;
slouken@1895
   524
        rwops->read = mem_read;
slouken@1895
   525
        rwops->write = mem_write;
slouken@1895
   526
        rwops->close = mem_close;
slouken@1895
   527
        rwops->hidden.mem.base = (Uint8 *) mem;
slouken@1895
   528
        rwops->hidden.mem.here = rwops->hidden.mem.base;
slouken@1895
   529
        rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
slouken@1895
   530
    }
slouken@1895
   531
    return (rwops);
slouken@0
   532
}
slouken@0
   533
slouken@1895
   534
SDL_RWops *
slouken@1895
   535
SDL_RWFromConstMem(const void *mem, int size)
slouken@764
   536
{
slouken@1895
   537
    SDL_RWops *rwops;
slouken@764
   538
slouken@1895
   539
    rwops = SDL_AllocRW();
slouken@1895
   540
    if (rwops != NULL) {
slouken@1895
   541
        rwops->seek = mem_seek;
slouken@1895
   542
        rwops->read = mem_read;
slouken@1895
   543
        rwops->write = mem_writeconst;
slouken@1895
   544
        rwops->close = mem_close;
slouken@1895
   545
        rwops->hidden.mem.base = (Uint8 *) mem;
slouken@1895
   546
        rwops->hidden.mem.here = rwops->hidden.mem.base;
slouken@1895
   547
        rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
slouken@1895
   548
    }
slouken@1895
   549
    return (rwops);
slouken@764
   550
}
slouken@764
   551
slouken@1895
   552
SDL_RWops *
slouken@1895
   553
SDL_AllocRW(void)
slouken@0
   554
{
slouken@1895
   555
    SDL_RWops *area;
slouken@0
   556
slouken@1895
   557
    area = (SDL_RWops *) SDL_malloc(sizeof *area);
slouken@1895
   558
    if (area == NULL) {
slouken@1895
   559
        SDL_OutOfMemory();
slouken@1895
   560
    }
slouken@1895
   561
    return (area);
slouken@0
   562
}
slouken@0
   563
slouken@1895
   564
void
slouken@1895
   565
SDL_FreeRW(SDL_RWops * area)
slouken@0
   566
{
slouken@1895
   567
    SDL_free(area);
slouken@0
   568
}
slouken@1354
   569
slouken@1354
   570
/* Functions for dynamically reading and writing endian-specific values */
slouken@1354
   571
slouken@1895
   572
Uint16
slouken@1895
   573
SDL_ReadLE16(SDL_RWops * src)
slouken@1354
   574
{
slouken@1895
   575
    Uint16 value;
slouken@1354
   576
slouken@1895
   577
    SDL_RWread(src, &value, (sizeof value), 1);
slouken@1895
   578
    return (SDL_SwapLE16(value));
slouken@1354
   579
}
slouken@1354
   580
slouken@1895
   581
Uint16
slouken@1895
   582
SDL_ReadBE16(SDL_RWops * src)
slouken@1354
   583
{
slouken@1895
   584
    Uint16 value;
slouken@1895
   585
slouken@1895
   586
    SDL_RWread(src, &value, (sizeof value), 1);
slouken@1895
   587
    return (SDL_SwapBE16(value));
slouken@1354
   588
}
slouken@1895
   589
slouken@1895
   590
Uint32
slouken@1895
   591
SDL_ReadLE32(SDL_RWops * src)
slouken@1354
   592
{
slouken@1895
   593
    Uint32 value;
slouken@1895
   594
slouken@1895
   595
    SDL_RWread(src, &value, (sizeof value), 1);
slouken@1895
   596
    return (SDL_SwapLE32(value));
slouken@1354
   597
}
slouken@1895
   598
slouken@1895
   599
Uint32
slouken@1895
   600
SDL_ReadBE32(SDL_RWops * src)
slouken@1354
   601
{
slouken@1895
   602
    Uint32 value;
slouken@1895
   603
slouken@1895
   604
    SDL_RWread(src, &value, (sizeof value), 1);
slouken@1895
   605
    return (SDL_SwapBE32(value));
slouken@1354
   606
}
slouken@1895
   607
slouken@1895
   608
Uint64
slouken@1895
   609
SDL_ReadLE64(SDL_RWops * src)
slouken@1354
   610
{
slouken@1895
   611
    Uint64 value;
slouken@1895
   612
slouken@1895
   613
    SDL_RWread(src, &value, (sizeof value), 1);
slouken@1895
   614
    return (SDL_SwapLE64(value));
slouken@1354
   615
}
slouken@1895
   616
slouken@1895
   617
Uint64
slouken@1895
   618
SDL_ReadBE64(SDL_RWops * src)
slouken@1354
   619
{
slouken@1895
   620
    Uint64 value;
slouken@1895
   621
slouken@1895
   622
    SDL_RWread(src, &value, (sizeof value), 1);
slouken@1895
   623
    return (SDL_SwapBE64(value));
slouken@1354
   624
}
slouken@1895
   625
slouken@3253
   626
size_t
slouken@1895
   627
SDL_WriteLE16(SDL_RWops * dst, Uint16 value)
slouken@1354
   628
{
slouken@1895
   629
    value = SDL_SwapLE16(value);
slouken@1895
   630
    return (SDL_RWwrite(dst, &value, (sizeof value), 1));
slouken@1354
   631
}
slouken@1895
   632
slouken@3253
   633
size_t
slouken@1895
   634
SDL_WriteBE16(SDL_RWops * dst, Uint16 value)
slouken@1895
   635
{
slouken@1895
   636
    value = SDL_SwapBE16(value);
slouken@1895
   637
    return (SDL_RWwrite(dst, &value, (sizeof value), 1));
slouken@1895
   638
}
slouken@1895
   639
slouken@3253
   640
size_t
slouken@1895
   641
SDL_WriteLE32(SDL_RWops * dst, Uint32 value)
slouken@1895
   642
{
slouken@1895
   643
    value = SDL_SwapLE32(value);
slouken@1895
   644
    return (SDL_RWwrite(dst, &value, (sizeof value), 1));
slouken@1895
   645
}
slouken@1895
   646
slouken@3253
   647
size_t
slouken@1895
   648
SDL_WriteBE32(SDL_RWops * dst, Uint32 value)
slouken@1895
   649
{
slouken@1895
   650
    value = SDL_SwapBE32(value);
slouken@1895
   651
    return (SDL_RWwrite(dst, &value, (sizeof value), 1));
slouken@1895
   652
}
slouken@1895
   653
slouken@3253
   654
size_t
slouken@1895
   655
SDL_WriteLE64(SDL_RWops * dst, Uint64 value)
slouken@1895
   656
{
slouken@1895
   657
    value = SDL_SwapLE64(value);
slouken@1895
   658
    return (SDL_RWwrite(dst, &value, (sizeof value), 1));
slouken@1895
   659
}
slouken@1895
   660
slouken@3253
   661
size_t
slouken@1895
   662
SDL_WriteBE64(SDL_RWops * dst, Uint64 value)
slouken@1895
   663
{
slouken@1895
   664
    value = SDL_SwapBE64(value);
slouken@1895
   665
    return (SDL_RWwrite(dst, &value, (sizeof value), 1));
slouken@1895
   666
}
slouken@1895
   667
slouken@1895
   668
/* vi: set ts=4 sw=4 expandtab: */